diff --git a/CHANGELOG.md b/CHANGELOG.md index 25277a46..84d48d35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ## Improvements - Django 3.1 - Handle status callbacks from Twilio, show delivery failures in Integrations +- Removing unused /api/v1/notifications/{uuid}/bounce endpoint ## Bug Fixes - Handle excessively long email addresses in the signup form. diff --git a/hc/api/models.py b/hc/api/models.py index a6d496e1..11bafe69 100644 --- a/hc/api/models.py +++ b/hc/api/models.py @@ -484,7 +484,6 @@ class Channel(models.Model): # These are not database fields. It is just a convenient way to pass # status_url to transport classes. - check.bounce_url = n.bounce_url() check.status_url = n.status_url() error = self.transport.notify(check) or "" @@ -760,9 +759,6 @@ class Notification(models.Model): created = models.DateTimeField(auto_now_add=True) error = models.CharField(max_length=200, blank=True) - def bounce_url(self): - return settings.SITE_ROOT + reverse("hc-api-bounce", args=[self.code]) - def status_url(self): path = reverse("hc-api-notification-status", args=[self.code]) return settings.SITE_ROOT + path diff --git a/hc/api/tests/test_bounce.py b/hc/api/tests/test_bounce.py deleted file mode 100644 index e123f5ec..00000000 --- a/hc/api/tests/test_bounce.py +++ /dev/null @@ -1,67 +0,0 @@ -from datetime import timedelta - -from hc.api.models import Channel, Check, Notification -from hc.test import BaseTestCase - - -class BounceTestCase(BaseTestCase): - def setUp(self): - super(BounceTestCase, self).setUp() - - self.check = Check(project=self.project, status="up") - self.check.save() - - self.channel = Channel(project=self.project, kind="email") - self.channel.value = "alice@example.org" - self.channel.email_verified = True - self.channel.save() - - self.n = Notification(owner=self.check, channel=self.channel) - self.n.save() - - def test_it_works(self): - url = "/api/v1/notifications/%s/bounce" % self.n.code - r = self.client.post(url, "foo", content_type="text/plain") - self.assertEqual(r.status_code, 200) - - self.n.refresh_from_db() - self.assertEqual(self.n.error, "foo") - - self.channel.refresh_from_db() - self.assertFalse(self.channel.email_verified) - self.assertEqual(self.channel.last_error, "foo") - - def test_it_checks_ttl(self): - self.n.created = self.n.created - timedelta(minutes=60) - self.n.save() - - url = "/api/v1/notifications/%s/bounce" % self.n.code - r = self.client.post(url, "foo", content_type="text/plain") - self.assertEqual(r.status_code, 403) - - def test_it_handles_long_payload(self): - url = "/api/v1/notifications/%s/bounce" % self.n.code - payload = "A" * 500 - r = self.client.post(url, payload, content_type="text/plain") - self.assertEqual(r.status_code, 200) - - def test_it_handles_missing_notification(self): - fake_code = "07c2f548-9850-4b27-af5d-6c9dc157ec02" - url = "/api/v1/notifications/%s/bounce" % fake_code - r = self.client.post(url, "", content_type="text/plain") - self.assertEqual(r.status_code, 404) - - def test_it_requires_post(self): - url = "/api/v1/notifications/%s/bounce" % self.n.code - r = self.client.get(url) - self.assertEqual(r.status_code, 405) - - def test_does_not_unsubscribe_transient_bounces(self): - url = "/api/v1/notifications/%s/bounce?type=Transient" % self.n.code - self.client.post(url, "foo", content_type="text/plain") - - self.n.refresh_from_db() - self.assertEqual(self.n.error, "foo") - - self.channel.refresh_from_db() - self.assertTrue(self.channel.email_verified) diff --git a/hc/api/tests/test_notify.py b/hc/api/tests/test_notify.py index 7899e956..880e79b7 100644 --- a/hc/api/tests/test_notify.py +++ b/hc/api/tests/test_notify.py @@ -314,7 +314,6 @@ class NotifyTestCase(BaseTestCase): email = mail.outbox[0] self.assertEqual(email.to[0], "alice@example.org") - self.assertTrue("X-Bounce-Url" in email.extra_headers) self.assertTrue("X-Status-Url" in email.extra_headers) self.assertTrue("List-Unsubscribe" in email.extra_headers) self.assertTrue("List-Unsubscribe-Post" in email.extra_headers) diff --git a/hc/api/transports.py b/hc/api/transports.py index 368debbf..5a9ce6c4 100644 --- a/hc/api/transports.py +++ b/hc/api/transports.py @@ -62,7 +62,6 @@ class Email(Transport): unsub_link = self.channel.get_unsub_link() headers = { - "X-Bounce-Url": check.bounce_url, "X-Status-Url": check.status_url, "List-Unsubscribe": "<%s>" % unsub_link, "List-Unsubscribe-Post": "List-Unsubscribe=One-Click", diff --git a/hc/api/urls.py b/hc/api/urls.py index cb69d104..a2109e03 100644 --- a/hc/api/urls.py +++ b/hc/api/urls.py @@ -36,7 +36,6 @@ urlpatterns = [ path("api/v1/checks/", views.single, name="hc-api-single"), path("api/v1/checks/", views.get_check_by_unique_key), path("api/v1/checks//pause", views.pause, name="hc-api-pause"), - path("api/v1/notifications//bounce", views.bounce, name="hc-api-bounce"), path( "api/v1/notifications//status", views.notification_status, diff --git a/hc/api/views.py b/hc/api/views.py index 9003d717..87924edd 100644 --- a/hc/api/views.py +++ b/hc/api/views.py @@ -391,30 +391,6 @@ def badge(request, badge_key, signature, tag, fmt="svg"): return HttpResponse(svg, content_type="image/svg+xml") -@csrf_exempt -@require_POST -def bounce(request, code): - notification = get_object_or_404(Notification, code=code) - - # If webhook is more than 10 minutes late, don't accept it: - td = timezone.now() - notification.created - if td.total_seconds() > 600: - return HttpResponseForbidden() - - notification.error = request.body.decode()[:200] - notification.save() - - notification.channel.last_error = notification.error - if request.GET.get("type") in (None, "Permanent"): - # For permanent bounces, mark the channel as not verified, so we - # will not try to deliver to it again. - notification.channel.email_verified = False - - notification.channel.save() - - return HttpResponse() - - @csrf_exempt @require_POST def notification_status(request, code): diff --git a/hc/front/tests/test_send_test_notification.py b/hc/front/tests/test_send_test_notification.py index 7918e323..3e795939 100644 --- a/hc/front/tests/test_send_test_notification.py +++ b/hc/front/tests/test_send_test_notification.py @@ -28,7 +28,7 @@ class SendTestNotificationTestCase(BaseTestCase): email = mail.outbox[0] self.assertEqual(email.to[0], "alice@example.org") - self.assertTrue("X-Bounce-Url" in email.extra_headers) + self.assertTrue("X-Status-Url" in email.extra_headers) self.assertTrue("List-Unsubscribe" in email.extra_headers) # It should create a notification