Exemple #1
0
    def on_create(self, docs):
        on_create_item(docs)

        for doc in docs:
            if doc.get('body_footer') and is_normal_package(doc):
                raise SuperdeskApiError.badRequestError("Package doesn't support Public Service Announcements")

            doc['version_creator'] = doc['original_creator']
            remove_unwanted(doc)
            update_word_count(doc)
            set_item_expiry({}, doc)

            if doc[ITEM_TYPE] == CONTENT_TYPE.COMPOSITE:
                self.packageService.on_create([doc])

            # Do the validation after Circular Reference check passes in Package Service
            self.validate_embargo(doc)

            if doc.get('media'):
                self.mediaService.on_create([doc])

            # let client create version 0 docs
            if doc.get('version') == 0:
                doc[config.VERSION] = doc['version']

            if not doc.get('ingest_provider'):
                doc['source'] = DEFAULT_SOURCE_VALUE_FOR_MANUAL_ARTICLES

            doc.setdefault('priority', DEFAULT_PRIORITY_VALUE_FOR_MANUAL_ARTICLES)
            doc.setdefault('urgency', DEFAULT_URGENCY_VALUE_FOR_MANUAL_ARTICLES)

            convert_task_attributes_to_objectId(doc)
Exemple #2
0
    def validate_embargo(self, item):
        """
        Validates the embargo of the item. Following are checked:
            1. Item can't be a package or a take or a re-write of another story
            2. Publish Schedule and Embargo are mutually exclusive
            3. Always a future date except in case of Corrected and Killed.
        :raises: SuperdeskApiError.badRequestError() if the validation fails
        """

        if item[ITEM_TYPE] != CONTENT_TYPE.COMPOSITE:
            embargo = item.get(EMBARGO)
            if embargo:
                if item.get('publish_schedule') or item[ITEM_STATE] == CONTENT_STATE.SCHEDULED:
                    raise SuperdeskApiError.badRequestError("An item can't have both Publish Schedule and Embargo")

                package = TakesPackageService().get_take_package(item)
                if package:
                    raise SuperdeskApiError.badRequestError("Takes doesn't support Embargo")

                if item.get('rewrite_of'):
                    raise SuperdeskApiError.badRequestError("Rewrites doesn't support Embargo")

                if not isinstance(embargo, datetime.date) or not embargo.time():
                    raise SuperdeskApiError.badRequestError("Invalid Embargo")

                if item[ITEM_STATE] not in PUBLISH_STATES and embargo <= utcnow():
                    raise SuperdeskApiError.badRequestError("Embargo cannot be earlier than now")
        elif is_normal_package(item):
            if item.get(EMBARGO):
                raise SuperdeskApiError.badRequestError("A Package doesn't support Embargo")

            self.packageService.check_if_any_item_in_package_has_embargo(item)
Exemple #3
0
    def on_create(self, docs):
        on_create_item(docs)

        for doc in docs:
            if doc.get('body_footer') and is_normal_package(doc):
                raise SuperdeskApiError.badRequestError("Package doesn't support Public Service Announcements")

            doc['version_creator'] = doc['original_creator']
            remove_unwanted(doc)
            update_word_count(doc)
            set_item_expiry({}, doc)

            if doc[ITEM_TYPE] == CONTENT_TYPE.COMPOSITE:
                self.packageService.on_create([doc])

            # Do the validation after Circular Reference check passes in Package Service
            update_schedule_settings(doc, EMBARGO, doc.get(EMBARGO))
            self.validate_embargo(doc)

            if doc.get('media'):
                self.mediaService.on_create([doc])

            # let client create version 0 docs
            if doc.get('version') == 0:
                doc[config.VERSION] = doc['version']

            self._add_desk_metadata(doc, {})

            convert_task_attributes_to_objectId(doc)
    def parse_item(self, tree):
        item = dict()
        item['guid'] = item['uri'] = tree.attrib['guid']
        item['version'] = tree.attrib['version']

        self.parse_item_meta(tree, item)
        self.parse_content_meta(tree, item)
        self.parse_rights_info(tree, item)

        if is_normal_package(item):
            self.parse_group_set(tree, item)
        else:
            self.parse_content_set(tree, item)

        return item
    def parse_item(self, tree):
        item = dict()
        item['guid'] = tree.attrib['guid'] + ':' + tree.attrib['version']
        item['uri'] = tree.attrib['guid']
        item['version'] = tree.attrib['version']

        self.parse_item_meta(tree, item)
        self.parse_content_meta(tree, item)
        self.parse_rights_info(tree, item)

        if is_normal_package(item):
            self.parse_group_set(tree, item)
        else:
            self.parse_content_set(tree, item)

        return item
Exemple #6
0
    def validate_embargo(self, item):
        """Validates the embargo of the item.

        Following are checked:
            1. Item can't be a package or a take or a re-write of another story
            2. Publish Schedule and Embargo are mutually exclusive
            3. Always a future date except in case of Corrected and Killed.
        :raises: SuperdeskApiError.badRequestError() if the validation fails
        """

        if item[ITEM_TYPE] != CONTENT_TYPE.COMPOSITE:
            if EMBARGO in item:
                embargo = item.get(SCHEDULE_SETTINGS,
                                   {}).get('utc_{}'.format(EMBARGO))
                if embargo:
                    if item.get(PUBLISH_SCHEDULE) or item[
                            ITEM_STATE] == CONTENT_STATE.SCHEDULED:
                        raise SuperdeskApiError.badRequestError(
                            "An item can't have both Publish Schedule and Embargo"
                        )

                    if (item[ITEM_STATE] not in {CONTENT_STATE.KILLED, CONTENT_STATE.SCHEDULED}) \
                            and embargo <= utcnow():
                        raise SuperdeskApiError.badRequestError(
                            "Embargo cannot be earlier than now")

                    package = TakesPackageService().get_take_package(item)
                    if package and package.get(SEQUENCE, 1) > 1:
                        raise SuperdeskApiError.badRequestError(
                            "Takes doesn't support Embargo")

                    if item.get('rewrite_of'):
                        raise SuperdeskApiError.badRequestError(
                            "Rewrites doesn't support Embargo")

                    if not isinstance(embargo,
                                      datetime.date) or not embargo.time():
                        raise SuperdeskApiError.badRequestError(
                            "Invalid Embargo")

        elif is_normal_package(item):
            if item.get(EMBARGO):
                raise SuperdeskApiError.badRequestError(
                    "A Package doesn't support Embargo")

            self.packageService.check_if_any_item_in_package_has_embargo(item)
    def on_create(self, docs):
        on_create_item(docs)

        for doc in docs:
            if doc.get('body_footer') and is_normal_package(doc):
                raise SuperdeskApiError.badRequestError(_("Package doesn't support Public Service Announcements"))

            self._test_readonly_stage(doc)

            doc['version_creator'] = doc['original_creator']
            remove_unwanted(doc)
            update_word_count(doc)
            set_item_expiry({}, doc)

            if doc[ITEM_TYPE] == CONTENT_TYPE.COMPOSITE:
                self.packageService.on_create([doc])

            # Do the validation after Circular Reference check passes in Package Service
            update_schedule_settings(doc, EMBARGO, doc.get(EMBARGO))
            self.validate_embargo(doc)

            update_associations(doc)
            for key, assoc in doc.get(ASSOCIATIONS, {}).items():
                # don't set time stamp for related items
                if not self._is_related_content(key):
                    self._set_association_timestamps(assoc, doc)
                    remove_unwanted(assoc)

            if doc.get('media'):
                self.mediaService.on_create([doc])

            # let client create version 0 docs
            if doc.get('version') == 0:
                doc[config.VERSION] = doc['version']

            self._add_desk_metadata(doc, {})

            convert_task_attributes_to_objectId(doc)
            transtype_metadata(doc)

            # send signal
            superdesk.item_create.send(self, item=doc)
    def parse_item(self, tree):
        # config is not accessible during __init__, so we check it here
        if self.__class__.missing_voc is None:
            self.__class__.missing_voc = app.config.get('QCODE_MISSING_VOC', 'continue')
            if self.__class__.missing_voc not in ('reject', 'create', 'continue'):
                logger.warning('Bad QCODE_MISSING_VOC value ({value}) using default ("continue")'
                               .format(value=self.missing_voc))
                self.__class__.missing_voc = 'continue'

        item = dict()
        item['guid'] = tree.attrib['guid'] + ':' + tree.attrib['version']
        item['uri'] = tree.attrib['guid']
        item['version'] = tree.attrib['version']

        self.parse_item_meta(tree, item)
        self.parse_content_meta(tree, item)
        self.parse_rights_info(tree, item)

        if is_normal_package(item):
            self.parse_group_set(tree, item)
        else:
            self.parse_content_set(tree, item)

        return item
    def parse_item(self, tree):
        # config is not accessible during __init__, so we check it here
        if self.__class__.missing_voc is None:
            self.__class__.missing_voc = app.config.get('QCODE_MISSING_VOC', 'continue')
            if self.__class__.missing_voc not in ('reject', 'create', 'continue'):
                logger.warning('Bad QCODE_MISSING_VOC value ({value}) using default ("continue")'
                               .format(value=self.missing_voc))
                self.__class__.missing_voc = 'continue'

        item = dict()
        item['guid'] = tree.attrib['guid'] + ':' + tree.attrib['version']
        item['uri'] = tree.attrib['guid']
        item['version'] = tree.attrib['version']

        self.parse_item_meta(tree, item)
        self.parse_content_meta(tree, item)
        self.parse_rights_info(tree, item)

        if is_normal_package(item):
            self.parse_group_set(tree, item)
        else:
            self.parse_content_set(tree, item)

        return item
Exemple #10
0
    def _validate_updates(self, original, updates, user):
        """Validates updates to the article for the below conditions.

        If any of these conditions are met then exception is raised:
            1.  Is article locked by another user other than the user requesting for update
            2.  Is state of the article is Killed or Recalled?
            3.  Is user trying to update the package with Public Service Announcements?
            4.  Is user authorized to update unique name of the article?
            5.  Is user trying to update the genre of a broadcast article?
            6.  Is article being scheduled and is in a package?
            7.  Is article being scheduled and schedule timestamp is invalid?
            8.  Does article has valid crops if the article type is a picture?
            9.  Is article a valid package if the article type is a package?
            10. Does article has a valid Embargo?
            11. Make sure that there are no duplicate anpa_category codes in the article.
            12. Make sure there are no duplicate subjects in the upadte
            13. Item is on readonly stage.

        :raises:
            SuperdeskApiError.forbiddenError()
                - if state of the article is killed or user is not authorized to update unique name or if article is
                  locked by another user
            SuperdeskApiError.badRequestError()
                - if Public Service Announcements are being added to a package or genre is being updated for a
                broadcast, is invalid for scheduling, the updates contain duplicate anpa_category or subject codes
        """
        updated = original.copy()
        updated.update(updates)

        self._test_readonly_stage(original, updates)

        lock_user = original.get('lock_user', None)
        force_unlock = updates.get('force_unlock', False)
        str_user_id = str(user.get(config.ID_FIELD)) if user else None

        if lock_user and str(lock_user) != str_user_id and not force_unlock:
            raise SuperdeskApiError.forbiddenError(
                'The item was locked by another user')

        if original.get(ITEM_STATE) in {
                CONTENT_STATE.KILLED, CONTENT_STATE.RECALLED
        }:
            raise SuperdeskApiError.forbiddenError(
                "Item isn't in a valid state to be updated.")

        if updates.get('body_footer') and is_normal_package(original):
            raise SuperdeskApiError.badRequestError(
                "Package doesn't support Public Service Announcements")

        if 'unique_name' in updates and not is_admin(user) \
                and (user['active_privileges'].get('metadata_uniquename', 0) == 0) \
                and not force_unlock:
            raise SuperdeskApiError.forbiddenError(
                "Unauthorized to modify Unique Name")

        # if broadcast then update to genre is not allowed.
        if original.get('broadcast') and updates.get('genre') and \
                any(genre.get('qcode', '').lower() != BROADCAST_GENRE.lower() for genre in updates.get('genre')):
            raise SuperdeskApiError.badRequestError(
                'Cannot change the genre for broadcast content.')

        if PUBLISH_SCHEDULE in updates or "schedule_settings" in updates:
            if is_item_in_package(original) and not force_unlock:
                raise SuperdeskApiError.badRequestError(
                    'This item is in a package and it needs to be removed before the item can be scheduled!'
                )

            update_schedule_settings(updated, PUBLISH_SCHEDULE,
                                     updated.get(PUBLISH_SCHEDULE))

            if updates.get(PUBLISH_SCHEDULE):
                validate_schedule(
                    updated.get(SCHEDULE_SETTINGS,
                                {}).get('utc_{}'.format(PUBLISH_SCHEDULE)))

            updates[SCHEDULE_SETTINGS] = updated.get(SCHEDULE_SETTINGS, {})

        if original[ITEM_TYPE] == CONTENT_TYPE.PICTURE:
            CropService().validate_multiple_crops(updates, original)
        elif original[ITEM_TYPE] == CONTENT_TYPE.COMPOSITE:
            self.packageService.on_update(updates, original)

        # update the embargo date
        update_schedule_settings(updated, EMBARGO, updated.get(EMBARGO))
        # Do the validation after Circular Reference check passes in Package Service
        self.validate_embargo(updated)
        if EMBARGO in updates or "schedule_settings" in updates:
            updates[SCHEDULE_SETTINGS] = updated.get(SCHEDULE_SETTINGS, {})

        # Ensure that there are no duplicate categories in the update
        category_qcodes = [
            q['qcode'] for q in updates.get('anpa_category', []) or []
        ]
        if category_qcodes and len(category_qcodes) != len(
                set(category_qcodes)):
            raise SuperdeskApiError.badRequestError(
                "Duplicate category codes are not allowed")

        # Ensure that there are no duplicate subjects in the update
        subject_qcodes = [q['qcode'] for q in updates.get('subject', []) or []]
        if subject_qcodes and len(subject_qcodes) != len(set(subject_qcodes)):
            raise SuperdeskApiError.badRequestError(
                "Duplicate subjects are not allowed")
Exemple #11
0
    def _validate_updates(self, original, updates, user):
        """
        Validates updates to the article for the below conditions, if any of them then exception is raised:
            1.  Is article locked by another user other than the user requesting for update
            2.  Is state of the article is Killed?
            3.  Is user trying to update the package with Public Service Announcements?
            4.  Is user authorized to update unique name of the article?
            5.  Is user trying to update the genre of a broadcast article?
            6.  Is article being scheduled and is in a package?
            7.  Is article being scheduled and schedule timestamp is invalid?
            8.  Does article has valid crops if the article type is a picture?
            9.  Is article a valid package if the article type is a package?
            10. Does article has a valid Embargo?
            11. Make sure that there are no duplicate anpa_category codes in the article.
            12. Make sure there are no duplicate subjects in the upadte

        :raises:
            SuperdeskApiError.forbiddenError()
                - if state of the article is killed or user is not authorized to update unique name or if article is
                  locked by another user
            SuperdeskApiError.badRequestError()
                - if Public Service Announcements are being added to a package or genre is being updated for a
                broadcast, is invalid for scheduling, the updates contain duplicate anpa_category or subject codes
        """

        lock_user = original.get('lock_user', None)
        force_unlock = updates.get('force_unlock', False)
        str_user_id = str(user.get(config.ID_FIELD)) if user else None

        if lock_user and str(lock_user) != str_user_id and not force_unlock:
            raise SuperdeskApiError.forbiddenError('The item was locked by another user')

        if original.get(ITEM_STATE) == CONTENT_STATE.KILLED:
            raise SuperdeskApiError.forbiddenError("Item isn't in a valid state to be updated.")

        if updates.get('body_footer') and is_normal_package(original):
            raise SuperdeskApiError.badRequestError("Package doesn't support Public Service Announcements")

        if 'unique_name' in updates and not is_admin(user) \
                and (user['active_privileges'].get('metadata_uniquename', 0) == 0):
            raise SuperdeskApiError.forbiddenError("Unauthorized to modify Unique Name")

        # if broadcast then update to genre is not allowed.
        if original.get('broadcast') and updates.get('genre') and \
                any(genre.get('value', '').lower() != BROADCAST_GENRE.lower() for genre in updates.get('genre')):
            raise SuperdeskApiError.badRequestError('Cannot change the genre for broadcast content.')

        if updates.get('publish_schedule') and original[ITEM_STATE] != CONTENT_STATE.SCHEDULED \
                and datetime.datetime.fromtimestamp(0).date() != updates['publish_schedule'].date():
            if is_item_in_package(original):
                raise SuperdeskApiError.badRequestError(
                    'This item is in a package and it needs to be removed before the item can be scheduled!')

            package = TakesPackageService().get_take_package(original) or {}
            validate_schedule(updates['publish_schedule'], package.get(SEQUENCE, 1))

        if original[ITEM_TYPE] == CONTENT_TYPE.PICTURE:
            CropService().validate_multiple_crops(updates, original)
        elif original[ITEM_TYPE] == CONTENT_TYPE.COMPOSITE:
            self.packageService.on_update(updates, original)

        # Do the validation after Circular Reference check passes in Package Service
        updated = original.copy()
        updated.update(updates)
        self.validate_embargo(updated)

        # Ensure that there are no duplicate categories in the update
        category_qcodes = [q['qcode'] for q in updates.get('anpa_category', []) or []]
        if category_qcodes and len(category_qcodes) != len(set(category_qcodes)):
            raise SuperdeskApiError.badRequestError("Duplicate category codes are not allowed")

        # Ensure that there are no duplicate subjects in the update
        subject_qcodes = [q['qcode'] for q in updates.get('subject', []) or []]
        if subject_qcodes and len(subject_qcodes) != len(set(subject_qcodes)):
            raise SuperdeskApiError.badRequestError("Duplicate subjects are not allowed")