From b75ab00d182bc20064b5f9575f48bb78f4db759a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C4=93teris=20Caune?= Date: Sat, 1 Aug 2015 15:55:43 +0300 Subject: [PATCH] Webhook for Mandrill inbound email notifications --- hc/api/migrations/0009_auto_20150801_1250.py | 29 ++++++++++++++++++ hc/api/models.py | 5 ++-- hc/api/tests/test_email_webhook.py | 31 ++++++++++++++++++++ hc/api/tests/test_ping.py | 3 ++ hc/api/urls.py | 1 + hc/api/views.py | 29 ++++++++++++++++++ 6 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 hc/api/migrations/0009_auto_20150801_1250.py create mode 100644 hc/api/tests/test_email_webhook.py diff --git a/hc/api/migrations/0009_auto_20150801_1250.py b/hc/api/migrations/0009_auto_20150801_1250.py new file mode 100644 index 00000000..e2c0f33f --- /dev/null +++ b/hc/api/migrations/0009_auto_20150801_1250.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0008_auto_20150801_1213'), + ] + + operations = [ + migrations.AddField( + model_name='ping', + name='scheme', + field=models.CharField(max_length=10, default='http'), + ), + migrations.AlterField( + model_name='ping', + name='method', + field=models.CharField(blank=True, max_length=10), + ), + migrations.AlterField( + model_name='ping', + name='remote_addr', + field=models.GenericIPAddressField(blank=True, null=True), + ), + ] diff --git a/hc/api/models.py b/hc/api/models.py index 9ffd3e2a..14687297 100644 --- a/hc/api/models.py +++ b/hc/api/models.py @@ -63,7 +63,8 @@ class Check(models.Model): class Ping(models.Model): owner = models.ForeignKey(Check) created = models.DateTimeField(auto_now_add=True) - remote_addr = models.GenericIPAddressField() - method = models.CharField(max_length=10) + scheme = models.CharField(max_length=10, default="http") + remote_addr = models.GenericIPAddressField(blank=True, null=True) + method = models.CharField(max_length=10, blank=True) ua = models.CharField(max_length=200, blank=True) body = models.TextField(blank=True) diff --git a/hc/api/tests/test_email_webhook.py b/hc/api/tests/test_email_webhook.py new file mode 100644 index 00000000..431d17c8 --- /dev/null +++ b/hc/api/tests/test_email_webhook.py @@ -0,0 +1,31 @@ +import json + +from django.test import TestCase + +from hc.api.models import Check, Ping + + +class EmailTestCase(TestCase): + + def test_it_works(self): + check = Check() + check.save() + + payload = [{ + "event": "inbound", + "msg": { + "raw_msg": "This is raw message", + "to": ["somewhere@example.com", "%s@example.com" % check.code] + } + }] + + data = {"mandrill_events": json.dumps(payload)} + r = self.client.post("/handle_email/", data=data) + assert r.status_code == 200 + + same_check = Check.objects.get(code=check.code) + assert same_check.status == "up" + + pings = list(Ping.objects.all()) + assert pings[0].scheme == "email" + assert pings[0].body == "This is raw message" diff --git a/hc/api/tests/test_ping.py b/hc/api/tests/test_ping.py index 0b36b85e..5af5f260 100644 --- a/hc/api/tests/test_ping.py +++ b/hc/api/tests/test_ping.py @@ -15,6 +15,9 @@ class PingTestCase(TestCase): same_check = Check.objects.get(code=check.code) assert same_check.status == "up" + pings = list(Ping.objects.all()) + assert pings[0].scheme == "http" + def test_post_works(self): check = Check() check.save() diff --git a/hc/api/urls.py b/hc/api/urls.py index ee1b829b..ab8c5842 100644 --- a/hc/api/urls.py +++ b/hc/api/urls.py @@ -6,4 +6,5 @@ urlpatterns = [ url(r'^ping/([\w-]+)/$', views.ping, name="hc-ping-slash"), url(r'^ping/([\w-]+)$', views.ping, name="hc-ping"), url(r'^status/([\w-]+)/$', views.status, name="hc-status"), + url(r'^handle_email/$', views.handle_email, name="hc-handle-email"), ] diff --git a/hc/api/views.py b/hc/api/views.py index e775b860..9b6b4aef 100644 --- a/hc/api/views.py +++ b/hc/api/views.py @@ -26,6 +26,7 @@ def ping(request, code): ping = Ping(owner=check) headers = request.META ping.remote_addr = headers.get("HTTP_X_REAL_IP", headers["REMOTE_ADDR"]) + ping.scheme = headers.get("HTTP_X_SCHEME", "http") ping.method = headers["REQUEST_METHOD"] # If User-Agent is longer than 200 characters, truncate it: ping.ua = headers.get("HTTP_USER_AGENT", "")[:200] @@ -37,6 +38,34 @@ def ping(request, code): return response +@csrf_exempt +def handle_email(request): + events = json.loads(request.POST["mandrill_events"]) + for event in events: + for to_address in event["msg"]["to"]: + code, domain = to_address.split("@") + try: + check = Check.objects.get(code=code) + except ValueError: + continue + except Check.DoesNotExist: + continue + + check.last_ping = timezone.now() + if check.status == "new": + check.status = "up" + + check.save() + + ping = Ping(owner=check) + ping.scheme = "email" + ping.body = event["msg"]["raw_msg"] + ping.save() + + response = HttpResponse("OK") + return response + + @uuid_or_400 def status(request, code): response = {