def __delete_page(self, page_id, trash_ancestor): """ Delete a page by moving it to the orphan folder :param page_id: confluence page id :return: None """ LOGGER.info('Moving page %s to ORPHAN...', page_id) url = '%s/rest/api/content/%s?expand=version' % (CONFLUENCE_API_URL, page_id) response = common.make_request_get(url) data = response.json() LOGGER.debug("data: %s", str(data)) page_id = data[u'id'] version = data[u'version'][u'number'] title = data[u'title'] ancestors = common.get_page_as_ancestor(trash_ancestor) url = '%s/rest/api/content/%s' % (CONFLUENCE_API_URL, page_id) page_json = { "id": page_id, "type": "page", "title": title, "version": { "number": version + 1, "minorEdit": True }, 'ancestors': ancestors } LOGGER.debug("data: %s", json.dumps(page_json)) common.make_request_put(url, data=json.dumps(page_json))
def __get_attachment(self, page_id, filename): """ Get page attachment :param page_id: confluence page id :param filename: attachment filename :return: attachment info in case of success, False otherwise """ url = '%s/rest/api/content/%s/child/attachment?filename=%s' \ '&expand=metadata.properties.hash' \ % (CONFLUENCE_API_URL, page_id, filename) response = common.make_request_get(url) data = response.json() LOGGER.debug('data: %s', str(data)) if len(data[u'results']) >= 1: data = data[u'results'][0] att_id = data[u'id'] att_hash = None props = data[u'metadata'][u'properties'] if u'hash' in props: hash_prop = props[u'hash'][u'value'] if u'sha256' in hash_prop: att_hash = hash_prop[u'sha256'] att_info = collections.namedtuple('AttachmentInfo', ['id', 'hash']) attr_info = att_info(att_id, att_hash) return attr_info return False
def get_html(self, filepath): """ Generate html from md file :param filepath: the file to translate to html :return: html translation """ with codecs.open(filepath, 'r', 'utf-8') as mdfile: read = mdfile.read() read = macros.remove_collapsible_headings(read) html = markdown.markdown(read, extensions=['markdown.extensions.tables', 'markdown.extensions.fenced_code', 'mdx_truly_sane_lists']) html = '\n'.join(html.split('\n')[1:]) html = macros.add_note(html) html = macros.convert_info_macros(html) html = macros.convert_comment_block(html) html = macros.convert_code_block(html) html = macros.remove_empty_list_items(html) if CONTENTS: html = macros.add_contents(html) html = macros.process_refs(html) html = PAGE_CACHE.resolve_refs(html, filepath) if LOG_HTML: title = self.get_title(filepath) html_log_file = open(os.path.dirname(LOG_FILE) + title + '.html', 'w+') html_log_file.write('<h1>' + title + '</h1>') html_log_file.write(html) else: LOGGER.debug('file: %s\n\nhtml: %s\n\n', filepath, html) return html
def create_or_update_page(self, title, body, ancestors, filepath): """ Create a new page :param title: confluence page title :param body: confluence page content :param ancestors: confluence page ancestor :param filepath: markdown file full path :return: created or updated page id """ page = PAGE_CACHE.get_page(title) if page: return self.update_page(page.id, title, body, page.version, ancestors, filepath) else: LOGGER.info('Creating page %s...', title) url = '%s/rest/api/content/' % CONFLUENCE_API_URL new_page = { 'type': 'page', 'title': title, 'space': { 'key': SPACE_KEY }, 'body': { 'storage': { 'value': body, 'representation': 'storage' } }, 'ancestors': ancestors } LOGGER.debug("data: %s", json.dumps(new_page)) response = common.make_request_post(url, data=json.dumps(new_page)) data = response.json() space_name = data[u'space'][u'name'] page_id = data[u'id'] version = data[u'version'][u'number'] link = '%s%s' % (CONFLUENCE_API_URL, data[u'_links'][u'webui']) LOGGER.info('Page created in %s with ID: %s.', space_name, page_id) LOGGER.info('URL: %s', link) # label the page self.__label_page(page_id) img_check = re.search(r'<img(.*?)\/>', body) if img_check: LOGGER.info('Attachments found, update procedure called.') return self.update_page(page_id, title, body, version, ancestors, filepath) else: return page_id
def get_page(self, title): """ Retrieve page details by title :param title: page tile :return: Confluence page info """ if title in self.__CACHED_PAGE_INFO: return self.__CACHED_PAGE_INFO[title] LOGGER.info('Retrieving page information: %s', title) url = '%s/rest/api/content?title=%s&spaceKey=%s' \ '&expand=version,ancestors,metadata.labels,body.storage' \ % (CONFLUENCE_API_URL, urllib.parse.quote_plus(title), SPACE_KEY) response = common.make_request_get(url) data = response.json() LOGGER.debug("data: %s", str(data)) if len(data[u'results']) >= 1: data = data[u'results'][0] page_id = data[u'id'] version_num = data[u'version'][u'number'] link = '%s%s' % (CONFLUENCE_API_URL, data[u'_links'][u'webui']) ancestor = data[u'ancestors'][-1][u'id'] labels = map(lambda r: r[u'name'], data[u'metadata'][u'labels'][u'results']) body = data[u'body'][u'storage'][u'value'] # These properties do not round-trip; confluence adds them, so strip them out body = re.sub(' ac:schema-version="[^"]+"', '', body) body = re.sub(' ac:macro-id="[^"]+"', '', body) # Confluence replaces some quotes (but not all) with xml quotes body = re.sub('"', '"', body) title = data[u'title'] page_info = collections.namedtuple('PageInfo', ['id', 'version', 'link', 'ancestor', 'labels', 'body', 'title']) page = page_info(page_id, version_num, link, ancestor, labels, body, title) self.__CACHED_PAGE_INFO[title] = page return page return False
def __get_direct_child_pages(self, page_id): """ Retrieve every direct child page id :param page_id: page id :return: ids of immediate child pages """ url = '%s/rest/api/content/search?cql=parent=%s' % \ (CONFLUENCE_API_URL, urllib.parse.quote_plus(page_id)) response = common.make_request_get(url) data = response.json() LOGGER.debug("data: %s", str(data)) page_ids = [] for result in data[u'results']: page_ids.append(result[u'id']) return page_ids
def createDB(dbFilePath_) : """Create table in the given database file :param String dbFilePath_: file path of the database file """ if os.path.isfile(dbFilePath_) : return #os.remove(dbFilePath_) LOGGER.info('Creating database file: %s', dbFilePath_) command = """create table series (id INTEGER PRIMARY KEY, name VARCHAR(50), title VARCHAR(255), season INTEGER, episode INTEGER, sub_en INTEGER, sub_fr INTEGER, downloading INTEGER)""" LOGGER.debug(command) conn = sqlite3.connect(dbFilePath_) c = conn.cursor() c.execute(command) conn.close()
def moveFile(srcFilePath_, destFilePath_) : LOGGER.debug('Moving file:'); LOGGER.debug(' From: %s', srcFilePath_) LOGGER.debug(' To: %s', destFilePath_) if SIMULATE_MODE : return if (not os.path.isdir(os.path.dirname(destFilePath_))) : os.makedirs(os.path.dirname(destFilePath_)) #os.rename(srcFilePath_, destFilePath_) shutil.move(srcFilePath_, destFilePath_)
def __upload_attachment(self, page_id, file, comment): """ Upload an attachment :param page_id: confluence page id :param file: attachment file :param comment: attachment comment :return: boolean """ if re.search('http.*', file): return False content_type = mimetypes.guess_type(file)[0] filename = os.path.basename(file) if not os.path.isfile(file): LOGGER.error('File %s cannot be found --> skip ', file) return False sha = FILE_API.get_sha_hash(file) file_to_upload = { 'comment': comment, 'file': (filename, open(file, 'rb'), content_type, { 'Expires': '0' }) } attachment = self.__get_attachment(page_id, filename) if attachment: if sha == attachment.hash: LOGGER.info('File %s has not changed --> skip', file) return True else: LOGGER.debug('File %s has changed', file) url = '%s/rest/api/content/%s/child/attachment/%s/data' % \ (CONFLUENCE_API_URL, page_id, attachment.id) else: LOGGER.debug('File %s is new', file) url = '%s/rest/api/content/%s/child/attachment/' % ( CONFLUENCE_API_URL, page_id) LOGGER.info('Uploading attachment %s...', filename) response = common.make_request_upload(url, file_to_upload) data = response.json() LOGGER.debug('data: %s', str(data)) # depending on create or update, sometimes you get a collection # and sometimes you get a single item if u'results' in data: data = data[u'results'][0] attachment_id = data['id'] # Set the SHA hash metadata on the attachment so that it can be later compared # first, get the current version of the property if it exists url = '%s/rest/api/content/%s/property/hash' % (CONFLUENCE_API_URL, attachment_id) response = common.make_request_get(url, False) if response.status_code == 200: data = response.json() LOGGER.debug('data: %s', str(data)) version = data[u'version'][u'number'] else: version = 0 # then set the hash propery page_json = { "value": { "sha256": sha }, "version": { "number": version + 1, "minorEdit": True } } LOGGER.debug('data: %s', json.dumps(page_json)) response = common.make_request_put(url, data=json.dumps(page_json)) return True
def update_page(self, page_id, title, body, version, ancestors, filepath): """ Update a page :param page_id: confluence page id :param title: confluence page title :param body: confluence page content :param version: confluence page version :param ancestors: confluence page ancestor :param filepath: markdown file full path :return: updated page id """ LOGGER.info('Updating page %s...', title) # Add images and attachments body = self.__add_images(page_id, body, filepath) # See if the page actually needs to be updated or not existing = PAGE_CACHE.get_page(title) if existing: if title == existing.title and \ body == existing.body and \ ancestors[0]['id'] == existing.ancestor: LOGGER.info('No changes on the page; update not necessary') return page_id else: LOGGER.info('Changes detected; update nessary') if title != existing.title: LOGGER.debug('update required: title %s != %s', title, existing.title) if body != existing.body: LOGGER.debug('update required: body %s != %s', body, existing.body) if ancestors[0]['id'] != existing.ancestor: LOGGER.debug('update required: ancestor %s != %s', ancestors[0]['id'], existing.ancestor) PAGE_CACHE.forget_page(title) url = '%s/rest/api/content/%s' % (CONFLUENCE_API_URL, page_id) page_json = { "id": page_id, "type": "page", "title": title, "space": { "key": SPACE_KEY }, "body": { "storage": { "value": body, "representation": "storage" } }, "version": { "number": version + 1, "minorEdit": True }, 'ancestors': ancestors } response = common.make_request_put(url, data=json.dumps(page_json)) data = response.json() link = '%s%s' % (CONFLUENCE_API_URL, data[u'_links'][u'webui']) LOGGER.info("Page updated successfully.") LOGGER.info('URL: %s', link) return data[u'id']