diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c108edf..f9d4fe5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. - Implement email body decoding in the "Ping Details" dialog - Add a "Subject" field in the "Ping Details" dialog - Improve HTML email display in the "Ping Details" dialog +- Add a link to check's details page in Slack notifications ## Bug Fixes - Fix downtime summary to handle months when the check didn't exist yet (#472) diff --git a/hc/accounts/views.py b/hc/accounts/views.py index fc1a9734..3897d03f 100644 --- a/hc/accounts/views.py +++ b/hc/accounts/views.py @@ -41,6 +41,7 @@ POST_LOGIN_ROUTES = ( "hc-add-pushover", "hc-add-telegram", "hc-project-settings", + "hc-uncloak", ) FIDO2_SERVER = Fido2Server(PublicKeyCredentialRpEntity(settings.RP_ID, "healthchecks")) diff --git a/hc/api/models.py b/hc/api/models.py index f28b5843..7feb3210 100644 --- a/hc/api/models.py +++ b/hc/api/models.py @@ -118,6 +118,9 @@ class Check(models.Model): def details_url(self): return settings.SITE_ROOT + reverse("hc-details", args=[self.code]) + def cloaked_url(self): + return settings.SITE_ROOT + reverse("hc-uncloak", args=[self.unique_key]) + def email(self): return "%s@%s" % (self.code, settings.PING_EMAIL_DOMAIN) diff --git a/hc/api/tests/test_notify_slack.py b/hc/api/tests/test_notify_slack.py index 69202d7a..50e3157e 100644 --- a/hc/api/tests/test_notify_slack.py +++ b/hc/api/tests/test_notify_slack.py @@ -39,6 +39,9 @@ class NotifyTestCase(BaseTestCase): fields = {f["title"]: f["value"] for f in attachment["fields"]} self.assertEqual(fields["Last Ping"], "an hour ago") + uncloak_url = "/cloaked/%s/" % self.check.unique_key + self.assertTrue(attachment["title_link"].endswith(uncloak_url)) + @patch("hc.api.transports.requests.request") def test_slack_with_complex_value(self, mock_post): v = json.dumps({"incoming_webhook": {"url": "123"}}) diff --git a/hc/front/tests/test_uncloak.py b/hc/front/tests/test_uncloak.py new file mode 100644 index 00000000..fb572b01 --- /dev/null +++ b/hc/front/tests/test_uncloak.py @@ -0,0 +1,29 @@ +from hc.api.models import Check +from hc.test import BaseTestCase + + +class UncloakTestCase(BaseTestCase): + def setUp(self): + super().setUp() + self.check = Check.objects.create(project=self.project, status="paused") + self.url = "/cloaked/%s/" % self.check.unique_key + self.redirect_url = "/checks/%s/details/" % self.check.code + + def test_it_redirects(self): + self.client.login(username="alice@example.org", password="password") + r = self.client.get(self.url) + self.assertRedirects(r, self.redirect_url) + + def test_it_handles_bad_unique_key(self): + self.client.login(username="alice@example.org", password="password") + r = self.client.get("/cloaked/0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33/") + self.assertEqual(r.status_code, 404) + + def test_it_checks_access(self): + self.client.login(username="charlie@example.org", password="password") + r = self.client.get(self.url) + self.assertEqual(r.status_code, 404) + + def test_it_requires_logged_in_user(self): + r = self.client.get(self.url) + self.assertRedirects(r, "/accounts/login/?next=" + self.url) diff --git a/hc/front/urls.py b/hc/front/urls.py index 8bb0a4e9..32db7814 100644 --- a/hc/front/urls.py +++ b/hc/front/urls.py @@ -92,6 +92,7 @@ urlpatterns = [ path("tv/", views.dashboard, name="hc-dashboard"), path("checks/cron_preview/", views.cron_preview), path("checks//", include(check_urls)), + path("cloaked//", views.uncloak, name="hc-uncloak"), path("integrations/", include(channel_urls)), path("projects//", include(project_urls)), path("docs/", views.serve_doc, name="hc-docs"), diff --git a/hc/front/views.py b/hc/front/views.py index ae0f602e..cce79c4f 100644 --- a/hc/front/views.py +++ b/hc/front/views.py @@ -637,6 +637,15 @@ def details(request, code): return render(request, "front/details.html", ctx) +@login_required +def uncloak(request, unique_key): + for check in request.profile.checks_from_all_projects().only("code"): + if check.unique_key == unique_key: + return redirect("hc-details", check.code) + + raise Http404("not found") + + @login_required def transfer(request, code): check = _get_rw_check_for_user(request, code) diff --git a/templates/integrations/slack_message.json b/templates/integrations/slack_message.json index 618bf6c3..1490a17d 100644 --- a/templates/integrations/slack_message.json +++ b/templates/integrations/slack_message.json @@ -11,7 +11,8 @@ "fallback": "The check \"{{ check.name_then_code|escapejs }}\" is {{ check.status|upper }}.", "mrkdwn_in": ["fields"], - "text": "“{{ check.name_then_code|escapejs }}” is {{ check.status|upper }}.", + "title": "“{{ check.name_then_code|escapejs }}” is {{ check.status|upper }}.", + "title_link": "{{ check.cloaked_url }}", "fields": [ {% if check.desc %} {"title": "Description",