コード例 #1
0
ファイル: messaging.py プロジェクト: wuchong718/dispatch
def send_incident_close_reminder(incident: Incident, db_session: SessionLocal):
    """Sends a direct message to the incident commander reminding them to close the incident if possible."""
    message_text = "Incident Status Reminder"
    message_template = INCIDENT_STATUS_REMINDER

    plugin = plugin_service.get_active_instance(
        db_session=db_session, project_id=incident.project.id, plugin_type="conversation"
    )
    if not plugin:
        log.warning("Incident close reminder message not sent, no conversation plugin enabled.")
        return

    update_command = plugin.instance.get_command_name(ConversationCommands.update_incident)

    items = [
        {
            "command": update_command,
            "name": incident.name,
            "ticket_weblink": incident.ticket.weblink,
            "title": incident.title,
            "status": incident.status,
        }
    ]

    plugin.instance.send_direct(
        incident.commander.individual.email,
        message_text,
        message_template,
        MessageType.incident_status_reminder,
        items=items,
    )

    log.debug(f"Incident close reminder sent to {incident.commander.individual.email}.")
コード例 #2
0
def send_incident_suggested_reading_messages(incident: Incident, items: list,
                                             participant_email: str,
                                             db_session: SessionLocal):
    """Sends a suggested reading message to a participant."""
    if items:
        plugin = plugin_service.get_active_instance(
            db_session=db_session,
            project_id=incident.project.id,
            plugin_type="conversation")
        if not plugin:
            log.warning(
                "Suggested reading message not sent, no conversation plugin enabled."
            )
            return

        plugin.instance.send_ephemeral(
            incident.conversation.channel_id,
            participant_email,
            "Suggested Reading",
            [INCIDENT_PARTICIPANT_SUGGESTED_READING_ITEM],
            MessageType.incident_participant_suggested_reading,
            items=items,
        )
        log.debug(
            f"Suggested reading ephemeral message sent to {participant_email}."
        )
コード例 #3
0
def update_notifications_group_from_submitted_form(action: dict,
                                                   db_session=None):
    """Updates notifications group based on submitted form data."""
    submitted_form = action.get("view")
    parsed_form_data = parse_submitted_form(submitted_form)

    current_members = (
        submitted_form["blocks"][1]["element"]["initial_value"].replace(
            " ", "").split(","))
    updated_members = (parsed_form_data.get(
        UpdateNotificationsGroupBlockFields.update_members).replace(
            " ", "").split(","))

    members_added = list(set(updated_members) - set(current_members))
    members_removed = list(set(current_members) - set(updated_members))

    incident_id = action["view"]["private_metadata"]["incident_id"]
    incident = incident_service.get(db_session=db_session,
                                    incident_id=incident_id)

    group_plugin = plugin_service.get_active_instance(
        db_session=db_session,
        project_id=incident.project.id,
        plugin_type="participant-group")

    group_plugin.instance.add(incident.notifications_group.email,
                              members_added)
    group_plugin.instance.remove(incident.notifications_group.email,
                                 members_removed)
コード例 #4
0
def send_incident_review_document_notification(conversation_id: str,
                                               review_document_weblink: str,
                                               incident: Incident,
                                               db_session: SessionLocal):
    """Sends the review document notification."""
    notification_text = "Incident Notification"
    notification_type = MessageType.incident_notification

    plugin = plugin_service.get_active_instance(db_session=db_session,
                                                project_id=incident.project.id,
                                                plugin_type="conversation")
    if not plugin:
        log.warning(
            "Incident review document not sent, no conversation enabled.")
        return

    plugin.instance.send(
        conversation_id,
        notification_text,
        [INCIDENT_REVIEW_DOCUMENT],
        notification_type,
        review_document_weblink=review_document_weblink,
    )

    log.debug("Incident review document notification sent.")
コード例 #5
0
def resolve_and_associate_role(
    db_session: SessionLocal, incident: Incident, role: ParticipantRoleType
):
    """For a given role type resolve which individual email should be assigned that role."""
    email_address = None
    service_id = None

    incident_role = resolve_role(db_session=db_session, role=role, incident=incident)
    if not incident_role:
        log.info(
            f"We were not able to resolve the email address for {role} via incident role policies."
        )
        return email_address, service_id

    if incident_role.service:
        service_id = incident_role.service.id
        service_external_id = incident_role.service.external_id
        oncall_plugin = plugin_service.get_active_instance(
            db_session=db_session, project_id=incident.project.id, plugin_type="oncall"
        )
        if not oncall_plugin:
            log.warning("Resolved incident role associated with a plugin that is not active.")
            return email_address, service_id

        email_address = oncall_plugin.instance.get(service_id=service_external_id)

    return email_address, service_id
コード例 #6
0
ファイル: scheduled.py プロジェクト: Netflix/dispatch
def sync_sources(db_session: SessionLocal, project: Project):
    """Syncs sources from external sources."""
    plugin = plugin_service.get_active_instance(
        db_session=db_session, plugin_type="source", project_id=project.id
    )

    if not plugin:
        log.debug(f"No active plugins were found. PluginType: 'source' ProjectId: {project.id}")
        return

    log.debug(f"Getting source information via: {plugin.plugin.slug}")

    sources = source_service.get_all(db_session=db_session, project_id=project.id)

    for s in sources:
        log.debug(f"Syncing Source. Source: {s}")
        if not s.external_id:
            log.debug(f"Skipping source, no externalId Source: {s}")
            continue

        data = plugin.instance.get(external_id=s.external_id)

        if data:
            for k, v in data.items():
                setattr(s, k, v)

            db_session.commit()
コード例 #7
0
ファイル: scheduled.py プロジェクト: Netflix/dispatch
def sync_active_stable_tasks(db_session: SessionLocal, project: Project):
    """Syncs incident tasks."""
    task_plugin = plugin_service.get_active_instance(db_session=db_session,
                                                     project_id=project.id,
                                                     plugin_type="task")

    if not task_plugin:
        log.warning(
            f"Skipping task sync no task plugin enabled. ProjectId: {project.id}"
        )
        return

    # we get all active and stable incidents
    active_incidents = incident_service.get_all_by_status(
        db_session=db_session,
        project_id=project.id,
        status=IncidentStatus.active)
    stable_incidents = incident_service.get_all_by_status(
        db_session=db_session,
        project_id=project.id,
        status=IncidentStatus.stable)

    incidents = active_incidents + stable_incidents
    lookback = 60 * 5  # 5 min
    sync_tasks(db_session,
               task_plugin,
               incidents,
               lookback=lookback,
               notify=True)
コード例 #8
0
def send_incident_participant_has_role_ephemeral_message(
    assigner_email: str,
    assignee_contact_info: dict,
    assignee_role: str,
    incident: Incident,
    db_session: SessionLocal,
):
    """Sends an ephemeral message to the assigner to let them know that the assignee already has the role."""
    notification_text = "Incident Assign Role Notification"

    plugin = plugin_service.get_active_instance(db_session=db_session,
                                                project_id=incident.project.id,
                                                plugin_type="conversation")
    if not plugin:
        log.warning(
            "Unabled to send incident participant has role message, no conversation plugin enabled."
        )
        return

    plugin.instance.send_ephemeral(
        incident.conversation.channel_id,
        assigner_email,
        notification_text,
        blocks=[{
            "type": "section",
            "text": {
                "type":
                "plain_text",
                "text":
                f"{assignee_contact_info['fullname']} already has the {assignee_role} role.",
            },
        }],
    )

    log.debug("Incident participant has role message sent.")
コード例 #9
0
ファイル: messaging.py プロジェクト: Netflix/dispatch
def send_tactical_report_to_conversation(incident_id: int, conditions: str,
                                         actions: str, needs: str,
                                         db_session: SessionLocal):
    """Sends a tactical report to the conversation."""
    # we load the incident instance
    incident = incident_service.get(db_session=db_session,
                                    incident_id=incident_id)

    plugin = plugin_service.get_active_instance(db_session=db_session,
                                                project_id=incident.project.id,
                                                plugin_type="conversation")

    if not plugin:
        log.warning(
            "Tactical report not sent, no conversation plugin enabled.")
        return

    plugin.instance.send(
        incident.conversation.channel_id,
        "Incident Tactical Report",
        INCIDENT_TACTICAL_REPORT,
        notification_type=MessageType.incident_tactical_report,
        persist=True,
        conditions=conditions,
        actions=actions,
        needs=needs,
    )

    log.debug(
        "Tactical report sent to conversation {incident.conversation.channel_id}."
    )
コード例 #10
0
def send_incident_rating_feedback_message(incident: Incident,
                                          db_session: SessionLocal):
    """
    Sends a direct message to all incident participants asking
    them to rate and provide feedback about the incident.
    """
    notification_text = "Incident Rating and Feedback"
    notification_template = INCIDENT_CLOSED_RATING_FEEDBACK_NOTIFICATION

    plugin = plugin_service.get_active_instance(db_session=db_session,
                                                project_id=incident.project.id,
                                                plugin_type="conversation")
    if not plugin:
        log.warning(
            "Incident rating and feedback message not sent, no conversation plugin enabled."
        )
        return

    items = [{
        "incident_id": incident.id,
        "name": incident.name,
        "title": incident.title,
        "ticket_weblink": incident.ticket.weblink,
    }]

    for participant in incident.participants:
        plugin.instance.send_direct(
            participant.individual.email,
            notification_text,
            notification_template,
            MessageType.incident_rating_feedback,
            items=items,
        )

    log.debug("Incident rating and feedback message sent to all participants.")
コード例 #11
0
def get_or_create(*,
                  db_session,
                  email: str,
                  incident: Incident = None,
                  **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_instance(
            db_session=db_session,
            project_id=incident.project.id,
            plugin_type="contact")
        individual_info = {}

        if contact_plugin:
            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, project=incident.project)
        contact = create(db_session=db_session,
                         individual_contact_in=individual_contact_in)

    return contact
コード例 #12
0
def send_task_notification(
    incident,
    message_template,
    creator,
    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_instance(db_session=db_session,
                                                project_id=incident.project.id,
                                                plugin_type="conversation")
    plugin.instance.send(
        incident.conversation.channel_id,
        notification_text,
        message_template,
        notification_type,
        task_creator=creator.individual.email,
        task_assignees=[x.individual.email for x in assignees],
        task_description=description,
        task_weblink=weblink,
    )
コード例 #13
0
ファイル: messaging.py プロジェクト: wuchong718/dispatch
def send_welcome_email_to_participant(
    participant_email: str, incident: Incident, db_session: SessionLocal
):
    """Sends a welcome email to the participant."""
    # we load the incident instance
    plugin = plugin_service.get_active_instance(
        db_session=db_session, project_id=incident.project.id, plugin_type="email"
    )
    if not plugin:
        log.warning("Participant welcome email not sent, not email plugin configured.")
        return

    message_kwargs = {
        "name": incident.name,
        "title": incident.title,
        "description": incident.description,
        "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_team": incident.commander.team,
        "commander_weblink": incident.commander.individual.weblink,
        "reporter_fullname": incident.reporter.individual.name,
        "reporter_team": incident.reporter.team,
        "reporter_weblink": incident.reporter.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}.")
コード例 #14
0
def create_task_reminders(db_session: SessionLocal, project: Project):
    """Creates multiple task reminders."""
    tasks = task_service.get_overdue_tasks(db_session=db_session,
                                           project_id=project.id)
    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_instance(
                db_session=db_session,
                project_id=project.id,
                plugin_type="oncall")

            if not oncall_plugin:
                log.warning(
                    f"Unable to resolve oncall. No oncall plugin is enabled. Project: {project.name}"
                )

            if oncall_plugin.plugin.slug != oncall_service.type:
                log.warning(
                    f"Unable to resolve the oncall. Oncall plugin enabled not of type {oncall_plugin.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.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)
コード例 #15
0
ファイル: actions.py プロジェクト: BuildJet/dispatch
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_instance(
        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)
コード例 #16
0
ファイル: service.py プロジェクト: wuchong718/dispatch
def update(*, db_session, task: Task, task_in: TaskUpdate, sync_external: bool = True) -> 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:
        # don't reactive participants if the tasks is already resolved
        if task_in.status != TaskStatus.resolved:
            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_instance(
        db_session=db_session, project_id=task.incident.project.id, plugin_type="task"
    )

    if drive_task_plugin:
        if sync_external:
            try:
                if task.incident.incident_document:
                    file_id = task.incident.incident_document.resource_id
                    drive_task_plugin.instance.update(
                        file_id, task.resource_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.resource_id, resolved=task.status
                    )

    db_session.add(task)
    db_session.commit()
    return task
コード例 #17
0
def get_or_create(
    *,
    db_session,
    incident_id: int,
    individual_id: int,
    service_id: int,
    participant_roles: List[ParticipantRoleCreate],
) -> Participant:
    """Gets an existing participant object or creates a new one."""
    from dispatch.incident import service as incident_service

    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_instance(
            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,
        )

        if service_id:
            participant_in.service = {"id": service_id}

        participant = create(db_session=db_session,
                             participant_in=participant_in)
    else:
        for participant_role in participant_roles:
            participant.participant_roles.append(
                participant_role_service.create(
                    db_session=db_session,
                    participant_role_in=participant_role))
        participant.service_id = service_id

    return participant
コード例 #18
0
ファイル: flows.py プロジェクト: wuchong718/dispatch
def send_workflow_notification(conversation_id, message_template, db_session,
                               **kwargs):
    """Sends a workflow notification."""
    notification_text = "Incident Notification"
    notification_type = "incident-notification"

    plugin = plugin_service.get_active_instance(db_session=db_session,
                                                plugin_type="conversation")
    plugin.instance.send(conversation_id, notification_text, message_template,
                         notification_type, **kwargs)
コード例 #19
0
ファイル: messaging.py プロジェクト: wuchong718/dispatch
def send_incident_resources_ephemeral_message_to_participant(
    user_id: str, incident: Incident, db_session: SessionLocal
):
    """Sends the list of incident resources to the participant via an ephemeral message."""
    plugin = plugin_service.get_active_instance(
        db_session=db_session, project_id=incident.project.id, plugin_type="conversation"
    )
    if not plugin:
        log.warning("Incident resource message not sent, no conversation plugin enabled.")
        return

    message_kwargs = {
        "title": incident.title,
        "description": incident.description,
        "commander_fullname": incident.commander.individual.name,
        "commander_team": incident.commander.team,
        "commander_weblink": incident.commander.individual.weblink,
        "reporter_fullname": incident.reporter.individual.name,
        "reporter_team": incident.reporter.team,
        "reporter_weblink": incident.reporter.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.")
コード例 #20
0
def send_monitor_notification(project_id: int, conversation_id: int,
                              message_template: str, db_session: SessionLocal,
                              **kwargs):
    """Sends a monitor notification."""
    notification_text = "Incident Notification"
    notification_type = "incident-notification"

    plugin = plugin_service.get_active_instance(db_session=db_session,
                                                plugin_type="conversation",
                                                project_id=project_id)
    plugin.instance.send(conversation_id, notification_text, message_template,
                         notification_type, **kwargs)
コード例 #21
0
def get_plugin_configuration_from_channel_id(db_session: SessionLocal,
                                             channel_id: str) -> Plugin:
    """Fetches the currently slack plugin configuration for this incident channel."""
    conversation = conversation_service.get_by_channel_id_ignoring_channel_type(
        db_session, channel_id)
    if conversation:
        plugin_instance = plugin_service.get_active_instance(
            db_session=db_session,
            plugin_type="conversation",
            project_id=conversation.incident.project.id,
        )
        return plugin_instance.configuration
コード例 #22
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_instance(db_session=db_session,
                                                project_id=project_id,
                                                plugin_type="conversation")
    plugin.instance.send_ephemeral(channel_id,
                                   user_id,
                                   "Conversation Command Feedback",
                                   blocks=blocks)
コード例 #23
0
ファイル: modals.py プロジェクト: wuchong718/dispatch
def build_update_notifications_group_blocks(incident: Incident, db_session: SessionLocal):
    """Builds all blocks required to update the membership of the notifications group."""
    modal_template = {
        "type": "modal",
        "title": {"type": "plain_text", "text": "Update Group Membership"},
        "blocks": [
            {
                "type": "context",
                "elements": [
                    {
                        "type": "plain_text",
                        "text": "Use this form to update the membership of the notifications group.",
                    }
                ],
            },
        ],
        "close": {"type": "plain_text", "text": "Cancel"},
        "submit": {"type": "plain_text", "text": "Update"},
        "callback_id": UpdateNotificationsGroupCallbacks.submit_form,
        "private_metadata": json.dumps(
            {"incident_id": str(incident.id), "channel_id": incident.conversation.channel_id}
        ),
    }

    group_plugin = plugin_service.get_active_instance(
        db_session=db_session, project_id=incident.project.id, plugin_type="participant-group"
    )
    members = group_plugin.instance.list(incident.notifications_group.email)

    members_block = {
        "type": "input",
        "block_id": UpdateNotificationsGroupBlockFields.update_members,
        "label": {"type": "plain_text", "text": "Members"},
        "element": {
            "type": "plain_text_input",
            "action_id": UpdateNotificationsGroupBlockFields.update_members,
            "multiline": True,
            "initial_value": (", ").join(members),
        },
    }
    modal_template["blocks"].append(members_block)

    modal_template["blocks"].append(
        {
            "type": "context",
            "elements": [{"type": "plain_text", "text": "Separate email addresses with commas."}],
        },
    )

    return modal_template
コード例 #24
0
def send_incident_management_help_tips_message(incident: Incident,
                                               db_session: SessionLocal):
    """
    Sends a direct message to the incident commander
    with help tips on how to manage the incident.
    """
    notification_text = "Incident Management Help Tips"
    message_template = INCIDENT_MANAGEMENT_HELP_TIPS_MESSAGE

    plugin = plugin_service.get_active_instance(db_session=db_session,
                                                project_id=incident.project.id,
                                                plugin_type="conversation")
    if not plugin:
        log.warning(
            "Incident management help tips message not sent, no conversation plugin enabled."
        )
        return

    engage_oncall_command = plugin.instance.get_command_name(
        ConversationCommands.engage_oncall)
    list_resources_command = plugin.instance.get_command_name(
        ConversationCommands.list_resources)
    executive_report_command = plugin.instance.get_command_name(
        ConversationCommands.executive_report)
    tactical_report_command = plugin.instance.get_command_name(
        ConversationCommands.tactical_report)
    update_command = plugin.instance.get_command_name(
        ConversationCommands.update_incident)

    items = [{
        "name": incident.name,
        "title": incident.title,
        "engage_oncall_command": engage_oncall_command,
        "list_resources_command": list_resources_command,
        "executive_report_command": executive_report_command,
        "tactical_report_command": tactical_report_command,
        "update_command": update_command,
    }]

    plugin.instance.send_direct(
        incident.commander.individual.email,
        notification_text,
        message_template,
        MessageType.incident_management_help_tips,
        items=items,
    )

    log.debug(
        f"Incident management help tips message sent to incident commander with email {incident.commander.individual.email}."
    )
コード例 #25
0
ファイル: scheduled.py プロジェクト: Netflix/dispatch
def create_evergreen_reminder(db_session: SessionLocal, project: Project,
                              owner_email: str, resource_groups: Any):
    """Contains the logic for evergreen reminders."""
    plugin = plugin_service.get_active_instance(db_session=db_session,
                                                plugin_type="email",
                                                project_id=project.id)
    if not plugin:
        log.warning("Evergreen reminder not sent, no email plugin enabled.")
        return

    notification_template = EVERGREEN_REMINDER

    items = []
    for resource_type, resources in resource_groups.items():
        for resource in resources:
            weblink = getattr(resource, "weblink", None)
            if not weblink:
                weblink = DISPATCH_UI_URL

            items.append({
                "resource_type":
                resource_type.replace("_", " ").title(),
                "name":
                resource.name,
                "description":
                getattr(resource, "description", None),
                "weblink":
                weblink,
            })

    notification_type = "evergreen-reminder"
    name = subject = notification_text = "Evergreen Reminder"
    success = plugin.instance.send(
        owner_email,
        notification_text,
        notification_template,
        notification_type,
        name=name,
        subject=subject,
        items=items,  # plugin expect dicts
    )

    if success:
        for item in items:
            item.evergreen_last_reminder_at = datetime.utcnow()

        db_session.commit()
    else:
        log.error(f"Unable to send evergreen message. Email: {owner_email}")
コード例 #26
0
def daily_sync_workflow(db_session: SessionLocal, project: Project):
    """Syncs all incident workflows daily."""
    workflow_plugin = plugin_service.get_active_instance(
        db_session=db_session, project_id=project.id, plugin_type="workflow")
    if not workflow_plugin:
        log.warning(f"No workflow plugin is enabled. ProjectId: {project.id}")
        return

    incidents = incident_service.get_all(db_session=db_session,
                                         project_id=project.id).all()
    sync_workflows(db_session,
                   project,
                   workflow_plugin,
                   incidents,
                   notify=False)
コード例 #27
0
ファイル: messaging.py プロジェクト: wuchong718/dispatch
def get_suggested_documents(db_session, incident: Incident) -> list:
    """Get additional incident documents based on priority, type, and description."""
    plugin = plugin_service.get_active_instance(
        db_session=db_session, project_id=incident.project.id, plugin_type="document-resolver"
    )

    documents = []
    if plugin:
        matches = plugin.instance.get(incident=incident, db_session=db_session)

        for m in matches:
            document = document_service.get(db_session=db_session, document_id=m.resource_state["id"])
            documents.append(document)

    return documents
コード例 #28
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_instance(
        db_session=db_session,
        project_id=incident.project.id,
        plugin_type="oncall")
    service_id = None
    if role == ParticipantRoleType.incident_commander:
        # default to reporter
        if incident.incident_type.commander_service:
            service = incident.incident_type.commander_service
            service_id = service.id
            if oncall_plugin:
                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,
                    )

    elif role == ParticipantRoleType.liaison:
        if incident.incident_type.liaison_service:
            service = incident.incident_type.liaison_service
            service_id = service.id
            if oncall_plugin:
                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,
        db_session,
        service_id=service_id,
        role=role,
    )
コード例 #29
0
ファイル: flows.py プロジェクト: BuildJet/dispatch
def reactivate_participant(user_email: str, incident: Incident,
                           db_session: SessionLocal):
    """Reactivates a participant."""

    # We get information about the individual
    contact_plugin = plugin_service.get_active_instance(
        db_session=db_session,
        project_id=incident.project.id,
        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
コード例 #30
0
def send_incident_closed_information_review_reminder(incident: Incident,
                                                     db_session: SessionLocal):
    """
    Sends a direct message to the incident commander
    asking them to review the incident's information
    and to tag the incident if appropriate.
    """
    message_text = "Incident Closed Information Review Reminder"
    message_template = INCIDENT_CLOSED_INFORMATION_REVIEW_REMINDER_NOTIFICATION

    plugin = plugin_service.get_active_instance(db_session=db_session,
                                                project_id=incident.project.id,
                                                plugin_type="conversation")
    if not plugin:
        log.warning(
            "Incident closed information review reminder message not sent, no conversation plugin enabled."
        )
        return

    items = [{
        "name":
        incident.name,
        "title":
        incident.title,
        "description":
        f"{incident.description[:100]}",
        "resolution":
        f"{incident.resolution[:100]}",
        "type":
        incident.incident_type.name,
        "priority":
        incident.incident_priority.name,
        "dispatch_ui_incident_url":
        f"{DISPATCH_UI_URL}/{incident.project.organization.name}/incidents/{incident.name}",
    }]

    plugin.instance.send_direct(
        incident.commander.individual.email,
        message_text,
        message_template,
        MessageType.incident_closed_information_review_reminder,
        items=items,
    )

    log.debug(
        f"Incident closed information review reminder sent to {incident.commander.individual.email}."
    )