def update_html_content(login, passw, html): c = Confluence(BASE_URL, login, passw) page = c.get_page_by_id(page_id=JENKINS_PAGE_ID, expand='body.storage') resp = c.update_existing_page(page_id=JENKINS_PAGE_ID, body=html, title=page['title']) return resp.ok
class ConfluenceAdapter(object): """ Adapter for Atlassian Confluence class. Encapsulates content retrieve and update functionality. """ NAMESPACES = { "atlassian-content": "http://atlassian.com/content", "ac": "http://atlassian.com/content", "ri": "http://atlassian.com/content", "atlassian-template": "http://atlassian.com/template", "at": "http://atlassian.com/template", } def __init__(self, url, username, password, space_key): self.confluence = Confluence(url=url, username=username, password=password) self.space_key = space_key self.get_space_or_create() def get_space_or_create(self): """ Check whether space exists or not. If it doesn't, then create the space. :rtype: dict :return: Space data. """ space = self.confluence.get_space(self.space_key) if type(space) is not dict: raise WikiUpdateException("Can't retrieve valid information about Confluence space." " Please check configurations. Data: {}".format(space)) if space.get('statusCode', None) == 404: space = self.confluence.create_space(self.space_key, self.space_key) return space def get_page_or_create(self, page_title): """ Get page content, if no such page then create it. :type page_title: str :param page_title: Title of the page which should be retrieved. :raises: WikiUpdateException :rtype: tuple(int, lxml.etree._Element) :returns: Tuple where first element is the id of the page. The second is the parsed content data. """ data = self.confluence.get_page_by_title(title=page_title, space=self.space_key, expand="body.storage,version") if not data: # No such page exist. Then create such page. data = self.create_page(page_title) try: content_xml = data['body']['storage']['value'] except KeyError: raise WikiUpdateException("Can't get partial-devices page content.") body_xml = render_to_string('wrapper.xml', { 'content': content_xml }) return data['id'], etree.fromstring(body_xml) def create_page(self, page_title): """ Create new page.+ :type page_title: str :param page_title: Title of the page which should be created. :raises: WikiUpdateException :rtype: dict :return: Data of newly created page. """ data = self.confluence.create_page(self.space_key, page_title, body="") if not data or 'id' not in data: raise WikiUpdateException("Page `{}` could not be created. Response data: {}".format(page_title, data)) return data def update_page_content(self, page_id, page_title, body): """ Update existing page with new body. :type page_id: int :param page_id: Page id which should be modified. :type page_title: str :param page_title: Title of the page which should be modified. :type body: lxml.etree._Element :param body: Page content data. :raises: WikiUpdateException :rtype: dict :returns: Data of newly updated page. """ # Get raw xml. body_xml = etree.tostring(body).decode('utf-8') # <xml xmlns:******> <p></p>***<ac:structured-macro>***</ac:structured-macro> </xml> # ^ ^ # Take the content starting right after `>` of the opening xml tag and till `<` of xml closing tag. content_xml = body_xml[body_xml.find('>') + 1:body_xml.rfind('<')] data = self.confluence.update_existing_page(page_id, page_title, content_xml) if not data or 'id' not in data: raise WikiUpdateException("Page `{}` could not be updated. Response data: {}".format(page_title, data)) return data @classmethod def get_field_element(cls, element, field): """ Get element from tree by field name. :rtype: lxml.etree._Element :returns: Element data. """ return element.xpath('//ac:structured-macro/ac:parameter' '[@ac:name="MultiExcerptName" and translate(normalize-space(text()), " ", "")="{}"]' '/following-sibling::ac:rich-text-body/*[local-name()="p"]'.format(field.name), namespaces=cls.NAMESPACES) @classmethod def update_content_for_field(cls, page_content, field): """ Update content for field. :type page_content: lxml.etree._Element :param page_content: Wiki page content. :type field: AbstractLinkedField :param field: Field for which the page_content should be updated. :rtype: lxml.etree._Element :returns: Page content data. """ field_elements = cls.get_field_element(page_content, field) if not field_elements: # If element does not exist then create it. macro_id = uuid.uuid4() data = render_to_string('multiexcerpt.xml', { "macro_id": macro_id, "field_name": field.name, "field_value": field.provide_value() }) element = etree.fromstring(data) page_content.insert(-1, element) # Can leave without this return, but `Explicit is better than implicit.` (C) Python Zen. return page_content for field_element in field_elements: field_element.text = field.provide_value() return page_content