示例#1
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)}")
    # lets 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)
            oncall_plugin = plugin_service.get_by_slug(
                db_session=db_session, slug=oncall_service.type)
            if oncall_plugin.enabled:
                log.warning(
                    f"Unable to resolve oncall, INCIDENT_ONCALL_SERVICE_ID configured but associated plugin ({oncall_plugin.name}) is not enabled."
                )
                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)
示例#2
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)
示例#3
0
def create(
    *,
    db_session,
    incident_priority: str,
    incident_type: str,
    reporter_email: str,
    title: str,
    status: str,
    description: str,
) -> Incident:
    participants = []

    # TODO should some of this logic be in the incident_create_flow_instead? (kglisson)
    incident_priority = incident_priority_service.get_by_name(
        db_session=db_session, name=incident_priority["name"])

    incident_type = incident_type_service.get_by_name(
        db_session=db_session, name=incident_type["name"])

    commander_email = resolve_incident_commander_email(
        db_session,
        reporter_email,
        incident_type.name,
        incident_priority.name,
        "",
        title,
        description,
    )

    commander_info = individual_service.resolve_user_by_email(commander_email)

    incident_commander_role = participant_role_service.create(
        db_session=db_session, role=ParticipantRoleType.incident_commander)

    commander_participant = participant_service.create(
        db_session=db_session, participant_role=[incident_commander_role])

    commander = individual_service.get_or_create(
        db_session=db_session,
        email=commander_info["email"],
        name=commander_info["fullname"],
        weblink=commander_info["weblink"],
    )

    incident_reporter_role = participant_role_service.create(
        db_session=db_session, role=ParticipantRoleType.reporter)

    if reporter_email == commander_email:
        commander_participant.participant_role.append(incident_reporter_role)
    else:
        reporter_participant = participant_service.create(
            db_session=db_session, participant_role=[incident_reporter_role])
        reporter_info = individual_service.resolve_user_by_email(
            reporter_email)
        reporter = individual_service.get_or_create(
            db_session=db_session,
            email=reporter_info["email"],
            name=reporter_info["fullname"],
            weblink=commander_info["weblink"],
        )
        reporter.participant.append(reporter_participant)
        db_session.add(reporter)
        participants.append(reporter_participant)

    participants.append(commander_participant)
    incident = Incident(
        title=title,
        description=description,
        status=status,
        incident_priority=incident_priority,
        incident_type=incident_type,
        participants=participants,
    )

    commander.participant.append(commander_participant)
    db_session.add(commander)
    db_session.add(incident)
    db_session.commit()
    return incident
示例#4
0
def daily_summary(db_session=None):
    """Fetches all open incidents and provides a daily summary."""

    blocks = []
    blocks.append({
        "type": "section",
        "text": {
            "type": "mrkdwn",
            "text": f"*{INCIDENT_DAILY_SUMMARY_DESCRIPTION}*"
        },
    })

    active_incidents = get_all_by_status(db_session=db_session,
                                         status=IncidentStatus.active)
    if active_incidents:
        blocks.append({
            "type": "section",
            "text": {
                "type": "mrkdwn",
                "text":
                f"*{INCIDENT_DAILY_SUMMARY_ACTIVE_INCIDENTS_DESCRIPTION}*",
            },
        })
        for idx, incident in enumerate(active_incidents):
            if incident.visibility == Visibility.open:
                try:
                    blocks.append({
                        "type": "section",
                        "text": {
                            "type":
                            "mrkdwn",
                            "text":
                            (f"*<{incident.ticket.weblink}|{incident.name}>*\n"
                             f"*Title*: {incident.title}\n"
                             f"*Type*: {incident.incident_type.name}\n"
                             f"*Priority*: {incident.incident_priority.name}\n"
                             f"*Incident Commander*: <{incident.commander.weblink}|{incident.commander.name}>"
                             ),
                        },
                        "block_id":
                        f"{ConversationButtonActions.invite_user}-active-{idx}",
                        "accessory": {
                            "type": "button",
                            "text": {
                                "type": "plain_text",
                                "text": "Join Incident"
                            },
                            "value": f"{incident.id}",
                        },
                    })
                except Exception as e:
                    sentry_sdk.capture_exception(e)
    else:
        blocks.append({
            "type": "section",
            "text": {
                "type": "mrkdwn",
                "text": INCIDENT_DAILY_SUMMARY_NO_ACTIVE_INCIDENTS_DESCRIPTION,
            },
        })

    blocks.append({"type": "divider"})
    blocks.append({
        "type": "section",
        "text": {
            "type":
            "mrkdwn",
            "text":
            f"*{INCIDENT_DAILY_SUMMARY_STABLE_CLOSED_INCIDENTS_DESCRIPTION}*",
        },
    })

    hours = 24
    stable_incidents = get_all_last_x_hours_by_status(
        db_session=db_session, status=IncidentStatus.stable, hours=hours)
    closed_incidents = get_all_last_x_hours_by_status(
        db_session=db_session, status=IncidentStatus.closed, hours=hours)
    if stable_incidents or closed_incidents:
        for idx, incident in enumerate(stable_incidents):
            if incident.visibility == Visibility.open:
                try:
                    blocks.append({
                        "type": "section",
                        "text": {
                            "type":
                            "mrkdwn",
                            "text":
                            (f"*<{incident.ticket.weblink}|{incident.name}>*\n"
                             f"*Title*: {incident.title}\n"
                             f"*Type*: {incident.incident_type.name}\n"
                             f"*Priority*: {incident.incident_priority.name}\n"
                             f"*Incident Commander*: <{incident.commander.weblink}|{incident.commander.name}>\n"
                             f"*Status*: {incident.status}"),
                        },
                        "block_id":
                        f"{ConversationButtonActions.invite_user}-{idx}",
                        "accessory": {
                            "type": "button",
                            "text": {
                                "type": "plain_text",
                                "text": "Join Incident"
                            },
                            "value": f"{incident.id}",
                        },
                    })
                except Exception as e:
                    sentry_sdk.capture_exception(e)

        for incident in closed_incidents:
            if incident.visibility == Visibility.open:
                try:
                    blocks.append({
                        "type": "section",
                        "text": {
                            "type":
                            "mrkdwn",
                            "text":
                            (f"*<{incident.ticket.weblink}|{incident.name}>*\n"
                             f"*Title*: {incident.title}\n"
                             f"*Type*: {incident.incident_type.name}\n"
                             f"*Priority*: {incident.incident_priority.name}\n"
                             f"*Incident Commander*: <{incident.commander.weblink}|{incident.commander.name}>\n"
                             f"*Status*: {incident.status}"),
                        },
                    })
                except Exception as e:
                    sentry_sdk.capture_exception(e)
    else:
        blocks.append({
            "type": "section",
            "text": {
                "type":
                "mrkdwn",
                "text":
                INCIDENT_DAILY_SUMMARY_NO_STABLE_CLOSED_INCIDENTS_DESCRIPTION,
            },
        })

    # NOTE INCIDENT_DAILY_SUMMARY_ONCALL_SERVICE_ID is optional
    if INCIDENT_DAILY_SUMMARY_ONCALL_SERVICE_ID:
        oncall_service = service_service.get_by_external_id(
            db_session=db_session,
            external_id=INCIDENT_DAILY_SUMMARY_ONCALL_SERVICE_ID)

        oncall_plugin = plugins.get(oncall_service.type)
        oncall_email = oncall_plugin.get(
            service_id=INCIDENT_DAILY_SUMMARY_ONCALL_SERVICE_ID)

        oncall_individual = individual_service.resolve_user_by_email(
            oncall_email)

        blocks.append({
            "type":
            "context",
            "elements": [{
                "type":
                "mrkdwn",
                "text":
                f"For questions about this notification, reach out to <{oncall_individual['weblink']}|{oncall_individual['fullname']}> (current on-call)",
            }],
        })

    convo_plugin = plugins.get(INCIDENT_PLUGIN_CONVERSATION_SLUG)
    for c in INCIDENT_NOTIFICATION_CONVERSATIONS:
        convo_plugin.send(c, "Incident Daily Summary", {}, "", blocks=blocks)
示例#5
0
def daily_summary(db_session=None):
    """
    Fetches all active, and stable and closed incidents in the last 24 hours
    and sends a daily summary to all incident notification conversations.
    """
    blocks = []
    blocks.append(
        {
            "type": "header",
            "text": {
                "type": "plain_text",
                "text": f"{INCIDENT_DAILY_SUMMARY_DESCRIPTION}",
            },
        }
    )

    active_incidents = get_all_by_status(db_session=db_session, status=IncidentStatus.active)
    if active_incidents:
        blocks.append(
            {
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": f"*{INCIDENT_DAILY_SUMMARY_ACTIVE_INCIDENTS_DESCRIPTION}*",
                },
            }
        )
        for idx, incident in enumerate(active_incidents):
            ticket_weblink = resolve_attr(incident, "ticket.weblink")
            if incident.visibility == Visibility.open:
                try:
                    blocks.append(
                        {
                            "type": "section",
                            "text": {
                                "type": "mrkdwn",
                                "text": (
                                    f"*<{ticket_weblink}|{incident.name}>*\n"
                                    f"*Title*: {incident.title}\n"
                                    f"*Type*: {incident.incident_type.name}\n"
                                    f"*Priority*: {incident.incident_priority.name}\n"
                                    f"*Incident Commander*: <{incident.commander.weblink}|{incident.commander.name}>"
                                ),
                            },
                            "block_id": f"{ConversationButtonActions.invite_user}-active-{idx}",
                            "accessory": {
                                "type": "button",
                                "text": {"type": "plain_text", "text": "Join Incident"},
                                "value": f"{incident.id}",
                            },
                        }
                    )
                except Exception as e:
                    log.exception(e)

        blocks.append(
            {
                "type": "context",
                "elements": [
                    {
                        "type": "mrkdwn",
                        "text": f"For more information about active incidents, please visit the active incidents status <{DISPATCH_UI_URL}/incidents/status|page>.",
                    }
                ],
            }
        )
    else:
        blocks.append(
            {
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": INCIDENT_DAILY_SUMMARY_NO_ACTIVE_INCIDENTS_DESCRIPTION,
                },
            }
        )

    blocks.append({"type": "divider"})
    blocks.append(
        {
            "type": "section",
            "text": {
                "type": "mrkdwn",
                "text": f"*{INCIDENT_DAILY_SUMMARY_STABLE_CLOSED_INCIDENTS_DESCRIPTION}*",
            },
        }
    )

    hours = 24
    stable_incidents = get_all_last_x_hours_by_status(
        db_session=db_session, status=IncidentStatus.stable, hours=hours
    )
    closed_incidents = get_all_last_x_hours_by_status(
        db_session=db_session, status=IncidentStatus.closed, hours=hours
    )
    if stable_incidents or closed_incidents:
        for idx, incident in enumerate(stable_incidents):
            ticket_weblink = resolve_attr(incident, "ticket.weblink")

            if incident.visibility == Visibility.open:
                try:
                    blocks.append(
                        {
                            "type": "section",
                            "text": {
                                "type": "mrkdwn",
                                "text": (
                                    f"*<{ticket_weblink}|{incident.name}>*\n"
                                    f"*Title*: {incident.title}\n"
                                    f"*Type*: {incident.incident_type.name}\n"
                                    f"*Priority*: {incident.incident_priority.name}\n"
                                    f"*Incident Commander*: <{incident.commander.weblink}|{incident.commander.name}>\n"
                                    f"*Status*: {incident.status}"
                                ),
                            },
                            "block_id": f"{ConversationButtonActions.invite_user}-stable-{idx}",
                            "accessory": {
                                "type": "button",
                                "text": {"type": "plain_text", "text": "Join Incident"},
                                "value": f"{incident.id}",
                            },
                        }
                    )
                except Exception as e:
                    log.exception(e)

        for incident in closed_incidents:
            ticket_weblink = resolve_attr(incident, "ticket.weblink")

            if incident.visibility == Visibility.open:
                try:
                    blocks.append(
                        {
                            "type": "section",
                            "text": {
                                "type": "mrkdwn",
                                "text": (
                                    f"*<{ticket_weblink}|{incident.name}>*\n"
                                    f"*Title*: {incident.title}\n"
                                    f"*Type*: {incident.incident_type.name}\n"
                                    f"*Priority*: {incident.incident_priority.name}\n"
                                    f"*Incident Commander*: <{incident.commander.weblink}|{incident.commander.name}>\n"
                                    f"*Status*: {incident.status}"
                                ),
                            },
                        }
                    )
                except Exception as e:
                    log.exception(e)
    else:
        blocks.append(
            {
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": INCIDENT_DAILY_SUMMARY_NO_STABLE_CLOSED_INCIDENTS_DESCRIPTION,
                },
            }
        )

    # 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 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."
            )
            return

        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

        oncall_email = oncall_plugin.instance.get(service_id=INCIDENT_ONCALL_SERVICE_ID)
        oncall_individual = individual_service.resolve_user_by_email(oncall_email, db_session)

        blocks.append(
            {
                "type": "context",
                "elements": [
                    {
                        "type": "mrkdwn",
                        "text": f"For any questions about this notification, please reach out to <{oncall_individual['weblink']}|{oncall_individual['fullname']}> (current on-call)",
                    }
                ],
            }
        )

    plugin = plugin_service.get_active(db_session=db_session, plugin_type="conversation")

    for c in INCIDENT_NOTIFICATION_CONVERSATIONS:
        plugin.instance.send(c, "Incident Daily Summary", {}, "", blocks=blocks)