Skip to content
This repository was archived by the owner on Sep 3, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions src/dispatch/case/flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from dispatch.incident.models import Incident, IncidentCreate
from dispatch.incident.priority.models import IncidentPriority
from dispatch.incident.type.models import IncidentType
from dispatch.individual import service as individual_service
from dispatch.individual.models import IndividualContactRead
from dispatch.models import OrganizationSlug, PrimaryKey
from dispatch.participant import flows as participant_flows
Expand All @@ -31,6 +32,7 @@
from dispatch.participant_role import flows as role_flow
from dispatch.participant_role.models import ParticipantRole, ParticipantRoleType
from dispatch.plugin import service as plugin_service
from dispatch.service import service as service_service
from dispatch.storage import flows as storage_flows
from dispatch.storage.enums import StorageAction
from dispatch.ticket import flows as ticket_flows
Expand Down Expand Up @@ -1105,3 +1107,83 @@ def case_create_resources_flow(

# we update the ticket
ticket_flows.update_case_ticket(case=case, db_session=db_session)


@background_task
def case_engage_oncall_flow(
user_email: str,
case_id: int,
oncall_service_external_id: str,
page=None,
organization_slug: str = None,
db_session=None,
):
"""Runs the case engage oncall flow."""
# we load the case instance
case = case_service.get(db_session=db_session, case_id=case_id)

# we resolve the oncall service
oncall_service = service_service.get_by_external_id_and_project_id(
db_session=db_session,
external_id=oncall_service_external_id,
project_id=case.project.id,
)

# we get the active oncall plugin
oncall_plugin = plugin_service.get_active_instance(
db_session=db_session, project_id=case.project.id, plugin_type="oncall"
)

if oncall_plugin:
if oncall_plugin.plugin.slug != oncall_service.type:
log.warning(
f"Unable to engage the oncall. Oncall plugin enabled not of type {oncall_plugin.plugin.slug}." # noqa
)
return None, None
else:
log.warning("Unable to engage the oncall. No oncall plugins enabled.")
return None, None

oncall_email = oncall_plugin.instance.get(service_id=oncall_service_external_id)

# we attempt to add the oncall to the case
oncall_participant_added = case_add_or_reactivate_participant_flow(
user_email=oncall_email,
case_id=case.id,
service_id=oncall_service.id,
db_session=db_session,
)

if not oncall_participant_added:
# we already have the oncall for the service in the case
return None, oncall_service

individual = individual_service.get_by_email_and_project(
db_session=db_session, email=user_email, project_id=case.project.id
)

event_service.log_case_event(
db_session=db_session,
source=oncall_plugin.plugin.title,
description=f"{individual.name} engages oncall service {oncall_service.name}",
case_id=case.id,
)

if page == "Yes":
# we page the oncall
oncall_plugin.instance.page(
service_id=oncall_service_external_id,
incident_name=case.name,
incident_title=case.title,
incident_description=case.description,
event_type="case",
)

event_service.log_case_event(
db_session=db_session,
source=oncall_plugin.plugin.title,
description=f"{oncall_service.name} on-call paged",
case_id=case.id,
)

return oncall_participant_added.individual, oncall_service
1 change: 1 addition & 0 deletions src/dispatch/plugins/dispatch_pagerduty/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ def page(
incident_name=incident_name,
incident_title=incident_title,
incident_description=incident_description,
event_type=kwargs.get("event_type", "incident"),
)

def did_oncall_just_go_off_shift(self, schedule_id: str, hour: int) -> Optional[dict]:
Expand Down
3 changes: 2 additions & 1 deletion src/dispatch/plugins/dispatch_pagerduty/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,15 @@ def page_oncall(
incident_name: str,
incident_title: str,
incident_description: str,
event_type: str = "incident",
) -> dict:
"""Pages the oncall for a given service id."""
service = get_service(client, service_id)
escalation_policy_id = service["escalation_policy"]["id"]

headers = {"from": from_email}
data = {
"type": "incident",
"type": event_type,
"title": f"{incident_name} - {incident_title}",
"service": {"id": service_id, "type": "service_reference"},
"body": {"type": "incident_body", "details": incident_description},
Expand Down
43 changes: 29 additions & 14 deletions src/dispatch/plugins/dispatch_slack/incident/interactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,10 @@ def configure(config):
app.command(config.slack_command_update_participant, middleware=middleware)(
handle_update_participant_command
)
app.command(config.slack_command_engage_oncall, middleware=middleware)(
handle_engage_oncall_command
)
app.command(
config.slack_command_engage_oncall,
middleware=[subject_middleware, configuration_middleware],
)(handle_engage_oncall_command)

# sensitive commands
middleware = [
Expand Down Expand Up @@ -1746,14 +1747,18 @@ def handle_engage_oncall_command(
"""Handles the engage oncall command."""
ack()

# TODO: handle cases
project_id = None
if context["subject"].type == CaseSubjects.case:
raise CommandError("Command is not currently available for cases.")

incident = incident_service.get(db_session=db_session, incident_id=context["subject"].id)
case = case_service.get(db_session=db_session, case_id=context["subject"].id)
if not case.dedicated_channel:
raise CommandError("Command is not currently available for threaded cases.")
project_id = case.project.id
else:
incident = incident_service.get(db_session=db_session, incident_id=context["subject"].id)
project_id = incident.project.id

oncall_services = service_service.get_all_by_project_id_and_status(
db_session=db_session, project_id=incident.project.id, is_active=True
db_session=db_session, project_id=project_id, is_active=True
)

if not oncall_services.count():
Expand Down Expand Up @@ -1837,12 +1842,22 @@ def handle_engage_oncall_submission_event(
page_block = form_data.get(EngageOncallBlockIds.page)
page = page_block[0]["value"] if page_block else None # page_block[0]["value"] == "Yes"

oncall_individual, oncall_service = incident_flows.incident_engage_oncall_flow(
user.email,
context["subject"].id,
oncall_service_external_id,
page=page,
db_session=db_session,
oncall_individual, oncall_service = (
case_flows.case_engage_oncall_flow(
user_email=user.email,
case_id=context["subject"].id,
oncall_service_external_id=oncall_service_external_id,
page=page,
db_session=db_session,
)
if context["subject"].type == CaseSubjects.case
else incident_flows.incident_engage_oncall_flow(
user_email=user.email,
incident_id=context["subject"].id,
oncall_service_external_id=oncall_service_external_id,
page=page,
db_session=db_session,
)
)

if not oncall_individual and not oncall_service:
Expand Down
Loading