Пример #1
0
 def setUp(self):
     self.formatter = NINJSFormatter()
     init_app(self.app)
     self.maxDiff = None
Пример #2
0
class PublishService(BaseService):
    """A service for publishing to the content api.

    Serves mainly as a proxy to the data layer.
    """

    formatter = NINJSFormatter()
    subscriber = {'config': {}}

    def publish(self, item, subscribers=[]):
        """Publish an item to content api.

        This must be enabled via ``PUBLISH_TO_CONTENT_API`` setting.

        :param item: item to publish
        """

        if not self._filter_item(item):
            doc = self.formatter._transform_to_ninjs(item, self.subscriber)
            now = utcnow()
            doc.setdefault('firstcreated', now)
            doc.setdefault('versioncreated', now)
            doc.setdefault(config.VERSION, item.get(config.VERSION, 1))
            doc['subscribers'] = [str(sub['_id']) for sub in subscribers]
            if 'evolvedfrom' in doc:
                parent_item = self.find_one(req=None, _id=doc['evolvedfrom'])
                if parent_item:
                    doc['ancestors'] = copy(parent_item.get('ancestors', []))
                    doc['ancestors'].append(doc['evolvedfrom'])
                else:
                    logger.warning(
                        "Failed to find evolvedfrom item '{}' for '{}'".format(
                            doc['evolvedfrom'], doc['guid']))

            self._assign_associations(item, doc)
            logger.info('publishing %s to %s' % (doc['guid'], subscribers))
            return self._create_doc(doc)
        else:
            return None

    def create(self, docs, **kwargs):
        ids = []
        for doc in docs:
            ids.extend(self._create_doc(doc, **kwargs))
        return ids

    def _create_doc(self, doc, **kwargs):
        """Create a new item or update existing."""
        item = copy(doc)
        item.setdefault('_id', item.get('guid'))
        _id = item[config.ID_FIELD] = item.pop('guid')

        # merging the existing and new subscribers
        original = self.find_one(req=None, _id=_id)
        if original:
            item['subscribers'] = list(
                set(original.get('subscribers', []))
                | set(item.get('subscribers', [])))

        self._process_associations(item, original)
        self._create_version_doc(item)
        if original:
            self.update(_id, item, original)
            return _id
        else:
            return super().create([item], **kwargs)[0]

    def _create_version_doc(self, item):
        """
        Store the item in the item version collection
        :param item:
        :return:
        """
        version_item = copy(item)
        version_item['_id_document'] = version_item.pop('_id')
        get_resource_service('items_versions').create([version_item])
        # if the update is a cancel we need to cancel all versions
        if item.get('pubstatus', '') == 'canceled':
            self._cancel_versions(item.get('_id'))

    def _cancel_versions(self, doc_id):
        """
        Given an id of a document set the pubstatus to canceled for all versions
        :param doc_id:
        :return:
        """
        query = {'_id_document': doc_id}
        update = {'pubstatus': 'canceled'}
        for item in get_resource_service('items_versions').get_from_mongo(
                req=None, lookup=query):
            if item.get('pubstatus') != 'canceled':
                get_resource_service('items_versions').update(
                    item['_id'], update, item)

    def _filter_item(self, item):
        """
        Filter the item out if it matches any API Block filter conditions
        :param item:
        :return: True of the item is blocked, False if it is OK to publish it on the API.
        """
        # Get the API blocking Filters
        req = ParsedRequest()
        filter_conditions = list(
            get_resource_service('content_filters').get(
                req=req, lookup={'api_block': True}))

        # No API blocking filters
        if not filter_conditions:
            return False

        filter_service = get_resource_service('content_filters')
        for fc in filter_conditions:
            if filter_service.does_match(fc, item):
                logger.info('API Filter block {} matched for item {}.'.format(
                    fc, item.get(config.ID_FIELD)))
                return True

        return False

    def _assign_associations(self, item, doc):
        """Assign Associations to published item

        :param dict item: item being published
        :param dit doc: ninjs documents
        """
        if item[ITEM_TYPE] != CONTENT_TYPE.TEXT:
            return

        for assoc, assoc_item in (item.get('associations') or {}).items():
            if not assoc_item:
                continue

            doc.get('associations', {}).get(assoc)['subscribers'] = list(
                map(str,
                    assoc_item.get('subscribers') or []))

    def _process_associations(self, updates, original):
        """Update associations using existing published item and ensure that associated item subscribers
        are equal or subset of the parent subscribers.
        :param updates:
        :param original:
        :return:
        """
        if updates[ITEM_TYPE] != CONTENT_TYPE.TEXT:
            return

        subscribers = updates.get('subscribers') or []
        for assoc, update_assoc in (updates.get('associations') or {}).items():
            if not update_assoc:
                continue

            if original:
                original_assoc = (original.get('associations')
                                  or {}).get(assoc)

                if original_assoc and original_assoc.get(
                        config.ID_FIELD) == update_assoc.get(config.ID_FIELD):
                    update_assoc['subscribers'] = list(
                        set(original_assoc.get('subscribers') or [])
                        | set(update_assoc.get('subscribers') or []))

            update_assoc['subscribers'] = list(
                set(update_assoc['subscribers']) & set(subscribers))
Пример #3
0
class PublishService(BaseService):
    """A service for publishing to the content api.

    Serves mainly as a proxy to the data layer.
    """

    formatter = NINJSFormatter()
    subscriber = {'config': {}}

    def publish(self, item, subscribers=[]):
        """Publish an item to content api.

        This must be enabled via ``PUBLISH_TO_CONTENT_API`` setting.

        :param item: item to publish
        """

        if not self._filter_item(item):
            doc = self.formatter._transform_to_ninjs(item, self.subscriber)
            now = utcnow()
            doc.setdefault('firstcreated', now)
            doc.setdefault('versioncreated', now)
            doc.setdefault(config.VERSION, item.get(config.VERSION, 1))
            doc['subscribers'] = [str(sub['_id']) for sub in subscribers]
            logger.info('publishing %s to %s' % (doc['guid'], subscribers))
            return self._create_doc(doc)
        else:
            return None

    def create(self, docs, **kwargs):
        ids = []
        for doc in docs:
            ids.extend(self._create_doc(doc, **kwargs))
        return ids

    def _create_doc(self, doc, **kwargs):
        """Create a new item or update existing."""
        item = copy(doc)
        item.setdefault('_id', item.get('guid'))
        _id = item[config.ID_FIELD] = item.pop('guid')

        # merging the existing and new subscribers
        original = self.find_one(req=None, _id=_id)
        if original:
            item['subscribers'] = list(set(original.get('subscribers', [])) | set(item.get('subscribers', [])))

        self._create_version_doc(item)
        if original:
            self.update(_id, item, original)
            return _id
        else:
            return super().create([item], **kwargs)[0]

    def _create_version_doc(self, item):
        """
        Store the item in the item version collection
        :param item:
        :return:
        """
        version_item = copy(item)
        version_item['_id_document'] = version_item.pop('_id')
        get_resource_service('items_versions').create([version_item])

    def _filter_item(self, item):
        """
        Filter the item out if it matches any API Block filter conditions
        :param item:
        :return: True of the item is blocked, False if it is OK to publish it on the API.
        """
        # Get the API blocking Filters
        req = ParsedRequest()
        filter_conditions = list(get_resource_service('content_filters').get(req=req, lookup={'api_block': True}))

        # No API blocking filters
        if not filter_conditions:
            return False

        filter_service = get_resource_service('content_filters')
        for fc in filter_conditions:
            if filter_service.does_match(fc, item):
                logger.info('API Filter block {} matched for item {}.'.format(fc, item.get(config.ID_FIELD)))
                return True

        return False