def send_feedack_to_user( channel_id: str, project_id: int, user_id: str, message: str, db_session: SessionLocal ): """Sends feedack to the user using an ephemeral message.""" blocks = [{"type": "section", "text": {"type": "mrkdwn", "text": message}}] plugin = plugin_service.get_active( db_session=db_session, project_id=project_id, plugin_type="conversation" ) plugin.instance.send_ephemeral( channel_id, user_id, "Conversation Command Feedback", blocks=blocks )
def send_welcome_email_to_participant( participant_email: str, incident_id: int, db_session: SessionLocal ): """Sends a welcome email to the participant.""" # we load the incident instance plugin = plugin_service.get_active(db_session=db_session, plugin_type="email") if not plugin: log.warning("Participant welcome email not sent, not email plugin configured.") return incident = incident_service.get(db_session=db_session, incident_id=incident_id) message_kwargs = { "name": incident.name, "title": incident.title, "status": incident.status, "type": incident.incident_type.name, "type_description": incident.incident_type.description, "priority": incident.incident_priority.name, "priority_description": incident.incident_priority.description, "commander_fullname": incident.commander.individual.name, "commander_weblink": incident.commander.individual.weblink, "document_weblink": resolve_attr(incident, "incident_document.weblink"), "storage_weblink": resolve_attr(incident, "storage.weblink"), "ticket_weblink": resolve_attr(incident, "ticket.weblink"), "conference_weblink": resolve_attr(incident, "conference.weblink"), "conference_challenge": resolve_attr(incident, "conference.conference_challenge"), "contact_fullname": incident.commander.individual.name, "contact_weblink": incident.commander.individual.weblink, } faq_doc = document_service.get_incident_faq_document(db_session=db_session) if faq_doc: message_kwargs.update({"faq_weblink": faq_doc.weblink}) conversation_reference = document_service.get_conversation_reference_document( db_session=db_session ) if conversation_reference: message_kwargs.update( {"conversation_commands_reference_document_weblink": conversation_reference.weblink} ) notification_text = "Incident Notification" plugin.instance.send( participant_email, notification_text, INCIDENT_PARTICIPANT_WELCOME_MESSAGE, MessageType.incident_participant_welcome, **message_kwargs, ) log.debug(f"Welcome email sent to {participant_email}.")
def delete_participant_groups(incident: Incident, db_session: SessionLocal): """Deletes the external participant groups.""" plugin = plugin_service.get_active(db_session=db_session, plugin_type="participant-group") plugin.instance.delete(email=incident.tactical_group.email) plugin.instance.delete(email=incident.notifications_group.email) event_service.log( db_session=db_session, source=plugin.title, description="Tactical and notification groups deleted", incident_id=incident.id, )
def get_suggested_documents(db_session, incident_type: str, priority: str, description: str) -> list: """Get additional incident documents based on priority, type, and description.""" plugin = plugin_service.get_active(db_session=db_session, plugin_type="document-resolver") documents = [] if plugin: documents = plugin.instance.get(incident_type, priority, description, db_session=db_session) return documents
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 = action["actions"][0]["value"].split("-") 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, 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 update(*, db_session, task: Task, task_in: TaskUpdate) -> Task: """Update an existing task.""" # ensure we add assignee as participant if they are not one already assignees = [] for i in task_in.assignees: assignees.append( incident_flows.incident_add_or_reactivate_participant_flow( db_session=db_session, incident_id=task.incident.id, user_email=i.individual.email, )) task.assignees = assignees # we add owner as a participant if they are not one already if task_in.owner: task.owner = incident_flows.incident_add_or_reactivate_participant_flow( db_session=db_session, incident_id=task.incident.id, user_email=task_in.owner.individual.email, ) update_data = task_in.dict( skip_defaults=True, exclude={"assignees", "owner", "creator", "incident", "tickets"}) for field in update_data.keys(): setattr(task, field, update_data[field]) # if we have an external task plugin enabled, attempt to update the external resource as well # 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, plugin_type="task") if drive_task_plugin: try: if task.incident.incident_document: file_id = task.incident.incident_document.resource_id drive_task_plugin.instance.update(file_id, task.external_task_id, resolved=task.status) except Exception: if task.incident.incident_review_document: file_id = task.incident.incident_review_document.resource_id drive_task_plugin.instance.update(file_id, task.external_task_id, resolved=task.status) db_session.add(task) db_session.commit() return task
def add_participant_to_tactical_group(user_email: str, incident_id: int, db_session: SessionLocal): """Adds participant to the tactical group.""" # we get the tactical group tactical_group = group_service.get_by_incident_id_and_resource_type( db_session=db_session, incident_id=incident_id, resource_type=INCIDENT_RESOURCE_TACTICAL_GROUP, ) plugin = plugin_service.get_active(db_session=db_session, plugin_type="participant-group") if plugin: plugin.instance.add(tactical_group.email, [user_email])
def assign_incident_role( db_session: SessionLocal, incident: Incident, reporter_email: str, role: ParticipantRoleType, ): """Assigns incident roles.""" # We resolve the incident role email # default to reporter if we don't have an oncall plugin enabled assignee_email = reporter_email oncall_plugin = plugin_service.get_active(db_session=db_session, plugin_type="oncall") if not oncall_plugin: assignee_email = reporter_email # Add a new participant (duplicate participants with different roles will be updated) participant_flows.add_participant( assignee_email, incident.id, db_session, role, ) return if role == ParticipantRoleType.incident_commander: # default to reporter if incident.incident_type.commander_service: service = incident.incident_type.commander_service assignee_email = oncall_plugin.instance.get( service_id=service.external_id) if incident.incident_priority.page_commander: oncall_plugin.instance.page( service_id=service.external_id, incident_name=incident.name, incident_title=incident.title, incident_description=incident.description, ) else: if incident.incident_type.liaison_service: service = incident.incident_type.liaison_service assignee_email = oncall_plugin.instance.get( service_id=service.external_id) # Add a new participant (duplicate participants with different roles will be updated) participant_flows.add_participant( assignee_email, incident.id, db_session, role, )
def get_or_create(*, db_session, code: str, **kwargs) -> Item: """Gets or creates an item.""" item = get_by_code(db_session=db_session, code=code) if not item: item_plugin = plugin_service.get_active(db_session=db_session, plugin_type="item") item_info = item_plugin.instance.get(code, db_session=db_session) kwargs["code"] = item_info.get("code", code) kwargs["name"] = item_info.get("fullname", "Unknown") kwargs["weblink"] = item_info.get("weblink", "Unknown") item_in = ItemCreate(**kwargs) item = create(db_session=db_session, item_in=item_in) return item
def delete_conference(incident: Incident, db_session: SessionLocal): """Deletes the conference.""" conference = conference_service.get_by_incident_id( db_session=db_session, incident_id=incident.id ) plugin = plugin_service.get_active(db_session=db_session, plugin_type="conference") plugin.instance.delete(conference.conference_id) event_service.log( db_session=db_session, source=plugin.title, description="Incident conference deleted", incident_id=incident.id, )
def create_conversation(incident: Incident, participants: List[str], db_session: SessionLocal): """Create external communication conversation.""" plugin = plugin_service.get_active(db_session=db_session, plugin_type="conversation") conversation = plugin.instance.create(incident.name, participants) conversation.update({"resource_type": plugin.slug, "resource_id": conversation["name"]}) event_service.log( db_session=db_session, source=plugin.title, description="Incident conversation created", incident_id=incident.id, ) return conversation
def incident_closed_status_flow(incident: Incident, db_session=None): """Runs the incident closed flow.""" # we set the closed time incident.closed_at = datetime.utcnow() # set time immediately db_session.add(incident) db_session.commit() # we archive the conversation convo_plugin = plugin_service.get_active(db_session=db_session, plugin_type="conversation") if convo_plugin: convo_plugin.instance.archive(incident.conversation.channel_id) if INCIDENT_STORAGE_OPEN_ON_CLOSE: # incidents with restricted visibility are never opened if incident.visibility == Visibility.open: # add organization wide permission storage_plugin = plugin_service.get_active(db_session=db_session, plugin_type="storage") if storage_plugin: storage_plugin.instance.open(incident.storage.resource_id)
def send_incident_resources_ephemeral_message_to_participant( user_id: str, incident_id: int, db_session: SessionLocal ): """Sends the list of incident resources to the participant via an ephemeral message.""" # we load the incident instance plugin = plugin_service.get_active(db_session=db_session, plugin_type="conversation") if not plugin: log.warning("Incident resource message not sent, no conversation plugin enabled.") return incident = incident_service.get(db_session=db_session, incident_id=incident_id) message_kwargs = { "commander_fullname": incident.commander.individual.name, "commander_weblink": incident.commander.individual.weblink, "document_weblink": resolve_attr(incident, "incident_document.weblink"), "storage_weblink": resolve_attr(incident, "storage.weblink"), "ticket_weblink": resolve_attr(incident, "ticket.weblink"), "conference_weblink": resolve_attr(incident, "conference.weblink"), "conference_challenge": resolve_attr(incident, "conference.conference_challenge"), } if incident.incident_review_document: message_kwargs.update( {"review_document_weblink": incident.incident_review_document.weblink} ) faq_doc = document_service.get_incident_faq_document(db_session=db_session) if faq_doc: message_kwargs.update({"faq_weblink": faq_doc.weblink}) conversation_reference = document_service.get_conversation_reference_document( db_session=db_session ) if conversation_reference: message_kwargs.update( {"conversation_commands_reference_document_weblink": conversation_reference.weblink} ) # we send the ephemeral message plugin.instance.send_ephemeral( incident.conversation.channel_id, user_id, "Incident Resources Message", INCIDENT_RESOURCES_MESSAGE, MessageType.incident_resources_message, **message_kwargs, ) log.debug(f"List of incident resources sent to {user_id} via ephemeral message.")
def create_incident_storage(incident: Incident, participant_group_emails: List[str], db_session: SessionLocal): """Create an external file store for incident storage.""" plugin = plugin_service.get_active(db_session=db_session, plugin_type="storage") storage = plugin.instance.create_file(INCIDENT_STORAGE_FOLDER_ID, incident.name, participant_group_emails) storage.update({ "resource_type": plugin.slug, "resource_id": storage["id"] }) return storage
def get_or_create(*, db_session, email: str, **kwargs) -> IndividualContact: """Gets or creates an individual.""" contact = get_by_email(db_session=db_session, email=email) if not contact: contact_plugin = plugin_service.get_active(db_session=db_session, plugin_type="contact") individual_info = contact_plugin.instance.get(email, db_session=db_session) kwargs["email"] = individual_info.get("email", email) kwargs["name"] = individual_info.get("fullname", "Unknown") kwargs["weblink"] = individual_info.get("weblink", "Unknown") individual_contact_in = IndividualContactCreate(**kwargs) contact = create(db_session=db_session, individual_contact_in=individual_contact_in) return contact
def incident_closed_flow(incident_id: int, command: Optional[dict] = None, db_session=None): """Runs the incident closed flow.""" # we load the incident instance incident = incident_service.get(db_session=db_session, incident_id=incident_id) # we set the closed time incident.closed_at = datetime.utcnow() # we archive the conversation convo_plugin = plugin_service.get_active(db_session=db_session, plugin_type="conversation") if convo_plugin: convo_plugin.instance.archive(incident.conversation.channel_id) # we update the external ticket update_external_incident_ticket(incident, db_session) if INCIDENT_STORAGE_OPEN_ON_CLOSE: # incidents with restricted visibility are never opened if incident.visibility == Visibility.open: # add organization wide permission storage_plugin = plugin_service.get_active(db_session=db_session, plugin_type="storage") if storage_plugin: storage_plugin.instance.open(incident.storage.resource_id) # we delete the tactical and notification groups delete_participant_groups(incident, db_session) # we delete the conference delete_conference(incident, db_session) db_session.add(incident) db_session.commit()
def create_task_reminders(db_session=None): """Creates multiple task reminders.""" tasks = task_service.get_overdue_tasks(db_session=db_session) log.debug(f"New tasks that need reminders. NumTasks: {len(tasks)}") # let's only remind for active incidents for now tasks = [t for t in tasks if t.incident.status == IncidentStatus.active] if tasks: contact_fullname = contact_weblink = DISPATCH_HELP_EMAIL # NOTE INCIDENT_ONCALL_SERVICE_ID is optional if INCIDENT_ONCALL_SERVICE_ID: oncall_service = service_service.get_by_external_id( db_session=db_session, external_id=INCIDENT_ONCALL_SERVICE_ID) if not oncall_service: log.warning( "INCIDENT_ONCALL_SERVICE_ID configured in the .env file, but not found in the database. Did you create the oncall service in the UI?" ) return oncall_plugin = plugin_service.get_active(db_session=db_session, plugin_type="oncall") if oncall_plugin.slug != oncall_service.type: log.warning( f"Unable to resolve the oncall. Oncall plugin enabled not of type {oncall_plugin.slug}." ) return if not oncall_plugin: log.warning( f"Unable to resolve the oncall, INCIDENT_ONCALL_SERVICE_ID configured, but associated plugin ({oncall_plugin.slug}) is not enabled." ) contact_fullname = "Unknown" contact_weblink = None else: oncall_email = oncall_plugin.instance.get( service_id=INCIDENT_ONCALL_SERVICE_ID) oncall_individual = individual_service.resolve_user_by_email( oncall_email, db_session) contact_fullname = oncall_individual["fullname"] contact_weblink = oncall_individual["weblink"] grouped_tasks = group_tasks_by_assignee(tasks) for assignee, tasks in grouped_tasks.items(): create_reminder(db_session, assignee, tasks, contact_fullname, contact_weblink)
def get_or_create(*, db_session, code: str, **kwargs) -> Worker: """Gets or creates an worker.""" contact = get_by_code(db_session=db_session, code=code) if not contact: contact_plugin = plugin_service.get_active(db_session=db_session, plugin_type="contact") worker_info = contact_plugin.instance.get(code, db_session=db_session) kwargs["code"] = worker_info.get("code", code) kwargs["name"] = worker_info.get("fullname", "Unknown") kwargs["weblink"] = worker_info.get("weblink", "Unknown") worker_in = WorkerCreate(**kwargs) contact = create(db_session=db_session, worker_in=worker_in) return contact
def set_conversation_topic(incident: Incident, db_session: SessionLocal): """Sets the conversation topic.""" conversation_topic = f":helmet_with_white_cross: {incident.commander.individual.name} - Type: {incident.incident_type.name} - Priority: {incident.incident_priority.name} - Status: {incident.status}" plugin = plugin_service.get_active(db_session=db_session, plugin_type="conversation") try: plugin.instance.set_topic(incident.conversation.channel_id, conversation_topic) except Exception as e: event_service.log( db_session=db_session, source="Dispatch Core App", description=f"Setting the incident conversation topic failed. Reason: {e}", incident_id=incident.id, ) log.exception(e)
def send(*, db_session, notification: Notification, notification_params: dict): """Send a notification via plugin.""" plugin = plugin_service.get_active(db_session=db_session, plugin_type=notification.type) if plugin: plugin.instance.send( notification.target, notification_params["text"], notification_params["template"], notification_params["type"], **notification_params["kwargs"], ) else: log.warning( f"Notification {notification.name} not sent. No {notification.type} plugin is active." )
def reactivate_participant(user_email: str, incident_id: int, db_session: SessionLocal): """Reactivates a participant.""" # We load the incident incident = incident_service.get(db_session=db_session, incident_id=incident_id) # We get information about the individual contact_plugin = plugin_service.get_active(db_session=db_session, plugin_type="contact") individual_info = contact_plugin.instance.get(user_email) individual_fullname = individual_info["fullname"] log.debug( f"Reactivating {individual_fullname} on incident {incident.name}...") participant = get_by_incident_id_and_email(db_session=db_session, incident_id=incident_id, email=user_email) if not participant: log.debug( f"{individual_fullname} is not an inactive participant of incident {incident.name}." ) return False # We mark the participant as active participant.is_active = True # We create a role for the participant participant_role_in = ParticipantRoleCreate( role=ParticipantRoleType.participant) participant_role = participant_role_service.create( db_session=db_session, participant_role_in=participant_role_in) participant.participant_roles.append(participant_role) # We add and commit the changes db_session.add(participant) db_session.commit() event_service.log( db_session=db_session, source="Dispatch Core App", description=f"{individual_fullname} reactivated", incident_id=incident_id, ) return True
def remove_participant(user_email: str, incident_id: int, db_session: SessionLocal): """Removes a participant.""" # We load the incident incident = incident_service.get(db_session=db_session, incident_id=incident_id) # We get information about the individual contact_plugin = plugin_service.get_active(db_session=db_session, plugin_type="contact") individual_info = contact_plugin.instance.get(user_email) individual_fullname = individual_info["fullname"] log.debug( f"Removing {individual_fullname} from incident {incident.name}...") participant = get_by_incident_id_and_email(db_session=db_session, incident_id=incident_id, email=user_email) if not participant: log.debug( f"Can't remove {individual_fullname}. They're not an active participant of incident {incident.name}." ) return False # We mark the participant as inactive participant.is_active = False # We make the participant renounce to their active roles participant_active_roles = participant_role_service.get_all_active_roles( db_session=db_session, participant_id=participant.id) for participant_active_role in participant_active_roles: participant_role_service.renounce_role( db_session=db_session, participant_role=participant_active_role) # We add and commit the changes db_session.add(participant) db_session.commit() event_service.log( db_session=db_session, source="Dispatch Core App", description=f"{participant.individual.name} removed from incident", incident_id=incident_id, ) return True
def add_participants_to_conversation( participant_emails: List[str], incident_id: int, db_session: SessionLocal ): """Adds one or more participants to the conversation.""" incident = incident_service.get(db_session=db_session, incident_id=incident_id) plugin = plugin_service.get_active(db_session=db_session, plugin_type="conversation") try: plugin.instance.add(incident.conversation.channel_id, participant_emails) except Exception as e: event_service.log( db_session=db_session, source="Dispatch Core App", description=f"Adding participant(s) to incident conversation failed. Reason: {e}", incident_id=incident.id, ) log.exception(e)
def send_task_notification(conversation_id, message_template, assignees, description, weblink, db_session: SessionLocal): """Sends a task notification.""" # we send a notification to the incident conversation notification_text = "Incident Notification" notification_type = "incident-notification" plugin = plugin_service.get_active(db_session=db_session, plugin_type="conversation") plugin.instance.send( conversation_id, notification_text, message_template, notification_type, task_assignees=[x.individual.email for x in assignees], task_description=description, task_weblink=weblink, )
def send_incident_report_reminder(incident: Incident, report_type: ReportTypes, db_session: SessionLocal): """Sends a direct message to the incident commander indicating that they should complete a report.""" message_text = f"Incident {report_type.value} Reminder" message_template = INCIDENT_REPORT_REMINDER command_name, message_type = get_report_reminder_settings(report_type) # check to see if there wasn't a recent report now = datetime.utcnow() if incident.last_tactical_report: last_reported_at = incident.last_tactical_report.created_at if now - last_reported_at < timedelta(hours=1): return plugin = plugin_service.get_active(db_session=db_session, project_id=incident.project.id, plugin_type="conversation") if not plugin: log.warning( "Incident report reminder not sent, no conversation plugin enabled." ) return report_command = plugin.instance.get_command_name(command_name) ticket_weblink = resolve_attr(incident, "ticket.weblink") items = [{ "command": report_command, "name": incident.name, "report_type": report_type.value, "ticket_weblink": ticket_weblink, "title": incident.title, }] plugin.instance.send_direct( incident.commander.individual.email, message_text, message_template, message_type, items=items, ) log.debug( f"Incident report reminder sent to {incident.commander.individual.email}." )
def get_or_create( *, db_session, incident_id: int, individual_id: int, service: Service, participant_roles: List[ParticipantRoleType], ) -> Participant: """Gets an existing participant object or creates a new one.""" participant = ( db_session.query(Participant) .filter(Participant.incident_id == incident_id) .filter(Participant.individual_contact_id == individual_id) .one_or_none() ) if not participant: incident = incident_service.get(db_session=db_session, incident_id=incident_id) # We get information about the individual individual_contact = individual_service.get( db_session=db_session, individual_contact_id=individual_id ) individual_info = {} contact_plugin = plugin_service.get_active( db_session=db_session, project_id=incident.project.id, plugin_type="contact" ) if contact_plugin: individual_info = contact_plugin.instance.get( individual_contact.email, db_session=db_session ) location = individual_info.get("location", "Unknown") team = individual_info.get("team", "Unknown") department = individual_info.get("department", "Unknown") participant_in = ParticipantCreate( participant_roles=participant_roles, team=team, department=department, location=location ) participant = create(db_session=db_session, participant_in=participant_in) participant.service = service else: participant.participant_roles += participant_roles return participant
def send_incident_feedback_daily_report(commander_email: str, feedback: List[Feedback], db_session: SessionLocal): """ Sends an incident feedback daily report to all incident commanders who received feedback. """ plugin = plugin_service.get_active(db_session=db_session, plugin_type="email") if not plugin: log.warning( "Incident feedback daily report not sent. Email plugin is not enabled." ) return items = [] for piece in feedback: participant = piece.participant.individual.name if piece.participant else "Anonymous" items.append({ "name": piece.incident.name, "title": piece.incident.title, "rating": piece.rating, "feedback": piece.feedback, "participant": participant, "created_at": piece.created_at, }) name = subject = notification_text = "Incident Feedback Daily Report" contact_fullname = contact_weblink = DISPATCH_HELP_EMAIL plugin.instance.send( commander_email, notification_text, INCIDENT_FEEDBACK_DAILY_REPORT, MessageType.incident_feedback_daily_report, name=name, subject=subject, cc=INCIDENT_RESPONSE_TEAM_EMAIL, contact_fullname=contact_fullname, contact_weblink=contact_weblink, items=items, ) log.debug(f"Incident feedback daily report sent to {commander_email}.")
def update_incident_ticket( db_session: SessionLocal, ticket_id: str, title: str = None, description: str = None, incident_type: str = None, priority: str = None, status: str = None, commander_email: str = None, reporter_email: str = None, conversation_weblink: str = None, document_weblink: str = None, storage_weblink: str = None, conference_weblink: str = None, labels: List[str] = None, cost: int = None, visibility: str = None, ): """Update external incident ticket.""" plugin = plugin_service.get_active(db_session=db_session, plugin_type="ticket") if visibility == Visibility.restricted: title = description = incident_type plugin.instance.update( ticket_id, title=title, description=description, incident_type=incident_type, priority=priority, status=status, commander_email=commander_email, reporter_email=reporter_email, conversation_weblink=conversation_weblink, document_weblink=document_weblink, storage_weblink=storage_weblink, conference_weblink=conference_weblink, labels=labels, cost=cost, incident_type_plugin_metadata=incident_type_plugin_metadata, ) log.debug("The external ticket has been updated.")
def create_participant_groups( incident: Incident, direct_participants: List[Any], indirect_participants: List[Any], db_session: SessionLocal, ): """Create external participant groups.""" plugin = plugin_service.get_active(db_session=db_session, plugin_type="participant-group") group_name = f"{incident.name}" notification_group_name = f"{group_name}-notifications" direct_participant_emails = [x.email for x in direct_participants] tactical_group = plugin.instance.create( group_name, direct_participant_emails ) # add participants to core group indirect_participant_emails = [x.email for x in indirect_participants] indirect_participant_emails.append( tactical_group["email"] ) # add all those already in the tactical group notification_group = plugin.instance.create( notification_group_name, indirect_participant_emails ) tactical_group.update( {"resource_type": INCIDENT_RESOURCE_TACTICAL_GROUP, "resource_id": tactical_group["id"]} ) notification_group.update( { "resource_type": INCIDENT_RESOURCE_NOTIFICATIONS_GROUP, "resource_id": notification_group["id"], } ) event_service.log( db_session=db_session, source=plugin.title, description="Tactical and notification groups created", incident_id=incident.id, ) return tactical_group, notification_group
def create_reminder(db_session, assignee_email, tasks, contact_fullname, contact_weblink): """Contains the logic for incident task reminders.""" # send email plugin = plugin_service.get_active(db_session=db_session, plugin_type="email") if not plugin: log.warning("Task reminder not sent, no email plugin enabled.") return message_template = INCIDENT_TASK_REMINDER items = [] for t in tasks: items.append({ "name": t.incident.name, "title": t.incident.title, "creator": t.creator.individual.name, "description": t.description, "priority": t.priority, "created_at": t.created_at, "resolve_by": t.resolve_by, "weblink": t.weblink, }) notification_type = "incident-task-reminder" name = subject = "Incident Task Reminder" plugin.instance.send( assignee_email, message_template, notification_type, name=name, subject=subject, contact_fullname=contact_fullname, contact_weblink=contact_weblink, items=items, # plugin expect dicts ) for task in tasks: task.last_reminder_at = datetime.utcnow() db_session.commit()