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

Remove template editor from Slack #1847

Merged
merged 4 commits into from
May 2, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion engine/apps/alerts/models/alert_receive_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ def created_name(self):

@property
def web_link(self):
return urljoin(self.organization.web_link, "?page=settings")
return urljoin(self.organization.web_link, f"integrations/{self.public_primary_key}")

@property
def integration_url(self):
Expand Down
249 changes: 11 additions & 238 deletions engine/apps/slack/scenarios/alertgroup_appearance.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import json

from django.apps import apps
from django.db import transaction
from jinja2 import TemplateSyntaxError
from rest_framework.response import Response

from apps.api.permissions import RBACPermission
from apps.slack.scenarios import scenario_step
from common.insight_log import EntityEvent, write_resource_insight_log
from common.jinja_templater import jinja_template_env

from .step_mixins import CheckAlertIsUnarchivedMixin, IncidentActionsAccessControlMixin

Expand All @@ -21,7 +16,6 @@ class OpenAlertAppearanceDialogStep(

def process_scenario(self, slack_user_identity, slack_team_identity, payload):
AlertGroup = apps.get_model("alerts", "AlertGroup")
AlertReceiveChannel = apps.get_model("alerts", "AlertReceiveChannel")

try:
message_ts = payload["message_ts"]
Expand All @@ -45,148 +39,17 @@ def process_scenario(self, slack_user_identity, slack_team_identity, payload):
"message_ts": message_ts,
}

integration = alert_group.channel.integration

PAYLOAD_TEXT_SIZE = 3000
raw_request_data = json.dumps(alert_group.alerts.first().raw_request_data, sort_keys=True, indent=4)

# This is a special case for amazon sns notifications in str format CHEKED
if (
hasattr(AlertReceiveChannel, "INTEGRATION_AMAZON_SNS")
and alert_group.channel.integration == AlertReceiveChannel.INTEGRATION_AMAZON_SNS
and raw_request_data == "{}"
):
raw_request_data = alert_group.alerts.first().message

raw_request_data_chunks = [
raw_request_data[i : i + PAYLOAD_TEXT_SIZE] for i in range(0, len(raw_request_data), PAYLOAD_TEXT_SIZE)
]
for idx, chunk in enumerate(raw_request_data_chunks):
block = {
"type": "input",
"block_id": f"payload_{idx}",
"label": {
"type": "plain_text",
"text": f"Payload (Part {idx + 1}):" if len(raw_request_data_chunks) > 1 else "Payload (Readonly)",
},
"element": {
"type": "plain_text_input",
"placeholder": {
"type": "plain_text",
"text": "Payload of the current alert",
},
"action_id": UpdateAppearanceStep.routing_uid(),
"multiline": True,
alert_receive_channel = alert_group.channel
blocks = [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": f":point_right: Click <{alert_receive_channel.web_link}|here> to open Integrations settings, edit Slack templates and return here",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Maybe use a button with a URL as shown in Slack docs to redirect to the web UI? A button with URL seems to be more appropriate for this use case

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the next version we’ll have 3 urls to 3 templates

},
"optional": True,
"hint": {"type": "plain_text", "text": "This is example payload of the first alert of the group"},
}
block["element"]["initial_value"] = chunk
blocks.append(block)
blocks.append({"type": "divider"})

for notification_channel in ["slack", "web", "sms", "phone_call", "telegram"]:
blocks.append(
{
"type": "header",
"text": {
"type": "plain_text",
"text": f"{notification_channel.replace('_', ' ').title()} Templates",
"emoji": True,
},
}
)
for templatizable_attr in ["title", "message", "image_url"]:
try:
attr = getattr(alert_group.channel, f"{notification_channel}_{templatizable_attr}_template")
except AttributeError:
continue
block = {
"type": "input",
"block_id": f"{notification_channel}_{templatizable_attr}_template",
"label": {
"type": "plain_text",
"text": f"{notification_channel.capitalize()} {templatizable_attr}:",
},
"element": {
"type": "plain_text_input",
"placeholder": {"type": "plain_text", "text": f"{{{{ payload.{templatizable_attr} }}}}"},
"action_id": UpdateAppearanceStep.routing_uid(),
"multiline": True,
},
"optional": True,
"hint": {
"type": "plain_text",
"text": "Jinja2 template",
},
}
if attr is not None:
block["element"]["initial_value"] = attr
else:
default_values = getattr(
AlertReceiveChannel,
f"INTEGRATION_TO_DEFAULT_{notification_channel.upper()}_{templatizable_attr.upper()}_TEMPLATE",
None,
)
if default_values is not None:
default_value = default_values.get(integration)
if default_value is not None:
block["element"]["initial_value"] = default_value
blocks.append(block)
blocks.append({"type": "divider"})

common_templates_meta_data = {
"source_link": {"placeholder": "{{ payload.link_to_upstream_details }}", "hint": "Jinja2 template."},
"grouping_id": {"placeholder": "{{ payload.uid }}", "hint": "Jinja2 template"},
"resolve_condition": {
"placeholder": '{{ 1 if payload.state == "OK" else 0 }}',
"hint": "This Jinja2 template should output one of the following values: ok, true, 1 (case insensitive)",
},
"acknowledge_condition": {
"placeholder": '{{ 1 if payload.state == "OK" else 0 }}',
"hint": "This Jinja2 template should output one of the following values: ok, true, 1 (case insensitive)",
},
}

for common_template in common_templates_meta_data.keys():
try:
attr = getattr(alert_group.channel, f"{common_template}_template")
except AttributeError:
continue

block = {
"type": "input",
"block_id": f"{common_template}_template",
"label": {
"type": "plain_text",
"text": f"{common_template.capitalize().replace('_', ' ')}:",
},
"element": {
"type": "plain_text_input",
"placeholder": {
"type": "plain_text",
"text": common_templates_meta_data[common_template]["placeholder"],
},
"action_id": UpdateAppearanceStep.routing_uid(),
"multiline": True,
},
"optional": True,
"hint": {
"type": "plain_text",
"text": common_templates_meta_data[common_template]["hint"],
},
}
if attr is not None:
block["element"]["initial_value"] = attr
else:
default_values = getattr(
AlertReceiveChannel, f"INTEGRATION_TO_DEFAULT_{common_template.upper()}_TEMPLATE", None
)
if default_values is not None:
default_value = default_values.get(integration)
if default_value:
block["element"]["initial_value"] = default_value
blocks.append(block)
{"type": "section", "text": {"type": "mrkdwn", "text": "Once changed Refresh the alert group"}},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need refresh alert group? We don't have this for msteams and telegram

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to silently remove the button, so keeping this for transition period and then decide

]

view = {
"callback_id": UpdateAppearanceStep.routing_uid(),
Expand All @@ -198,7 +61,7 @@ def process_scenario(self, slack_user_identity, slack_team_identity, payload):
},
"submit": {
"type": "plain_text",
"text": "Submit",
"text": "Refresh alert group",
},
"private_metadata": json.dumps(private_metadata),
}
Expand All @@ -213,101 +76,11 @@ def process_scenario(self, slack_user_identity, slack_team_identity, payload):
class UpdateAppearanceStep(scenario_step.ScenarioStep):
def process_scenario(self, slack_user_identity, slack_team_identity, payload):
AlertGroup = apps.get_model("alerts", "AlertGroup")
AlertReceiveChannel = apps.get_model("alerts", "AlertReceiveChannel")

private_metadata = json.loads(payload["view"]["private_metadata"])
alert_group_pk = private_metadata["alert_group_pk"]
payload_values = payload["view"]["state"]["values"]

with transaction.atomic():
alert_group = AlertGroup.all_objects.filter(pk=alert_group_pk).select_for_update().get()
integration = alert_group.channel.integration
alert_receive_channel = alert_group.channel
prev_state = alert_receive_channel.insight_logs_serialized

for templatizable_attr in ["title", "message", "image_url"]:
for notification_channel in ["slack", "web", "sms", "phone_call", "telegram"]:
attr_name = f"{notification_channel}_{templatizable_attr}_template"
try:
old_value = getattr(alert_receive_channel, attr_name)
except AttributeError:
continue
new_value = payload_values[attr_name][self.routing_uid()].get("value")

if new_value is None and old_value is not None:
setattr(alert_receive_channel, attr_name, None)
alert_receive_channel.save()
elif new_value is not None:
default_values = getattr(
AlertReceiveChannel,
f"INTEGRATION_TO_DEFAULT_{notification_channel.upper()}_{templatizable_attr.upper()}_TEMPLATE",
None,
)
if default_values is not None:
default_value = default_values.get(integration)

try:
if default_value is None or new_value.strip() != default_value.strip():
jinja_template_env.from_string(new_value)
setattr(alert_receive_channel, attr_name, new_value)
alert_receive_channel.save()
elif default_value is not None and new_value.strip() == default_value.strip():
new_value = None
setattr(alert_receive_channel, attr_name, new_value)
alert_receive_channel.save()
except TemplateSyntaxError:
return Response(
{"response_action": "errors", "errors": {attr_name: "Template has incorrect format"}},
headers={"content-type": "application/json"},
)

common_templates = ["source_link", "grouping_id", "resolve_condition", "acknowledge_condition"]
for common_template in common_templates:
attr_name = f"{common_template}_template"
try:
old_value = getattr(alert_receive_channel, attr_name)
except AttributeError:
continue
new_value = payload_values[attr_name][self.routing_uid()].get("value")

if new_value is None and old_value is not None:
setattr(alert_receive_channel, attr_name, None)
alert_receive_channel.save()
alert_group.save()
elif new_value is not None:
default_values = getattr(
AlertReceiveChannel, f"INTEGRATION_TO_DEFAULT_{common_template.upper()}_TEMPLATE", None
)
if default_values is not None:
default_value = default_values.get(integration)

try:
if default_value is None or new_value.strip() != default_value.strip():
jinja_template_env.from_string(new_value)
setattr(alert_receive_channel, attr_name, new_value)
alert_receive_channel.save()
alert_group.save()
elif default_value is not None and new_value.strip() == default_value.strip():
new_value = None
setattr(alert_receive_channel, attr_name, new_value)
alert_receive_channel.save()
alert_group.save()
except TemplateSyntaxError:
return Response(
{"response_action": "errors", "errors": {common_template: "Template has incorrect format"}},
headers={"content-type": "application/json"},
)

new_state = alert_receive_channel.insight_logs_serialized

if new_state != prev_state:
write_resource_insight_log(
instance=alert_receive_channel,
author=slack_user_identity.get_user(alert_receive_channel.organization),
event=EntityEvent.UPDATED,
prev_state=prev_state,
new_state=new_state,
)
alert_group = AlertGroup.all_objects.get(pk=alert_group_pk)

attachments = alert_group.render_slack_attachments()
blocks = alert_group.render_slack_blocks()
Expand Down