def update_task_status( user_id: str, user_email: str, channel_id: str, incident_id: int, action: dict, db_session=None, slack_client=None, ): """Updates a task based on user input.""" action_type, external_task_id_b64 = action["actions"][0]["value"].split( "-") external_task_id = base64_decode(external_task_id_b64) resolve = True if action_type == "reopen": resolve = False # we only update the external task allowing syncing to care of propagation to dispatch task = task_service.get_by_resource_id(db_session=db_session, resource_id=external_task_id) # avoid external calls if we are already in the desired state if resolve and task.status == TaskStatus.resolved: message = "Task is already resolved." dispatch_slack_service.send_ephemeral_message(slack_client, channel_id, user_id, message) return if not resolve and task.status == TaskStatus.open: message = "Task is already open." dispatch_slack_service.send_ephemeral_message(slack_client, channel_id, user_id, message) return # we don't currently have a good way to get the correct file_id (we don't store a task <-> relationship) # lets try in both the incident doc and PIR doc drive_task_plugin = plugin_service.get_active( db_session=db_session, project_id=task.incident.project.id, plugin_type="task") try: file_id = task.incident.incident_document.resource_id drive_task_plugin.instance.update(file_id, external_task_id, resolved=resolve) except Exception: file_id = task.incident.incident_review_document.resource_id drive_task_plugin.instance.update(file_id, external_task_id, resolved=resolve) status = "resolved" if task.status == TaskStatus.open else "re-opened" message = f"Task successfully {status}." dispatch_slack_service.send_ephemeral_message(slack_client, channel_id, user_id, message)
def create_or_update_task(db_session, incident, task: dict, notify: bool = False, sync_external: bool = True): """Creates a new task in the database or updates an existing one.""" existing_task = task_service.get_by_resource_id( db_session=db_session, resource_id=task["resource_id"]) if existing_task: # we save the existing task status before we attempt to update the record existing_status = existing_task.status task = task_service.update( db_session=db_session, task=existing_task, task_in=TaskUpdate( **task, incident=incident, ), sync_external=sync_external, ) if notify: # determine if task was previously resolved if task.status == TaskStatus.resolved: if existing_status != TaskStatus.resolved: send_task_notification( incident, INCIDENT_TASK_RESOLVED_NOTIFICATION, task.creator, task.assignees, task.description, task.weblink, db_session, ) else: # we don't attempt to create new tasks if the incident is currently closed if incident.status == IncidentStatus.closed: return task = task_service.create( db_session=db_session, task_in=TaskCreate(**task, incident=incident), ) if notify: send_task_notification( incident, INCIDENT_TASK_NEW_NOTIFICATION, task.creator, task.assignees, task.description, task.weblink, db_session, ) db_session.commit()
def create_or_update_task(db_session, incident, task: dict, notify: bool = False): """Creates a new task in the database or updates an existing one.""" existing_task = task_service.get_by_resource_id( db_session=db_session, resource_id=task["resource_id"]) if existing_task: # save the status before we attempt to update the record existing_status = existing_task.status task = task_service.update(db_session=db_session, task=existing_task, task_in=TaskUpdate(**task)) if notify: # determine if task was previously resolved if task.status == TaskStatus.resolved.value: if existing_status != TaskStatus.resolved.value: send_task_notification( incident.conversation.channel_id, INCIDENT_TASK_RESOLVED_NOTIFICATION, task.assignees, task.description, task.weblink, db_session, ) else: task = task_service.create( db_session=db_session, incident=incident, task_in=TaskCreate(**task), ) if notify: send_task_notification( incident.conversation.channel_id, INCIDENT_TASK_NEW_NOTIFICATION, task.assignees, task.description, task.weblink, db_session, ) db_session.commit()
def create_or_update_task(db_session, incident, task: dict, notify: bool = False): """Creates a new task in the database or updates an existing one.""" incident_task = task_service.get_by_resource_id(db_session=db_session, resource_id=task["id"]) assignees = [] for a in task["assignees"]: assignees.append( db_session.merge( incident_add_or_reactivate_participant_flow( a, incident_id=incident.id, db_session=db_session))) description = task["description"][0] status = TaskStatus.open if not task["status"] else TaskStatus.resolved resource_id = task["id"] weblink = task["web_link"] # TODO we can build this out as our scraping gets more advanced tickets = [ ticket_service.get_or_create_by_weblink(db_session=db_session, weblink=t["web_link"]) for t in task["tickets"] ] if incident_task: # allways update tickets and assignees incident_task.assignees = assignees incident_task.tickets = tickets # only notify if it's newly resolved if status == TaskStatus.resolved: if incident_task.status != TaskStatus.resolved: incident_task.status = status if notify: send_task_notification( incident.conversation.channel_id, INCIDENT_TASK_RESOLVED_NOTIFICATION, assignees, description, weblink, ) else: # we add the task to the incident creator = db_session.merge( incident_add_or_reactivate_participant_flow( task["owner"], incident_id=incident.id, db_session=db_session)) task = task_service.create( db_session=db_session, creator=creator, assignees=assignees, description=description, status=status, tickets=tickets, resource_id=resource_id, resource_type=INCIDENT_RESOURCE_INCIDENT_TASK, weblink=weblink, ) incident.tasks.append(task) if notify: send_task_notification( incident.conversation.channel_id, INCIDENT_TASK_NEW_NOTIFICATION, assignees, description, weblink, ) db_session.commit()
def create_or_update_task(db_session, incident, task: dict, notify: bool = False): """Creates a new task in the database or updates an existing one.""" # TODO we should standarize this interface (kglisson) creator = task["owner"] assignees = ", ".join(task["assignees"]) description = task["description"][0] status = TaskStatus.open if not task["status"] else TaskStatus.resolved resource_id = task["id"] weblink = task["web_link"] incident_task = task_service.get_by_resource_id(db_session=db_session, resource_id=task["id"]) if incident_task: if status == TaskStatus.open: # we don't need to take any actions if the status of the task in the collaboration doc is open return else: if incident_task.status == TaskStatus.resolved: # we don't need to take any actions if the task has already been marked as resolved in the database return else: # we mark the task as resolved in the database incident_task.status = TaskStatus.resolved db_session.add(incident_task) db_session.commit() if notify: send_task_notification( incident.conversation.channel_id, INCIDENT_TASK_RESOLVED_NOTIFICATION, assignees, description, weblink, ) else: # we add the task to the incident task = task_service.create( db_session=db_session, creator=creator, assignees=assignees, description=description, status=status, resource_id=resource_id, resource_type=INCIDENT_RESOURCE_INCIDENT_TASK, weblink=weblink, ) incident.tasks.append(task) db_session.add(incident) db_session.commit() if notify: send_task_notification( incident.conversation.channel_id, INCIDENT_TASK_NEW_NOTIFICATION, assignees, description, weblink, )
def sync_tasks(db_session=None): """Syncs incident tasks.""" # we get all active and stable incidents active_incidents = incident_service.get_all_by_status( db_session=db_session, status=IncidentStatus.active) stable_incidents = incident_service.get_all_by_status( db_session=db_session, status=IncidentStatus.stable) incidents = active_incidents + stable_incidents # we create an instance of the drive task plugin drive_task_plugin = plugins.get(INCIDENT_PLUGIN_TASK_SLUG) for incident in incidents: for doc_type in [ INCIDENT_RESOURCE_INVESTIGATION_DOCUMENT, INCIDENT_RESOURCE_INCIDENT_REVIEW_DOCUMENT, ]: # we get the document object document = get_document(db_session=db_session, incident_id=incident.id, resource_type=doc_type) if not document: # the document may have not been created yet (e.g. incident review document) break # we get the list of tasks in the document tasks = drive_task_plugin.list(file_id=document.resource_id) for t in tasks: # we get the task information creator = t["task"]["owner"] assignees = ", ".join(t["task"]["assignees"]) description = t["task"]["description"][0] status = TaskStatus.open if not t["task"][ "status"] else TaskStatus.resolved resource_id = t["task"]["id"] weblink = t["task"]["web_link"] incident_task = task_service.get_by_resource_id( db_session=db_session, resource_id=t["task"]["id"]) if incident_task: if status == TaskStatus.open: # we don't need to take any actions if the status of the task in the collaboration doc is open break else: if incident_task.status == TaskStatus.resolved: # we don't need to take any actions if the task has already been marked as resolved in the database break else: # we mark the task as resolved in the database incident_task.status = TaskStatus.resolved db_session.add(incident_task) db_session.commit() # we send a notification to the incident conversation notification_text = "Incident Notification" notification_type = "incident-notification" convo_plugin = plugins.get( INCIDENT_PLUGIN_CONVERSATION_SLUG) convo_plugin.send( incident.conversation.channel_id, notification_text, INCIDENT_TASK_RESOLVED_NOTIFICATION, notification_type, task_assignees=assignees, task_description=description, task_weblink=weblink, ) else: # we add the task to the incident task = task_service.create( db_session=db_session, creator=creator, assignees=assignees, description=description, status=status, resource_id=resource_id, resource_type=INCIDENT_RESOURCE_INCIDENT_TASK, weblink=weblink, ) incident.tasks.append(task) db_session.add(incident) db_session.commit() # we send a notification to the incident conversation notification_text = "Incident Notification" notification_type = "incident-notification" convo_plugin = plugins.get( INCIDENT_PLUGIN_CONVERSATION_SLUG) convo_plugin.send( incident.conversation.channel_id, notification_text, INCIDENT_TASK_NEW_NOTIFICATION, notification_type, task_assignees=assignees, task_description=description, task_weblink=weblink, )