Пример #1
0
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
    )
Пример #2
0
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}.")
Пример #3
0
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,
    )
Пример #4
0
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
Пример #5
0
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)
Пример #6
0
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
Пример #7
0
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])
Пример #8
0
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,
    )
Пример #9
0
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
Пример #10
0
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,
    )
Пример #11
0
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
Пример #12
0
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)
Пример #13
0
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.")
Пример #14
0
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
Пример #15
0
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
Пример #16
0
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()
Пример #17
0
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)
Пример #18
0
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
Пример #19
0
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)
Пример #20
0
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."
        )
Пример #21
0
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
Пример #22
0
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
Пример #23
0
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)
Пример #24
0
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,
    )
Пример #25
0
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}."
    )
Пример #26
0
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
Пример #27
0
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}.")
Пример #28
0
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.")
Пример #29
0
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
Пример #30
0
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()