def _reschedule_coverage(self, coverage, reason): note = '''------------------------------------------------------------ Event has been rescheduled ''' if reason: note += 'Reason: {}\n'.format(reason) if not coverage.get('planning'): coverage['planning'] = {} if len(coverage['planning'].get('internal_note') or '') > 0: coverage['planning']['internal_note'] += '\n\n' + note else: coverage['planning']['internal_note'] = note if len(coverage['planning'].get('ednote') or '') > 0: coverage['planning']['ednote'] += '\n\n' + note else: coverage['planning']['ednote'] = note assigned_to = coverage.get('assigned_to') if assigned_to: assignment_service = get_resource_service('assignments') assignment = assignment_service.find_one(req=None, _id=assigned_to.get('assignment_id')) slugline = assignment.get('planning').get('slugline', '') coverage_type = assignment.get('planning').get('g2_content_type', '') PlanningNotifications().notify_assignment(coverage_status=coverage.get('workflow_status'), target_user=assignment.get('assigned_to').get('user'), target_desk=assignment.get('assigned_to').get( 'desk') if not assignment.get('assigned_to').get( 'user') else None, message='The event associated with {{coverage_type}} coverage ' '\"{{slugline}}\" has been marked as rescheduled', slugline=slugline, coverage_type=get_coverage_type_name(coverage_type))
def create(self, docs): ids = [] production = get_resource_service('archive') assignments_service = get_resource_service('assignments') items = [] for doc in docs: assignment = assignments_service.find_one( req=None, _id=doc.pop('assignment_id')) item = production.find_one(req=None, _id=doc.pop('item_id')) # Boolean set to true if the unlink is as the result of spiking the content item spike = doc.pop('spike', False) # Set the state to 'assigned' if the item is 'submitted' updates = {'assigned_to': deepcopy(assignment.get('assigned_to'))} updates['assigned_to'][ 'state'] = ASSIGNMENT_WORKFLOW_STATE.ASSIGNED assignments_service.patch(assignment[config.ID_FIELD], updates) production.system_update(item[config.ID_FIELD], {'assignment_id': None}, item) get_resource_service('delivery').delete_action( lookup={ 'assignment_id': assignment[config.ID_FIELD], 'item_id': item[config.ID_FIELD] }) doc.update(item) ids.append(doc[config.ID_FIELD]) items.append(item) user = get_user() PlanningNotifications().notify_assignment( target_desk=item.get('task').get('desk'), message='{{actioning_user}} has {{action}} ' 'a {{coverage_type}} coverage for \"{{slugline}}\"', actioning_user=user.get('display_name', user.get('username', 'Unknown')), action='unlinked' if not spike else 'spiked', coverage_type=get_coverage_type_name(item.get('type', '')), slugline=item.get('slugline'), omit_user=True) push_content_notification(items) push_notification('content:unlink', item=str(item[config.ID_FIELD]), assignment=str(assignment[config.ID_FIELD])) assignment_history_service = get_resource_service( 'assignments_history') if spike: get_resource_service('assignments_history').on_item_content_unlink( updates, assignment, ASSIGNMENT_HISTORY_ACTIONS.SPIKE_UNLINK) else: assignment_history_service.on_item_content_unlink( updates, assignment) return ids
def update(self, id, updates, original): user = get_user(required=True).get(config.ID_FIELD, '') session = get_auth().get(config.ID_FIELD, '') updates['assigned_to'] = deepcopy(original).get('assigned_to') # If we are confirming availability, save the revert state for revert action coverage_type = original.get('planning', {}).get('g2_content_type') if coverage_type != 'text': updates['assigned_to']['revert_state'] = updates['assigned_to'][ 'state'] updates['assigned_to']['state'] = ASSIGNMENT_WORKFLOW_STATE.COMPLETED remove_lock_information(updates) item = self.backend.update(self.datasource, id, updates, original) # Save history if user initiates complete if coverage_type == 'text': get_resource_service('assignments_history').on_item_complete( updates, original) else: get_resource_service( 'assignments_history').on_item_confirm_availability( updates, original) push_notification('assignments:completed', item=str(original[config.ID_FIELD]), planning=original.get('planning_item'), assigned_user=(original.get('assigned_to') or {}).get('user'), assigned_desk=(original.get('assigned_to') or {}).get('desk'), assignment_state=ASSIGNMENT_WORKFLOW_STATE.COMPLETED, user=str(user), session=str(session), coverage=original.get('coverage_item')) # Send notification that the work has been completed # Determine the display name of the assignee assigned_to_user = get_resource_service('users').find_one(req=None, _id=user) assignee = assigned_to_user.get( 'display_name') if assigned_to_user else 'Unknown' PlanningNotifications().notify_assignment( target_user=str( original.get('assigned_to', {}).get('assignor_user')), message='{{coverage_type}} coverage \"{{slugline}}\" has been ' 'completed by {{assignee}}', assignee=assignee, coverage_type=get_coverage_type_name( original.get('planning', {}).get('g2_content_type', '')), slugline=original.get('planning', {}).get('slugline'), omit_user=True) return item
def create(self, docs): ids = [] production = get_resource_service('archive') assignments_service = get_resource_service('assignments') for doc in docs: assignment = assignments_service.find_one(req=None, _id=doc.pop('assignment_id')) item = get_item_from_assignment(assignment, doc.pop('template_name', None)) item[config.VERSION] = 1 item.setdefault('type', 'text') item['assignment_id'] = assignment[config.ID_FIELD] # create content ids = production.post([item]) insert_into_versions(doc=item) # create delivery references get_resource_service('delivery').post([{ 'item_id': item[config.ID_FIELD], 'assignment_id': assignment[config.ID_FIELD], 'planning_id': assignment['planning_item'], 'coverage_id': assignment['coverage_item'] }]) updates = {'assigned_to': deepcopy(assignment.get('assigned_to'))} updates['assigned_to']['user'] = str(item.get('task').get('user')) updates['assigned_to']['desk'] = str(item.get('task').get('desk')) updates['assigned_to']['state'] = ASSIGNMENT_WORKFLOW_STATE.IN_PROGRESS updates['assigned_to']['assignor_user'] = str(item.get('task').get('user')) updates['assigned_to']['assigned_date_user'] = utcnow() # set the assignment to in progress assignments_service.patch(assignment[config.ID_FIELD], updates) doc.update(item) ids.append(doc['_id']) # Send notification that the work has commenced # Determine the display name of the assignee assigned_to_user = superdesk.get_resource_service('users').find_one(req=None, _id=str(item.get('task').get('user'))) assignee = assigned_to_user.get('display_name') if assigned_to_user else 'Unknown' PlanningNotifications().notify_assignment(target_desk=item.get('task').get('desk'), target_user=str(item.get('task').get('user')), message='assignment_commenced_msg', assignee=assignee, coverage_type=get_coverage_type_name(item.get('type', '')), slugline=item.get('slugline'), omit_user=True) # Save history get_resource_service('assignments_history').on_item_start_working(updates, assignment) # publishing planning item assignments_service.publish_planning(assignment['planning_item']) return ids
def update(self, id, updates, original): user = get_user(required=True) updates['revert_state'] = original[ITEM_STATE] updates[ITEM_STATE] = WORKFLOW_STATE.SPIKED set_item_expiry(updates) # Mark item as unlocked directly in order to avoid more queries and notifications # coming from lockservice. updates.update({ LOCK_USER: None, LOCK_SESSION: None, 'lock_time': None, 'lock_action': None }) remove_autosave_on_spike(original) item = self.backend.update(self.datasource, id, updates, original) push_notification('planning:spiked', item=str(id), user=str(user.get(config.ID_FIELD)), etag=item['_etag'], revert_state=item['revert_state']) coverages = original.get('coverages') or [] for coverage in coverages: assigned_to = coverage.get('assigned_to') if assigned_to: user = get_user() assignment_service = get_resource_service('assignments') assignment = assignment_service.find_one( req=None, _id=assigned_to.get('assignment_id')) slugline = assignment.get('planning').get('slugline', '') coverage_type = assignment.get('planning').get( 'g2_content_type', '') PlanningNotifications().notify_assignment( coverage_status=coverage.get('workflow_status'), target_user=assignment.get('assigned_to').get('user'), target_desk=assignment.get('assigned_to').get('desk') if not assignment.get('assigned_to').get('user') else None, message='{{actioning_user}} has spiked a {{coverage_type}} ' 'coverage for \"{{slugline}}\"', slugline=slugline, coverage_type=get_coverage_type_name(coverage_type), actioning_user=user.get('display_name', user.get('username', 'Unknown')), omit_user=True) return item
def send_assignment_cancellation_notification(self, assignment, original_state, event_cancellation=False): """Set the assignment information and send notification :param dict doc: Updates related to assignments """ # No notifications for 'draft' assignments if not assignment or original_state == ASSIGNMENT_WORKFLOW_STATE.DRAFT: return user = get_user() assigned_to = assignment.get('assigned_to') slugline = assignment.get('planning').get('slugline', '') coverage_type = assignment.get('planning').get('g2_content_type', '') desk = get_resource_service('desks').find_one( req=None, _id=assigned_to.get('desk')) if event_cancellation: PlanningNotifications().notify_assignment( target_user=assigned_to.get('user'), target_desk=assigned_to.get('desk') if not assigned_to.get('user') else None, message='The event associated with {{coverage_type}} coverage ' '\"{{slugline}}\" has been marked as cancelled', slugline=slugline, coverage_type=get_coverage_type_name(coverage_type)) return PlanningNotifications().notify_assignment( target_user=assigned_to.get('user'), target_desk=assigned_to.get('desk') if not assigned_to.get('user') else None, message='Assignment {{slugline}} for desk {{desk}} has been' ' cancelled by {{user}}', user=user.get('display_name', 'Unknown') if str(user.get(config.ID_FIELD, None)) != assigned_to.get('user') else 'You', omit_user=True, slugline=slugline, desk=desk.get('name'))
def notify_draft_coverage_on_spike(self, coverage): assigned_to = coverage.get('assigned_to') if assigned_to: user = get_user() assignment_service = get_resource_service('assignments') assignment = assignment_service.find_one( req=None, _id=assigned_to.get('assignment_id')) slugline = assignment.get('planning').get('slugline', '') coverage_type = assignment.get('planning').get( 'g2_content_type', '') PlanningNotifications().notify_assignment( coverage_status=coverage.get('workflow_status'), target_user=assignment.get('assigned_to').get('user'), target_desk=assignment.get('assigned_to').get('desk') if not assignment.get('assigned_to').get('user') else None, message='assignment_spiked_msg', slugline=slugline, coverage_type=get_coverage_type_name(coverage_type), actioning_user=user.get('display_name', user.get('username', 'Unknown')), omit_user=True)
def _reschedule_coverage(self, coverage, reason): if coverage.get('workflow_status') != WORKFLOW_STATE.CANCELLED: coverage['planning']['workflow_status_reason'] = reason coverage['workflow_status'] = WORKFLOW_STATE.CANCELLED assigned_to = coverage.get('assigned_to') if assigned_to: assignment_service = get_resource_service('assignments') assignment = assignment_service.find_one( req=None, _id=assigned_to.get('assignment_id')) slugline = assignment.get('planning').get('slugline', '') coverage_type = assignment.get('planning').get( 'g2_content_type', '') PlanningNotifications().notify_assignment( coverage_status=coverage.get('workflow_status'), target_user=assignment.get('assigned_to').get('user'), target_desk=assignment.get('assigned_to').get('desk') if not assignment.get('assigned_to').get('user') else None, message='assignment_rescheduled_msg', slugline=slugline, coverage_type=get_coverage_type_name(coverage_type))
def _postpone_coverage(self, updates, coverage): if coverage.get('workflow_status') != WORKFLOW_STATE.CANCELLED: coverage['planning']['workflow_status_reason'] = updates.get( 'reason') assigned_to = coverage.get('assigned_to') if assigned_to: assignment_service = get_resource_service('assignments') assignment = assignment_service.find_one( req=None, _id=assigned_to.get('assignment_id')) slugline = assignment.get('planning').get('slugline', '') coverage_type = assignment.get('planning').get( 'g2_content_type', '') PlanningNotifications().notify_assignment( coverage_status=assignment.get('assigned_to').get('state'), target_user=assignment.get('assigned_to').get('user'), target_desk=assignment.get('assigned_to').get('desk') if not assignment.get('assigned_to').get('user') else None, message='The event associated with {{coverage_type}} coverage ' '\"{{slugline}}\" has been marked as postponed', slugline=slugline, coverage_type=get_coverage_type_name(coverage_type))
def remove_assignment(self, assignment_item, unlock_planning=False): coverage_id = assignment_item.get('coverage_item') planning_item = self.find_one(req=None, _id=assignment_item.get('planning_item')) if planning_item: coverages = planning_item.get('coverages') or [] try: coverage_item = next(c for c in coverages if c.get('coverage_id') == coverage_id) except StopIteration: raise SuperdeskApiError.badRequestError( 'Coverage does not exist') assigned_to = assignment_item.get('assigned_to') message = 'The {{coverage_type}} assignment {{slugline}} has been removed' PlanningNotifications().notify_assignment( coverage_status=coverage_item.get('workflow_status'), target_desk=assigned_to.get('desk') if assigned_to.get('user') is None else None, target_user=assigned_to.get('user'), message=message, coverage_type=get_coverage_type_name( coverage_item.get('planning', {}).get('g2_content_type', '')), slugline=planning_item.get('slugline', '')) coverage_item['assigned_to'] = None coverage_item['workflow_status'] = WORKFLOW_STATE.DRAFT updates = {'coverages': coverages} if unlock_planning: remove_lock_information(updates) updated_planning = self.update(planning_item[config.ID_FIELD], updates, planning_item) return updated_planning
def _create_update_assignment(self, planning_original, planning_updates, updates, original=None): """Create or update the assignment. :param dict planning_original: original parent planning document :param dict planning_updates: updates for the parent planning document :param dict updates: coverage update document :param dict original: coverage original document """ if not original: original = {} planning = deepcopy(planning_original) planning.update(planning_updates) planning_id = planning.get(config.ID_FIELD) doc = deepcopy(original) doc.update(updates) assignment_service = get_resource_service('assignments') assigned_to = updates.get('assigned_to') or original.get('assigned_to') if not assigned_to: return if not planning_id: raise SuperdeskApiError.badRequestError( 'Planning item is required to create assignments.') # Coverage is draft if original was draft and updates is still maintaining that state is_coverage_draft = updates.get( 'workflow_status', original.get('workflow_status')) == WORKFLOW_STATE.DRAFT if not assigned_to.get('assignment_id') and (assigned_to.get('user') or assigned_to.get('desk')): # Creating a new assignment assign_state = ASSIGNMENT_WORKFLOW_STATE.DRAFT if is_coverage_draft else ASSIGNMENT_WORKFLOW_STATE.ASSIGNED if not is_coverage_draft: # In case of article_rewrites, this will be 'in_progress' directly if assigned_to.get('state') and assigned_to[ 'state'] != ASSIGNMENT_WORKFLOW_STATE.DRAFT: assign_state = assigned_to.get('state') assignment = { 'assigned_to': { 'user': assigned_to.get('user'), 'desk': assigned_to.get('desk'), 'state': assign_state }, 'planning_item': planning_id, 'coverage_item': doc.get('coverage_id'), 'planning': doc.get('planning'), 'priority': assigned_to.get('priority', DEFAULT_ASSIGNMENT_PRIORITY), 'description_text': planning.get('description_text') } if 'coverage_provider' in assigned_to: assignment['assigned_to'][ 'coverage_provider'] = assigned_to.get('coverage_provider') assignment_id = assignment_service.post([assignment]) updates['assigned_to']['assignment_id'] = str(assignment_id[0]) updates['assigned_to']['state'] = assign_state elif assigned_to.get('assignment_id'): if not updates.get('assigned_to'): if not is_coverage_draft: raise SuperdeskApiError.badRequestError( 'Coverage not in draft state to remove assignment.') # Removing assignment assignment_service.delete( lookup={'_id': assigned_to.get('assignment_id')}) assignment = { 'planning_item': planning_id, 'coverage_item': doc.get('coverage_id') } get_resource_service('assignments_history').on_item_deleted( assignment) return # update the assignment using the coverage details original_assignment = assignment_service.find_one( req=None, _id=assigned_to.get('assignment_id')) if not original: raise SuperdeskApiError.badRequestError( 'Assignment related to the coverage does not exists.') # Check if coverage was cancelled coverage_cancel_state = get_coverage_cancellation_state() if original.get('workflow_status') != updates.get( 'workflow_status') and updates.get( 'workflow_status') == WORKFLOW_STATE.CANCELLED: self.cancel_coverage( updates, coverage_cancel_state, original.get('workflow_status'), original_assignment, updates.get('planning').get('workflow_status_reason')) return assignment = {} if self.is_coverage_planning_modified(updates, original): assignment['planning'] = doc.get('planning') if original_assignment.get('assigned_to').get( 'state') == ASSIGNMENT_WORKFLOW_STATE.DRAFT: if self.is_coverage_assignment_modified( updates, original_assignment): user = get_user() assignment['priority'] = assigned_to.pop( 'priority', original_assignment.get('priority')) assignment['assigned_to'] = assigned_to if original_assignment.get( 'assigned_to', {}).get('desk') != assigned_to.get('desk'): assigned_to['assigned_date_desk'] = utcnow() assigned_to['assignor_desk'] = user.get( config.ID_FIELD) if assigned_to.get('user') and original.get('assigned_to', {}).get('user') != \ assigned_to.get('user'): assigned_to['assigned_date_user'] = utcnow() assigned_to['assignor_user'] = user.get( config.ID_FIELD) # If we made a coverage 'active' - change assignment status to active if original.get( 'workflow_status' ) == WORKFLOW_STATE.DRAFT and not is_coverage_draft: assigned_to['state'] = ASSIGNMENT_WORKFLOW_STATE.ASSIGNED assignment['assigned_to'] = assigned_to # If the Planning description has been changed if planning_original.get( 'description_text') != planning_updates.get( 'description_text'): assignment['description_text'] = planning['description_text'] # If there has been a change in the planning internal note then notify the assigned users/desk if planning_updates.get('internal_note') and planning_original.get( 'internal_note') != planning_updates.get('internal_note'): PlanningNotifications().notify_assignment( coverage_status=updates.get('workflow_status'), target_desk=assigned_to.get('desk') if assigned_to.get('user') is None else None, target_user=assigned_to.get('user'), message='assignment_planning_internal_note_msg', coverage_type=get_coverage_type_name( updates.get('planning', {}).get('g2_content_type', '')), slugline=planning.get('slugline', ''), internal_note=planning.get('internal_note', '')) # Update only if anything got modified if 'planning' in assignment or 'assigned_to' in assignment or 'description_text' in assignment: assignment_service.system_update( ObjectId(assigned_to.get('assignment_id')), assignment, original_assignment)
def _set_coverage(self, updates, original=None): if not original: original = {} # [SDESK-3073]: Commenting the following section as we cannot reproduce the ****** # scenario where a patch is sent without any coverages (unless all coverages are removed) # if not updates.get('coverages'): # # If the description text has changed, make sure to update the assignment(s) # if updates.get('description_text') or updates.get('internal_note'): # for coverage in (original.get('coverages') or []): # self._create_update_assignment(original, updates, coverage, coverage) # return # ********* [SDESK-3073]: End revert ***************""" for coverage in original.get('coverages') or []: updated_coverage = next( (cov for cov in updates.get('coverages') or [] if cov.get('coverage_id') == coverage.get('coverage_id')), None) assignment = coverage.get('assigned_to', None) if not updated_coverage: if assignment and assignment.get( 'state') != WORKFLOW_STATE.DRAFT: raise SuperdeskApiError.badRequestError( 'Assignment already exists. Coverage cannot be deleted.' ) else: updated_coverage = deepcopy(coverage) updated_coverage.pop('assigned_to', None) self._create_update_assignment(original, updates, updated_coverage, coverage) for coverage in (updates.get('coverages') or []): original_coverage = None coverage_id = coverage.get('coverage_id') if not coverage_id or TEMP_ID_PREFIX in coverage_id: # coverage to be created coverage['coverage_id'] = generate_guid(type=GUID_NEWSML) coverage['firstcreated'] = utcnow() set_original_creator(coverage) else: original_coverage = next( (cov for cov in original.get('coverages') or [] if cov['coverage_id'] == coverage_id), None) if not original_coverage: continue if self.coverage_changed(coverage, original_coverage): user = get_user() coverage['version_creator'] = str(user.get( config.ID_FIELD)) if user else None coverage['versioncreated'] = utcnow() # If the internal note has changed send a notification, except if it's been cancelled if coverage.get('planning', {}).get('internal_note', '') != original_coverage.get('planning', {}).get( 'internal_note', '') \ and coverage.get('news_coverage_status', {}).get('qcode') != 'ncostat:notint': target_user = coverage.get( 'assigned_to', original_coverage.get('assigned_to', {})).get('user', None) target_desk = coverage.get( 'assigned_to', original_coverage.get('assigned_to', {})).get('desk', None) PlanningNotifications().notify_assignment( coverage_status=coverage.get('workflow_status'), target_desk=target_desk if target_user is None else None, target_user=target_user, message='assignment_internal_note_msg', coverage_type=get_coverage_type_name( coverage.get('planning', {}).get('g2_content_type', '')), slugline=coverage.get('planning', {}).get('slugline', ''), internal_note=coverage.get('planning', {}).get( 'internal_note', '')) # If the scheduled time for the coverage changes if coverage.get('planning', {}).get('scheduled', datetime.min).strftime('%c') != \ original_coverage.get('planning', {}).get('scheduled', datetime.min).strftime('%c'): target_user = coverage.get( 'assigned_to', original_coverage.get('assigned_to', {})).get('user', None) target_desk = coverage.get( 'assigned_to', original_coverage.get('assigned_to', {})).get('desk', None) PlanningNotifications().notify_assignment( coverage_status=coverage.get('workflow_status'), target_desk=target_desk if target_user is None else None, target_user=target_user, message='assignment_due_time_msg', due=utc_to_local( app.config['DEFAULT_TIMEZONE'], coverage.get( 'planning', {}).get('scheduled')).strftime('%c'), coverage_type=get_coverage_type_name( coverage.get('planning', {}).get('g2_content_type', '')), slugline=coverage.get('planning', {}).get('slugline', '')) self._create_update_assignment(original, updates, coverage, original_coverage)
def send_assignment_notification(self, updates, original=None, force=False): """Set the assignment information and send notification :param dict doc: Updates related to assignments """ # No notifications for 'draft' assignments if self.is_assignment_draft(updates, original): return if not original: original = {} if not force and not self.is_assignment_modified(updates, original): return assigned_to = updates.get('assigned_to', {}) assignment_id = assigned_to.get('assignment_id', 'Unknown') user = get_user() # Determine the name of the desk that the assigment has been allocated to assigned_to_desk = get_resource_service('desks').find_one( req=None, _id=assigned_to.get('desk')) desk_name = assigned_to_desk.get( 'name') if assigned_to_desk else 'Unknown' # Determine the display name of the assignee assigned_to_user = get_resource_service('users').find_one( req=None, _id=assigned_to.get('user')) assignee = assigned_to_user.get( 'display_name') if assigned_to_user else 'Unknown' coverage_type = updates.get('planning', original.get('planning', {})).get( 'g2_content_type', '') slugline = updates.get('planning', original.get('planning', {})).get('slugline', 'with no slugline') client_url = app.config['CLIENT_URL'] meta_message = 'Planning Item: {{slugline}}<br>' \ 'Assignment ID: {{assignment_id}}<br>' \ '{{client_url}}/#/workspace/assignments?assignment={{assignment_id}}' # The assignment is to a user if assigned_to.get('user'): # If it is a reassignment if original.get('assigned_to'): # it is being reassigned by the original assignee, notify the new assignee if original.get('assigned_to', {}).get('user', '') == str( user.get(config.ID_FIELD, None)): message = '{{coverage_type}} coverage \"{{slugline}}\" has been reassigned to ' \ 'you on desk ({{desk}})' PlanningNotifications().notify_assignment( target_user=assigned_to.get('user'), message=message, meta_message=meta_message, coverage_type=get_coverage_type_name(coverage_type), slugline=slugline, desk=desk_name, client_url=client_url, assignment_id=assignment_id) else: # if it was assigned to a desk before, test if there has been a change of desk if original.get('assigned_to') and original.get( 'assigned_to').get('desk') != updates.get( 'assigned_to').get('desk'): # Determine the name of the desk that the assigment was allocated to assigned_from_desk = get_resource_service( 'desks').find_one( req=None, _id=original.get('assigned_to').get('desk')) desk_from_name = assigned_from_desk.get( 'name') if assigned_from_desk else 'Unknown' assigned_from = original.get('assigned_to') assigned_from_user = get_resource_service( 'users').find_one(req=None, _id=assigned_from.get('user')) old_assignee = assigned_from_user.get( 'display_name') if assigned_from_user else '' message = '{{coverage_type}} coverage \"{{slugline}}\" has been reassigned ' \ 'to {{assignee}} ({{desk}}) from {{old_assignee}} ({{old_desk}}) by {{assignor}}' PlanningNotifications().notify_assignment( target_desk=assigned_to.get('desk'), target_desk2=original.get('assigned_to').get( 'desk'), message=message, meta_message=meta_message, coverage_type=get_coverage_type_name( coverage_type), slugline=slugline, assignee=assignee, desk=desk_name, old_assignee=old_assignee, client_url=client_url, assignment_id=assignment_id, old_desk=desk_from_name, assignor=user.get('display_name'), omit_user=True) else: # it is being reassigned by someone else so notify both the new assignee and the old message = '{{coverage_type}} coverage \"{{slugline}}\" has been reassigned to {{assignee}} ' \ 'on desk ({{desk}}) by {{assignor}}' PlanningNotifications().notify_assignment( target_user=original.get('assigned_to').get( 'user'), target_desk=original.get('assigned_to').get('desk') if original.get('assigned_to').get('user') is None else None, message=message, meta_message=meta_message, coverage_type=get_coverage_type_name( coverage_type), slugline=slugline, assignee=assignee, client_url=client_url, assignment_id=assignment_id, desk=desk_name, assignor=user.get('display_name'), omit_user=True) # notify the assignee message = '{{coverage_type}} coverage \"{{slugline}}\" has been reassigned' \ '{{old_assignee}} to you on desk ({{desk}}) ' assigned_from = original.get('assigned_to') assigned_from_user = get_resource_service( 'users').find_one(req=None, _id=assigned_from.get('user')) old_assignee = assigned_from_user.get( 'display_name') if assigned_from_user else None PlanningNotifications().notify_assignment( target_user=assigned_to.get('user'), message=message, meta_message=meta_message, coverage_type=get_coverage_type_name( coverage_type), slugline=slugline, old_assignee=' from ' + old_assignee if old_assignee else '', client_url=client_url, assignment_id=assignment_id, desk=desk_name) else: # A new assignment # notify the user the assignment has been made to PlanningNotifications().notify_assignment( target_user=assigned_to.get('user'), message='You have been assigned \"{{coverage_type}}\" ' 'coverage \"{{slugline}}\" {{assignor}}', meta_message=meta_message, coverage_type=get_coverage_type_name(coverage_type), slugline=slugline, client_url=client_url, assignment_id=assignment_id, assignor='by ' + user.get('display_name', '') if str(user.get(config.ID_FIELD, None)) != assigned_to.get( 'user', '') else 'to yourself', omit_user=True) else: # Assigned/Reassigned to a desk, notify all desk members # if it was assigned to a desk before, test if there has been a change of desk if original.get('assigned_to') and original.get('assigned_to').get( 'desk') != updates.get('assigned_to', {}).get('desk'): # Determine the name of the desk that the assigment was allocated to assigned_from_desk = get_resource_service('desks').find_one( req=None, _id=original.get('assigned_to').get('desk')) desk_from_name = assigned_from_desk.get( 'name') if assigned_from_desk else 'Unknown' message = '{{coverage_type}} coverage \"{{slugline}}\" has been submitted to ' \ 'desk {{desk}} from {{from_desk}}' PlanningNotifications().notify_assignment( target_desk=assigned_to.get('desk'), target_desk2=original.get('assigned_to').get('desk'), message=message, meta_message=meta_message, coverage_type=get_coverage_type_name(coverage_type), slugline=slugline, desk=desk_name, client_url=client_url, assignment_id=assignment_id, from_desk=desk_from_name) else: assign_type = 'reassigned' if original.get( 'assigned_to') else 'assigned' message = '{{coverage_type}} coverage \"{{slugline}}\" {{assign_type}} to desk {{desk}} by {{assignor}}' PlanningNotifications().notify_assignment( target_desk=assigned_to.get('desk'), message=message, meta_message=meta_message, coverage_type=get_coverage_type_name(coverage_type), slugline=slugline, assign_type=assign_type, client_url=client_url, assignment_id=assignment_id, desk=desk_name, assignor=user.get('display_name'), omit_user=True)
def create(self, docs): ids = [] archive_service = get_resource_service('archive') assignments_service = get_resource_service('assignments') for doc in docs: assignment = assignments_service.find_one( req=None, _id=doc.pop('assignment_id')) item = get_item_from_assignment(assignment, doc.pop('template_name', None)) item[config.VERSION] = 1 item.setdefault('type', 'text') item['assignment_id'] = assignment[config.ID_FIELD] if assignment.get('scheduled_update_id'): # get the latest archive item to be updated archive_item = self.get_latest_news_item_for_coverage( assignment) if not archive_item: raise SuperdeskApiError.badRequestError( 'Archive item not found to create a rewrite.') # create a rewrite request.view_args['original_id'] = archive_item.get( config.ID_FIELD) ids = get_resource_service('archive_rewrite').post([{ 'desk_id': str(item.get('task').get('desk')) }]) item = archive_service.find_one(_id=ids[0], req=None) item['task']['user'] = get_user_id() # link the rewrite get_resource_service('assignments_link').post([{ 'assignment_id': assignment[config.ID_FIELD], 'item_id': ids[0], 'reassign': True }]) else: # create content ids = archive_service.post([item]) insert_into_versions(doc=item) # create delivery references get_resource_service('delivery').post([{ 'item_id': item[config.ID_FIELD], 'assignment_id': assignment[config.ID_FIELD], 'planning_id': assignment['planning_item'], 'coverage_id': assignment['coverage_item'] }]) updates = {'assigned_to': deepcopy(assignment.get('assigned_to'))} updates['assigned_to']['user'] = str(item.get('task').get('user')) updates['assigned_to']['desk'] = str(item.get('task').get('desk')) updates['assigned_to']['state'] = get_next_assignment_status( updates, ASSIGNMENT_WORKFLOW_STATE.IN_PROGRESS) updates['assigned_to']['assignor_user'] = str( item.get('task').get('user')) updates['assigned_to']['assigned_date_user'] = utcnow() if not assignment.get('scheduled_update_id'): # set the assignment to in progress assignments_service.patch(assignment[config.ID_FIELD], updates) assignments_service.publish_planning( assignment['planning_item']) doc.update(item) ids.append(doc['_id']) # Send notification that the work has commenced to the user who assigned the task # Get the id of the user who assigned the task assignor = assignment.get('assigned_to', {}).get( 'assignor_user', assignment.get('assigned_to', {}).get('assignor_desk')) if str(assignor) != str(item.get('task').get('user')): # Determine the display name of the assignee assigned_to_user = get_resource_service('users').find_one( req=None, _id=str(item.get('task').get('user'))) assignee = assigned_to_user.get( 'display_name') if assigned_to_user else 'Unknown' PlanningNotifications().notify_assignment( target_desk=None, target_user=assignor, message='assignment_commenced_msg', assignee=assignee, coverage_type=get_coverage_type_name(item.get('type', '')), slugline=item.get('slugline'), omit_user=True, assignment_id=assignment[config.ID_FIELD], is_link=True, no_email=True) # Save history get_resource_service('assignments_history').on_item_start_working( updates, assignment) return ids
def update(self, id, updates, original): # if the completion is being done by an external application then ensure that it is not locked if 'proxy_user' in updates: if original.get('lock_user'): raise SuperdeskApiError.forbiddenError('Assignment is locked') user = updates.pop('proxy_user', None) proxy_user = True else: user = get_user(required=True).get(config.ID_FIELD, '') proxy_user = False session = get_auth().get(config.ID_FIELD, '') original_assigned_to = deepcopy(original).get('assigned_to') if not updates.get('assigned_to'): updates['assigned_to'] = {} original_assigned_to.update(updates['assigned_to']) updates['assigned_to'] = original_assigned_to assignments_service = get_resource_service('assignments') # If we are confirming availability, save the revert state for revert action text_assignment = assignments_service.is_text_assignment(original) if not text_assignment: updates['assigned_to']['revert_state'] = updates['assigned_to'][ 'state'] updates['assigned_to']['state'] = get_next_assignment_status( updates, ASSIGNMENT_WORKFLOW_STATE.COMPLETED) remove_lock_information(updates) item = self.backend.update(self.datasource, id, updates, original) # publish the planning item assignments_service.publish_planning(original['planning_item']) # Save history if user initiates complete if text_assignment: get_resource_service('assignments_history').on_item_complete( updates, original) else: if proxy_user: updates['proxy_user'] = user get_resource_service( 'assignments_history').on_item_confirm_availability( updates, original) push_notification('assignments:completed', item=str(original[config.ID_FIELD]), planning=original.get('planning_item'), assigned_user=(original.get('assigned_to') or {}).get('user'), assigned_desk=(original.get('assigned_to') or {}).get('desk'), assignment_state=ASSIGNMENT_WORKFLOW_STATE.COMPLETED, user=str(user), session=str(session), coverage=original.get('coverage_item')) # Send notification that the work has been completed # Determine the display name of the assignee assigned_to_user = get_resource_service('users').find_one(req=None, _id=user) assignee = assigned_to_user.get( 'display_name') if assigned_to_user else 'Unknown' target_user = original.get('assigned_to', {}).get('assignor_user') if target_user is None: target_user = original.get('assigned_to', {}).get('assignor_desk') PlanningNotifications().notify_assignment( target_user=target_user, message='assignment_fulfilled_msg', assignee=assignee, coverage_type=get_coverage_type_name( original.get('planning', {}).get('g2_content_type', '')), slugline=original.get('planning', {}).get('slugline'), omit_user=True, assignment_id=original[config.ID_FIELD], is_link=True, no_email=True) return item
def send_assignment_notification(self, updates, original=None, force=False): """Set the assignment information and send notification :param dict doc: Updates related to assignments """ # No notifications for 'draft' assignments if self.is_assignment_draft(updates, original): return if not original: original = {} if not force and not self.is_assignment_modified(updates, original): return assigned_to = updates.get('assigned_to', {}) assignment_id = assigned_to.get('assignment_id', 'Unknown') user = get_user() # Determine the name of the desk that the assigment has been allocated to assigned_to_desk = get_resource_service('desks').find_one( req=None, _id=assigned_to.get('desk')) desk_name = assigned_to_desk.get( 'name') if assigned_to_desk else 'Unknown' # Determine the display name of the assignee assigned_to_user = get_resource_service('users').find_one( req=None, _id=assigned_to.get('user')) assignee = assigned_to_user.get( 'display_name') if assigned_to_user else 'Unknown' coverage_type = updates.get('planning', original.get('planning', {})).get( 'g2_content_type', '') slugline = updates.get('planning', original.get('planning', {})).get('slugline', 'with no slugline') client_url = app.config['CLIENT_URL'] assignment = deepcopy(original) assignment.update(updates) planning_id = assignment.get('planning_item', -1) planning_item = get_resource_service('planning').find_one( req=None, _id=planning_id) if planning_item and planning_item.get('event_item'): event_item = get_resource_service('events').find_one( req=None, _id=planning_item.get('event_item')) contacts = [] for contact_id in event_item.get('event_contact_info', []): contact_details = get_resource_service('contacts').find_one( req=None, _id=contact_id) if contact_details: contacts.append(contact_details) if len(contacts): event_item['event_contact_info'] = contacts else: event_item = None # The assignment is to a user if assigned_to.get('user'): # If it is a reassignment if original.get('assigned_to'): # it is being reassigned by the original assignee, notify the new assignee if original.get('assigned_to', {}).get('user', '') == str( user.get(config.ID_FIELD, None)): PlanningNotifications().notify_assignment( target_user=assigned_to.get('user'), message='assignment_reassigned_1_msg', meta_message='assignment_details_email', coverage_type=get_coverage_type_name(coverage_type), slugline=slugline, desk=desk_name, client_url=client_url, assignment_id=assignment_id, assignment=assignment, event=event_item) else: # if it was assigned to a desk before, test if there has been a change of desk if original.get('assigned_to') and original.get( 'assigned_to').get('desk') != updates.get( 'assigned_to').get('desk'): # Determine the name of the desk that the assigment was allocated to assigned_from_desk = get_resource_service( 'desks').find_one( req=None, _id=original.get('assigned_to').get('desk')) desk_from_name = assigned_from_desk.get( 'name') if assigned_from_desk else 'Unknown' assigned_from = original.get('assigned_to') assigned_from_user = get_resource_service( 'users').find_one(req=None, _id=assigned_from.get('user')) old_assignee = assigned_from_user.get( 'display_name') if assigned_from_user else '' PlanningNotifications().notify_assignment( target_desk=assigned_to.get('desk'), target_desk2=original.get('assigned_to').get( 'desk'), message='assignment_reassigned_2_msg', meta_message='assignment_details_email', coverage_type=get_coverage_type_name( coverage_type), slugline=slugline, assignee=assignee, desk=desk_name, old_assignee=old_assignee, client_url=client_url, assignment_id=assignment_id, old_desk=desk_from_name, assignor=user.get('display_name'), assignment=assignment, event=event_item, omit_user=True) else: # it is being reassigned by someone else so notify both the new assignee and the old PlanningNotifications().notify_assignment( target_user=original.get('assigned_to').get( 'user'), target_desk=original.get('assigned_to').get('desk') if original.get('assigned_to').get('user') is None else None, message='assignment_reassigned_3_msg', meta_message='assignment_details_email', coverage_type=get_coverage_type_name( coverage_type), slugline=slugline, assignee=assignee, client_url=client_url, assignment_id=assignment_id, desk=desk_name, assignor=user.get('display_name'), assignment=assignment, event=event_item, omit_user=True) # notify the assignee assigned_from = original.get('assigned_to') assigned_from_user = get_resource_service( 'users').find_one(req=None, _id=assigned_from.get('user')) old_assignee = assigned_from_user.get( 'display_name') if assigned_from_user else None PlanningNotifications().notify_assignment( target_user=assigned_to.get('user'), message='assignment_reassigned_4_msg', meta_message='assignment_details_email', coverage_type=get_coverage_type_name( coverage_type), slugline=slugline, old_assignee=' from ' + old_assignee if old_assignee else '', client_url=client_url, assignment_id=assignment_id, desk=desk_name, event=event_item, assignment=assignment) else: # A new assignment # Notify the user the assignment has been made to unless assigning to your self if str(user.get(config.ID_FIELD, None)) != assigned_to.get( 'user', ''): PlanningNotifications().notify_assignment( target_user=assigned_to.get('user'), message='assignment_assigned_msg', meta_message='assignment_details_email', coverage_type=get_coverage_type_name(coverage_type), slugline=slugline, client_url=client_url, assignment_id=assignment_id, assignor='by ' + user.get('display_name', '') if str(user.get(config.ID_FIELD, None)) != assigned_to.get('user', '') else 'to yourself', assignment=assignment, event=event_item, omit_user=True) else: # Assigned/Reassigned to a desk, notify all desk members # if it was assigned to a desk before, test if there has been a change of desk if original.get('assigned_to') and original.get('assigned_to').get( 'desk') != updates.get('assigned_to', {}).get('desk'): # Determine the name of the desk that the assigment was allocated to assigned_from_desk = get_resource_service('desks').find_one( req=None, _id=original.get('assigned_to').get('desk')) desk_from_name = assigned_from_desk.get( 'name') if assigned_from_desk else 'Unknown' PlanningNotifications().notify_assignment( target_desk=assigned_to.get('desk'), target_desk2=original.get('assigned_to').get('desk'), message='assignment_submitted_msg', meta_message='assignment_details_email', coverage_type=get_coverage_type_name(coverage_type), slugline=slugline, desk=desk_name, client_url=client_url, assignment_id=assignment_id, from_desk=desk_from_name, assignment=assignment, event=event_item) else: assign_type = 'reassigned' if original.get( 'assigned_to') else 'assigned' PlanningNotifications().notify_assignment( target_desk=assigned_to.get('desk'), message='assignment_to_desk_msg', meta_message='assignment_details_email', coverage_type=get_coverage_type_name(coverage_type), slugline=slugline, assign_type=assign_type, client_url=client_url, assignment_id=assignment_id, desk=desk_name, assignor=user.get('display_name'), assignment=assignment, event=event_item, omit_user=True)
def update_assignment_on_archive_operation(self, updates, original, operation=None): if operation == ITEM_MOVE: assignment_update_data = \ self._get_assignment_data_on_archive_update(updates, original) if assignment_update_data.get('assignment') and \ assignment_update_data['assignment'].get('assigned_to')['desk'] != \ assignment_update_data.get('item_desk_id'): updated_assignment = self._set_user_for_assignment( assignment_update_data['assignment'], None, assignment_update_data.get('item_user_id')) updated_assignment.get('assigned_to')[ 'desk'] = assignment_update_data.get('item_desk_id') updated_assignment.get( 'assigned_to' )['assignor_user'] = assignment_update_data.get('item_user_id') updated_assignment.get('assigned_to')[ 'state'] = ASSIGNMENT_WORKFLOW_STATE.SUBMITTED self._update_assignment_and_notify( updated_assignment, assignment_update_data['assignment']) get_resource_service('assignments_history').on_item_updated( updated_assignment, assignment_update_data.get('assignment'), ASSIGNMENT_HISTORY_ACTIONS.SUBMITTED) elif operation == ITEM_PUBLISH: assignment_update_data = \ self._get_assignment_data_on_archive_update(updates, original) if assignment_update_data.get('assignment'): updated_assignment = self._get_empty_updates_for_assignment( assignment_update_data['assignment']) if updates.get(ITEM_STATE, original.get( ITEM_STATE, '')) != CONTENT_STATE.SCHEDULED: updated_assignment.get('assigned_to')[ 'state'] = ASSIGNMENT_WORKFLOW_STATE.COMPLETED self._update_assignment_and_notify( updated_assignment, assignment_update_data['assignment']) get_resource_service( 'assignments_history').on_item_complete( updated_assignment, assignment_update_data.get('assignment')) # publish planning self.publish_planning( assignment_update_data.get('assignment').get( 'planning_item')) assigned_to_user = get_resource_service('users').find_one( req=None, _id=get_user().get(config.ID_FIELD, '')) assignee = assigned_to_user.get( 'display_name') if assigned_to_user else 'Unknown' target_user = assignment_update_data['assignment'].get( 'assigned_to', {}).get('assignor_desk') PlanningNotifications().notify_assignment( target_user=target_user, message='assignment_complete_msg', assignee=assignee, coverage_type=get_coverage_type_name( original.get('planning', {}).get('g2_content_type', '')), slugline=original.get('slugline'), omit_user=True)
def create(self, docs): ids = [] production = get_resource_service('archive') archived = get_resource_service('archived') assignments_service = get_resource_service('assignments') updated_items = [] published_updated_items = [] for doc in docs: # Boolean set to true if the unlink is as the result of spiking the content item spike = doc.pop('spike', False) cancel = doc.pop('cancel', False) assignment = assignments_service.find_one( req=None, _id=doc.pop('assignment_id')) assignments_service.validate_assignment_action(assignment) actioned_item_id = doc.pop('item_id') actioned_item = production.find_one(req=None, _id=actioned_item_id) if not actioned_item: actioned_item = archived.find_one(req=None, _id=actioned_item_id) actioned_item_id = actioned_item.get('item_id') coverage = get_coverage_for_assignment(assignment) related_items = get_related_items( actioned_item, assignment if coverage and len(coverage.get('scheduled_updates')) <= 0 else None) for item in related_items: # For all items, update news item for unlinking assignment_id = item.get('assignment_id') update_assignment_on_link_unlink(None, item, published_updated_items) ids.append(item[config.ID_FIELD]) updated_items.append(item) push_notification('content:unlink', item=str(item[config.ID_FIELD]), assignment=str(assignment_id)) # Delete delivery records associated with all the items unlinked item_ids = [ i.get(config.ID_FIELD) if not i.get('_type') == 'archived' else i.get('item_id') for i in related_items ] get_resource_service('delivery').delete_action( lookup={'item_id': { '$in': item_ids }}) # Update assignment if no other archive item is linked to it doc.update(actioned_item) assignments = self.get_all_assignments_for_coverage( assignment.get('coverage_item')) for a in assignments: # Update all assignments in the coverage including scheduled_updates updates = {'assigned_to': deepcopy(a.get('assigned_to'))} archive_items = assignments_service.get_archive_items_for_assignment( a) other_linked_items = [ a for a in archive_items if str(a.get(config.ID_FIELD)) != str(actioned_item[config.ID_FIELD]) ] if len(other_linked_items) <= 0: updates['assigned_to'][ 'state'] = ASSIGNMENT_WORKFLOW_STATE.ASSIGNED assignments_service.patch(a.get(config.ID_FIELD), updates) assignment_history_service = get_resource_service( 'assignments_history') if spike: get_resource_service('assignments_history') \ .on_item_content_unlink(updates, a, ASSIGNMENT_HISTORY_ACTIONS.SPIKE_UNLINK) else: assignment_history_service.on_item_content_unlink( updates, a) if not cancel: user = get_user() PlanningNotifications().notify_assignment( target_desk=actioned_item.get('task').get('desk'), message='assignment_spiked_unlinked_msg', actioning_user=user.get( 'display_name', user.get('username', 'Unknown')), action='unlinked' if not spike else 'spiked', coverage_type=get_coverage_type_name( actioned_item.get('type', '')), slugline=actioned_item.get('slugline'), omit_user=True, assignment_id=a[config.ID_FIELD], is_link=True, no_email=True) push_content_notification(updated_items) # Update assignment history with all items affected updates['item_ids'] = ids # publishing planning item assignments_service.publish_planning(assignment['planning_item']) return ids