Пример #1
0
    def on_update(self, updates, original):
        """ Called on the patch request to mark a activity/notification/comment as having been read and
        nothing else
        :param updates:
        :param original:
        :return:
        """
        user = getattr(g, "user", None)
        if not user:
            raise SuperdeskApiError.notFoundError("Can not determine user")
        user_id = str(user.get("_id"))

        # make sure that the user making the read notification is in the notification list
        if user_id not in updates.get("read").keys():
            raise SuperdeskApiError.forbiddenError("User is not in the notification list")

        # make sure the transition is from not read to read
        if not (updates.get("read")[user_id] == 1 and original.get("read")[user_id] == 0):
            raise SuperdeskApiError.forbiddenError("Can not set notification as read")

        # make sure that no other users are being marked as read
        for read_entry in updates.get("read"):
            if read_entry != user_id:
                if updates.get("read")[read_entry] != original.get("read")[read_entry]:
                    raise SuperdeskApiError.forbiddenError("Can not set other users notification as read")

        # make sure that no other fields are being up dated just read and _updated
        if len(updates) != 2:
            raise SuperdeskApiError.forbiddenError("Can not update")
Пример #2
0
    def on_update(self, updates, original):
        """Called on the patch request to mark a activity/notification/comment as read and nothing else

        :param updates:
        :param original:
        :return:
        """
        user = getattr(g, 'user', None)
        if not user:
            raise SuperdeskApiError.notFoundError('Can not determine user')
        user_id = user.get('_id')

        # make sure that the user making the read notification is in the notification list
        if not self.is_recipient(updates, user_id):
            raise SuperdeskApiError.forbiddenError('User is not in the notification list')

        # make sure the transition is from not read to read
        if not self.is_read(updates, user_id) and self.is_read(original, user_id):
            raise SuperdeskApiError.forbiddenError('Can not set notification as read')

        # make sure that no other users are being marked as read
        for recipient in updates.get('recipients', []):
            if recipient['user_id'] != user_id:
                if self.is_read(updates, recipient['user_id']) != self.is_read(original, recipient['user_id']):
                    raise SuperdeskApiError.forbiddenError('Can not set other users notification as read')

        # make sure that no other fields are being up dated just read and _updated
        if len(updates) != 2:
            raise SuperdeskApiError.forbiddenError('Can not update')
Пример #3
0
 def _validate_user(self, doc_user_id, doc_is_global):
     session_user = get_user(required=True)
     if str(session_user['_id']) != str(doc_user_id):
         if not doc_is_global:
             raise SuperdeskApiError.forbiddenError('Unauthorized to modify other user\'s local search.')
         elif not current_user_has_privilege('global_saved_searches'):
             raise SuperdeskApiError.forbiddenError('Unauthorized to modify global search.')
Пример #4
0
    def on_update(self, updates, original):
        user = get_user()

        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")

        remove_unwanted(updates)

        if self.__is_req_for_save(updates):
            update_state(original, updates)

        lock_user = original.get('lock_user', None)
        force_unlock = updates.get('force_unlock', False)

        original_creator = updates.get('original_creator', None)
        if not original_creator:
            updates['original_creator'] = original['original_creator']

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

        updates['versioncreated'] = utcnow()
        set_item_expiry(updates, original)
        updates['version_creator'] = str_user_id
        update_word_count(updates)

        if force_unlock:
            del updates['force_unlock']
Пример #5
0
 def on_delete(self, docs):
     if docs.get('is_default'):
         raise SuperdeskApiError.forbiddenError('Cannot delete the default role')
     # check if there are any users in the role
     user = get_resource_service('users').find_one(req=None, role=docs.get('_id'))
     if user:
         raise SuperdeskApiError.forbiddenError('Cannot delete the role, it still has users in it!')
Пример #6
0
    def on_delete(self, doc):
        """
        Checks if deleting the stage would not violate data integrity, raises an exception if it does.

            1/ Can't delete the default incomming stage
            2/ The stage must have no unspiked documents
            3/ The stage can not be refered to by a ingest routing rule

        :param doc:
        :return:
        """
        if doc['default_incoming'] is True:
            desk_id = doc.get('desk', None)
            if desk_id and superdesk.get_resource_service('desks').find_one(req=None, _id=desk_id):
                raise SuperdeskApiError.forbiddenError(message='Cannot delete a default stage.')

        # check if the stage has any documents in it
        items = self._get_unspiked_stage_documents(str(doc['_id']))
        if items.count() > 0:  # cannot delete
            raise SuperdeskApiError.forbiddenError(message='Only empty stages can be deleted.')

        # check if the stage is refered to in a ingest routing rule
        rules = self._stage_in_rule(doc['_id'])
        if rules.count() > 0:
            rule_names = ', '.join(rule.get('name') for rule in rules)
            raise SuperdeskApiError.forbiddenError(
                message='Stage is refered to by Ingest Routing Schemes : {}'.format(rule_names))
Пример #7
0
    def on_update(self, updates, original):
        if updates.get('content_expiry') == 0:
            updates['content_expiry'] = app.settings['CONTENT_EXPIRY_MINUTES']

        super().on_update(updates, original)

        if updates.get('content_expiry', None):
            docs = self.get_stage_documents(str(original[config.ID_FIELD]))
            for doc in docs:
                expiry = get_expiry_date(updates['content_expiry'], doc['versioncreated'])
                item_model = get_model(ItemModel)
                item_model.update({'_id': doc[config.ID_FIELD]}, {'expiry': expiry})

        if updates.get('working_stage', False):
            if not original.get('working_stage'):
                self.remove_old_default(original.get('desk'), 'working_stage')
                self.set_desk_ref(original, 'working_stage')
        else:
            if original.get('working_stage') and 'working_stage' in updates:
                raise SuperdeskApiError.forbiddenError(message='Must have one working stage in a desk')

        if updates.get('default_incoming', False):
            if not original.get('default_incoming'):
                self.remove_old_default(original.get('desk'), 'default_incoming')
                self.set_desk_ref(original, 'incoming_stage')
        else:
            if original.get('default_incoming') and 'default_incoming' in updates:
                raise SuperdeskApiError.forbiddenError(message='Must have one incoming stage in a desk')
Пример #8
0
 def on_delete(self, doc):
     if doc['default_incoming'] is True:
         desk_id = doc.get('desk', None)
         if desk_id and superdesk.get_resource_service('desks').find_one(req=None, _id=desk_id):
             raise SuperdeskApiError.forbiddenError(message='Cannot delete a default stage.')
     else:
         # check if the stage has any documents in it
         items = self.get_stage_documents(str(doc['_id']))
         if items.count() > 0:  # cannot delete
             raise SuperdeskApiError.forbiddenError(message='Only empty stages can be deleted.')
Пример #9
0
    def on_update(self, updates, original):
        is_update_allowed(original)
        user = get_user()

        if "publish_schedule" in updates and original["state"] == "scheduled":
            # this is an descheduling action
            self.deschedule_item(updates, original)
            return

        if updates.get("publish_schedule"):
            if datetime.datetime.fromtimestamp(False).date() == updates.get("publish_schedule").date():
                # publish_schedule field will be cleared
                updates["publish_schedule"] = None
            else:
                # validate the schedule
                self.validate_schedule(updates.get("publish_schedule"))

        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")

        remove_unwanted(updates)

        if self.__is_req_for_save(updates):
            update_state(original, updates)

        lock_user = original.get("lock_user", None)
        force_unlock = updates.get("force_unlock", False)

        updates.setdefault("original_creator", original.get("original_creator"))

        str_user_id = str(user.get("_id")) 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")

        updates["versioncreated"] = utcnow()
        set_item_expiry(updates, original)
        updates["version_creator"] = str_user_id
        set_sign_off(updates, original)
        update_word_count(updates)

        if force_unlock:
            del updates["force_unlock"]

        if original["type"] == "composite":
            self.packageService.on_update(updates, original)

        update_version(updates, original)
Пример #10
0
    def check_for_duplicates(self, package, associations):
        counter = Counter()
        package_id = package[config.ID_FIELD]
        for itemRef in [assoc[ITEM_REF] for assoc in associations if assoc.get(ITEM_REF)]:
            if itemRef == package_id:
                message = 'Trying to self reference as an association.'
                logger.error(message)
                raise SuperdeskApiError.forbiddenError(message=message)
            counter[itemRef] += 1

        if any(itemRef for itemRef, value in counter.items() if value > 1):
            message = 'Content associated multiple times'
            logger.error(message)
            raise SuperdeskApiError.forbiddenError(message=message)
Пример #11
0
    def on_update(self, updates, original):
        updates[ITEM_OPERATION] = ITEM_UPDATE
        is_update_allowed(original)
        user = get_user()

        if 'publish_schedule' in updates and original['state'] == 'scheduled':
            # this is an descheduling action
            self.deschedule_item(updates, original)
            return

        if updates.get('publish_schedule'):
            if datetime.datetime.fromtimestamp(False).date() == updates.get('publish_schedule').date():
                # publish_schedule field will be cleared
                updates['publish_schedule'] = None
            else:
                # validate the schedule
                self.validate_schedule(updates.get('publish_schedule'))

        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")

        remove_unwanted(updates)

        if self.__is_req_for_save(updates):
            update_state(original, updates)

        lock_user = original.get('lock_user', None)
        force_unlock = updates.get('force_unlock', False)

        updates.setdefault('original_creator', original.get('original_creator'))

        str_user_id = str(user.get('_id')) 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')

        updates['versioncreated'] = utcnow()
        set_item_expiry(updates, original)
        updates['version_creator'] = str_user_id
        set_sign_off(updates, original)
        update_word_count(updates)

        if force_unlock:
            del updates['force_unlock']

        if original['type'] == 'composite':
            self.packageService.on_update(updates, original)

        update_version(updates, original)
Пример #12
0
 def on_delete(self, deleted_theme):
     global_default_theme = get_resource_service('global_preferences').get_global_prefs()['theme']
     # raise an exception if the removed theme is the default one
     if deleted_theme['name'] == global_default_theme:
         raise SuperdeskApiError.forbiddenError('This is a default theme and can not be deleted')
     # raise an exception if the removed theme has children
     if self.get(req=None, lookup={'extends': deleted_theme['name']}).count() > 0:
         raise SuperdeskApiError.forbiddenError('This theme has children. It can\'t be removed')
     # update all the blogs using the removed theme and assign the default theme
     blogs_service = get_resource_service('blogs')
     default_theme = blogs_service.get_theme_snapshot(global_default_theme)
     blogs = blogs_service.get(req=None, lookup={'theme._id': deleted_theme['_id']})
     for blog in blogs:
         # will assign the default theme to this blog
         blogs_service.system_update(ObjectId(blog['_id']), {'theme': default_theme}, blog)
Пример #13
0
    def check_root_group(self, docs):
        for groups in [doc.get('groups') for doc in docs if doc.get('groups')]:
            self.check_all_groups_have_id_set(groups)
            root_groups = [group for group in groups if group.get('id') == 'root']

            if len(root_groups) == 0:
                message = 'Root group is missing.'
                logger.error(message)
                raise SuperdeskApiError.forbiddenError(message=message)

            if len(root_groups) > 1:
                message = 'Only one root group is allowed.'
                logger.error(message)
                raise SuperdeskApiError.forbiddenError(message=message)

            self.check_that_all_groups_are_referenced_in_root(root_groups[0], groups)
Пример #14
0
    def unlock(self, item_filter, user_id, session_id, etag):
        item_model = get_model(ItemModel)
        item = item_model.find_one(item_filter)

        if not item:
            raise SuperdeskApiError.notFoundError()

        if not item.get(LOCK_USER):
            raise SuperdeskApiError.badRequestError(message="Item is not locked.")

        can_user_unlock, error_message = self.can_unlock(item, user_id)

        if can_user_unlock:
            self.app.on_item_unlock(item, user_id)

            # delete the item if nothing is saved so far
            if item['_version'] == 1 and item['state'] == 'draft':
                superdesk.get_resource_service('archive').delete(lookup={'_id': item['_id']})
                return

            updates = {LOCK_USER: None, LOCK_SESSION: None, 'lock_time': None, 'force_unlock': True}
            item_model.update(item_filter, updates)
            self.app.on_item_unlocked(item, user_id)
            push_notification('item:unlock', item=str(item_filter.get(config.ID_FIELD)), user=str(user_id),
                              lock_session=str(session_id))
        else:
            raise SuperdeskApiError.forbiddenError(message=error_message)

        item = item_model.find_one(item_filter)
        return item
Пример #15
0
    def unlock(self, item_filter, user_id, session_id, etag):
        item_model = get_model(ItemModel)
        item = item_model.find_one(item_filter)

        if not item:
            raise SuperdeskApiError.notFoundError()

        if not item.get(LOCK_USER):
            raise SuperdeskApiError.badRequestError(message="Item is not locked.")

        can_user_unlock, error_message = self.can_unlock(item, user_id)

        if can_user_unlock:
            self.app.on_item_unlock(item, user_id)

            # delete the item if nothing is saved so far
            # version 0 created on lock item
            if item[config.VERSION] == 0 and item["state"] == "draft":
                superdesk.get_resource_service("archive").delete(lookup={"_id": item["_id"]})
                return

            updates = {LOCK_USER: None, LOCK_SESSION: None, "lock_time": None, "force_unlock": True}
            item_model.update(item_filter, updates)
            self.app.on_item_unlocked(item, user_id)
            push_notification(
                "item:unlock",
                item=str(item_filter.get(config.ID_FIELD)),
                user=str(user_id),
                lock_session=str(session_id),
            )
        else:
            raise SuperdeskApiError.forbiddenError(message=error_message)

        item = item_model.find_one(item_filter)
        return item
Пример #16
0
    def create(self, docs, **kwargs):
        target_id = request.view_args['target_id']
        doc = docs[0]
        link_id = doc.get('link_id')
        desk_id = doc.get('desk')
        service = get_resource_service(ARCHIVE)
        target = service.find_one(req=None, _id=target_id)
        self._validate_link(target, target_id)
        link = {}

        if is_genre(target, BROADCAST_GENRE):
            raise SuperdeskApiError.badRequestError("Cannot add new take to the story with genre as broadcast.")

        if desk_id:
            link = {'task': {'desk': desk_id}}
            user = get_user()
            lookup = {'_id': desk_id, 'members.user': user['_id']}
            desk = get_resource_service('desks').find_one(req=None, **lookup)
            if not desk:
                raise SuperdeskApiError.forbiddenError("No privileges to create new take on requested desk.")

            link['task']['stage'] = desk['working_stage']

        if link_id:
            link = service.find_one(req=None, _id=link_id)

        linked_item = self.packageService.link_as_next_take(target, link)
        doc.update(linked_item)
        build_custom_hateoas(CUSTOM_HATEOAS, doc)
        return [linked_item['_id']]
Пример #17
0
    def create(self, docs, **kwargs):
        target_id = request.view_args['target_id']
        doc = docs[0]
        link_id = doc.get('link_id')
        desk_id = doc.get('desk')
        service = get_resource_service(ARCHIVE)
        target = service.find_one(req=None, _id=target_id)
        self._validate_link(target, target_id)
        link = {}

        if desk_id:
            link = {'task': {'desk': desk_id}}
            user = get_user()
            lookup = {'_id': desk_id, 'members.user': user['_id']}
            desk = get_resource_service('desks').find_one(req=None, **lookup)
            if not desk:
                raise SuperdeskApiError.forbiddenError("No privileges to create new take on requested desk.")

            link['task']['stage'] = desk['working_stage']

        if link_id:
            link = service.find_one(req=None, _id=link_id)

        linked_item = self.packageService.link_as_next_take(target, link)
        insert_into_versions(id_=linked_item[config.ID_FIELD])
        doc.update(linked_item)
        build_custom_hateoas(CUSTOM_HATEOAS, doc)
        return [linked_item['_id']]
Пример #18
0
    def on_delete(self, doc):
        """
        Overriding to check if the search provider being requested to delete has been used to fetch items.
        """

        if doc.get('last_item_update'):
            raise SuperdeskApiError.forbiddenError("Deleting a Search Provider after receiving items is prohibited.")
    def on_delete(self, doc):
        """
        Overriding to check if the Ingest Source which has received item being deleted.
        """

        if doc.get('last_item_update'):
            raise SuperdeskApiError.forbiddenError("Deleting an Ingest Source after receiving items is prohibited.")
Пример #20
0
    def delete(self, lookup):
        """Delete user session.

        Deletes all the records from auth and corresponding
        session_preferences from user collections
        If there are any orphan session_preferences exist they get deleted as well
        """
        users_service = get_resource_service('users')
        user_id = request.view_args['user_id']
        user = users_service.find_one(req=None, _id=user_id)
        sessions = get_resource_service('auth').get(req=None, lookup={'user': user_id})

        error_message = self.__can_clear_sessions(user)
        if error_message:
            raise SuperdeskApiError.forbiddenError(message=error_message)

        # Delete all the sessions
        for session in sessions:
            get_resource_service('auth').delete_action({config.ID_FIELD: str(session[config.ID_FIELD])})

        # Check if any orphan session_preferences exist for the user
        if user.get('session_preferences'):
            # Delete the orphan sessions
            users_service.patch(user[config.ID_FIELD], {'session_preferences': {}})

        return [{'complete': True}]
Пример #21
0
    def lock(self, item_filter, user_id, session_id, etag):
        item_model = get_model(ItemModel)
        item = item_model.find_one(item_filter)

        if not item:
            raise SuperdeskApiError.notFoundError()

        can_user_lock, error_message = self.can_lock(item, user_id, session_id)

        if can_user_lock:
            self.app.on_item_lock(item, user_id)
            updates = {LOCK_USER: user_id, LOCK_SESSION: session_id, 'lock_time': utcnow()}
            item_model.update(item_filter, updates)

            if item.get(TASK):
                item[TASK]['user'] = user_id
            else:
                item[TASK] = {'user': user_id}

            superdesk.get_resource_service('tasks').assign_user(item[config.ID_FIELD], item[TASK])
            self.app.on_item_locked(item, user_id)
            push_notification('item:lock',
                              item=str(item.get(config.ID_FIELD)),
                              item_version=str(item.get(config.VERSION)),
                              user=str(user_id), lock_time=updates['lock_time'],
                              lock_session=str(session_id))
        else:
            raise SuperdeskApiError.forbiddenError(message=error_message)

        item = item_model.find_one(item_filter)
        return item
Пример #22
0
    def unlock(self, item_filter, user_id, session_id, etag):
        item_model = get_model(ItemModel)
        item = item_model.find_one(item_filter)

        if not item:
            raise SuperdeskApiError.notFoundError()

        if not item.get(LOCK_USER):
            raise SuperdeskApiError.badRequestError(message="Item is not locked.")

        can_user_unlock, error_message = self.can_unlock(item, user_id)

        if can_user_unlock:
            self.app.on_item_unlock(item, user_id)

            # delete the item if nothing is saved so far
            # version 0 created on lock item
            if item.get(config.VERSION, 0) == 0 and item[ITEM_STATE] == CONTENT_STATE.DRAFT:
                superdesk.get_resource_service('archive').delete_action(lookup={'_id': item['_id']})
                push_content_notification([item])
            else:
                updates = {LOCK_USER: None, LOCK_SESSION: None, 'lock_time': None, 'force_unlock': True}
                item_model.update(item_filter, updates)
                self.app.on_item_unlocked(item, user_id)

            push_notification('item:unlock',
                              item=str(item_filter.get(config.ID_FIELD)),
                              item_version=str(item.get(config.VERSION)),
                              state=item.get(ITEM_STATE),
                              user=str(user_id), lock_session=str(session_id))
        else:
            raise SuperdeskApiError.forbiddenError(message=error_message)

        item = item_model.find_one(item_filter)
        return item
    def _validate(self, doc_in_archive, doc, guid_to_duplicate):
        """Validates if the given archived_doc is still eligible to be duplicated.

        Rules:
            1. Is the item requested found in archive collection?
            2. Is workflow transition valid?
            3. Is item locked by another user?

        :param doc_in_archive: object representing the doc in archive collection
        :type doc_in_archive: dict
        :param doc: object received as part of request
        :type doc: dict
        :param guid_to_duplicate: GUID of the item to duplicate
        :type guid_to_duplicate: str
        :raises
            SuperdeskApiError.notFoundError: If doc_in_archive is None
            SuperdeskApiError.forbiddenError: if item is locked
            InvalidStateTransitionError: if workflow transition is invalid
        """

        if not doc_in_archive:
            raise SuperdeskApiError.notFoundError('Fail to found item with guid: %s' % guid_to_duplicate)

        if not is_workflow_state_transition_valid('duplicate', doc_in_archive[ITEM_STATE]):
            raise InvalidStateTransitionError()

        lock_user = doc_in_archive.get('lock_user', None)
        force_unlock = doc_in_archive.get('force_unlock', False)
        user = get_user()
        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')
Пример #24
0
    def lock(self, item_filter, user_id, session_id, action):
        item_model = get_model(ItemModel)
        item = item_model.find_one(item_filter)

        # set the lock_id it per item
        lock_id = "item_lock {}".format(item.get(config.ID_FIELD))

        if not item:
            raise SuperdeskApiError.notFoundError()

        # get the lock it not raise forbidden exception
        if not lock(lock_id, expire=5):
            raise SuperdeskApiError.forbiddenError(message="Item is locked by another user.")

        try:
            can_user_lock, error_message = self.can_lock(item, user_id, session_id)

            if can_user_lock:
                self.app.on_item_lock(item, user_id)
                updates = {LOCK_USER: user_id, LOCK_SESSION: session_id, 'lock_time': utcnow()}
                if action:
                    updates['lock_action'] = action

                item_model.update(item_filter, updates)

                if item.get(TASK):
                    item[TASK]['user'] = user_id
                else:
                    item[TASK] = {'user': user_id}

                superdesk.get_resource_service('tasks').assign_user(item[config.ID_FIELD], item[TASK])
                self.app.on_item_locked(item, user_id)
                item = item_model.find_one(item_filter)
                push_notification('item:lock',
                                  item=str(item.get(config.ID_FIELD)),
                                  item_version=str(item.get(config.VERSION)),
                                  user=str(user_id), lock_time=updates['lock_time'],
                                  lock_session=str(session_id),
                                  _etag=item.get(config.ETAG))
            else:
                raise SuperdeskApiError.forbiddenError(message=error_message)

            item = item_model.find_one(item_filter)
            return item
        finally:
            # unlock the lock :)
            unlock(lock_id, remove=True)
Пример #25
0
    def check_permissions(self, resource, method, user):
        """Checks user permissions.

        1. If there's no user associated with the request or HTTP Method is GET then return True.
        2. Get User's Privileges
        3. Intrinsic Privileges:
            Check if resource has intrinsic privileges.
                If it has then check if HTTP Method is allowed.
                    Return True if `is_authorized()` on the resource service returns True.
                    Otherwise, raise ForbiddenError.
                HTTP Method not allowed continue
            No intrinsic privileges continue
        4. User's Privileges
            Get Resource Privileges and validate it against user's privileges. Return True if validation is successful.
            Otherwise continue.
        5. If method didn't return True, then user is not authorized to perform the requested operation on the resource.
        """

        # Step 1:
        if not user:
            return True

        # Step 2: Get User's Privileges
        get_resource_service('users').set_privileges(user, flask.g.role)

        if method == 'GET':
            return True

        # Step 3: Intrinsic Privileges
        intrinsic_privileges = get_intrinsic_privileges()
        if intrinsic_privileges.get(resource) and method in intrinsic_privileges[resource]:
            service = get_resource_service(resource)
            authorized = service.is_authorized(user_id=str(user.get('_id')), _id=request.view_args.get('_id'))

            if not authorized:
                raise SuperdeskApiError.forbiddenError()

            return authorized

        # Step 4: User's privileges
        privileges = user.get('active_privileges', {})
        resource_privileges = get_resource_privileges(resource).get(method, None)
        if privileges.get(resource_privileges, False):
            return True

        # Step 5:
        raise SuperdeskApiError.forbiddenError()
Пример #26
0
    def create(self, docs, **kwargs):
        """Generate highlights text item for given package.

        If doc.preview is True it won't save the item, only return.
        """
        service = superdesk.get_resource_service('archive')
        for doc in docs:
            preview = doc.get('preview', False)
            package = service.find_one(req=None, _id=doc['package'])
            if not package:
                superdesk.abort(404)
            export = doc.get('export')
            template = get_template(package.get('highlight'))
            stringTemplate = None
            if template and 'body_html' in template.get('data', {}):
                stringTemplate = template['data']['body_html']

            doc.clear()
            doc[ITEM_TYPE] = CONTENT_TYPE.TEXT
            doc['family_id'] = package.get('guid')
            doc[ITEM_STATE] = CONTENT_STATE.SUBMITTED
            doc[config.VERSION] = 1

            for field in package:
                if field not in PACKAGE_FIELDS:
                    doc[field] = package[field]

            items = []
            for group in package.get('groups', []):
                for ref in group.get('refs', []):
                    if 'residRef' in ref:
                        item = service.find_one(req=None, _id=ref.get('residRef'))
                        if item:
                            if not (export or preview) and \
                                    (item.get('lock_session') or item.get('state') != 'published'):
                                message = 'Locked or not published items in highlight list.'
                                raise SuperdeskApiError.forbiddenError(message)

                            items.append(item)
                            if not preview:
                                app.on_archive_item_updated(
                                    {'highlight_id': package.get('highlight'),
                                     'highlight_name': get_highlight_name(package.get('highlight'))}, item,
                                    ITEM_EXPORT_HIGHLIGHT)

            if stringTemplate:
                doc['body_html'] = render_template_string(stringTemplate, package=package, items=items)
            else:
                doc['body_html'] = render_template('default_highlight_template.txt', package=package, items=items)
        if preview:
            return ['' for doc in docs]
        else:
            ids = service.post(docs, **kwargs)
            for id in ids:
                app.on_archive_item_updated(
                    {'highlight_id': package.get('highlight'),
                     'highlight_name': get_highlight_name(package.get('highlight'))}, {'_id': id},
                    ITEM_CREATE_HIGHLIGHT)
            return ids
Пример #27
0
    def check_get_access_privilege(self):
        if not hasattr(g, 'user'):
            return

        privileges = g.user.get('active_privileges', {})
        resource_privileges = get_resource_privileges(self.datasource).get('GET', None)
        if privileges.get(resource_privileges, 0) == 0:
            raise SuperdeskApiError.forbiddenError()
Пример #28
0
    def on_update(self, updates, original):
        """
        Overriding the method to prevent a user without 'User Management' privilege from changing a role.
        """

        if 'role' in updates and 'active_privileges' in flask.g.user:
            if not get_resource_privileges('users')['PATCH'] in flask.g.user['active_privileges']:
                raise SuperdeskApiError.forbiddenError("Insufficient privileges to change the role")
Пример #29
0
    def find_one(self, req, **lookup):
        item = super().find_one(req, **lookup)

        if item and str(item.get('task', {}).get('stage', '')) in \
                get_resource_service('users').get_invisible_stages_ids(get_user().get('_id')):
            raise SuperdeskApiError.forbiddenError("User does not have permissions to read the item.")

        return item
Пример #30
0
def is_update_allowed(archive_doc):
    """
    Checks if the archive_doc is valid to be updated. If invalid then the method raises ForbiddenError.
    For instance, a published item shouldn't be allowed to update.
    """

    if archive_doc.get(ITEM_STATE) == CONTENT_STATE.KILLED:
        raise SuperdeskApiError.forbiddenError("Item isn't in a valid state to be updated.")
Пример #31
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.COMPOSITE:
            self.packageService.on_update(updates, original)

        if original[ITEM_TYPE] == CONTENT_TYPE.PICTURE and not force_unlock:
            CropService().validate_multiple_crops(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
        if not force_unlock:
            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"))
Пример #32
0
 def on_delete(self, doc):
     events_using_file = get_resource_service("events").find(
         where={'files': doc.get("_id")})
     if events_using_file.count() > 0:
         raise SuperdeskApiError.forbiddenError(
             'Delete failed. File still used by other events.')
Пример #33
0
 def on_create(self, docs):
     subscription = SUBSCRIPTION_LEVEL
     if subscription in SUBSCRIPTION_MAX_THEMES:
         all = self.find()
         if (all.count() + len(docs) > SUBSCRIPTION_MAX_THEMES[subscription]):
             raise SuperdeskApiError.forbiddenError(message='Cannot add another theme.')
Пример #34
0
    def unlock(self, item_filter, user_id, session_id, etag):
        item_model = get_model(ItemModel)
        item = item_model.find_one(item_filter)

        if not item:
            raise SuperdeskApiError.notFoundError()

        if not item.get(LOCK_USER):
            raise SuperdeskApiError.badRequestError(
                message=_("Item is not locked."))

        can_user_unlock, error_message = self.can_unlock(item, user_id)

        if can_user_unlock:
            self.app.on_item_unlock(item, user_id)
            updates = {}

            # delete the item if nothing is saved so far
            # version 0 created on lock item
            if item.get(config.VERSION,
                        0) == 0 and item[ITEM_STATE] == CONTENT_STATE.DRAFT:
                if item.get(ITEM_TYPE) == CONTENT_TYPE.COMPOSITE:
                    # if item is composite then update referenced items in package.
                    PackageService().update_groups({}, item)

                superdesk.get_resource_service('archive').delete_action(
                    lookup={'_id': item['_id']})
                push_content_notification([item])
            else:
                updates = {
                    LOCK_USER: None,
                    LOCK_SESSION: None,
                    LOCK_TIME: None,
                    LOCK_ACTION: None,
                    'force_unlock': True
                }
                autosave = superdesk.get_resource_service(
                    'archive_autosave').find_one(req=None, _id=item['_id'])
                if autosave and item[ITEM_STATE] not in PUBLISH_STATES:
                    if not hasattr(
                            flask.g,
                            'user'):  # user is not set when session expires
                        flask.g.user = superdesk.get_resource_service(
                            'users').find_one(req=None, _id=user_id)
                    autosave.update(updates)
                    resolve_document_version(autosave, 'archive', 'PATCH',
                                             item)
                    superdesk.get_resource_service('archive').patch(
                        item['_id'], autosave)
                    item = superdesk.get_resource_service('archive').find_one(
                        req=None, _id=item['_id'])
                    insert_versioning_documents('archive', item)
                else:
                    item_model.update(item_filter, updates)
                    item = item_model.find_one(item_filter)
                self.app.on_item_unlocked(item, user_id)

            push_unlock_notification(item, user_id, session_id)
        else:
            raise SuperdeskApiError.forbiddenError(message=error_message)

        return item
Пример #35
0
def send_to(doc,
            update=None,
            desk_id=None,
            stage_id=None,
            user_id=None,
            default_stage='incoming_stage'):
    """Send item to given desk and stage.

    Applies the outgoing and incoming macros of current and destination stages

    :param doc: original document to be sent
    :param update: updates for the document
    :param desk: id of desk where item should be sent
    :param stage: optional stage within the desk
    :param default_stage: if no stage_id is passed then it determines the stage in that desk the doc is assigned,
            either the the incomming stage or the working stage.
    """

    original_task = doc.setdefault('task', {})
    current_stage = None
    if original_task.get('stage'):
        current_stage = get_resource_service('stages').find_one(
            req=None, _id=original_task.get('stage'))
    desk = destination_stage = None
    task = {
        'desk': desk_id,
        'stage': stage_id,
        'user': original_task.get('user') if user_id is None else user_id
    }

    if current_stage:
        apply_stage_rule(doc, update, current_stage, MACRO_OUTGOING)

    if desk_id:
        desk = superdesk.get_resource_service('desks').find_one(req=None,
                                                                _id=desk_id)
        if not desk:
            raise SuperdeskApiError.notFoundError(
                _('Invalid desk identifier {desk_id}').format(desk_id=desk_id))

        if not current_user_has_privilege('move') and \
                str(user_id) not in [str(x.get('user', '')) for x in desk.get('members', [])]:
            raise SuperdeskApiError.forbiddenError(
                _('User is not member of desk: {desk_id}').format(
                    desk_id=desk_id))

        task['desk'] = desk_id
        if not stage_id:
            task['stage'] = desk.get(default_stage)
            destination_stage = get_resource_service('stages').find_one(
                req=None, _id=desk.get(default_stage))

    if stage_id:
        destination_stage = get_resource_service('stages').find_one(
            req=None, _id=stage_id)
        if not destination_stage:
            raise SuperdeskApiError.notFoundError(
                _('Invalid stage identifier {stage_id}').format(
                    stage_id=stage_id))

        task['desk'] = destination_stage['desk']
        task['stage'] = stage_id

    if destination_stage:
        apply_stage_rule(doc,
                         update,
                         destination_stage,
                         MACRO_INCOMING,
                         desk=desk,
                         task=task)
        if destination_stage.get('task_status'):
            task['status'] = destination_stage['task_status']

    if update:
        update.setdefault('task', {})
        update['task'].update(task)
        update['expiry'] = get_item_expiry(desk=desk, stage=destination_stage)
    else:
        doc['task'].update(task)
        doc['expiry'] = get_item_expiry(desk=desk, stage=destination_stage)
        superdesk.get_resource_service('desks').apply_desk_metadata(doc, doc)
Пример #36
0
    def _validate(self, doc):
        assignments_service = get_resource_service('assignments')
        assignment = assignments_service.find_one(req=None,
                                                  _id=doc.get('assignment_id'))

        user = get_user(required=True)
        user_id = user.get(config.ID_FIELD)

        session = get_auth()
        session_id = session.get(config.ID_FIELD)

        if not assignment:
            raise SuperdeskApiError.badRequestError('Assignment not found.')

        if not assignments_service.is_text_assignment(assignment):
            raise SuperdeskApiError.badRequestError(
                'Cannot unlink media assignments.')

        if assignment.get(LOCK_USER):
            if str(assignment.get(LOCK_USER)) != str(user_id):
                raise SuperdeskApiError.forbiddenError(
                    'Assignment is locked by another user. Cannot unlink assignment and content.'
                )

            if str(assignment.get(LOCK_SESSION)) != str(session_id):
                raise SuperdeskApiError.forbiddenError(
                    'Assignment is locked by you in another session. Cannot unlink assignment and content.'
                )

        item = get_resource_service('archive').find_one(req=None,
                                                        _id=doc.get('item_id'))

        # try looking in the archived content
        if not item:
            item = get_resource_service('archived').find_one(
                req=None, _id=doc.get('item_id'))
            if not item:
                raise SuperdeskApiError.badRequestError(
                    'Content item not found.')

        # If the item is locked, then check to see if it is locked by the
        # current user in their current session
        if item.get(LOCK_USER):
            if str(item.get(LOCK_USER)) != str(user_id):
                raise SuperdeskApiError.forbiddenError(
                    'Item is locked by another user. Cannot unlink assignment and content.'
                )

            if str(item.get(LOCK_SESSION)) != str(session_id):
                raise SuperdeskApiError.forbiddenError(
                    'Item is locked by you in another session. Cannot unlink assignment and content.'
                )

        if not item.get('assignment_id'):
            raise SuperdeskApiError.badRequestError(
                'Content not linked to an assignment. Cannot unlink assignment and content.'
            )

        if str(item.get('assignment_id')) != str(
                assignment.get(config.ID_FIELD)):
            raise SuperdeskApiError.badRequestError(
                'Assignment and Content are not linked.')

        deliveries = get_resource_service('delivery').get(
            req=None,
            lookup={'assignment_id': assignment.get(config.ID_FIELD)})
        # Match the passed item_id in doc or if the item is archived the archived item_id
        delivery = [
            d for d in deliveries
            if d.get('item_id') == item.get('item_id', doc.get('item_id'))
        ]
        if len(delivery) <= 0:
            raise SuperdeskApiError.badRequestError(
                'Content doesnt exist for the assignment. Cannot unlink assignment and content.'
            )
Пример #37
0
 def _validate_user(self, doc_user_id, doc_is_global):
     session_user = get_user(required=True)
     if str(session_user['_id']) != doc_user_id and \
             not (current_user_has_privilege('global_saved_searches') and doc_is_global):
         raise SuperdeskApiError.forbiddenError(
             'Unauthorized to modify global search.')
Пример #38
0
    def lock(self, item, user_id, session_id, action, resource):
        if not item:
            raise SuperdeskApiError.notFoundError()

        item_service = get_resource_service(resource)
        item_id = item.get(config.ID_FIELD)

        # lock_id will be:
        # 1 - Recurrence Id for items part of recurring series (event or planning)
        # 2 - event_item for planning with associated event
        # 3 - item's _id for all other cases
        lock_id_field = config.ID_FIELD
        if item.get('recurrence_id'):
            lock_id_field = 'recurrence_id'
        elif item.get('type') != 'event' and item.get('event_item'):
            lock_id_field = 'event_item'

        # set the lock_id it per item
        lock_id = "item_lock {}".format(item.get(lock_id_field))

        # get the lock it not raise forbidden exception
        if not lock(lock_id, expire=5):
            raise SuperdeskApiError.forbiddenError(
                message="Item is locked by another user.")

        try:
            can_user_lock, error_message = self.can_lock(
                item, user_id, session_id, resource)

            if can_user_lock:
                # following line executes handlers attached to function:
                # on_lock_'resource' - ex. on_lock_planning, on_lock_event
                getattr(self.app, 'on_lock_%s' % resource)(item, user_id)

                updates = {
                    LOCK_USER: user_id,
                    LOCK_SESSION: session_id,
                    'lock_time': utcnow()
                }
                if action:
                    updates['lock_action'] = action

                item_service.update(item.get(config.ID_FIELD), updates, item)

                push_notification(resource + ':lock',
                                  item=str(item.get(config.ID_FIELD)),
                                  user=str(user_id),
                                  lock_time=updates['lock_time'],
                                  lock_session=str(session_id),
                                  lock_action=updates.get('lock_action'),
                                  etag=updates['_etag'])
            else:
                raise SuperdeskApiError.forbiddenError(message=error_message)

            item = item_service.find_one(req=None, _id=item_id)

            # following line executes handlers attached to function:
            # on_locked_'resource' - ex. on_locked_planning, on_locked_event
            getattr(self.app, 'on_locked_%s' % resource)(item, user_id)
            return item
        finally:
            # unlock the lock :)
            unlock(lock_id, remove=True)
Пример #39
0
    def on_update(self, updates, original):
        updates[ITEM_OPERATION] = ITEM_UPDATE
        is_update_allowed(original)
        user = get_user()

        if 'publish_schedule' in updates and original['state'] == 'scheduled':
            # this is an deschedule action
            self.deschedule_item(updates, original)
            # check if there is a takes package and deschedule the takes package.
            package = TakesPackageService().get_take_package(original)
            if package and package.get('state') == 'scheduled':
                package_updates = {
                    'publish_schedule': None,
                    'groups': package.get('groups')
                }
                self.patch(package.get(config.ID_FIELD), package_updates)
            return

        if updates.get('publish_schedule'):

            if datetime.datetime.fromtimestamp(0).date() == updates.get(
                    'publish_schedule').date():
                # publish_schedule field will be cleared
                updates['publish_schedule'] = None
            else:
                # validate the schedule
                if is_item_in_package(original):
                    raise SuperdeskApiError.\
                        badRequestError(message='This item is in a package' +
                                                ' it needs to be removed before the item can be scheduled!')
                package = TakesPackageService().get_take_package(
                    original) or {}
                validate_schedule(updates.get('publish_schedule'),
                                  package.get(SEQUENCE, 1))

        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")

        remove_unwanted(updates)

        if self.__is_req_for_save(updates):
            update_state(original, updates)

        lock_user = original.get('lock_user', None)
        force_unlock = updates.get('force_unlock', False)

        updates.setdefault('original_creator',
                           original.get('original_creator'))

        str_user_id = str(user.get('_id')) 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')

        updates['versioncreated'] = utcnow()
        set_item_expiry(updates, original)
        updates['version_creator'] = str_user_id
        set_sign_off(updates, original=original)
        update_word_count(updates)

        if force_unlock:
            del updates['force_unlock']

        # create crops
        crop_service = ArchiveCropService()
        crop_service.validate_multiple_crops(updates, original)
        crop_service.create_multiple_crops(updates, original)

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

        update_version(updates, original)

        # Do the validation after Circular Reference check passes in Package Service
        updated = original.copy()
        updated.update(updates)
        self.validate_embargo(updated)
Пример #40
0
 def _check_max_active(self, increment):
     subscription = SUBSCRIPTION_LEVEL
     if subscription in SUBSCRIPTION_MAX_ACTIVE_BLOGS:
         active = self.find({'blog_status': 'open'})
         if active.count() + increment > SUBSCRIPTION_MAX_ACTIVE_BLOGS[subscription]:
             raise SuperdeskApiError.forbiddenError(message='Cannot add another active blog.')
Пример #41
0
 def on_delete(self, doc):
     if self.backend.find_one('ingest_providers',
                              req=None,
                              rule_set=doc['_id']):
         raise SuperdeskApiError.forbiddenError('rule set is in use')
Пример #42
0
 def check_all_groups_have_id_set(self, groups):
     if any(group for group in groups if not group.get('id')):
         message = 'Group is missing id.'
         logger.error(message)
         raise SuperdeskApiError.forbiddenError(message=message)
Пример #43
0
    def check_permissions(self, resource, method, user):
        """Checks user permissions.

        1. If there's no user associated with the request or HTTP Method is GET or the Resource is a Flask Blueprint
        then return True.
        2. Get User's Privileges
        3. Intrinsic Privileges:
            Check if resource has intrinsic privileges.
                If it has then check if HTTP Method is allowed.
                    Return True if `is_authorized()` on the resource service returns True.
                    Otherwise, raise ForbiddenError.
                HTTP Method not allowed continue
            No intrinsic privileges continue
        4. User's Privileges
            Get Resource Privileges and validate it against user's privileges. Return True if validation is successful.
            Otherwise continue.
        5. If method didn't return True, then user is not authorized to perform the requested operation on the resource.
        """

        # Step 1:
        if not user:
            return True

        if resource == "_blueprint":
            return True

        # Step 2: Get User's Privileges
        get_resource_service("users").set_privileges(user, flask.g.role)

        try:
            resource_privileges = get_resource_privileges(resource).get(
                method, None)
        except KeyError:
            resource_privileges = None

        if method == "GET" and not resource_privileges:
            return True

        # Step 3: Intrinsic Privileges
        message = _("Insufficient privileges for the requested operation.")
        intrinsic_privileges = get_intrinsic_privileges()
        if intrinsic_privileges.get(
                resource) and method in intrinsic_privileges[resource]:
            service = get_resource_service(resource)
            authorized = service.is_authorized(
                user_id=str(user.get("_id")),
                _id=request.view_args.get("_id"),
                method=method)

            if not authorized:
                raise SuperdeskApiError.forbiddenError(message=message)

            return authorized

        # Step 4: User's privileges
        privileges = user.get("active_privileges", {})

        if not resource_privileges and get_no_resource_privileges(resource):
            return True

        if privileges.get(resource_privileges, False):
            return True

        # Step 5:
        raise SuperdeskApiError.forbiddenError(message=message)