Manual incidents for all teams (#194)
* Fix creation of manual incident via submenu * Remove legacy finish_configuration_attachments * Add manual incidents for all teams * Fix manual incident creation from slash command * Fix slack title template * Get rid of migration
This commit is contained in:
parent
f8f86db7b0
commit
37187ef18a
11 changed files with 949 additions and 644 deletions
|
|
@ -14,7 +14,7 @@ class AlertWebRenderer(AlertBaseRenderer):
|
|||
"title": str_or_backup(templated_alert.title, "Alert"),
|
||||
"message": str_or_backup(templated_alert.message, ""),
|
||||
"image_url": str_or_backup(templated_alert.image_url, None),
|
||||
"source_link": str_or_backup(templated_alert.image_url, None),
|
||||
"source_link": str_or_backup(templated_alert.source_link, None),
|
||||
}
|
||||
return rendered_alert
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
from django.apps import apps
|
||||
|
||||
from apps.alerts.incident_appearance.templaters.alert_templater import AlertTemplater
|
||||
|
||||
|
||||
|
|
@ -12,3 +14,55 @@ class AlertSlackTemplater(AlertTemplater):
|
|||
if templated_alert.title:
|
||||
templated_alert.title = templated_alert.title.replace("\n", "").replace("\r", "")
|
||||
return templated_alert
|
||||
|
||||
def render(self):
|
||||
"""
|
||||
Overriden render method to modify payload of manual integration alerts
|
||||
"""
|
||||
self._modify_payload_for_manual_integration_if_needed()
|
||||
return super().render()
|
||||
|
||||
def _modify_payload_for_manual_integration_if_needed(self):
|
||||
"""
|
||||
Modifies payload of alerts made from manual incident integration.
|
||||
It is needed to simplify templates.
|
||||
"""
|
||||
payload = self.alert.raw_request_data
|
||||
# First check if payload look like payload from manual incident integration and was not modified before.
|
||||
if "view" in payload and "private_metadata" in payload.get("view", {}) and "oncall" not in payload:
|
||||
AlertReceiveChannel = apps.get_model("alerts", "AlertReceiveChannel")
|
||||
# If so - check it with db query.
|
||||
if self.alert.group.channel.integration == AlertReceiveChannel.INTEGRATION_MANUAL:
|
||||
metadata = payload.get("view", {}).get("private_metadata", {})
|
||||
payload["oncall"] = {}
|
||||
if "message" in metadata:
|
||||
# If alert was made from message
|
||||
domain = payload.get("team", {}).get("domain", "unknown")
|
||||
channel_id = metadata.get("channel_id", "unknown")
|
||||
message = metadata.get("message", {})
|
||||
message_ts = message.get("ts", "unknown")
|
||||
message_text = message.get("text", "unknown")
|
||||
payload["oncall"]["permalink"] = f"https://{domain}.slack.com/archives/{channel_id}/p{message_ts}"
|
||||
payload["oncall"]["author_username"] = metadata.get("author_username", "Unknown")
|
||||
payload["oncall"]["title"] = "Message from @" + payload["oncall"]["author_username"]
|
||||
payload["oncall"]["message"] = message_text
|
||||
else:
|
||||
# If alert was made via slash command
|
||||
message_text = (
|
||||
payload.get("view", {})
|
||||
.get("state", {})
|
||||
.get("values", {})
|
||||
.get("MESSAGE_INPUT", {})
|
||||
.get("FinishCreateIncidentViewStep", {})
|
||||
.get("value", "unknown")
|
||||
)
|
||||
payload["oncall"]["permalink"] = None
|
||||
payload["oncall"]["title"] = self.alert.title
|
||||
payload["oncall"]["message"] = message_text
|
||||
created_by = self.alert.integration_unique_data.get("created_by", None)
|
||||
username = payload.get("user", {}).get("name", None)
|
||||
author_username = created_by or username or "unknown"
|
||||
payload["oncall"]["author_username"] = author_username
|
||||
|
||||
self.alert.raw_request_data = payload
|
||||
self.alert.save(update_fields=["raw_request_data"])
|
||||
|
|
|
|||
|
|
@ -32,5 +32,5 @@ class AlertWebTemplater(AlertTemplater):
|
|||
|
||||
def _slack_format_for_web(self, data):
|
||||
sf = self.slack_formatter
|
||||
sf.hyperlink_mention_format = "[title](url)"
|
||||
sf.hyperlink_mention_format = "[{title}]({url})"
|
||||
return sf.format(data)
|
||||
|
|
|
|||
|
|
@ -448,7 +448,9 @@ class AlertReceiveChannel(IntegrationOptionsMixin, MaintainableObject):
|
|||
def get_or_create_manual_integration(cls, defaults, **kwargs):
|
||||
try:
|
||||
alert_receive_channel = cls.objects.get(
|
||||
organization=kwargs["organization"], integration=kwargs["integration"]
|
||||
organization=kwargs["organization"],
|
||||
integration=kwargs["integration"],
|
||||
team=kwargs["team"],
|
||||
)
|
||||
except cls.DoesNotExist:
|
||||
kwargs.update(defaults)
|
||||
|
|
|
|||
42
engine/apps/slack/scenarios/invited_to_channel.py
Normal file
42
engine/apps/slack/scenarios/invited_to_channel.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import logging
|
||||
|
||||
from django.utils import timezone
|
||||
|
||||
from apps.slack.scenarios import scenario_step
|
||||
from apps.slack.slack_client import SlackClientWithErrorHandling
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
class InvitedToChannelStep(scenario_step.ScenarioStep):
|
||||
tags = [
|
||||
scenario_step.ScenarioStep.TAG_TRIGGERED_BY_SYSTEM,
|
||||
]
|
||||
|
||||
def process_scenario(self, slack_user_identity, slack_team_identity, payload, action=None):
|
||||
if payload["event"]["user"] == slack_team_identity.bot_user_id:
|
||||
channel_id = payload["event"]["channel"]
|
||||
slack_client = SlackClientWithErrorHandling(slack_team_identity.bot_access_token)
|
||||
channel = slack_client.api_call("conversations.info", channel=channel_id)["channel"]
|
||||
|
||||
slack_team_identity.cached_channels.update_or_create(
|
||||
slack_id=channel["id"],
|
||||
defaults={
|
||||
"name": channel["name"],
|
||||
"is_archived": channel["is_archived"],
|
||||
"is_shared": channel["is_shared"],
|
||||
"last_populated": timezone.now().date(),
|
||||
},
|
||||
)
|
||||
else:
|
||||
logger.info("Other user was invited to a channel with a bot.")
|
||||
|
||||
|
||||
STEPS_ROUTING = [
|
||||
{
|
||||
"payload_type": scenario_step.PAYLOAD_TYPE_EVENT_CALLBACK,
|
||||
"event_type": scenario_step.EVENT_TYPE_MEMBER_JOINED_CHANNEL,
|
||||
"step": InvitedToChannelStep,
|
||||
},
|
||||
]
|
||||
687
engine/apps/slack/scenarios/manual_incident.py
Normal file
687
engine/apps/slack/scenarios/manual_incident.py
Normal file
|
|
@ -0,0 +1,687 @@
|
|||
import json
|
||||
from uuid import uuid4
|
||||
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
|
||||
from apps.alerts.models import AlertReceiveChannel
|
||||
from apps.slack.scenarios import scenario_step
|
||||
from apps.slack.slack_client.exceptions import SlackAPIException
|
||||
|
||||
MANUAL_INCIDENT_TEAM_SELECT_ID = "manual_incident_team_select"
|
||||
MANUAL_INCIDENT_ORG_SELECT_ID = "manual_incident_org_select"
|
||||
MANUAL_INCIDENT_ROUTE_SELECT_ID = "manual_incident_route_select"
|
||||
MANUAL_INCIDENT_TITLE_INPUT_ID = "manual_incident_title_input"
|
||||
MANUAL_INCIDENT_MESSAGE_INPUT_ID = "manual_incident_message_input"
|
||||
|
||||
DEFAULT_TEAM_VALUE = "default_team"
|
||||
|
||||
|
||||
class StartCreateIncidentFromMessage(scenario_step.ScenarioStep):
|
||||
"""
|
||||
StartCreateIncidentFromMessage triggers creation of a manual incident from the slack message via submenu
|
||||
"""
|
||||
|
||||
callback_id = [
|
||||
"incident_create",
|
||||
"incident_create_staging",
|
||||
"incident_create_develop",
|
||||
]
|
||||
|
||||
def process_scenario(self, slack_user_identity, slack_team_identity, payload, action=None):
|
||||
input_id_prefix = _generate_input_id_prefix()
|
||||
|
||||
channel_id = payload["channel"]["id"]
|
||||
try:
|
||||
image_url = payload["message"]["files"][0]["permalink"]
|
||||
except KeyError:
|
||||
image_url = None
|
||||
private_metadata = {
|
||||
"channel_id": channel_id,
|
||||
"image_url": image_url,
|
||||
"message": {
|
||||
"user": payload["message"].get("user"),
|
||||
"text": payload["message"].get("text"),
|
||||
"ts": payload["message"].get("ts"),
|
||||
},
|
||||
"input_id_prefix": input_id_prefix,
|
||||
"with_title_and_message_inputs": False,
|
||||
"submit_routing_uid": FinishCreateIncidentFromMessage.routing_uid(),
|
||||
}
|
||||
|
||||
blocks = _get_manual_incident_initial_form_fields(
|
||||
slack_team_identity, slack_user_identity, input_id_prefix, payload
|
||||
)
|
||||
view = _get_manual_incident_form_view(
|
||||
FinishCreateIncidentFromMessage.routing_uid(), blocks, json.dumps(private_metadata)
|
||||
)
|
||||
self._slack_client.api_call(
|
||||
"views.open",
|
||||
trigger_id=payload["trigger_id"],
|
||||
view=view,
|
||||
)
|
||||
|
||||
|
||||
class FinishCreateIncidentFromMessage(scenario_step.ScenarioStep):
|
||||
"""
|
||||
FinishCreateIncidentFromMessage creates a manual incident from the slack message via submenu
|
||||
"""
|
||||
|
||||
def process_scenario(self, slack_user_identity, slack_team_identity, payload, action=None):
|
||||
Alert = apps.get_model("alerts", "Alert")
|
||||
|
||||
private_metadata = json.loads(payload["view"]["private_metadata"])
|
||||
|
||||
channel_id = private_metadata["channel_id"]
|
||||
|
||||
input_id_prefix = private_metadata["input_id_prefix"]
|
||||
selected_organization = _get_selected_org_from_payload(payload, input_id_prefix)
|
||||
selected_team = _get_selected_team_from_payload(payload, input_id_prefix)
|
||||
selected_route = _get_selected_route_from_payload(payload, input_id_prefix)
|
||||
|
||||
user = slack_user_identity.get_user(selected_organization)
|
||||
alert_receive_channel = AlertReceiveChannel.get_or_create_manual_integration(
|
||||
organization=selected_organization,
|
||||
team=selected_team,
|
||||
integration=AlertReceiveChannel.INTEGRATION_MANUAL,
|
||||
deleted_at=None,
|
||||
defaults={
|
||||
"author": user,
|
||||
"verbal_name": f"Manual incidents ({selected_team.name if selected_team else 'General'} team)",
|
||||
},
|
||||
)
|
||||
|
||||
author_username = slack_user_identity.slack_verbal
|
||||
try:
|
||||
permalink = self._slack_client.api_call(
|
||||
"chat.getPermalink",
|
||||
channel=private_metadata["channel_id"],
|
||||
message_ts=private_metadata["message"]["ts"],
|
||||
)
|
||||
permalink = permalink.get("permalink", None)
|
||||
except SlackAPIException:
|
||||
permalink = None
|
||||
title = "Message from {}".format(author_username)
|
||||
message = private_metadata["message"]["text"]
|
||||
|
||||
# Deprecated, use custom oncall property instead.
|
||||
# update private metadata in payload to use it in alert rendering
|
||||
payload["view"]["private_metadata"] = private_metadata
|
||||
payload["view"]["private_metadata"]["author_username"] = author_username
|
||||
# Custom oncall property in payload to simplify rendering
|
||||
payload["oncall"] = {}
|
||||
payload["oncall"]["title"] = title
|
||||
payload["oncall"]["message"] = message
|
||||
payload["oncall"]["author_username"] = author_username
|
||||
payload["oncall"]["permalink"] = permalink
|
||||
Alert.create(
|
||||
title=title,
|
||||
message=message,
|
||||
image_url=private_metadata["image_url"],
|
||||
# Link to the slack message is not here bc it redirects to browser
|
||||
link_to_upstream_details=None,
|
||||
alert_receive_channel=alert_receive_channel,
|
||||
raw_request_data=payload,
|
||||
integration_unique_data={"created_by": user.get_user_verbal_for_team_for_slack()},
|
||||
force_route_id=selected_route.pk,
|
||||
)
|
||||
|
||||
try:
|
||||
self._slack_client.api_call(
|
||||
"chat.postEphemeral",
|
||||
channel=channel_id,
|
||||
user=slack_user_identity.slack_id,
|
||||
text=":white_check_mark: Alert successfully submitted",
|
||||
)
|
||||
except SlackAPIException as e:
|
||||
if e.response["error"] == "channel_not_found" or e.response["error"] == "user_not_in_channel":
|
||||
self._slack_client.api_call(
|
||||
"chat.postEphemeral",
|
||||
channel=slack_user_identity.im_channel_id,
|
||||
user=slack_user_identity.slack_id,
|
||||
text=":white_check_mark: Alert successfully submitted",
|
||||
)
|
||||
else:
|
||||
raise e
|
||||
|
||||
|
||||
class StartCreateIncidentFromSlashCommand(scenario_step.ScenarioStep):
|
||||
"""
|
||||
StartCreateIncidentFromSlashCommand triggers creation of a manual incident from the slack message via slash command
|
||||
"""
|
||||
|
||||
command_name = [settings.SLACK_SLASH_COMMAND_NAME]
|
||||
TITLE_INPUT_BLOCK_ID = "TITLE_INPUT"
|
||||
MESSAGE_INPUT_BLOCK_ID = "MESSAGE_INPUT"
|
||||
|
||||
def process_scenario(self, slack_user_identity, slack_team_identity, payload, action=None):
|
||||
input_id_prefix = _generate_input_id_prefix()
|
||||
|
||||
try:
|
||||
channel_id = payload["event"]["channel"]
|
||||
except KeyError:
|
||||
channel_id = payload["channel_id"]
|
||||
|
||||
private_metadata = {
|
||||
"channel_id": channel_id,
|
||||
"input_id_prefix": input_id_prefix,
|
||||
"with_title_and_message_inputs": True,
|
||||
"submit_routing_uid": FinishCreateIncidentFromSlashCommand.routing_uid(),
|
||||
}
|
||||
|
||||
blocks = _get_manual_incident_initial_form_fields(
|
||||
slack_team_identity, slack_user_identity, input_id_prefix, payload, with_title_and_message_inputs=True
|
||||
)
|
||||
view = _get_manual_incident_form_view(
|
||||
FinishCreateIncidentFromSlashCommand.routing_uid(), blocks, json.dumps(private_metadata)
|
||||
)
|
||||
|
||||
self._slack_client.api_call(
|
||||
"views.open",
|
||||
trigger_id=payload["trigger_id"],
|
||||
view=view,
|
||||
)
|
||||
|
||||
|
||||
class FinishCreateIncidentFromSlashCommand(scenario_step.ScenarioStep):
|
||||
"""
|
||||
FinishCreateIncidentFromSlashCommand creates a manual incident from the slack message via slash message
|
||||
"""
|
||||
|
||||
def process_scenario(self, slack_user_identity, slack_team_identity, payload, action=None):
|
||||
Alert = apps.get_model("alerts", "Alert")
|
||||
|
||||
title = _get_title_from_payload(payload)
|
||||
message = _get_message_from_payload(payload)
|
||||
|
||||
private_metadata = json.loads(payload["view"]["private_metadata"])
|
||||
|
||||
channel_id = private_metadata["channel_id"]
|
||||
|
||||
input_id_prefix = private_metadata["input_id_prefix"]
|
||||
selected_organization = _get_selected_org_from_payload(payload, input_id_prefix)
|
||||
selected_team = _get_selected_team_from_payload(payload, input_id_prefix)
|
||||
selected_route = _get_selected_route_from_payload(payload, input_id_prefix)
|
||||
|
||||
user = slack_user_identity.get_user(selected_organization)
|
||||
alert_receive_channel = AlertReceiveChannel.get_or_create_manual_integration(
|
||||
organization=selected_organization,
|
||||
team=selected_team,
|
||||
integration=AlertReceiveChannel.INTEGRATION_MANUAL,
|
||||
deleted_at=None,
|
||||
defaults={
|
||||
"author": user,
|
||||
"verbal_name": f"Manual incidents ({selected_team.name if selected_team else 'General'} team)",
|
||||
},
|
||||
)
|
||||
|
||||
author_username = slack_user_identity.slack_verbal
|
||||
|
||||
try:
|
||||
self._slack_client.api_call(
|
||||
"chat.postEphemeral",
|
||||
channel=channel_id,
|
||||
user=slack_user_identity.slack_id,
|
||||
text=":white_check_mark: Alert *{}* successfully submitted".format(title),
|
||||
)
|
||||
except SlackAPIException as e:
|
||||
if e.response["error"] == "channel_not_found":
|
||||
self._slack_client.api_call(
|
||||
"chat.postEphemeral",
|
||||
channel=slack_user_identity.im_channel_id,
|
||||
user=slack_user_identity.slack_id,
|
||||
text=":white_check_mark: Alert *{}* successfully submitted".format(title),
|
||||
)
|
||||
else:
|
||||
raise e
|
||||
|
||||
# Deprecated, use custom oncall property instead.
|
||||
# Update private metadata to use it in rendering:
|
||||
payload["view"]["private_metadata"] = private_metadata
|
||||
# Custom oncall property to simplify rendering
|
||||
payload["oncall"] = {}
|
||||
payload["oncall"]["title"] = title
|
||||
payload["oncall"]["message"] = message
|
||||
payload["oncall"]["author_username"] = author_username
|
||||
payload["oncall"]["permalink"] = None
|
||||
|
||||
Alert.create(
|
||||
title=title,
|
||||
message=message,
|
||||
image_url=None,
|
||||
link_to_upstream_details=None,
|
||||
alert_receive_channel=alert_receive_channel,
|
||||
raw_request_data=payload,
|
||||
integration_unique_data={
|
||||
"created_by": author_username,
|
||||
},
|
||||
force_route_id=selected_route.pk,
|
||||
)
|
||||
|
||||
|
||||
# OnChange steps responsible for rerendering manual incident creation form on change values in selects.
|
||||
# They are works both with incident creation from submenu and slack command.
|
||||
|
||||
|
||||
class OnOrgChange(scenario_step.ScenarioStep):
|
||||
def process_scenario(self, slack_user_identity, slack_team_identity, payload, action=None):
|
||||
private_metadata = json.loads(payload["view"]["private_metadata"])
|
||||
with_title_and_message_inputs = private_metadata.get("with_title_and_message_inputs", False)
|
||||
submit_routing_uid = private_metadata.get("submit_routing_uid")
|
||||
old_input_id_prefix, new_input_id_prefix, new_private_metadata = _get_and_change_input_id_prefix_from_metadata(
|
||||
private_metadata
|
||||
)
|
||||
|
||||
selected_organization = _get_selected_org_from_payload(payload, old_input_id_prefix)
|
||||
# Set selected team to default because org is changed.
|
||||
selected_team = None
|
||||
|
||||
user = slack_user_identity.get_user(selected_organization)
|
||||
manual_integration = AlertReceiveChannel.get_or_create_manual_integration(
|
||||
organization=selected_organization,
|
||||
team=selected_team,
|
||||
integration=AlertReceiveChannel.INTEGRATION_MANUAL,
|
||||
deleted_at=None,
|
||||
defaults={
|
||||
"author": user,
|
||||
"verbal_name": f"Manual incidents ({selected_team.name if selected_team else 'General'} team)",
|
||||
},
|
||||
)
|
||||
selected_route = manual_integration.default_channel_filter
|
||||
|
||||
organization_select = _get_organization_select(
|
||||
slack_team_identity, slack_user_identity, selected_organization, new_input_id_prefix
|
||||
)
|
||||
team_select = _get_team_select(slack_user_identity, selected_organization, selected_team, new_input_id_prefix)
|
||||
route_select = _get_route_select(manual_integration, selected_route, new_input_id_prefix)
|
||||
|
||||
blocks = [organization_select, team_select, route_select]
|
||||
if with_title_and_message_inputs:
|
||||
blocks.extend([_get_title_input(payload), _get_message_input(payload)])
|
||||
view = _get_manual_incident_form_view(submit_routing_uid, blocks, json.dumps(new_private_metadata))
|
||||
self._slack_client.api_call(
|
||||
"views.update",
|
||||
trigger_id=payload["trigger_id"],
|
||||
view=view,
|
||||
view_id=payload["view"]["id"],
|
||||
)
|
||||
|
||||
|
||||
class OnTeamChange(scenario_step.ScenarioStep):
|
||||
def process_scenario(self, slack_user_identity, slack_team_identity, payload, action=None):
|
||||
private_metadata = json.loads(payload["view"]["private_metadata"])
|
||||
with_title_and_message_inputs = private_metadata.get("with_title_and_message_inputs", False)
|
||||
submit_routing_uid = private_metadata.get("submit_routing_uid")
|
||||
old_input_id_prefix, new_input_id_prefix, new_private_metadata = _get_and_change_input_id_prefix_from_metadata(
|
||||
private_metadata
|
||||
)
|
||||
|
||||
selected_organization = _get_selected_org_from_payload(payload, old_input_id_prefix)
|
||||
selected_team = _get_selected_team_from_payload(payload, old_input_id_prefix)
|
||||
|
||||
user = slack_user_identity.get_user(selected_organization)
|
||||
manual_integration = AlertReceiveChannel.get_or_create_manual_integration(
|
||||
organization=selected_organization,
|
||||
team=selected_team,
|
||||
integration=AlertReceiveChannel.INTEGRATION_MANUAL,
|
||||
deleted_at=None,
|
||||
defaults={
|
||||
"author": user,
|
||||
"verbal_name": f"Manual incidents ({selected_team.name if selected_team else 'General'} team)",
|
||||
},
|
||||
)
|
||||
initial_route = manual_integration.default_channel_filter
|
||||
|
||||
organization_select = _get_organization_select(
|
||||
slack_team_identity, slack_user_identity, selected_organization, new_input_id_prefix
|
||||
)
|
||||
team_select = _get_team_select(slack_user_identity, selected_organization, selected_team, new_input_id_prefix)
|
||||
route_select = _get_route_select(manual_integration, initial_route, new_input_id_prefix)
|
||||
|
||||
blocks = [organization_select, team_select, route_select]
|
||||
if with_title_and_message_inputs:
|
||||
blocks.extend([_get_title_input(payload), _get_message_input(payload)])
|
||||
view = _get_manual_incident_form_view(submit_routing_uid, blocks, json.dumps(new_private_metadata))
|
||||
self._slack_client.api_call(
|
||||
"views.update",
|
||||
trigger_id=payload["trigger_id"],
|
||||
view=view,
|
||||
view_id=payload["view"]["id"],
|
||||
)
|
||||
|
||||
|
||||
class OnRouteChange(scenario_step.ScenarioStep):
|
||||
"""
|
||||
OnRouteChange is just a plug to handle change of value on route select
|
||||
"""
|
||||
|
||||
def process_scenario(self, slack_user_identity, slack_team_identity, payload, action=None):
|
||||
pass
|
||||
|
||||
|
||||
def _get_manual_incident_form_view(routing_uid, blocks, private_metatada):
|
||||
view = {
|
||||
"type": "modal",
|
||||
"callback_id": routing_uid,
|
||||
"title": {
|
||||
"type": "plain_text",
|
||||
"text": "Create an Incident",
|
||||
},
|
||||
"close": {
|
||||
"type": "plain_text",
|
||||
"text": "Cancel",
|
||||
"emoji": True,
|
||||
},
|
||||
"submit": {
|
||||
"type": "plain_text",
|
||||
"text": "Submit",
|
||||
},
|
||||
"blocks": blocks,
|
||||
"private_metadata": private_metatada,
|
||||
}
|
||||
|
||||
return view
|
||||
|
||||
|
||||
def _get_manual_incident_initial_form_fields(
|
||||
slack_team_identity, slack_user_identity, input_id_prefix, payload, with_title_and_message_inputs=False
|
||||
):
|
||||
initial_organization = (
|
||||
slack_team_identity.organizations.filter(users__slack_user_identity=slack_user_identity)
|
||||
.order_by("pk")
|
||||
.distinct()
|
||||
.first()
|
||||
)
|
||||
|
||||
organization_select = _get_organization_select(
|
||||
slack_team_identity, slack_user_identity, initial_organization, input_id_prefix
|
||||
)
|
||||
|
||||
initial_team = None # means default team
|
||||
team_select = _get_team_select(slack_user_identity, initial_organization, initial_team, input_id_prefix)
|
||||
|
||||
user = slack_user_identity.get_user(initial_organization)
|
||||
manual_integration = AlertReceiveChannel.get_or_create_manual_integration(
|
||||
organization=initial_organization,
|
||||
team=initial_team,
|
||||
integration=AlertReceiveChannel.INTEGRATION_MANUAL,
|
||||
deleted_at=None,
|
||||
defaults={
|
||||
"author": user,
|
||||
"verbal_name": f"Manual incidents ({initial_team.name if initial_team else 'General'} team)",
|
||||
},
|
||||
)
|
||||
|
||||
initial_route = manual_integration.default_channel_filter
|
||||
route_select = _get_route_select(manual_integration, initial_route, input_id_prefix)
|
||||
blocks = [organization_select, team_select, route_select]
|
||||
if with_title_and_message_inputs:
|
||||
title_input = _get_title_input(payload)
|
||||
message_input = _get_message_input(payload)
|
||||
blocks.append(title_input)
|
||||
blocks.append(message_input)
|
||||
return blocks
|
||||
|
||||
|
||||
def _get_organization_select(slack_team_identity, slack_user_identity, value, input_id_prefix):
|
||||
organizations = slack_team_identity.organizations.filter(
|
||||
users__slack_user_identity=slack_user_identity,
|
||||
).distinct()
|
||||
organizations_options = []
|
||||
initial_option_idx = 0
|
||||
for idx, org in enumerate(organizations):
|
||||
if org == value:
|
||||
initial_option_idx = idx
|
||||
organizations_options.append(
|
||||
{
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": f"{org.org_title}",
|
||||
"emoji": True,
|
||||
},
|
||||
"value": f"{org.pk}",
|
||||
}
|
||||
)
|
||||
|
||||
organization_select = {
|
||||
"type": "section",
|
||||
"text": {"type": "mrkdwn", "text": "Select an organization"},
|
||||
"block_id": input_id_prefix + MANUAL_INCIDENT_ORG_SELECT_ID,
|
||||
"accessory": {
|
||||
"type": "static_select",
|
||||
"placeholder": {"type": "plain_text", "text": "Select an organization", "emoji": True},
|
||||
"options": organizations_options,
|
||||
"action_id": OnOrgChange.routing_uid(),
|
||||
"initial_option": organizations_options[initial_option_idx],
|
||||
},
|
||||
}
|
||||
|
||||
return organization_select
|
||||
|
||||
|
||||
def _get_selected_org_from_payload(payload, input_id_prefix):
|
||||
Organization = apps.get_model("user_management", "Organization")
|
||||
selected_org_id = payload["view"]["state"]["values"][input_id_prefix + MANUAL_INCIDENT_ORG_SELECT_ID][
|
||||
OnOrgChange.routing_uid()
|
||||
]["selected_option"]["value"]
|
||||
org = Organization.objects.filter(pk=selected_org_id).first()
|
||||
return org
|
||||
|
||||
|
||||
def _get_team_select(slack_user_identity, organization, value, input_id_prefix):
|
||||
teams = organization.teams.filter(
|
||||
users__slack_user_identity=slack_user_identity,
|
||||
).distinct()
|
||||
team_options = []
|
||||
# Adding pseudo option for default team
|
||||
initial_option_idx = 0
|
||||
team_options.append(
|
||||
{
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": f"General",
|
||||
"emoji": True,
|
||||
},
|
||||
"value": DEFAULT_TEAM_VALUE,
|
||||
}
|
||||
)
|
||||
for idx, team in enumerate(teams):
|
||||
if team == value:
|
||||
# Add 1 because default team option was added before cycle, so option indicies are shifted
|
||||
initial_option_idx = idx + 1
|
||||
team_options.append(
|
||||
{
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": f"{team.name}",
|
||||
"emoji": True,
|
||||
},
|
||||
"value": f"{team.pk}",
|
||||
}
|
||||
)
|
||||
|
||||
team_select = {
|
||||
"type": "section",
|
||||
"text": {"type": "mrkdwn", "text": "Select a team"},
|
||||
"block_id": input_id_prefix + MANUAL_INCIDENT_TEAM_SELECT_ID,
|
||||
"accessory": {
|
||||
"type": "static_select",
|
||||
"placeholder": {"type": "plain_text", "text": "Select a team", "emoji": True},
|
||||
"options": team_options,
|
||||
"action_id": OnTeamChange.routing_uid(),
|
||||
"initial_option": team_options[initial_option_idx],
|
||||
},
|
||||
}
|
||||
return team_select
|
||||
|
||||
|
||||
def _get_selected_team_from_payload(payload, input_id_prefix):
|
||||
Team = apps.get_model("user_management", "Team")
|
||||
selected_team_id = payload["view"]["state"]["values"][input_id_prefix + MANUAL_INCIDENT_TEAM_SELECT_ID][
|
||||
OnTeamChange.routing_uid()
|
||||
]["selected_option"]["value"]
|
||||
if selected_team_id == DEFAULT_TEAM_VALUE:
|
||||
return None
|
||||
team = Team.objects.filter(pk=selected_team_id).first()
|
||||
return team
|
||||
|
||||
|
||||
def _get_route_select(integration, value, input_id_prefix):
|
||||
route_options = []
|
||||
initial_option_idx = 0
|
||||
for idx, route in enumerate(integration.channel_filters.all()):
|
||||
filtering_term = f'"{route.filtering_term}"'
|
||||
if route.is_default:
|
||||
filtering_term = "default"
|
||||
if value == route:
|
||||
initial_option_idx = idx
|
||||
route_options.append(
|
||||
{
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": f"{filtering_term}",
|
||||
"emoji": True,
|
||||
},
|
||||
"value": f"{route.pk}",
|
||||
}
|
||||
)
|
||||
route_select = {
|
||||
"type": "section",
|
||||
"text": {"type": "mrkdwn", "text": "Select a route"},
|
||||
"block_id": input_id_prefix + MANUAL_INCIDENT_ROUTE_SELECT_ID,
|
||||
"accessory": {
|
||||
"type": "static_select",
|
||||
"placeholder": {"type": "plain_text", "text": "Select a route", "emoji": True},
|
||||
"options": route_options,
|
||||
"initial_option": route_options[initial_option_idx],
|
||||
"action_id": OnRouteChange.routing_uid(),
|
||||
},
|
||||
}
|
||||
return route_select
|
||||
|
||||
|
||||
def _get_selected_route_from_payload(payload, input_id_prefix):
|
||||
ChannelFilter = apps.get_model("alerts", "ChannelFilter")
|
||||
selected_org_id = payload["view"]["state"]["values"][input_id_prefix + MANUAL_INCIDENT_ROUTE_SELECT_ID][
|
||||
OnRouteChange.routing_uid()
|
||||
]["selected_option"]["value"]
|
||||
channel_filter = ChannelFilter.objects.filter(pk=selected_org_id).first()
|
||||
return channel_filter
|
||||
|
||||
|
||||
def _get_and_change_input_id_prefix_from_metadata(metadata):
|
||||
old_input_id_prefix = metadata["input_id_prefix"]
|
||||
new_input_id_prefix = _generate_input_id_prefix()
|
||||
metadata["input_id_prefix"] = new_input_id_prefix
|
||||
return old_input_id_prefix, new_input_id_prefix, metadata
|
||||
|
||||
|
||||
def _get_title_input(payload):
|
||||
title_input_block = {
|
||||
"type": "input",
|
||||
"block_id": MANUAL_INCIDENT_TITLE_INPUT_ID,
|
||||
"label": {
|
||||
"type": "plain_text",
|
||||
"text": "Title:",
|
||||
},
|
||||
"element": {
|
||||
"type": "plain_text_input",
|
||||
"action_id": FinishCreateIncidentFromSlashCommand.routing_uid(),
|
||||
"placeholder": {
|
||||
"type": "plain_text",
|
||||
"text": " ",
|
||||
},
|
||||
},
|
||||
}
|
||||
if payload.get("text", None) is not None:
|
||||
title_input_block["element"]["initial_value"] = payload["text"]
|
||||
return title_input_block
|
||||
|
||||
|
||||
def _get_title_from_payload(payload):
|
||||
title = payload["view"]["state"]["values"][MANUAL_INCIDENT_TITLE_INPUT_ID][
|
||||
FinishCreateIncidentFromSlashCommand.routing_uid()
|
||||
]["value"]
|
||||
return title
|
||||
|
||||
|
||||
def _get_message_input(payload):
|
||||
message_input_block = {
|
||||
"type": "input",
|
||||
"block_id": MANUAL_INCIDENT_MESSAGE_INPUT_ID,
|
||||
"label": {
|
||||
"type": "plain_text",
|
||||
"text": "Message:",
|
||||
},
|
||||
"element": {
|
||||
"type": "plain_text_input",
|
||||
"action_id": FinishCreateIncidentFromSlashCommand.routing_uid(),
|
||||
"multiline": True,
|
||||
"placeholder": {
|
||||
"type": "plain_text",
|
||||
"text": " ",
|
||||
},
|
||||
},
|
||||
"optional": True,
|
||||
}
|
||||
if payload.get("message", {}).get("text") is not None:
|
||||
message_input_block["element"]["initial_value"] = payload["message"]["text"]
|
||||
return message_input_block
|
||||
|
||||
|
||||
def _get_message_from_payload(payload):
|
||||
message = (
|
||||
payload["view"]["state"]["values"][MANUAL_INCIDENT_MESSAGE_INPUT_ID][
|
||||
FinishCreateIncidentFromSlashCommand.routing_uid()
|
||||
]["value"]
|
||||
or ""
|
||||
)
|
||||
return message
|
||||
|
||||
|
||||
# _generate_input_id_prefix returns uniq str to not to preserve input's values between view update
|
||||
# https://api.slack.com/methods/views.update#markdown
|
||||
def _generate_input_id_prefix():
|
||||
return str(uuid4())
|
||||
|
||||
|
||||
STEPS_ROUTING = [
|
||||
{
|
||||
"payload_type": scenario_step.PAYLOAD_TYPE_MESSAGE_ACTION,
|
||||
"message_action_callback_id": StartCreateIncidentFromMessage.callback_id,
|
||||
"step": StartCreateIncidentFromMessage,
|
||||
},
|
||||
{
|
||||
"payload_type": scenario_step.PAYLOAD_TYPE_BLOCK_ACTIONS,
|
||||
"block_action_type": scenario_step.BLOCK_ACTION_TYPE_STATIC_SELECT,
|
||||
"block_action_id": OnOrgChange.routing_uid(),
|
||||
"step": OnOrgChange,
|
||||
},
|
||||
{
|
||||
"payload_type": scenario_step.PAYLOAD_TYPE_BLOCK_ACTIONS,
|
||||
"block_action_type": scenario_step.BLOCK_ACTION_TYPE_STATIC_SELECT,
|
||||
"block_action_id": OnTeamChange.routing_uid(),
|
||||
"step": OnTeamChange,
|
||||
},
|
||||
{
|
||||
"payload_type": scenario_step.PAYLOAD_TYPE_BLOCK_ACTIONS,
|
||||
"block_action_type": scenario_step.BLOCK_ACTION_TYPE_STATIC_SELECT,
|
||||
"block_action_id": OnRouteChange.routing_uid(),
|
||||
"step": OnRouteChange,
|
||||
},
|
||||
{
|
||||
"payload_type": scenario_step.PAYLOAD_TYPE_VIEW_SUBMISSION,
|
||||
"view_callback_id": FinishCreateIncidentFromMessage.routing_uid(),
|
||||
"step": FinishCreateIncidentFromMessage,
|
||||
},
|
||||
{
|
||||
"payload_type": scenario_step.PAYLOAD_TYPE_SLASH_COMMAND,
|
||||
"command_name": StartCreateIncidentFromSlashCommand.command_name,
|
||||
"step": StartCreateIncidentFromSlashCommand,
|
||||
},
|
||||
{
|
||||
"payload_type": scenario_step.PAYLOAD_TYPE_VIEW_SUBMISSION,
|
||||
"view_callback_id": FinishCreateIncidentFromSlashCommand.routing_uid(),
|
||||
"step": FinishCreateIncidentFromSlashCommand,
|
||||
},
|
||||
]
|
||||
|
|
@ -1,536 +0,0 @@
|
|||
import json
|
||||
import logging
|
||||
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.http import JsonResponse
|
||||
from django.utils import timezone
|
||||
|
||||
from apps.slack.scenarios import scenario_step
|
||||
from apps.slack.slack_client import SlackClientWithErrorHandling
|
||||
from apps.slack.slack_client.exceptions import SlackAPIException
|
||||
|
||||
from .step_mixins import CheckAlertIsUnarchivedMixin
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
class InvitedToChannelStep(scenario_step.ScenarioStep):
|
||||
|
||||
tags = [
|
||||
scenario_step.ScenarioStep.TAG_TRIGGERED_BY_SYSTEM,
|
||||
]
|
||||
|
||||
def process_scenario(self, slack_user_identity, slack_team_identity, payload, action=None):
|
||||
if payload["event"]["user"] == slack_team_identity.bot_user_id:
|
||||
channel_id = payload["event"]["channel"]
|
||||
slack_client = SlackClientWithErrorHandling(slack_team_identity.bot_access_token)
|
||||
channel = slack_client.api_call("conversations.info", channel=channel_id)["channel"]
|
||||
|
||||
slack_team_identity.cached_channels.update_or_create(
|
||||
slack_id=channel["id"],
|
||||
defaults={
|
||||
"name": channel["name"],
|
||||
"is_archived": channel["is_archived"],
|
||||
"is_shared": channel["is_shared"],
|
||||
"last_populated": timezone.now().date(),
|
||||
},
|
||||
)
|
||||
else:
|
||||
logger.info("Other user was invited to a channel with a bot.")
|
||||
|
||||
|
||||
class CloseEphemeralButtonStep(scenario_step.ScenarioStep):
|
||||
|
||||
random_prefix_for_routing = "qwe2id"
|
||||
|
||||
def process_scenario(self, slack_user_identity, slack_team_identity, payload, action=None):
|
||||
return JsonResponse({"response_type": "ephemeral", "delete_original": True})
|
||||
|
||||
|
||||
class CreateIncidentManuallyStep(scenario_step.ScenarioStep):
|
||||
command_name = [settings.SLACK_SLASH_COMMAND_NAME]
|
||||
tags = [
|
||||
scenario_step.ScenarioStep.TAG_INCIDENT_ROUTINE,
|
||||
]
|
||||
|
||||
TITLE_INPUT_BLOCK_ID = "TITLE_INPUT"
|
||||
MESSAGE_INPUT_BLOCK_ID = "MESSAGE_INPUT"
|
||||
|
||||
def process_scenario(self, slack_user_identity, slack_team_identity, payload, action=None):
|
||||
try:
|
||||
channel_id = payload["event"]["channel"]
|
||||
except KeyError:
|
||||
channel_id = payload["channel_id"]
|
||||
|
||||
blocks = self.get_create_incident_blocks(payload, slack_team_identity, slack_user_identity)
|
||||
|
||||
view = {
|
||||
"type": "modal",
|
||||
"callback_id": FinishCreateIncidentViewStep.routing_uid(),
|
||||
"title": {
|
||||
"type": "plain_text",
|
||||
"text": "Create an Incident",
|
||||
},
|
||||
"close": {
|
||||
"type": "plain_text",
|
||||
"text": "Cancel",
|
||||
"emoji": True,
|
||||
},
|
||||
"submit": {
|
||||
"type": "plain_text",
|
||||
"text": "Submit",
|
||||
},
|
||||
"blocks": blocks,
|
||||
"private_metadata": json.dumps({"channel_id": channel_id}),
|
||||
}
|
||||
self._slack_client.api_call(
|
||||
"views.open",
|
||||
trigger_id=payload["trigger_id"],
|
||||
view=view,
|
||||
)
|
||||
|
||||
def get_create_incident_blocks(self, payload, slack_team_identity, slack_user_identity):
|
||||
blocks = []
|
||||
organization_selection_block = self.get_select_organization_route_element(
|
||||
slack_team_identity, slack_user_identity
|
||||
)
|
||||
title_incident_block = {
|
||||
"type": "input",
|
||||
"block_id": self.TITLE_INPUT_BLOCK_ID,
|
||||
"label": {
|
||||
"type": "plain_text",
|
||||
"text": "Title:",
|
||||
},
|
||||
"element": {
|
||||
"type": "plain_text_input",
|
||||
"action_id": FinishCreateIncidentViewStep.routing_uid(),
|
||||
"placeholder": {
|
||||
"type": "plain_text",
|
||||
"text": " ",
|
||||
},
|
||||
},
|
||||
}
|
||||
if payload.get("text", None) is not None:
|
||||
title_incident_block["element"]["initial_value"] = payload["text"]
|
||||
message_incident_block = {
|
||||
"type": "input",
|
||||
"block_id": self.MESSAGE_INPUT_BLOCK_ID,
|
||||
"label": {
|
||||
"type": "plain_text",
|
||||
"text": "Message:",
|
||||
},
|
||||
"element": {
|
||||
"type": "plain_text_input",
|
||||
"action_id": FinishCreateIncidentViewStep.routing_uid(),
|
||||
"multiline": True,
|
||||
"placeholder": {
|
||||
"type": "plain_text",
|
||||
"text": " ",
|
||||
},
|
||||
},
|
||||
"optional": True,
|
||||
}
|
||||
if payload.get("message", {}).get("text") is not None:
|
||||
message_incident_block["element"]["initial_value"] = payload["message"]["text"]
|
||||
|
||||
blocks.append(organization_selection_block)
|
||||
blocks.append(title_incident_block)
|
||||
blocks.append(message_incident_block)
|
||||
return blocks
|
||||
|
||||
|
||||
class FinishCreateIncidentViewStep(scenario_step.ScenarioStep):
|
||||
|
||||
tags = [
|
||||
scenario_step.ScenarioStep.TAG_INCIDENT_ROUTINE,
|
||||
]
|
||||
|
||||
def process_scenario(self, slack_user_identity, slack_team_identity, payload, action=None):
|
||||
AlertReceiveChannel = apps.get_model("alerts", "AlertReceiveChannel")
|
||||
ChannelFilter = apps.get_model("alerts", "ChannelFilter")
|
||||
|
||||
Alert = apps.get_model("alerts", "Alert")
|
||||
payload_values = payload["view"]["state"]["values"]
|
||||
title = payload_values[CreateIncidentManuallyStep.TITLE_INPUT_BLOCK_ID][self.routing_uid()]["value"]
|
||||
text = payload_values[CreateIncidentManuallyStep.MESSAGE_INPUT_BLOCK_ID][self.routing_uid()]["value"] or ""
|
||||
|
||||
private_metadata = json.loads(payload["view"]["private_metadata"])
|
||||
# update private metadata in payload to use it in alert rendering
|
||||
payload["view"]["private_metadata"] = private_metadata
|
||||
|
||||
channel_id = private_metadata["channel_id"]
|
||||
|
||||
alert_receive_channel = AlertReceiveChannel.get_or_create_manual_integration(
|
||||
organization=self.organization,
|
||||
integration=AlertReceiveChannel.INTEGRATION_MANUAL,
|
||||
deleted_at=None,
|
||||
defaults={"author": self.user},
|
||||
)
|
||||
try:
|
||||
self._slack_client.api_call(
|
||||
"chat.postEphemeral",
|
||||
channel=channel_id,
|
||||
user=slack_user_identity.slack_id,
|
||||
text=":white_check_mark: Alert *{}* successfully submitted".format(title),
|
||||
)
|
||||
except SlackAPIException as e:
|
||||
if e.response["error"] == "channel_not_found":
|
||||
self._slack_client.api_call(
|
||||
"chat.postEphemeral",
|
||||
channel=slack_user_identity.im_channel_id,
|
||||
user=slack_user_identity.slack_id,
|
||||
text=":white_check_mark: Alert *{}* successfully submitted".format(title),
|
||||
)
|
||||
else:
|
||||
raise e
|
||||
user_verbal = self.user.get_user_verbal_for_team_for_slack()
|
||||
channel_filter_pk = payload["view"]["state"]["values"][
|
||||
scenario_step.ScenarioStep.SELECT_ORGANIZATION_AND_ROUTE_BLOCK_ID
|
||||
][scenario_step.ScenarioStep.SELECT_ORGANIZATION_AND_ROUTE_BLOCK_ID]["selected_option"]["value"].split("-")[1]
|
||||
channel_filter = ChannelFilter.objects.get(pk=channel_filter_pk)
|
||||
Alert.create(
|
||||
title=title,
|
||||
message="{} created by {}".format(
|
||||
text,
|
||||
user_verbal,
|
||||
),
|
||||
image_url=None,
|
||||
link_to_upstream_details=None,
|
||||
alert_receive_channel=alert_receive_channel,
|
||||
raw_request_data=payload,
|
||||
integration_unique_data={
|
||||
"created_by": user_verbal,
|
||||
},
|
||||
force_route_id=channel_filter.pk,
|
||||
)
|
||||
|
||||
|
||||
class CreateIncidentSubmenuStep(scenario_step.ScenarioStep):
|
||||
callback_id = [
|
||||
"incident_create",
|
||||
"incident_create_staging",
|
||||
"incident_create_develop",
|
||||
]
|
||||
tags = [
|
||||
scenario_step.ScenarioStep.TAG_INCIDENT_ROUTINE,
|
||||
]
|
||||
|
||||
def process_scenario(self, slack_user_identity, slack_team_identity, payload, action=None):
|
||||
try:
|
||||
image_url = payload["message"]["files"][0]["permalink"]
|
||||
except KeyError:
|
||||
image_url = None
|
||||
channel_id = payload["channel"]["id"]
|
||||
|
||||
private_metadata = {
|
||||
"channel_id": channel_id,
|
||||
"image_url": image_url,
|
||||
"message": {
|
||||
"user": payload["message"].get("user"),
|
||||
"text": payload["message"].get("text"),
|
||||
"ts": payload["message"].get("ts"),
|
||||
},
|
||||
}
|
||||
|
||||
organization_selection_block = self.get_select_organization_route_element(
|
||||
slack_team_identity, slack_user_identity
|
||||
)
|
||||
view = {
|
||||
"type": "modal",
|
||||
"callback_id": FinishCreateIncidentSubmenuStep.routing_uid(),
|
||||
"title": {
|
||||
"type": "plain_text",
|
||||
"text": "Create an Incident",
|
||||
},
|
||||
"close": {
|
||||
"type": "plain_text",
|
||||
"text": "Cancel",
|
||||
"emoji": True,
|
||||
},
|
||||
"submit": {
|
||||
"type": "plain_text",
|
||||
"text": "Submit",
|
||||
},
|
||||
"blocks": [organization_selection_block],
|
||||
"private_metadata": json.dumps(private_metadata),
|
||||
}
|
||||
self._slack_client.api_call(
|
||||
"views.open",
|
||||
trigger_id=payload["trigger_id"],
|
||||
view=view,
|
||||
)
|
||||
|
||||
|
||||
class FinishCreateIncidentSubmenuStep(scenario_step.ScenarioStep):
|
||||
|
||||
tags = [
|
||||
scenario_step.ScenarioStep.TAG_INCIDENT_ROUTINE,
|
||||
]
|
||||
|
||||
def process_scenario(self, slack_user_identity, slack_team_identity, payload, action=None):
|
||||
AlertReceiveChannel = apps.get_model("alerts", "AlertReceiveChannel")
|
||||
Alert = apps.get_model("alerts", "Alert")
|
||||
|
||||
private_metadata = json.loads(payload["view"]["private_metadata"])
|
||||
# update private metadata in payload to use it in alert rendering
|
||||
payload["view"]["private_metadata"] = private_metadata
|
||||
|
||||
channel_id = private_metadata["channel_id"]
|
||||
author = private_metadata["message"]["user"]
|
||||
|
||||
alert_receive_channel = AlertReceiveChannel.get_or_create_manual_integration(
|
||||
organization=self.organization,
|
||||
integration=AlertReceiveChannel.INTEGRATION_MANUAL,
|
||||
deleted_at=None,
|
||||
defaults={"author": self.user},
|
||||
)
|
||||
|
||||
author_username = "Unknown"
|
||||
if author:
|
||||
try:
|
||||
author_username = self._slack_client.api_call(
|
||||
"users.info",
|
||||
user=author,
|
||||
)
|
||||
author_username = author_username.get("user", {}).get("real_name", None)
|
||||
except SlackAPIException:
|
||||
pass
|
||||
payload["view"]["private_metadata"]["author_username"] = author_username
|
||||
|
||||
try:
|
||||
permalink = self._slack_client.api_call(
|
||||
"chat.getPermalink",
|
||||
channel=private_metadata["channel_id"],
|
||||
message_ts=private_metadata["message"]["ts"],
|
||||
)
|
||||
permalink = permalink.get("permalink", None)
|
||||
except SlackAPIException:
|
||||
permalink = None
|
||||
|
||||
permalink = "<{}|Original message...>".format(permalink) if permalink is not None else ""
|
||||
Alert.create(
|
||||
title="Message from {}".format(author_username),
|
||||
message="{}\n{}".format(private_metadata["message"]["text"], permalink),
|
||||
image_url=private_metadata["image_url"],
|
||||
# Link to the slack message is not here bc it redirects to browser
|
||||
link_to_upstream_details=None,
|
||||
alert_receive_channel=alert_receive_channel,
|
||||
raw_request_data=payload,
|
||||
integration_unique_data={"created_by": self.user.get_user_verbal_for_team_for_slack()},
|
||||
)
|
||||
try:
|
||||
self._slack_client.api_call(
|
||||
"chat.postEphemeral",
|
||||
channel=channel_id,
|
||||
user=slack_user_identity.slack_id,
|
||||
text=":white_check_mark: Alert successfully submitted",
|
||||
)
|
||||
except SlackAPIException as e:
|
||||
if e.response["error"] == "channel_not_found" or e.response["error"] == "user_not_in_channel":
|
||||
self._slack_client.api_call(
|
||||
"chat.postEphemeral",
|
||||
channel=slack_user_identity.im_channel_id,
|
||||
user=slack_user_identity.slack_id,
|
||||
text=":white_check_mark: Alert successfully submitted",
|
||||
)
|
||||
else:
|
||||
raise e
|
||||
|
||||
|
||||
class AddToResolutionoteStep(CheckAlertIsUnarchivedMixin, scenario_step.ScenarioStep):
|
||||
callback_id = [
|
||||
"add_resolution_note",
|
||||
"add_resolution_note_staging",
|
||||
"add_resolution_note_develop",
|
||||
]
|
||||
tags = [
|
||||
scenario_step.ScenarioStep.TAG_INCIDENT_ROUTINE,
|
||||
]
|
||||
|
||||
def process_scenario(self, slack_user_identity, slack_team_identity, payload, action=None):
|
||||
SlackMessage = apps.get_model("slack", "SlackMessage")
|
||||
ResolutionNoteSlackMessage = apps.get_model("alerts", "ResolutionNoteSlackMessage")
|
||||
ResolutionNote = apps.get_model("alerts", "ResolutionNote")
|
||||
SlackUserIdentity = apps.get_model("slack", "SlackUserIdentity")
|
||||
|
||||
try:
|
||||
channel_id = payload["channel"]["id"]
|
||||
except KeyError:
|
||||
raise Exception("Channel was not found")
|
||||
|
||||
if self.organization and self.organization.general_log_channel_id is None:
|
||||
try:
|
||||
return self._slack_client.api_call(
|
||||
"chat.postEphemeral",
|
||||
channel=channel_id,
|
||||
user=slack_user_identity.slack_id,
|
||||
attachments=CreateIncidentSubmenuStep.finish_configuration_attachments(self.organization),
|
||||
)
|
||||
except SlackAPIException as e:
|
||||
if e.response["error"] == "channel_not_found" or e.response["error"] == "user_not_in_channel":
|
||||
return self._slack_client.api_call(
|
||||
"chat.postEphemeral",
|
||||
channel=slack_user_identity.im_channel_id,
|
||||
user=slack_user_identity.slack_id,
|
||||
attachments=CreateIncidentSubmenuStep.finish_configuration_attachments(self.organization),
|
||||
)
|
||||
else:
|
||||
raise e
|
||||
|
||||
warning_text = "Unable to add this message to resolution note, this command works only in incident threads."
|
||||
|
||||
try:
|
||||
slack_message = SlackMessage.objects.get(
|
||||
slack_id=payload["message"]["thread_ts"],
|
||||
_slack_team_identity=slack_team_identity,
|
||||
channel_id=channel_id,
|
||||
)
|
||||
except KeyError:
|
||||
self.open_warning_window(payload, warning_text)
|
||||
return
|
||||
except SlackMessage.DoesNotExist:
|
||||
self.open_warning_window(payload, warning_text)
|
||||
return
|
||||
|
||||
try:
|
||||
alert_group = slack_message.get_alert_group()
|
||||
except SlackMessage.alert.RelatedObjectDoesNotExist as e:
|
||||
self.open_warning_window(payload, warning_text)
|
||||
print(
|
||||
f"Exception: tried to add message from thread to Resolution Note: "
|
||||
f"Slack Team Identity pk: {self.slack_team_identity.pk}, "
|
||||
f"Slack Message id: {slack_message.slack_id}"
|
||||
)
|
||||
raise e
|
||||
|
||||
if not self.check_alert_is_unarchived(slack_team_identity, payload, alert_group):
|
||||
return
|
||||
|
||||
if payload["message"]["type"] == "message" and "user" in payload["message"]:
|
||||
message_ts = payload["message_ts"]
|
||||
thread_ts = payload["message"]["thread_ts"]
|
||||
|
||||
result = self._slack_client.api_call(
|
||||
"chat.getPermalink",
|
||||
channel=channel_id,
|
||||
message_ts=message_ts,
|
||||
)
|
||||
permalink = None
|
||||
if result["permalink"] is not None:
|
||||
permalink = result["permalink"]
|
||||
|
||||
if payload["message"]["ts"] in [
|
||||
message.ts
|
||||
for message in alert_group.resolution_note_slack_messages.filter(added_to_resolution_note=True)
|
||||
]:
|
||||
warning_text = "Unable to add the same message again."
|
||||
self.open_warning_window(payload, warning_text)
|
||||
return
|
||||
|
||||
elif len(payload["message"]["text"]) > 2900:
|
||||
warning_text = (
|
||||
"Unable to add the message to Resolution note: the message is too long ({}). "
|
||||
"Max length - 2900 symbols.".format(len(payload["message"]["text"]))
|
||||
)
|
||||
self.open_warning_window(payload, warning_text)
|
||||
return
|
||||
|
||||
else:
|
||||
try:
|
||||
resolution_note_slack_message = ResolutionNoteSlackMessage.objects.get(
|
||||
ts=message_ts, thread_ts=thread_ts
|
||||
)
|
||||
except ResolutionNoteSlackMessage.DoesNotExist:
|
||||
text = payload["message"]["text"]
|
||||
text = text.replace("```", "")
|
||||
slack_message = SlackMessage.objects.get(
|
||||
slack_id=thread_ts,
|
||||
_slack_team_identity=slack_team_identity,
|
||||
channel_id=channel_id,
|
||||
)
|
||||
alert_group = slack_message.get_alert_group()
|
||||
author_slack_user_identity = SlackUserIdentity.objects.get(
|
||||
slack_id=payload["message"]["user"], slack_team_identity=slack_team_identity
|
||||
)
|
||||
author_user = self.organization.users.get(slack_user_identity=author_slack_user_identity)
|
||||
resolution_note_slack_message = ResolutionNoteSlackMessage(
|
||||
alert_group=alert_group,
|
||||
user=author_user,
|
||||
added_by_user=self.user,
|
||||
text=text,
|
||||
slack_channel_id=channel_id,
|
||||
thread_ts=thread_ts,
|
||||
ts=message_ts,
|
||||
permalink=permalink,
|
||||
)
|
||||
resolution_note_slack_message.added_to_resolution_note = True
|
||||
resolution_note_slack_message.save()
|
||||
resolution_note = resolution_note_slack_message.get_resolution_note()
|
||||
if resolution_note is None:
|
||||
ResolutionNote(
|
||||
alert_group=alert_group,
|
||||
author=resolution_note_slack_message.user,
|
||||
source=ResolutionNote.Source.SLACK,
|
||||
resolution_note_slack_message=resolution_note_slack_message,
|
||||
).save()
|
||||
else:
|
||||
resolution_note.recreate()
|
||||
alert_group.drop_cached_after_resolve_report_json()
|
||||
alert_group.schedule_cache_for_web()
|
||||
try:
|
||||
self._slack_client.api_call(
|
||||
"reactions.add",
|
||||
channel=channel_id,
|
||||
name="memo",
|
||||
timestamp=resolution_note_slack_message.ts,
|
||||
)
|
||||
except SlackAPIException:
|
||||
pass
|
||||
|
||||
self._update_slack_message(alert_group)
|
||||
else:
|
||||
warning_text = "Unable to add this message to resolution note."
|
||||
self.open_warning_window(payload, warning_text)
|
||||
return
|
||||
|
||||
|
||||
STEPS_ROUTING = [
|
||||
{
|
||||
"payload_type": scenario_step.PAYLOAD_TYPE_SLASH_COMMAND,
|
||||
"command_name": CreateIncidentManuallyStep.command_name,
|
||||
"step": CreateIncidentManuallyStep,
|
||||
},
|
||||
{
|
||||
"payload_type": scenario_step.PAYLOAD_TYPE_EVENT_CALLBACK,
|
||||
"event_type": scenario_step.EVENT_TYPE_MEMBER_JOINED_CHANNEL,
|
||||
"step": InvitedToChannelStep,
|
||||
},
|
||||
{
|
||||
"payload_type": scenario_step.PAYLOAD_TYPE_INTERACTIVE_MESSAGE,
|
||||
"action_type": scenario_step.ACTION_TYPE_BUTTON,
|
||||
"action_name": CloseEphemeralButtonStep.routing_uid(),
|
||||
"step": CloseEphemeralButtonStep,
|
||||
},
|
||||
{
|
||||
"payload_type": scenario_step.PAYLOAD_TYPE_VIEW_SUBMISSION,
|
||||
"view_callback_id": FinishCreateIncidentViewStep.routing_uid(),
|
||||
"step": FinishCreateIncidentViewStep,
|
||||
},
|
||||
{
|
||||
"payload_type": scenario_step.PAYLOAD_TYPE_VIEW_SUBMISSION,
|
||||
"view_callback_id": FinishCreateIncidentSubmenuStep.routing_uid(),
|
||||
"step": FinishCreateIncidentSubmenuStep,
|
||||
},
|
||||
{
|
||||
"payload_type": scenario_step.PAYLOAD_TYPE_MESSAGE_ACTION,
|
||||
"message_action_callback_id": CreateIncidentSubmenuStep.callback_id,
|
||||
"step": CreateIncidentSubmenuStep,
|
||||
},
|
||||
{
|
||||
"payload_type": scenario_step.PAYLOAD_TYPE_MESSAGE_ACTION,
|
||||
"message_action_callback_id": AddToResolutionoteStep.callback_id,
|
||||
"step": AddToResolutionoteStep,
|
||||
},
|
||||
]
|
||||
|
|
@ -15,6 +15,144 @@ from .step_mixins import CheckAlertIsUnarchivedMixin
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AddToResolutionNoteStep(CheckAlertIsUnarchivedMixin, scenario_step.ScenarioStep):
|
||||
callback_id = [
|
||||
"add_resolution_note",
|
||||
"add_resolution_note_staging",
|
||||
"add_resolution_note_develop",
|
||||
]
|
||||
tags = [
|
||||
scenario_step.ScenarioStep.TAG_INCIDENT_ROUTINE,
|
||||
]
|
||||
|
||||
def process_scenario(self, slack_user_identity, slack_team_identity, payload, action=None):
|
||||
SlackMessage = apps.get_model("slack", "SlackMessage")
|
||||
ResolutionNoteSlackMessage = apps.get_model("alerts", "ResolutionNoteSlackMessage")
|
||||
ResolutionNote = apps.get_model("alerts", "ResolutionNote")
|
||||
SlackUserIdentity = apps.get_model("slack", "SlackUserIdentity")
|
||||
|
||||
try:
|
||||
channel_id = payload["channel"]["id"]
|
||||
except KeyError:
|
||||
raise Exception("Channel was not found")
|
||||
|
||||
warning_text = "Unable to add this message to resolution note, this command works only in incident threads."
|
||||
|
||||
try:
|
||||
slack_message = SlackMessage.objects.get(
|
||||
slack_id=payload["message"]["thread_ts"],
|
||||
_slack_team_identity=slack_team_identity,
|
||||
channel_id=channel_id,
|
||||
)
|
||||
except KeyError:
|
||||
self.open_warning_window(payload, warning_text)
|
||||
return
|
||||
except SlackMessage.DoesNotExist:
|
||||
self.open_warning_window(payload, warning_text)
|
||||
return
|
||||
|
||||
try:
|
||||
alert_group = slack_message.get_alert_group()
|
||||
except SlackMessage.alert.RelatedObjectDoesNotExist as e:
|
||||
self.open_warning_window(payload, warning_text)
|
||||
print(
|
||||
f"Exception: tried to add message from thread to Resolution Note: "
|
||||
f"Slack Team Identity pk: {self.slack_team_identity.pk}, "
|
||||
f"Slack Message id: {slack_message.slack_id}"
|
||||
)
|
||||
raise e
|
||||
|
||||
if not self.check_alert_is_unarchived(slack_team_identity, payload, alert_group):
|
||||
return
|
||||
|
||||
if payload["message"]["type"] == "message" and "user" in payload["message"]:
|
||||
message_ts = payload["message_ts"]
|
||||
thread_ts = payload["message"]["thread_ts"]
|
||||
|
||||
result = self._slack_client.api_call(
|
||||
"chat.getPermalink",
|
||||
channel=channel_id,
|
||||
message_ts=message_ts,
|
||||
)
|
||||
permalink = None
|
||||
if result["permalink"] is not None:
|
||||
permalink = result["permalink"]
|
||||
|
||||
if payload["message"]["ts"] in [
|
||||
message.ts
|
||||
for message in alert_group.resolution_note_slack_messages.filter(added_to_resolution_note=True)
|
||||
]:
|
||||
warning_text = "Unable to add the same message again."
|
||||
self.open_warning_window(payload, warning_text)
|
||||
return
|
||||
|
||||
elif len(payload["message"]["text"]) > 2900:
|
||||
warning_text = (
|
||||
"Unable to add the message to Resolution note: the message is too long ({}). "
|
||||
"Max length - 2900 symbols.".format(len(payload["message"]["text"]))
|
||||
)
|
||||
self.open_warning_window(payload, warning_text)
|
||||
return
|
||||
|
||||
else:
|
||||
try:
|
||||
resolution_note_slack_message = ResolutionNoteSlackMessage.objects.get(
|
||||
ts=message_ts, thread_ts=thread_ts
|
||||
)
|
||||
except ResolutionNoteSlackMessage.DoesNotExist:
|
||||
text = payload["message"]["text"]
|
||||
text = text.replace("```", "")
|
||||
slack_message = SlackMessage.objects.get(
|
||||
slack_id=thread_ts,
|
||||
_slack_team_identity=slack_team_identity,
|
||||
channel_id=channel_id,
|
||||
)
|
||||
alert_group = slack_message.get_alert_group()
|
||||
author_slack_user_identity = SlackUserIdentity.objects.get(
|
||||
slack_id=payload["message"]["user"], slack_team_identity=slack_team_identity
|
||||
)
|
||||
author_user = self.organization.users.get(slack_user_identity=author_slack_user_identity)
|
||||
resolution_note_slack_message = ResolutionNoteSlackMessage(
|
||||
alert_group=alert_group,
|
||||
user=author_user,
|
||||
added_by_user=self.user,
|
||||
text=text,
|
||||
slack_channel_id=channel_id,
|
||||
thread_ts=thread_ts,
|
||||
ts=message_ts,
|
||||
permalink=permalink,
|
||||
)
|
||||
resolution_note_slack_message.added_to_resolution_note = True
|
||||
resolution_note_slack_message.save()
|
||||
resolution_note = resolution_note_slack_message.get_resolution_note()
|
||||
if resolution_note is None:
|
||||
ResolutionNote(
|
||||
alert_group=alert_group,
|
||||
author=resolution_note_slack_message.user,
|
||||
source=ResolutionNote.Source.SLACK,
|
||||
resolution_note_slack_message=resolution_note_slack_message,
|
||||
).save()
|
||||
else:
|
||||
resolution_note.recreate()
|
||||
alert_group.drop_cached_after_resolve_report_json()
|
||||
alert_group.schedule_cache_for_web()
|
||||
try:
|
||||
self._slack_client.api_call(
|
||||
"reactions.add",
|
||||
channel=channel_id,
|
||||
name="memo",
|
||||
timestamp=resolution_note_slack_message.ts,
|
||||
)
|
||||
except SlackAPIException:
|
||||
pass
|
||||
|
||||
self._update_slack_message(alert_group)
|
||||
else:
|
||||
warning_text = "Unable to add this message to resolution note."
|
||||
self.open_warning_window(payload, warning_text)
|
||||
return
|
||||
|
||||
|
||||
class UpdateResolutionNoteStep(scenario_step.ScenarioStep):
|
||||
def process_signal(self, alert_group, resolution_note):
|
||||
if resolution_note.deleted_at:
|
||||
|
|
@ -625,4 +763,9 @@ STEPS_ROUTING = [
|
|||
"block_action_id": AddRemoveThreadMessageStep.routing_uid(),
|
||||
"step": AddRemoveThreadMessageStep,
|
||||
},
|
||||
{
|
||||
"payload_type": scenario_step.PAYLOAD_TYPE_MESSAGE_ACTION,
|
||||
"message_action_callback_id": AddToResolutionNoteStep.callback_id,
|
||||
"step": AddToResolutionNoteStep,
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -135,28 +135,6 @@ class ScenarioStep(object):
|
|||
channel = user.im_channel_id
|
||||
return channel
|
||||
|
||||
@staticmethod
|
||||
def finish_configuration_attachments(organization):
|
||||
text = (
|
||||
f"A few steps left to finish configuration!\n"
|
||||
f"Go to your <{organization.web_link}?page=slack|OnCall workspace> and select default channel "
|
||||
f"for your incidents!"
|
||||
)
|
||||
return [
|
||||
{
|
||||
"color": "#008000",
|
||||
"blocks": [
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": text,
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def routing_uid(cls):
|
||||
return cls.random_prefix_for_routing + cls.__name__
|
||||
|
|
@ -431,55 +409,3 @@ class ScenarioStep(object):
|
|||
element["initial_option"] = initial_option
|
||||
|
||||
return element
|
||||
|
||||
def get_select_organization_route_element(self, slack_team_identity, slack_user_identity):
|
||||
AlertReceiveChannel = apps.get_model("alerts", "AlertReceiveChannel")
|
||||
|
||||
organizations = slack_team_identity.organizations.filter(
|
||||
users__slack_user_identity=slack_user_identity
|
||||
).distinct()
|
||||
organizations_options = []
|
||||
|
||||
for organization in organizations:
|
||||
manual_integration = AlertReceiveChannel.get_or_create_manual_integration(
|
||||
organization=organization,
|
||||
integration=AlertReceiveChannel.INTEGRATION_MANUAL,
|
||||
deleted_at=None,
|
||||
defaults={"author": self.user},
|
||||
)
|
||||
|
||||
for route in manual_integration.channel_filters.all():
|
||||
filtering_term = f'"{route.filtering_term}"'
|
||||
if route.is_default:
|
||||
filtering_term = "default"
|
||||
organizations_options.append(
|
||||
{
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": f"{organization.org_title}: {filtering_term}",
|
||||
"emoji": True,
|
||||
},
|
||||
"value": f"{organization.pk}-{route.pk}",
|
||||
}
|
||||
)
|
||||
|
||||
organization_selection_block = {
|
||||
"type": "input",
|
||||
"block_id": ScenarioStep.SELECT_ORGANIZATION_AND_ROUTE_BLOCK_ID,
|
||||
"element": {
|
||||
"type": "static_select",
|
||||
"placeholder": {
|
||||
"type": "plain_text",
|
||||
"text": "Select organization",
|
||||
},
|
||||
"action_id": ScenarioStep.SELECT_ORGANIZATION_AND_ROUTE_BLOCK_ID,
|
||||
"options": organizations_options,
|
||||
"initial_option": organizations_options[0],
|
||||
},
|
||||
"label": {
|
||||
"type": "plain_text",
|
||||
"text": "Select organization and route:",
|
||||
"emoji": True,
|
||||
},
|
||||
}
|
||||
return organization_selection_block
|
||||
|
|
|
|||
|
|
@ -16,11 +16,12 @@ from apps.auth_token.auth import PluginAuthentication
|
|||
from apps.base.utils import live_settings
|
||||
from apps.slack.scenarios.alertgroup_appearance import STEPS_ROUTING as ALERTGROUP_APPEARANCE_ROUTING
|
||||
from apps.slack.scenarios.distribute_alerts import STEPS_ROUTING as DISTRIBUTION_STEPS_ROUTING
|
||||
from apps.slack.scenarios.invited_to_channel import STEPS_ROUTING as INVITED_TO_CHANNEL_ROUTING
|
||||
from apps.slack.scenarios.manual_incident import STEPS_ROUTING as MANUAL_INCIDENT_ROUTING
|
||||
|
||||
# Importing routes from scenarios
|
||||
from apps.slack.scenarios.onboarding import STEPS_ROUTING as ONBOARDING_STEPS_ROUTING
|
||||
from apps.slack.scenarios.profile_update import STEPS_ROUTING as PROFILE_UPDATE_ROUTING
|
||||
from apps.slack.scenarios.public_menu import STEPS_ROUTING as PUBLIC_MENU_ROUTING
|
||||
from apps.slack.scenarios.resolution_note import STEPS_ROUTING as RESOLUTION_NOTE_ROUTING
|
||||
from apps.slack.scenarios.scenario_step import (
|
||||
EVENT_SUBTYPE_BOT_MESSAGE,
|
||||
|
|
@ -57,7 +58,7 @@ from .models import SlackActionRecord, SlackMessage, SlackTeamIdentity, SlackUse
|
|||
SCENARIOS_ROUTES = [] # Add all other routes here
|
||||
SCENARIOS_ROUTES.extend(ONBOARDING_STEPS_ROUTING)
|
||||
SCENARIOS_ROUTES.extend(DISTRIBUTION_STEPS_ROUTING)
|
||||
SCENARIOS_ROUTES.extend(PUBLIC_MENU_ROUTING)
|
||||
SCENARIOS_ROUTES.extend(INVITED_TO_CHANNEL_ROUTING)
|
||||
SCENARIOS_ROUTES.extend(SCHEDULES_ROUTING)
|
||||
SCENARIOS_ROUTES.extend(SLACK_CHANNEL_INTEGRATION_ROUTING)
|
||||
SCENARIOS_ROUTES.extend(ALERTGROUP_APPEARANCE_ROUTING)
|
||||
|
|
@ -65,6 +66,7 @@ SCENARIOS_ROUTES.extend(RESOLUTION_NOTE_ROUTING)
|
|||
SCENARIOS_ROUTES.extend(SLACK_USERGROUP_UPDATE_ROUTING)
|
||||
SCENARIOS_ROUTES.extend(CHANNEL_ROUTING)
|
||||
SCENARIOS_ROUTES.extend(PROFILE_UPDATE_ROUTING)
|
||||
SCENARIOS_ROUTES.extend(MANUAL_INCIDENT_ROUTING)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,39 +12,28 @@ is_demo_alert_enabled = False
|
|||
description = None
|
||||
|
||||
# Default templates
|
||||
slack_title = """{% set metadata = payload.view.private_metadata %}
|
||||
{%-if "message" in metadata -%}
|
||||
{% set title = "Message from @" + metadata.author_username %}
|
||||
{%- else -%}
|
||||
{% set title = payload.view.state["values"].TITLE_INPUT.FinishCreateIncidentViewStep.value %}
|
||||
{%- endif -%}
|
||||
*<{{ grafana_oncall_link }}|#{{ grafana_oncall_incident_id }} {{ title }}>* via {{ integration_name }}
|
||||
slack_title = """\
|
||||
*<{{ grafana_oncall_link }}|#{{ grafana_oncall_incident_id }} {{ payload.oncall.title }}>* via {{ integration_name }}
|
||||
{% if source_link %}
|
||||
(*<{{ source_link }}|source>*)
|
||||
{%- endif %}
|
||||
{% endif %}
|
||||
"""
|
||||
|
||||
slack_message = """{% set metadata = payload.view.private_metadata %}
|
||||
{% if "message" in metadata -%}
|
||||
{{ metadata.message.text }}
|
||||
slack_message = """{{ payload.oncall.message }}
|
||||
|
||||
<https://{{ payload.team.domain }}.slack.com/archives/{{ metadata.channel_id }}/{{ metadata.message.ts }} | Original message... >
|
||||
{%- else -%}
|
||||
{{ payload.view.state["values"].MESSAGE_INPUT.FinishCreateIncidentViewStep.value }}
|
||||
|
||||
created by {{ payload.user.name }}
|
||||
{%- endif -%}"""
|
||||
created by {{ payload.oncall.author_username }}
|
||||
"""
|
||||
|
||||
slack_image_url = None
|
||||
|
||||
web_title = """{% set metadata = payload.view.private_metadata %}
|
||||
{%-if "message" in metadata -%}
|
||||
{{ "Message from @" + metadata.author_username }}
|
||||
{%- else -%}
|
||||
{{ payload.view.state["values"].TITLE_INPUT.FinishCreateIncidentViewStep.value }}
|
||||
{%- endif -%}"""
|
||||
web_title = "{{ payload.oncall.title }}"
|
||||
|
||||
web_message = slack_message
|
||||
web_message = """{{ payload.oncall.message }}
|
||||
{% if source_link %}
|
||||
<{{ source_link }} | Link to the original message >
|
||||
{% endif %}
|
||||
created by {{ payload.oncall.author_username }}
|
||||
"""
|
||||
|
||||
web_image_url = slack_image_url
|
||||
|
||||
|
|
@ -62,11 +51,7 @@ telegram_message = slack_message
|
|||
|
||||
telegram_image_url = slack_image_url
|
||||
|
||||
source_link = """\
|
||||
{% set metadata = payload.view.private_metadata %}
|
||||
{%- if "message" in metadata %}
|
||||
https://{{ payload.team.domain }}.slack.com/archives/{{ payload.channel.id }}/{{ payload.message.ts }}
|
||||
{% endif -%}"""
|
||||
source_link = "{{ payload.oncall.permalink }}"
|
||||
|
||||
grouping_id = """{{ payload }}"""
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue