Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send ephemeral message when participant is added to an incident due to an assigned task #4586

Merged
merged 4 commits into from
Apr 5, 2024
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
14 changes: 12 additions & 2 deletions src/dispatch/database/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,13 +377,16 @@ def apply_filter_specific_joins(model: Base, filter_spec: dict, query: orm.query
model_map.update({(Incident, "IndividualContact"): (Incident.commander, True)})

filter_models = get_named_models(filters)
joined_models = []
for filter_model in filter_models:
if model_map.get((model, filter_model)):
joined_model, is_outer = model_map[(model, filter_model)]
try:
query = query.join(joined_model, isouter=is_outer)
if joined_model not in joined_models:
query = query.join(joined_model, isouter=is_outer)
joined_models.append(joined_model)
except Exception as e:
log.debug(str(e))
log.exception(e)

return query

Expand Down Expand Up @@ -436,6 +439,13 @@ def create_sort_spec(model, sort_by, descending):
for field, direction in zip(sort_by, descending, strict=False):
direction = "desc" if direction else "asc"

# check to see if field is json with a key parameter
try:
new_field = json.loads(field)
field = new_field.get("key", "")
except json.JSONDecodeError:
pass
whitdog47 marked this conversation as resolved.
Show resolved Hide resolved

# we have a complex field, we may need to join
if "." in field:
complex_model, complex_field = field.split(".")[-2:]
Expand Down
42 changes: 42 additions & 0 deletions src/dispatch/incident/messaging.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@
INCIDENT_STATUS_CHANGE,
INCIDENT_TYPE_CHANGE,
INCIDENT_COMPLETED_FORM_MESSAGE,
INCIDENT_TASK_ADD_TO_INCIDENT,
MessageType,
generate_welcome_message,
)
from dispatch.participant import service as participant_service
from dispatch.participant_role import service as participant_role_service
from dispatch.plugin import service as plugin_service
from dispatch.task.models import TaskCreate


log = logging.getLogger(__name__)
Expand Down Expand Up @@ -1033,3 +1035,43 @@ def send_incident_open_tasks_ephemeral_message(
)

log.debug(f"Open incident tasks message sent to {participant_email}.")


def send_task_add_ephemeral_message(
*,
assignee_email: str,
incident: Incident,
db_session: SessionLocal,
task: TaskCreate,
):
"""
Sends an ephemeral message to the assignee letting them know why they have been added to the incident.
"""

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

notification_text = "Task Added Notification"
message_type = MessageType.task_add_to_incident
message_template = INCIDENT_TASK_ADD_TO_INCIDENT
message_kwargs = {
"title": notification_text,
"dispatch_ui_url": f"{DISPATCH_UI_URL}/{incident.project.organization.name}/tasks?incident={incident.name}",
"task_description": task.description,
"task_weblink": task.weblink,
}

plugin.instance.send_ephemeral(
incident.conversation.channel_id,
assignee_email,
notification_text,
message_template,
message_type,
**message_kwargs,
)

log.debug(f"Task add message sent to {assignee_email}.")
14 changes: 14 additions & 0 deletions src/dispatch/messaging/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class MessageType(DispatchEnum):
incident_task_reminder = "incident-task-reminder"
case_status_reminder = "case-status-reminder"
service_feedback = "service-feedback"
task_add_to_incident = "task-add-to-incident"


INCIDENT_STATUS_DESCRIPTIONS = {
Expand Down Expand Up @@ -253,6 +254,12 @@ class MessageType(DispatchEnum):
then wait about 30 seconds for Dispatch to update the tasks before leaving the incident conversation.
""".replace("\n", " ").strip()

INCIDENT_TASK_ADD_TO_INCIDENT_DESCRIPTION = """
You have been added to this incident because you were assigned a task related to it. View all tasks for this incident using the <{{dispatch_ui_url}}|Dispatch Web UI>
\n\n *Task Description:* {{task_description}}
\n\n *Link to task in document:* {{task_weblink}}
"""

INCIDENT_MONITOR_CREATED_DESCRIPTION = """
A new monitor instance has been created.
\n\n *Weblink:* {{weblink}}
Expand Down Expand Up @@ -816,6 +823,13 @@ class MessageType(DispatchEnum):
}
]

INCIDENT_TASK_ADD_TO_INCIDENT = [
{
"title": "{{title}}",
"text": INCIDENT_TASK_ADD_TO_INCIDENT_DESCRIPTION,
}
]

ONCALL_SHIFT_FEEDBACK_BUTTONS = [
{
"button_text": "Provide Feedback",
Expand Down
6 changes: 3 additions & 3 deletions src/dispatch/static/dispatch/src/task/Table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -155,12 +155,12 @@ export default {
{ title: "Incident Priority", value: "incident_priority.name", sortable: true },
{ title: "Incident Type", value: "incident_type.name", sortable: true },
{ title: "Status", value: "status", sortable: true },
{ title: "Creator", value: "creator.individual_contact.name", sortable: true },
{ title: "Owner", value: "owner.individual_contact.name", sortable: true },
{ title: "Creator", value: "creator.individual_contact.name", sortable: false },
{ title: "Owner", value: "owner.individual_contact.name", sortable: false },
{ title: "Assignees", value: "assignees", sortable: false },
{ title: "Description", value: "description", sortable: false },
{ title: "Source", value: "source", sortable: true },
{ title: "Project", value: "project.name", sortable: true },
{ title: "Project", value: "project.name", sortable: false },
{ title: "Due By", value: "resolve_by", sortable: true },
{ title: "Created At", value: "created_at", sortable: true },
{ title: "Resolved At", value: "resolved_at", sortable: true },
Expand Down
15 changes: 15 additions & 0 deletions src/dispatch/task/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from dispatch.incident.flows import incident_service
from dispatch.incident.models import Incident
from dispatch.plugin import service as plugin_service
from dispatch.participant import service as participant_service
from dispatch.incident.messaging import send_task_add_ephemeral_message

from .enums import TaskStatus
from .models import Task, TaskCreate, TaskUpdate
Expand Down Expand Up @@ -73,6 +75,19 @@ def create(*, db_session, task_in: TaskCreate) -> Task:

assignees = []
for i in task_in.assignees:
participant = participant_service.get_by_incident_id_and_email(
db_session=db_session, incident_id=incident.id, email=i.individual.email
)

if not participant or not participant.active_roles:
# send emphemeral message to user about why they are being added to the incident
send_task_add_ephemeral_message(
assignee_email=i.individual.email,
incident=incident,
db_session=db_session,
task=task_in,
)

assignee = incident_flows.incident_add_or_reactivate_participant_flow(
db_session=db_session,
incident_id=incident.id,
Expand Down
Loading