def restore_version(self, id, doc): item_id = id old_version = int(doc.get('old_version', 0)) last_version = int(doc.get('last_version', 0)) if (not all([item_id, old_version, last_version])): return None old = get_resource_service('archive_versions').find_one(req=None, _id_document=item_id, _version=old_version) if old is None: raise SuperdeskApiError.notFoundError('Invalid version %s' % old_version) curr = get_resource_service(SOURCE).find_one(req=None, _id=item_id) if curr is None: raise SuperdeskApiError.notFoundError('Invalid item id %s' % item_id) if curr[config.VERSION] != last_version: raise SuperdeskApiError.preconditionFailedError('Invalid last version %s' % last_version) old['_id'] = old['_id_document'] old['_updated'] = old['versioncreated'] = utcnow() set_item_expiry(old, doc) del old['_id_document'] resolve_document_version(old, 'archive', 'PATCH', curr) remove_unwanted(old) res = super().replace(id=item_id, document=old) del doc['old_version'] del doc['last_version'] doc.update(old) return res
def get_expiry(desk_id, stage_id, offset=None): """ Calculates the expiry for a content from fetching the expiry duration from one of the below 1. desk identified by desk_id 2. stage identified by stage_id :param desk_id: desk identifier :param stage_id: stage identifier :return: when the doc will expire """ stage = None desk = None 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 %s' % desk_id) if stage_id: stage = get_resource_service('stages').find_one(req=None, _id=stage_id) if not stage: raise SuperdeskApiError.notFoundError('Invalid stage identifier %s' % stage_id) return get_item_expiry(desk, stage, offset)
def get_expiry(desk_id=None, stage_id=None, desk_or_stage_doc=None): """ Calculates the expiry for a content from fetching the expiry duration from one of the below 1. desk identified by desk_id 2. stage identified by stage_id. This will ignore desk_id if specified 3. desk doc or stage doc identified by doc_or_stage_doc. This will ignore desk_id and stage_id if specified :param desk_id: desk identifier :param stage_id: stage identifier :param desk_or_stage_doc: doc from either desks collection or stages collection :return: when the doc will expire """ stage = None if desk_or_stage_doc is None and desk_id: desk = superdesk.get_resource_service('desks').find_one(req=None, _id=desk_id) if not desk: raise SuperdeskApiError.notFoundError('Invalid desk identifier %s' % desk_id) if not stage_id: stage = get_resource_service('stages').find_one(req=None, _id=desk['incoming_stage']) if not stage: raise SuperdeskApiError.notFoundError('Invalid stage identifier %s' % stage_id) if desk_or_stage_doc is None and stage_id: stage = get_resource_service('stages').find_one(req=None, _id=stage_id) if not stage: raise SuperdeskApiError.notFoundError('Invalid stage identifier %s' % stage_id) return get_item_expiry(app=app, stage=desk_or_stage_doc or stage)
def restore_version(self, id, doc, original): item_id = id old_version = int(doc.get('old_version', 0)) last_version = int(doc.get('last_version', 0)) if (not all([item_id, old_version, last_version])): return None old = get_resource_service('archive_versions').find_one( req=None, _id_document=item_id, _version=old_version) if old is None: raise SuperdeskApiError.notFoundError('Invalid version %s' % old_version) curr = get_resource_service(SOURCE).find_one(req=None, _id=item_id) if curr is None: raise SuperdeskApiError.notFoundError('Invalid item id %s' % item_id) if curr[config.VERSION] != last_version: raise SuperdeskApiError.preconditionFailedError( 'Invalid last version %s' % last_version) old['_id'] = old['_id_document'] old['_updated'] = old['versioncreated'] = utcnow() set_item_expiry(old, doc) del old['_id_document'] resolve_document_version(old, 'archive', 'PATCH', curr) remove_unwanted(old) super().replace(id=item_id, document=old, original=curr) del doc['old_version'] del doc['last_version'] doc.update(old) return item_id
def restore_version(self, id, doc, original): item_id = id old_version = int(doc.get("old_version", 0)) last_version = int(doc.get("last_version", 0)) if not all([item_id, old_version, last_version]): return None old = get_resource_service("archive_versions").find_one( req=None, _id_document=item_id, _current_version=old_version ) if old is None: raise SuperdeskApiError.notFoundError("Invalid version %s" % old_version) curr = get_resource_service(SOURCE).find_one(req=None, _id=item_id) if curr is None: raise SuperdeskApiError.notFoundError("Invalid item id %s" % item_id) if curr[config.VERSION] != last_version: raise SuperdeskApiError.preconditionFailedError("Invalid last version %s" % last_version) old["_id"] = old["_id_document"] old["_updated"] = old["versioncreated"] = utcnow() set_item_expiry(old, doc) del old["_id_document"] resolve_document_version(old, "archive", "PATCH", curr) remove_unwanted(old) super().replace(id=item_id, document=old, original=curr) del doc["old_version"] del doc["last_version"] doc.update(old) return item_id
def get_expiry(desk_id, stage_id, offset=None): """Calculates the expiry for an item. Fetches the expiry duration from one of the below 1. desk identified by desk_id 2. stage identified by stage_id :param desk_id: desk identifier :param stage_id: stage identifier :return: when the doc will expire """ stage = None desk = None 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 stage_id: stage = get_resource_service("stages").find_one(req=None, _id=stage_id) if not stage: raise SuperdeskApiError.notFoundError( _("Invalid stage identifier {stage_id}").format( stage_id=stage_id)) return get_item_expiry(desk, stage, offset)
def get_keywords(self, text): if not app.config['KEYWORDS_KEY_API']: raise SuperdeskApiError.notFoundError('AlchemyAPI key is not set') params = { 'apikey': app.config['KEYWORDS_KEY_API'], 'outputMode': 'json' } url = app.config['KEYWORDS_BASE_URL'] + '/text/TextGetRankedNamedEntities' + \ '?' + urllib.parse.urlencode(params) values = {'text': text} result = "" try: result = self._http.post(url, data=values) except Exception: raise SuperdeskApiError.notFoundError( 'Fail to connect to Alchemy service') try: keywords = result.json() return keywords.get('entities', []) except Exception: raise SuperdeskApiError.notFoundError( 'Fail to parse the response from Alchemy service')
def get_expiry(desk_id=None, stage_id=None): stage = None 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 %s' % desk_id) if not stage_id: stage = get_resource_service('stages').find_one( req=None, _id=desk['incoming_stage']) if not stage: raise SuperdeskApiError.notFoundError( 'Invalid stage identifier %s' % stage_id) if stage_id: stage = get_resource_service('stages').find_one(req=None, _id=stage_id) if not stage: raise SuperdeskApiError.notFoundError( 'Invalid stage identifier %s' % stage_id) return get_item_expiry(app=app, stage=stage)
def _validate_rewrite(self, original): """ Validates the article to be rewritten :param original: article to be rewritten :raises: SuperdeskApiError """ if not original: raise SuperdeskApiError.notFoundError( message='Cannot find the article') if original.get(EMBARGO): raise SuperdeskApiError.badRequestError( "Rewrite of an Item having embargo isn't possible") if not original.get('event_id'): raise SuperdeskApiError.notFoundError( message='Event id does not exist') if get_resource_service('published').is_rewritten_before( original['_id']): raise SuperdeskApiError.badRequestError( message='Article has been rewritten before !') if not is_workflow_state_transition_valid('rewrite', original[ITEM_STATE]): raise InvalidStateTransitionError() if not TakesPackageService().is_last_takes_package_item(original): raise SuperdeskApiError.badRequestError( message="Only last take of the package can be rewritten.")
def send_to(doc, desk_id=None, stage_id=None): """Send item to given desk and stage. :param doc: item to be sent :param desk: id of desk where item should be sent :param stage: optional stage within the desk """ task = doc.get('task', {}) task.setdefault('desk', desk_id) task.setdefault('stage', stage_id) calculate_expiry_from = None if desk_id and not stage_id: desk = superdesk.get_resource_service('desks').find_one(req=None, _id=desk_id) if not desk: raise SuperdeskApiError.notFoundError('Invalid desk identifier %s' % desk_id) calculate_expiry_from = desk task['desk'] = desk_id task['stage'] = desk.get('incoming_stage') if stage_id: stage = get_resource_service('stages').find_one(req=None, _id=stage_id) if not stage: raise SuperdeskApiError.notFoundError('Invalid stage identifier %s' % stage_id) calculate_expiry_from = stage task['desk'] = stage['desk'] task['stage'] = stage_id if stage.get('task_status'): task['status'] = stage['task_status'] doc['task'] = task doc['expiry'] = get_expiry(desk_or_stage_doc=calculate_expiry_from)
def _change_request(self, endpoint_name, id, updates, original): backend = self._backend(endpoint_name) search_backend = self._lookup_backend(endpoint_name) try: backend.update(endpoint_name, id, updates, original) except eve.io.base.DataLayer.OriginalChangedError: if not backend.find_one(endpoint_name, req=None, _id=id) and search_backend: # item is in elastic, not in mongo - not good logger.warn("Item is missing in mongo resource=%s id=%s".format(endpoint_name, id)) self.remove_from_search(endpoint_name, id) raise SuperdeskApiError.notFoundError() else: # item is there, but no change was done - ok logger.error('Item : {} not updated in collection {}. ' 'Updates are : {}'.format(id, endpoint_name, updates)) return updates if search_backend: doc = backend.find_one(endpoint_name, req=None, _id=id) if not doc: # there is no doc in mongo, remove it from elastic logger.warn("Item is missing in mongo resource=%s id=%s".format(endpoint_name, id)) self.remove_from_search(endpoint_name, id) raise SuperdeskApiError.notFoundError() search_backend.update(endpoint_name, id, doc) return updates
def send_to(doc, desk_id=None, stage_id=None): """Send item to given desk and stage. :param doc: item to be sent :param desk: id of desk where item should be sent :param stage: optional stage within the desk """ task = doc.get('task', {}) task.setdefault('desk', desk_id) task.setdefault('stage', stage_id) if desk_id and not stage_id: desk = superdesk.get_resource_service('desks').find_one(req=None, _id=desk_id) if not desk: raise SuperdeskApiError.notFoundError( 'Invalid desk identifier %s' % desk_id) task['stage'] = desk.get('incoming_stage') if task['stage']: stage = get_resource_service('stages').find_one(req=None, _id=task['stage']) if not stage: raise SuperdeskApiError.notFoundError( 'Invalid stage identifier %s' % task['stage']) if stage.get('task_status'): doc['task'] = doc.get('task', {}) doc['task']['status'] = stage['task_status'] doc['task'] = task doc['expiry'] = get_expiry(desk_id, stage_id)
def _change_request(self, endpoint_name, id, updates, original): backend = self._backend(endpoint_name) search_backend = self._lookup_backend(endpoint_name) try: backend.update(endpoint_name, id, updates, original) except eve.io.base.DataLayer.OriginalChangedError: if not backend.find_one(endpoint_name, req=None, _id=id) and search_backend: # item is in elastic, not in mongo - not good logger.warn("Item is missing in mongo resource=%s id=%s".format(endpoint_name, id)) item = search_backend.find_one(endpoint_name, req=None, _id=id) if item: self.remove_from_search(endpoint_name, item) raise SuperdeskApiError.notFoundError() else: # item is there, but no change was done - ok logger.error('Item : {} not updated in collection {}. ' 'Updates are : {}'.format(id, endpoint_name, updates)) return updates if search_backend: doc = backend.find_one(endpoint_name, req=None, _id=id) if not doc: # there is no doc in mongo, remove it from elastic logger.warn("Item is missing in mongo resource=%s id=%s".format(endpoint_name, id)) item = search_backend.find_one(endpoint_name, req=None, _id=id) if item: self.remove_from_search(endpoint_name, item) raise SuperdeskApiError.notFoundError() search_backend.update(endpoint_name, id, doc) return updates
def send_to(doc, update=None, desk_id=None, stage_id=None, user_id=None): """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 """ 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, is_incoming=False) 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 %s' % desk_id) task['desk'] = desk_id if not stage_id: task['stage'] = desk.get('incoming_stage') destination_stage = get_resource_service('stages').find_one( req=None, _id=desk.get('incoming_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 %s' % stage_id) task['desk'] = destination_stage['desk'] task['stage'] = stage_id if destination_stage: apply_stage_rule(doc, update, destination_stage, is_incoming=True) 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)
def _validate_rewrite(self, original, update): """ Validates the article to be rewritten :param original: article to be rewritten :param update: article as the rewrite :raises: SuperdeskApiError """ if not original: raise SuperdeskApiError.notFoundError( message='Cannot find the article') if original.get(EMBARGO): raise SuperdeskApiError.badRequestError( "Rewrite of an Item having embargo isn't possible") if not original.get('event_id'): raise SuperdeskApiError.notFoundError( message='Event id does not exist') if original.get('rewritten_by'): raise SuperdeskApiError.badRequestError( message='Article has been rewritten before !') if not is_workflow_state_transition_valid('rewrite', original[ITEM_STATE]): raise InvalidStateTransitionError() if not TakesPackageService().is_last_takes_package_item(original): raise SuperdeskApiError.badRequestError( message="Only last take of the package can be rewritten.") if original.get('rewrite_of') and not (original.get(ITEM_STATE) in PUBLISH_STATES): raise SuperdeskApiError.badRequestError( message= "Rewrite is not published. Cannot rewrite the story again.") if update: # in case of associate as update if update.get('rewrite_of'): raise SuperdeskApiError.badRequestError( "Rewrite story has been used as update before !") if update.get(ITEM_STATE) in [ CONTENT_STATE.PUBLISHED, CONTENT_STATE.CORRECTED, CONTENT_STATE.KILLED, CONTENT_STATE.SCHEDULED, CONTENT_STATE.SPIKED ]: raise InvalidStateTransitionError() if update.get(ITEM_TYPE) not in [ CONTENT_TYPE.TEXT, CONTENT_TYPE.PREFORMATTED ]: raise SuperdeskApiError.badRequestError( "Rewrite story can only be text or pre-formatted !") if update.get('genre') and \ any(genre.get('value', '').lower() == BROADCAST_GENRE.lower() for genre in update.get('genre')): raise SuperdeskApiError.badRequestError( "Broadcast cannot be a update story !")
def _change_request(self, endpoint_name, id, updates, original, change_request=False, push_notification=True): backend = self._backend(endpoint_name) search_backend = self._lookup_backend(endpoint_name) try: if change_request: # allows using mongo operations other than $set backend._change_request(endpoint_name, id, updates, original) else: backend.update(endpoint_name, id, updates, original) if push_notification: self._push_resource_notification("updated", endpoint_name, _id=str(id), fields=get_diff_keys( updates, original)) except eve.io.base.DataLayer.OriginalChangedError: if not backend.find_one(endpoint_name, req=None, _id=id) and search_backend: # item is in elastic, not in mongo - not good logger.warn( "Item is missing in mongo resource={} id={}".format( endpoint_name, id)) item = search_backend.find_one(endpoint_name, req=None, _id=id) if item: self.remove_from_search(endpoint_name, item) raise SuperdeskApiError.notFoundError() else: # item is there, but no change was done logger.error( "Item was not updated in mongo, it has changed from the original.", extra=dict( id=id, resource=endpoint_name, updates=updates, original=original, ), ) return updates if search_backend: doc = backend.find_one(endpoint_name, req=None, _id=id) if not doc: # there is no doc in mongo, remove it from elastic logger.warn( "Item is missing in mongo resource={} id={}".format( endpoint_name, id)) item = search_backend.find_one(endpoint_name, req=None, _id=id) if item: self.remove_from_search(endpoint_name, item) raise SuperdeskApiError.notFoundError() search_backend.update(endpoint_name, id, doc) return updates
def _validate_rewrite(self, original, update): """Validates the article to be rewritten. :param original: article to be rewritten :param update: article as the rewrite :raises: SuperdeskApiError """ if not original: raise SuperdeskApiError.notFoundError(message=_('Cannot find the article')) if original.get(EMBARGO): raise SuperdeskApiError.badRequestError(_("Rewrite of an Item having embargo isn't possible")) if not original.get('event_id'): raise SuperdeskApiError.notFoundError(message=_('Event id does not exist')) if original.get('rewritten_by'): raise SuperdeskApiError.badRequestError(message=_('Article has been rewritten before !')) if (not is_workflow_state_transition_valid('rewrite', original[ITEM_STATE]) and not config.ALLOW_UPDATING_SCHEDULED_ITEMS): raise InvalidStateTransitionError() if ( original.get('rewrite_of') and not (original.get(ITEM_STATE) in PUBLISH_STATES) and not app.config['WORKFLOW_ALLOW_MULTIPLE_UPDATES'] ): raise SuperdeskApiError.badRequestError( message=_("Rewrite is not published. Cannot rewrite the story again.")) if update: # in case of associate as update if update.get('rewrite_of'): raise SuperdeskApiError.badRequestError(_("Rewrite story has been used as update before !")) if update.get(ITEM_STATE) in [CONTENT_STATE.PUBLISHED, CONTENT_STATE.CORRECTED, CONTENT_STATE.KILLED, CONTENT_STATE.RECALLED, CONTENT_STATE.SCHEDULED, CONTENT_STATE.SPIKED]: raise InvalidStateTransitionError() if update.get(ITEM_TYPE) not in [CONTENT_TYPE.TEXT, CONTENT_TYPE.PREFORMATTED]: raise SuperdeskApiError.badRequestError(_("Rewrite story can only be text or pre-formatted !")) if update.get('genre') and \ any(genre.get('value', '').lower() == BROADCAST_GENRE.lower() for genre in update.get('genre')): raise SuperdeskApiError.badRequestError(_("Broadcast cannot be a update story !")) if original.get('profile') and original.get('profile') != update.get('profile'): raise SuperdeskApiError.badRequestError(_("Rewrite item content profile does " "not match with Original item."))
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 %s' % 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 %s' % 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) 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)
def send_to(doc, update=None, desk_id=None, stage_id=None, user_id=None): """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 """ 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")) destination_stage = calculate_expiry_from = 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, is_incoming=False) if desk_id and not stage_id: desk = superdesk.get_resource_service("desks").find_one(req=None, _id=desk_id) if not desk: raise SuperdeskApiError.notFoundError("Invalid desk identifier %s" % desk_id) calculate_expiry_from = desk task["desk"] = desk_id task["stage"] = desk.get("incoming_stage") destination_stage = get_resource_service("stages").find_one(req=None, _id=desk.get("incoming_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 %s" % stage_id) calculate_expiry_from = destination_stage task["desk"] = destination_stage["desk"] task["stage"] = stage_id if destination_stage: apply_stage_rule(doc, update, destination_stage, is_incoming=True) if destination_stage.get("task_status"): task["status"] = destination_stage["task_status"] if update: update.setdefault("task", {}) update["task"].update(task) update["expiry"] = get_expiry(desk_or_stage_doc=calculate_expiry_from) else: doc["task"].update(task) doc["expiry"] = get_expiry(desk_or_stage_doc=calculate_expiry_from)
def send_to(doc, update=None, desk_id=None, stage_id=None, user_id=None): """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 """ task = doc.get('task', {}) current_stage = get_resource_service('stages').find_one(req=None, _id=task.get('stage')) destination_stage = None task.setdefault('desk', desk_id) task.setdefault('stage', stage_id) task.setdefault('user', user_id) calculate_expiry_from = None if current_stage: apply_stage_rule(doc, update, current_stage, is_incoming=False) if desk_id and not stage_id: desk = superdesk.get_resource_service('desks').find_one(req=None, _id=desk_id) if not desk: raise SuperdeskApiError.notFoundError('Invalid desk identifier %s' % desk_id) calculate_expiry_from = desk task['desk'] = desk_id task['stage'] = desk.get('incoming_stage') destination_stage = get_resource_service('stages').find_one(req=None, _id=desk.get('incoming_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 %s' % stage_id) calculate_expiry_from = destination_stage task['desk'] = destination_stage['desk'] task['stage'] = stage_id if destination_stage: apply_stage_rule(doc, update, destination_stage, is_incoming=True) if destination_stage.get('task_status'): task['status'] = destination_stage['task_status'] if update: update['task'] = task update['expiry'] = get_expiry(desk_or_stage_doc=calculate_expiry_from) else: doc['task'] = task doc['expiry'] = get_expiry(desk_or_stage_doc=calculate_expiry_from)
def _validate_rewrite(self, original, update): """Validates the article to be rewritten. :param original: article to be rewritten :param update: article as the rewrite :raises: SuperdeskApiError """ if not original: raise SuperdeskApiError.notFoundError(message='Cannot find the article') if original.get(EMBARGO): raise SuperdeskApiError.badRequestError("Rewrite of an Item having embargo isn't possible") if not original.get('event_id'): raise SuperdeskApiError.notFoundError(message='Event id does not exist') if original.get('rewritten_by'): raise SuperdeskApiError.badRequestError(message='Article has been rewritten before !') if not is_workflow_state_transition_valid('rewrite', original[ITEM_STATE]): raise InvalidStateTransitionError() if original.get('rewrite_of') and not (original.get(ITEM_STATE) in PUBLISH_STATES): raise SuperdeskApiError.badRequestError(message="Rewrite is not published. Cannot rewrite the story again.") if update: # in case of associate as update if update.get('rewrite_of'): raise SuperdeskApiError.badRequestError("Rewrite story has been used as update before !") if update.get(ITEM_STATE) in [CONTENT_STATE.PUBLISHED, CONTENT_STATE.CORRECTED, CONTENT_STATE.KILLED, CONTENT_STATE.RECALLED, CONTENT_STATE.SCHEDULED, CONTENT_STATE.SPIKED]: raise InvalidStateTransitionError() if update.get(ITEM_TYPE) not in [CONTENT_TYPE.TEXT, CONTENT_TYPE.PREFORMATTED]: raise SuperdeskApiError.badRequestError("Rewrite story can only be text or pre-formatted !") if update.get('genre') and \ any(genre.get('value', '').lower() == BROADCAST_GENRE.lower() for genre in update.get('genre')): raise SuperdeskApiError.badRequestError("Broadcast cannot be a update story !") if original.get('profile') and original.get('profile') != update.get('profile'): raise SuperdeskApiError.badRequestError("Rewrite item content profile does " "not match with Original item.")
def create(self, docs, **kwargs): guid_of_item_to_be_copied = request.view_args['guid'] guid_of_copied_items = [] for doc in docs: archive_service = get_resource_service(ARCHIVE) archived_doc = archive_service.find_one(req=None, _id=guid_of_item_to_be_copied) if not archived_doc: raise SuperdeskApiError.notFoundError('Fail to found item with guid: %s' % guid_of_item_to_be_copied) current_desk_of_item = archived_doc.get('task', {}).get('desk') if current_desk_of_item: raise SuperdeskApiError.preconditionFailedError(message='Copy is not allowed on items in a desk.') if not is_workflow_state_transition_valid('copy', archived_doc[ITEM_STATE]): raise InvalidStateTransitionError() new_guid = archive_service.duplicate_content(archived_doc) guid_of_copied_items.append(new_guid) if kwargs.get('notify', True): push_notification('item:copy', copied=1) return guid_of_copied_items
def get_upload_as_data_uri(media_id): if not request.args.get('resource'): media_id = app.media.getFilename(media_id) media_file = app.media.get(media_id, 'upload') else: media_file = app.media.get(media_id, request.args['resource']) if media_file: data = wrap_file(request.environ, media_file, buffer_size=1024 * 256) response = app.response_class(data, mimetype=media_file.content_type, direct_passthrough=True) response.content_length = media_file.length response.last_modified = media_file.upload_date response.set_etag(media_file.md5) response.cache_control.max_age = cache_for response.cache_control.s_max_age = cache_for response.cache_control.public = True response.make_conditional(request) if strtobool(request.args.get('download', 'False')): response.headers['Content-Disposition'] = 'attachment' else: response.headers['Content-Disposition'] = 'inline' return response raise SuperdeskApiError.notFoundError('File not found on media storage.')
def create(self, docs, **kwargs): guid_of_item_to_be_duplicated = request.view_args['guid'] guid_of_duplicated_items = [] for doc in docs: archive_service = get_resource_service(ARCHIVE) archived_doc = archive_service.find_one(req=None, _id=guid_of_item_to_be_duplicated) if not archived_doc: raise SuperdeskApiError.notFoundError('Fail to found item with guid: %s' % guid_of_item_to_be_duplicated) current_desk_of_item = archived_doc.get('task', {}).get('desk') if current_desk_of_item is None or str(current_desk_of_item) != str(doc.get('desk')): raise SuperdeskApiError.preconditionFailedError(message='Duplicate is allowed within the same desk.') if not is_workflow_state_transition_valid('duplicate', archived_doc[ITEM_STATE]): raise InvalidStateTransitionError() send_to(doc=archived_doc, desk_id=doc.get('desk')) new_guid = archive_service.duplicate_content(archived_doc) guid_of_duplicated_items.append(new_guid) if kwargs.get('notify', True): push_content_notification([archived_doc]) return guid_of_duplicated_items
def _send_report(scheduled_report): email_service = get_resource_service('email_report') saved_report = get_resource_service('saved_reports').find_one( req=None, _id=scheduled_report.get('saved_report')) if not saved_report: raise SuperdeskApiError.notFoundError('Saved report not found') extra = scheduled_report.get('extra') or {} body = extra.get('body') or 'Superdesk Analytics - {}'.format( scheduled_report.get('name')) email_service.post([{ 'report': { 'type': saved_report.get('report'), 'params': saved_report.get('params'), 'mimetype': scheduled_report.get('mimetype'), 'width': scheduled_report.get('report_width') }, 'email': { 'recipients': scheduled_report.get('recipients'), 'subject': 'Superdesk Analytics - {}'.format( scheduled_report.get('name')), 'txt': { 'body': body }, 'html': { 'body': body } } }])
def move_content(self, id, doc): archive_service = get_resource_service(ARCHIVE) archived_doc = archive_service.find_one(req=None, _id=id) if not archived_doc: raise SuperdeskApiError.notFoundError('Fail to found item with guid: %s' % id) current_stage_of_item = archived_doc.get('task', {}).get('stage') if current_stage_of_item and str(current_stage_of_item) == str(doc.get('task', {}).get('stage')): raise SuperdeskApiError.preconditionFailedError(message='Move is not allowed within the same stage.') if not is_workflow_state_transition_valid('submit_to_desk', archived_doc[config.CONTENT_STATE]): raise InvalidStateTransitionError() original = dict(archived_doc) send_to(archived_doc, doc.get('task', {}).get('desc'), doc.get('task', {}).get('stage')) if archived_doc[config.CONTENT_STATE] not in ['published', 'scheduled', 'killed']: archived_doc[config.CONTENT_STATE] = 'submitted' resolve_document_version(archived_doc, ARCHIVE, 'PATCH', original) del archived_doc['_id'] archive_service.update(original['_id'], archived_doc, original) insert_into_versions(id_=original['_id']) return archived_doc
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 = { 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
def create(self, docs, **kwargs): guid_of_item_to_be_copied = request.view_args['guid'] guid_of_copied_items = [] for doc in docs: archive_service = get_resource_service(ARCHIVE) archived_doc = archive_service.find_one(req=None, _id=guid_of_item_to_be_copied) if not archived_doc: raise SuperdeskApiError.notFoundError(_( 'Fail to found item with guid: {guid}').format(guid=guid_of_item_to_be_copied)) current_desk_of_item = archived_doc.get('task', {}).get('desk') if current_desk_of_item: raise SuperdeskApiError.preconditionFailedError(message=_('Copy is not allowed on items in a desk.')) if not is_workflow_state_transition_valid('copy', archived_doc[ITEM_STATE]): raise InvalidStateTransitionError() new_guid = archive_service.duplicate_content(archived_doc) guid_of_copied_items.append(new_guid) if kwargs.get('notify', True): user = get_user() push_notification('item:copy', copied=1, user=str(user.get(config.ID_FIELD, ''))) return guid_of_copied_items
def create(self, docs, **kwargs): guid_of_item_to_be_copied = request.view_args["guid"] guid_of_copied_items = [] for doc in docs: archive_service = get_resource_service(ARCHIVE) archived_doc = archive_service.find_one(req=None, _id=guid_of_item_to_be_copied) if not archived_doc: raise SuperdeskApiError.notFoundError( _("Fail to found item with guid: {guid}").format(guid=guid_of_item_to_be_copied) ) current_desk_of_item = archived_doc.get("task", {}).get("desk") if current_desk_of_item and not app.config["WORKFLOW_ALLOW_COPY_TO_PERSONAL"]: raise SuperdeskApiError.preconditionFailedError(message=_("Copy is not allowed on items in a desk.")) elif current_desk_of_item: archived_doc["task"] = {} archived_doc["original_creator"] = get_user_id() if not is_workflow_state_transition_valid("copy", archived_doc[ITEM_STATE]): raise InvalidStateTransitionError() new_guid = archive_service.duplicate_content(archived_doc) guid_of_copied_items.append(new_guid) if kwargs.get("notify", True): user = get_user() push_notification("item:copy", copied=1, user=str(user.get(config.ID_FIELD, ""))) return guid_of_copied_items
def create(self, docs, **kwargs): # we override create because we don't want anything stored in database doc = docs[0] sc_name = doc["spellchecker"] language = doc.get("language") try: spellchecker = registered_spellcheckers[sc_name] except KeyError: raise SuperdeskApiError.notFoundError( "{sc_name} spellchecker can't be found".format( sc_name=sc_name)) if doc["suggestions"]: check_data = spellchecker.suggest(doc["text"], language) assert "suggestions" in check_data else: check_data = spellchecker.check(doc["text"], language) assert "errors" in check_data if doc["use_internal_dict"]: self.remove_errors_in_dict(spellchecker, language, check_data) ignore = doc.get("ignore") if ignore: self.remove_ignored(check_data, ignore) docs[0].update(check_data) return [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")
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')
def create(self, docs, **kwargs): guid_of_translated_items = [] for doc in docs: guid_of_item_to_be_translated = doc.get('guid') archive_service = get_resource_service(ARCHIVE) archived_doc = archive_service.find_one( req=None, _id=guid_of_item_to_be_translated) if not archived_doc: raise SuperdeskApiError.notFoundError( 'Fail to found item with guid: %s' % guid_of_item_to_be_translated) if not is_workflow_state_transition_valid( 'translate', archived_doc[ITEM_STATE]): raise InvalidStateTransitionError() get_resource_service('macros').execute_translation_macro( archived_doc, archived_doc.get('language', None), doc.get('language')) archived_doc['language'] = doc.get('language') new_guid = archive_service.duplicate_content(archived_doc) guid_of_translated_items.append(new_guid) if kwargs.get('notify', True): push_content_notification([archived_doc]) return guid_of_translated_items
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
def create(self, docs, **kwargs): guid_of_translated_items = [] for doc in docs: guid_of_item_to_be_translated = doc.get('guid') archive_service = get_resource_service(ARCHIVE) archived_doc = archive_service.find_one(req=None, _id=guid_of_item_to_be_translated) if not archived_doc: raise SuperdeskApiError.notFoundError('Fail to found item with guid: %s' % guid_of_item_to_be_translated) if not is_workflow_state_transition_valid('translate', archived_doc[ITEM_STATE]): raise InvalidStateTransitionError() get_resource_service('macros').execute_translation_macro( archived_doc, archived_doc.get('language', None), doc.get('language')) archived_doc['language'] = doc.get('language') new_guid = archive_service.duplicate_content(archived_doc) guid_of_translated_items.append(new_guid) if kwargs.get('notify', True): push_content_notification([archived_doc]) return guid_of_translated_items
def authenticate(self, credentials): """Authenticates the user against Active Directory :param credentials: an object having "username" and "password" attributes :return: if success returns User object, otherwise throws Error """ settings = app.settings ad_auth = ADAuth(settings['LDAP_SERVER'], settings['LDAP_SERVER_PORT'], settings['LDAP_BASE_FILTER'], settings['LDAP_USER_FILTER'], settings['LDAP_USER_ATTRIBUTES'], settings['LDAP_FQDN']) username = credentials.get('username') password = credentials.get('password') profile_to_import = credentials.get('profile_to_import', username) user_data = ad_auth.authenticate_and_fetch_profile(username, password, username_for_profile=profile_to_import) if len(user_data) == 0: raise SuperdeskApiError.notFoundError( message='No user has been found in AD', payload={'profile_to_import': 1}) query = get_user_query(profile_to_import) user = superdesk.get_resource_service('users').find_one(req=None, **query) if not user: add_default_values(user_data, profile_to_import, user_type=None if 'user_type' not in user_data else user_data['user_type']) user = user_data else: superdesk.get_resource_service('users').patch(user.get('_id'), user_data) user = superdesk.get_resource_service('users').find_one(req=None, **query) return user
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')
def run(self, ad_username, ad_password, username, admin='false'): """ Imports or Updates a User Profile from AD to Mongo. :param ad_username: Active Directory Username :param ad_password: Password of Active Directory Username :param username: Username as in Active Directory whose profile needs to be imported to Superdesk. :return: User Profile. """ # force type conversion to boolean user_type = 'administrator' if admin is not None and admin.lower() == 'true' else 'user' # Authenticate and fetch profile from AD settings = app.settings ad_auth = ADAuth(settings['LDAP_SERVER'], settings['LDAP_SERVER_PORT'], settings['LDAP_BASE_FILTER'], settings['LDAP_USER_FILTER'], settings['LDAP_USER_ATTRIBUTES'], settings['LDAP_FQDN']) user_data = ad_auth.authenticate_and_fetch_profile(ad_username, ad_password, username) if len(user_data) == 0: raise SuperdeskApiError.notFoundError('Username not found') # Check if User Profile already exists in Mongo user = superdesk.get_resource_service('users').find_one(username=username, req=None) if user: superdesk.get_resource_service('users').patch(user.get('_id'), user_data) else: add_default_values(user_data, username, user_type=user_type) superdesk.get_resource_service('users').post([user_data]) return user_data
def get(self, req, lookup): """Filter out personal activity on personal items if inquired by another user.""" if req is None: req = ParsedRequest() user = getattr(g, "user", None) if not user: raise SuperdeskApiError.notFoundError("Can not determine user") where_cond = {} if req.where: if req.where[0] != "{": req.where = "{" + req.where + "}" where_cond = json.loads(req.where) for_user = where_cond.get("user", str(user.get("_id"))) if for_user != str(user.get("_id")): where_item = { "$and": [{ "desk": { "$ne": None } }, { "desk": { "$exists": True } }, { "resource": "archive" }] } where_cond["$or"] = [where_item, {"resource": {"$ne": "archive"}}] req.where = json.dumps(where_cond) return self.backend.get(self.datasource, req=req, lookup=lookup)
def create(self, docs, **kwargs): guid_of_item_to_be_moved = request.view_args['guid'] guid_of_moved_items = [] for doc in docs: archive_service = get_resource_service(ARCHIVE) archived_doc = archive_service.find_one(req=None, _id=guid_of_item_to_be_moved) if not archived_doc: raise SuperdeskApiError.notFoundError('Fail to found item with guid: %s' % guid_of_item_to_be_moved) current_stage_of_item = archived_doc.get('task', {}).get('stage') if current_stage_of_item and str(current_stage_of_item) == str(doc.get('stage')): raise SuperdeskApiError.preconditionFailedError(message='Move is not allowed within the same stage.') if not is_workflow_state_transition_valid('submit_to_desk', archived_doc[config.CONTENT_STATE]): raise InvalidStateTransitionError() original = dict(archived_doc) send_to(archived_doc, doc.get('desk'), doc.get('stage')) archived_doc[config.CONTENT_STATE] = 'submitted' resolve_document_version(archived_doc, ARCHIVE, 'PATCH', original) del archived_doc['_id'] archive_service.update(original['_id'], archived_doc, original) insert_into_versions(guid=original['_id']) guid_of_moved_items.append(archived_doc['guid']) return guid_of_moved_items
def move_content(self, id, doc): archive_service = get_resource_service(ARCHIVE) archived_doc = archive_service.find_one(req=None, _id=id) if not archived_doc: raise SuperdeskApiError.notFoundError('Fail to found item with guid: %s' % id) current_stage_of_item = archived_doc.get('task', {}).get('stage') if current_stage_of_item and str(current_stage_of_item) == str(doc.get('task', {}).get('stage')): raise SuperdeskApiError.preconditionFailedError(message='Move is not allowed within the same stage.') if not is_workflow_state_transition_valid('submit_to_desk', archived_doc[ITEM_STATE]): raise InvalidStateTransitionError() original = dict(archived_doc) user = get_user() send_to(doc=archived_doc, desk_id=doc.get('task', {}).get('desc'), stage_id=doc.get('task', {}).get('stage'), user_id=user.get(config.ID_FIELD)) if archived_doc[ITEM_STATE] not in {CONTENT_STATE.PUBLISHED, CONTENT_STATE.SCHEDULED, CONTENT_STATE.KILLED}: archived_doc[ITEM_STATE] = CONTENT_STATE.SUBMITTED archived_doc[ITEM_OPERATION] = ITEM_MOVE set_sign_off(archived_doc, original=original) resolve_document_version(archived_doc, ARCHIVE, 'PATCH', original) del archived_doc[config.ID_FIELD] archive_service.update(original[config.ID_FIELD], archived_doc, original) insert_into_versions(id_=original[config.ID_FIELD]) return archived_doc
def validate(self, updates, original): """ Generic validation for event actions A lock must be held by the user in their current session As well as the lock must solely be for the action being processed, i.e. lock_action='update_time' """ if not original: raise SuperdeskApiError.notFoundError() if self.REQUIRE_LOCK: user_id = get_user_id() session_id = get_auth().get(config.ID_FIELD, None) lock_user = original.get(LOCK_USER, None) lock_session = original.get(LOCK_SESSION, None) lock_action = original.get(LOCK_ACTION, None) if not lock_user: raise SuperdeskApiError.forbiddenError( message='The event must be locked') elif str(lock_user) != str(user_id): raise SuperdeskApiError.forbiddenError( message='The event is locked by another user') elif str(lock_session) != str(session_id): raise SuperdeskApiError.forbiddenError( message='The event is locked by you in another session') elif str(lock_action) != self.ACTION: raise SuperdeskApiError.forbiddenError( message='The lock must be for the `{}` action'.format( self.ACTION.lower().replace('_', ' '))) get_resource_service('events').validate_event(updates, original)
def create(self, docs, **kwargs): guid_of_item_to_be_duplicated = request.view_args['guid'] guid_of_duplicated_items = [] for doc in docs: archive_service = get_resource_service(ARCHIVE) archived_doc = archive_service.find_one(req=None, _id=guid_of_item_to_be_duplicated) if not archived_doc: raise SuperdeskApiError.notFoundError('Fail to found item with guid: %s' % guid_of_item_to_be_duplicated) current_desk_of_item = archived_doc.get('task', {}).get('desk') if current_desk_of_item is None or str(current_desk_of_item) != str(doc.get('desk')): raise SuperdeskApiError.preconditionFailedError(message='Duplicate is allowed within the same desk.') send_to(doc=archived_doc, desk_id=doc.get('desk')) new_guid = archive_service.duplicate_content(archived_doc) guid_of_duplicated_items.append(new_guid) if kwargs.get('notify', True): task = archived_doc.get('task', {}) push_notification( 'content:update', duplicated=1, item=str(new_guid), desk=str(task.get('desk', '')), stage=str(task.get('stage', '')) ) return guid_of_duplicated_items
def get(self, req, lookup): """ Return a list of items related to the given item. The given item id is retrieved from the lookup dictionary as 'item_id' """ if 'item_id' not in lookup: raise SuperdeskApiError.badRequestError('The item identifier is required') item = get_resource_service('archive_autosave').find_one(req=None, _id=lookup['item_id']) if not item: item = get_resource_service('archive').find_one(req=None, _id=lookup['item_id']) if not item: raise SuperdeskApiError.notFoundError('Invalid item identifer') keywords = self.provider.get_keywords(self._transform(item)) if not keywords: return ElasticCursor([]) query = { 'query': { 'filtered': { 'query': { 'query_string': { 'query': ' '.join(kwd['text'] for kwd in keywords) } } } } } req = ParsedRequest() req.args = {'source': json.dumps(query), 'repo': 'archive,published,archived'} return get_resource_service('search').get(req=req, lookup=None)
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')
def get(self, req, lookup): """Filter out personal activity on personal items if inquired by another user.""" if req is None: req = ParsedRequest() user = getattr(g, 'user', None) if not user: raise SuperdeskApiError.notFoundError('Can not determine user') where_cond = {} if req.where: if req.where[0] != '{': req.where = '{' + req.where + '}' where_cond = json.loads(req.where) for_user = where_cond.get('user', str(user.get('_id'))) if for_user != str(user.get('_id')): where_item = { '$and': [{ 'desk': { '$ne': None } }, { 'desk': { '$exists': True } }, { 'resource': 'archive' }] } where_cond['$or'] = [where_item, {'resource': {'$ne': 'archive'}}] req.where = json.dumps(where_cond) return self.backend.get(self.datasource, req=req, lookup=lookup)
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')
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')
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
def create(self, docs, **kwargs): guid_of_item_to_be_duplicated = request.view_args['guid'] guid_of_duplicated_items = [] for doc in docs: archive_service = get_resource_service(ARCHIVE) archived_doc = archive_service.find_one( req=None, _id=guid_of_item_to_be_duplicated) if not archived_doc: raise SuperdeskApiError.notFoundError( 'Fail to found item with guid: %s' % guid_of_item_to_be_duplicated) current_desk_of_item = archived_doc.get('task', {}).get('desk') if current_desk_of_item is None or str( current_desk_of_item) != str(doc.get('desk')): raise SuperdeskApiError.preconditionFailedError( message='Duplicate is allowed within the same desk.') if not is_workflow_state_transition_valid( 'duplicate', archived_doc[ITEM_STATE]): raise InvalidStateTransitionError() send_to(doc=archived_doc, desk_id=doc.get('desk')) new_guid = archive_service.duplicate_content(archived_doc) guid_of_duplicated_items.append(new_guid) if kwargs.get('notify', True): push_content_notification([archived_doc]) return guid_of_duplicated_items
def _translate_item(self, guid, language, task=None, service=None, state=None, **kwargs): if not service: service = ARCHIVE archive_service = get_resource_service(service) macros_service = get_resource_service("macros") published_service = get_resource_service("published") item = archive_service.find_one(req=None, guid=guid) if not item: raise SuperdeskApiError.notFoundError(_("Fail to found item with guid: {guid}").format(guid=guid)) if not is_workflow_state_transition_valid("translate", item[ITEM_STATE]): raise InvalidStateTransitionError() if item.get("language") == language: return guid if package_service.is_package(item): refs = package_service.get_item_refs(item) for ref in refs: ref[RESIDREF] = self._translate_item(ref[RESIDREF], language, service=ref.get("location"), task=task) if not item.get("translation_id"): item["translation_id"] = item["guid"] macros_service.execute_translation_macro(item, item.get("language", None), language) item["language"] = language item["translated_from"] = guid item["versioncreated"] = utcnow() item["firstcreated"] = utcnow() if task: item["task"] = task extra_fields = ["translation_id", "translated_from"] UPDATE_TRANSLATION_METADATA_MACRO = app.config.get("UPDATE_TRANSLATION_METADATA_MACRO") if UPDATE_TRANSLATION_METADATA_MACRO and macros_service.get_macro_by_name(UPDATE_TRANSLATION_METADATA_MACRO): macros_service.execute_macro(item, UPDATE_TRANSLATION_METADATA_MACRO) translation_guid = archive_service.duplicate_item( item, extra_fields=extra_fields, state=state, operation="translate" ) item.setdefault("translations", []).append(translation_guid) updates = { "translation_id": item["translation_id"], "translations": item["translations"], } archive_service.system_update(item["_id"], updates, item) published_service.update_published_items(item["_id"], "translation_id", item["_id"]) published_service.update_published_items(item["_id"], "translations", item["translations"]) if kwargs.get("notify", True): push_content_notification([item]) return translation_guid
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 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
def get_associated_item(self, assoc, throw_if_not_found=True): endpoint = assoc.get('location', 'archive') item_id = assoc[ITEM_REF] item = get_resource_service(endpoint).find_one(req=None, _id=item_id) if not item and throw_if_not_found: message = 'Invalid item reference: ' + assoc[ITEM_REF] logger.error(message) raise SuperdeskApiError.notFoundError(message=message) return item, item_id, endpoint
def create(self, docs, **kwargs): if not docs: raise SuperdeskApiError.notFoundError('Content is missing') req = parse_request(self.datasource) try: get_component(ItemAutosave).autosave(docs[0]['_id'], docs[0], get_user(required=True), req.if_match) except InvalidEtag: raise SuperdeskApiError.preconditionFailedError('Client and server etags don\'t match') return [docs[0]['_id']]
def get(self, req, **lookup): saved_search_id = lookup['lookup']['saved_search_id'] saved_search = get_resource_service('saved_searches').find_one(req=None, _id=saved_search_id) if not saved_search: raise SuperdeskApiError.notFoundError("Invalid Saved Search") repo, query = super().process_query(saved_search) return super().validate_and_run_elastic_query(query, repo)