Beispiel #1
0
    def storePage(self, page_name, data, parent_id=None):
        uploaded_page_id = None

        if self.config.confluence_adv_trace_data:
            ConfluenceLogger.trace('data', data['content'])

        if self.dryrun:
            _, page = self.getPage(page_name, 'version,ancestors')

            if not page:
                self._dryrun('adding new page ' + page_name)
                return None
            else:
                misc = ''
                if parent_id and 'ancestors' in page:
                    if not any(a['id'] == parent_id for a in page['ancestors']):
                        if parent_id in self._name_cache:
                            misc += '[new parent page {} ({})]'.format(
                                self._name_cache[parent_id], parent_id)
                        else:
                            misc += '[new parent page]'

                self._dryrun('updating existing page', page['id'], misc)
                return page['id']

        can_labels = 'labels' not in self.config.confluence_adv_restricted
        expand = 'version'
        if can_labels and self.append_labels:
            expand += ',metadata.labels'

        _, page = self.getPage(page_name, expand=expand)

        if self.onlynew and page:
            self._onlynew('skipping existing page', page['id'])
            return page['id']

        try:
            # new page
            if not page:
                newPage = {
                    'type': 'page',
                    'title': page_name,
                    'body': {
                        'storage': {
                            'representation': 'storage',
                            'value': data['content'],
                        }
                    },
                    'space': {
                        'key': self.space_name
                    },
                }

                if can_labels:
                    self._populate_labels(newPage, data['labels'])

                if parent_id:
                    newPage['ancestors'] = [{'id': parent_id}]

                try:
                    rsp = self.rest_client.post('content', newPage)

                    if 'id' not in rsp:
                        api_err = ('Confluence reports a successful page ' +
                                  'creation; however, provided no ' +
                                  'identifier.\n\n')
                        try:
                            api_err += 'DATA: {}'.format(json.dumps(
                                rsp, indent=2))
                        except TypeError:
                            api_err += 'DATA: <not-or-invalid-json>'
                        raise ConfluenceBadApiError(api_err)

                    uploaded_page_id = rsp['id']
                except ConfluenceBadApiError as ex:
                    # Check if Confluence reports that the new page request
                    # fails, indicating it already exists. This is usually
                    # (outside of possible permission use cases) that the page
                    # name's casing does not match. In this case, attempt to
                    # re-check for the page in a case-insensitive fashion. If
                    # found, attempt to perform an update request instead.
                    if str(ex).find('title already exists') == -1:
                        raise

                    ConfluenceLogger.verbose('title already exists warning '
                        'for page {}'.format(page_name))

                    _, page = self.getPageCaseInsensitive(page_name)
                    if not page:
                        raise

                    if self.onlynew:
                        self._onlynew('skipping existing page', page['id'])
                        return page['id']

            # update existing page
            if page:
                last_version = int(page['version']['number'])
                updatePage = {
                    'id': page['id'],
                    'type': 'page',
                    'title': page_name,
                    'body': {
                        'storage': {
                            'representation': 'storage',
                            'value': data['content'],
                        }
                    },
                    'space': {
                        'key': self.space_name
                    },
                    'version': {
                        'number': last_version + 1
                    },
                }

                if can_labels:
                    labels = list(data['labels'])
                    if self.append_labels:
                        labels.extend([lbl.get('name')
                            for lbl in page.get('metadata', {}).get(
                                'labels', {}).get('results', {})
                        ])

                    self._populate_labels(updatePage, labels)

                if not self.notify:
                    updatePage['version']['minorEdit'] = True

                if parent_id:
                    updatePage['ancestors'] = [{'id': parent_id}]

                try:
                    self.rest_client.put('content', page['id'], updatePage)
                except ConfluenceBadApiError as ex:
                    if str(ex).find('unreconciled') != -1:
                        raise ConfluenceUnreconciledPageError(
                            page_name, page['id'], self.server_url, ex)

                    # Confluence Cloud may (rarely) fail to complete a
                    # content request with an OptimisticLockException/
                    # StaleObjectStateException exception. It is suspected
                    # that this is just an instance timing/processing issue.
                    # If this is observed, wait a moment and retry the
                    # content request. If it happens again, the put request
                    # will fail as it normally would.
                    if str(ex).find('OptimisticLockException') == -1:
                        raise
                    ConfluenceLogger.warn(
                        'remote page updated failed; retrying...')
                    time.sleep(1)
                    self.rest_client.put('content', page['id'], updatePage)

                uploaded_page_id = page['id']
        except ConfluencePermissionError:
            raise ConfluencePermissionError(
                """Publish user does not have permission to add page """
                """content to the configured space."""
            )

        if not self.watch:
            self.rest_client.delete('user/watch/content', uploaded_page_id)

        return uploaded_page_id
    def store_page(self, page_name, data, parent_id=None):
        """
        request to store page information to a confluence instance

        Performs a request which will attempt to store the provided page
        information and publish it to either a new page with the provided page
        name or update an existing page with a matching page name. Pages will be
        published at the root of a Confluence space unless a provided parent
        page identifier is provided.

        Args:
            page_name: the page title to use on the updated page
            data: the page data to apply
            parent_id (optional): the id of the ancestor to use
        """
        uploaded_page_id = None

        if self.config.confluence_adv_trace_data:
            logger.trace('data', data['content'])

        if self.dryrun:
            _, page = self.get_page(page_name, 'version,ancestors')

            if not page:
                self._dryrun('adding new page ' + page_name)
                return None
            else:
                misc = ''
                if parent_id and 'ancestors' in page:
                    if not any(a['id'] == parent_id
                               for a in page['ancestors']):
                        if parent_id in self._name_cache:
                            misc += '[new parent page {} ({})]'.format(
                                self._name_cache[parent_id], parent_id)
                        else:
                            misc += '[new parent page]'

                self._dryrun('updating existing page', page['id'], misc)
                return page['id']

        expand = 'version'
        if self.append_labels:
            expand += ',metadata.labels'

        _, page = self.get_page(page_name, expand=expand)

        if self.onlynew and page:
            self._onlynew('skipping existing page', page['id'])
            return page['id']

        try:
            # new page
            if not page:
                new_page = self._build_page(page_name, data)
                self._populate_labels(new_page, data['labels'])

                if parent_id:
                    new_page['ancestors'] = [{'id': parent_id}]

                try:
                    rsp = self.rest_client.post('content', new_page)

                    if 'id' not in rsp:
                        api_err = ('Confluence reports a successful page ' +
                                   'creation; however, provided no ' +
                                   'identifier.\n\n')
                        try:
                            api_err += 'DATA: {}'.format(
                                json.dumps(rsp, indent=2))
                        except TypeError:
                            api_err += 'DATA: <not-or-invalid-json>'
                        raise ConfluenceBadApiError(-1, api_err)

                    uploaded_page_id = rsp['id']

                    # if we have labels and this is a non-cloud instance,
                    # initial labels need to be applied in their own request
                    labels = new_page['metadata']['labels']
                    if not self.cloud and labels:
                        url = 'content/{}/label'.format(uploaded_page_id)
                        self.rest_client.post(url, labels)

                except ConfluenceBadApiError as ex:
                    # Check if Confluence reports that the new page request
                    # fails, indicating it already exists. This is usually
                    # (outside of possible permission use cases) that the page
                    # name's casing does not match. In this case, attempt to
                    # re-check for the page in a case-insensitive fashion. If
                    # found, attempt to perform an update request instead.
                    if str(ex).find('title already exists') == -1:
                        raise

                    logger.verbose('title already exists warning '
                                   'for page {}'.format(page_name))

                    _, page = self.get_page_case_insensitive(page_name)
                    if not page:
                        raise

                    if self.onlynew:
                        self._onlynew('skipping existing page', page['id'])
                        return page['id']

            # update existing page
            if page:
                self._update_page(page, page_name, data, parent_id=parent_id)
                uploaded_page_id = page['id']

        except ConfluencePermissionError:
            raise ConfluencePermissionError(
                """Publish user does not have permission to add page """
                """content to the configured space.""")

        if not self.watch:
            self.rest_client.delete('user/watch/content', uploaded_page_id)

        return uploaded_page_id