From ee9ac0ffefca6131192baf0b14ed2d497432755f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C4=93teris=20Caune?= <cuu508@gmail.com>
Date: Wed, 29 Jul 2020 18:30:50 +0300
Subject: [PATCH] New integration: phone calls. Fixes #403

---
 CHANGELOG.md                             |   1 +
 hc/api/models.py                         |   5 +-
 hc/api/tests/test_notify.py              |  38 ++++++++++
 hc/api/transports.py                     |  25 +++++++
 hc/front/tests/test_add_call.py          |  59 ++++++++++++++++
 hc/front/urls.py                         |   1 +
 hc/front/views.py                        |  28 ++++++++
 static/css/icomoon.css                   |  14 ++--
 static/fonts/icomoon.eot                 | Bin 12428 -> 12844 bytes
 static/fonts/icomoon.svg                 |   1 +
 static/fonts/icomoon.ttf                 | Bin 12264 -> 12680 bytes
 static/fonts/icomoon.woff                | Bin 12340 -> 12756 bytes
 static/img/integrations/call.png         | Bin 0 -> 3499 bytes
 templates/emails/sms-limit-subject.html  |   2 +-
 templates/front/channels.html            |  16 ++++-
 templates/front/event_summary.html       |   5 ++
 templates/front/welcome.html             |  14 +++-
 templates/integrations/add_call.html     |  84 +++++++++++++++++++++++
 templates/integrations/call_message.html |   1 +
 templates/payments/pricing.html          |  14 ++--
 20 files changed, 292 insertions(+), 16 deletions(-)
 create mode 100644 hc/front/tests/test_add_call.py
 create mode 100644 static/img/integrations/call.png
 create mode 100644 templates/integrations/add_call.html
 create mode 100644 templates/integrations/call_message.html

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8b5f2da3..0d2f1ea9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file.
 - Updated Discord integration to use discord.com instead of discordapp.com
 - Add "Failure Keyword" filtering for inbound emails (#396)
 - Add support for multiple, comma-separated keywords (#396)
+- New integration: phone calls (#403)
 
 ### Bug Fixes
 - Removing Pager Team integration, project appears to be discontinued
diff --git a/hc/api/models.py b/hc/api/models.py
index 8e7b3040..37e0771b 100644
--- a/hc/api/models.py
+++ b/hc/api/models.py
@@ -50,6 +50,7 @@ CHANNEL_KINDS = (
     ("shell", "Shell Command"),
     ("zulip", "Zulip"),
     ("spike", "Spike"),
+    ("call", "Phone Call"),
 )
 
 PO_PRIORITIES = {-2: "lowest", -1: "low", 0: "normal", 1: "high", 2: "emergency"}
@@ -460,6 +461,8 @@ class Channel(models.Model):
             return transports.Zulip(self)
         elif self.kind == "spike":
             return transports.Spike(self)
+        elif self.kind == "call":
+            return transports.Call(self)
         else:
             raise NotImplementedError("Unknown channel kind: %s" % self.kind)
 
@@ -640,7 +643,7 @@ class Channel(models.Model):
 
     @property
     def sms_number(self):
-        assert self.kind in ("sms", "whatsapp")
+        assert self.kind in ("call", "sms", "whatsapp")
         if self.value.startswith("{"):
             doc = json.loads(self.value)
             return doc["value"]
diff --git a/hc/api/tests/test_notify.py b/hc/api/tests/test_notify.py
index b7ec1c8b..a64da31f 100644
--- a/hc/api/tests/test_notify.py
+++ b/hc/api/tests/test_notify.py
@@ -754,6 +754,44 @@ class NotifyTestCase(BaseTestCase):
         self.assertEqual(email.to[0], "alice@example.org")
         self.assertEqual(email.subject, "Monthly WhatsApp Limit Reached")
 
+    @patch("hc.api.transports.requests.request")
+    def test_call(self, mock_post):
+        value = {"label": "foo", "value": "+1234567890"}
+        self._setup_data("call", json.dumps(value))
+        self.check.last_ping = now() - td(hours=2)
+
+        mock_post.return_value.status_code = 200
+
+        self.channel.notify(self.check)
+        assert Notification.objects.count() == 1
+
+        args, kwargs = mock_post.call_args
+        payload = kwargs["data"]
+        self.assertEqual(payload["To"], "+1234567890")
+
+    @patch("hc.api.transports.requests.request")
+    def test_call_limit(self, mock_post):
+        # At limit already:
+        self.profile.last_sms_date = now()
+        self.profile.sms_sent = 50
+        self.profile.save()
+
+        definition = {"value": "+1234567890"}
+        self._setup_data("call", json.dumps(definition))
+
+        self.channel.notify(self.check)
+        self.assertFalse(mock_post.called)
+
+        n = Notification.objects.get()
+        self.assertTrue("Monthly phone call limit exceeded" in n.error)
+
+        # And email should have been sent
+        self.assertEqual(len(mail.outbox), 1)
+
+        email = mail.outbox[0]
+        self.assertEqual(email.to[0], "alice@example.org")
+        self.assertEqual(email.subject, "Monthly Phone Call Limit Reached")
+
     @patch("apprise.Apprise")
     @override_settings(APPRISE_ENABLED=True)
     def test_apprise_enabled(self, mock_apprise):
diff --git a/hc/api/transports.py b/hc/api/transports.py
index 1333a350..3ed517e5 100644
--- a/hc/api/transports.py
+++ b/hc/api/transports.py
@@ -478,6 +478,31 @@ class Sms(HttpTransport):
         return self.post(url, data=data, auth=auth)
 
 
+class Call(HttpTransport):
+    URL = "https://api.twilio.com/2010-04-01/Accounts/%s/Calls.json"
+
+    def is_noop(self, check):
+        return check.status != "down"
+
+    def notify(self, check):
+        profile = Profile.objects.for_user(self.channel.project.owner)
+        if not profile.authorize_sms():
+            profile.send_sms_limit_notice("phone call")
+            return "Monthly phone call limit exceeded"
+
+        url = self.URL % settings.TWILIO_ACCOUNT
+        auth = (settings.TWILIO_ACCOUNT, settings.TWILIO_AUTH)
+        twiml = tmpl("call_message.html", check=check, site_name=settings.SITE_NAME)
+
+        data = {
+            "From": settings.TWILIO_FROM,
+            "To": self.channel.sms_number,
+            "Twiml": twiml,
+        }
+
+        return self.post(url, data=data, auth=auth)
+
+
 class WhatsApp(HttpTransport):
     URL = "https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json"
 
diff --git a/hc/front/tests/test_add_call.py b/hc/front/tests/test_add_call.py
new file mode 100644
index 00000000..ecf14ce9
--- /dev/null
+++ b/hc/front/tests/test_add_call.py
@@ -0,0 +1,59 @@
+from django.test.utils import override_settings
+from hc.api.models import Channel
+from hc.test import BaseTestCase
+
+
+@override_settings(TWILIO_ACCOUNT="foo", TWILIO_AUTH="foo", TWILIO_FROM="123")
+class AddCallTestCase(BaseTestCase):
+    def setUp(self):
+        super(AddCallTestCase, self).setUp()
+        self.url = "/projects/%s/add_call/" % self.project.code
+
+    def test_instructions_work(self):
+        self.client.login(username="alice@example.org", password="password")
+        r = self.client.get(self.url)
+        self.assertContains(r, "Get a phone call")
+
+    @override_settings(USE_PAYMENTS=True)
+    def test_it_warns_about_limits(self):
+        self.profile.sms_limit = 0
+        self.profile.save()
+
+        self.client.login(username="alice@example.org", password="password")
+        r = self.client.get(self.url)
+        self.assertContains(r, "upgrade to a")
+
+    def test_it_creates_channel(self):
+        form = {"label": "My Phone", "value": "+1234567890"}
+
+        self.client.login(username="alice@example.org", password="password")
+        r = self.client.post(self.url, form)
+        self.assertRedirects(r, self.channels_url)
+
+        c = Channel.objects.get()
+        self.assertEqual(c.kind, "call")
+        self.assertEqual(c.sms_number, "+1234567890")
+        self.assertEqual(c.name, "My Phone")
+        self.assertEqual(c.project, self.project)
+
+    def test_it_rejects_bad_number(self):
+        form = {"value": "not a phone number"}
+
+        self.client.login(username="alice@example.org", password="password")
+        r = self.client.post(self.url, form)
+        self.assertContains(r, "Invalid phone number format.")
+
+    def test_it_trims_whitespace(self):
+        form = {"value": "   +1234567890   "}
+
+        self.client.login(username="alice@example.org", password="password")
+        self.client.post(self.url, form)
+
+        c = Channel.objects.get()
+        self.assertEqual(c.sms_number, "+1234567890")
+
+    @override_settings(TWILIO_AUTH=None)
+    def test_it_requires_credentials(self):
+        self.client.login(username="alice@example.org", password="password")
+        r = self.client.get(self.url)
+        self.assertEqual(r.status_code, 404)
diff --git a/hc/front/urls.py b/hc/front/urls.py
index 016918cb..bce15731 100644
--- a/hc/front/urls.py
+++ b/hc/front/urls.py
@@ -55,6 +55,7 @@ channel_urls = [
 
 project_urls = [
     path("add_apprise/", views.add_apprise, name="hc-add-apprise"),
+    path("add_call/", views.add_call, name="hc-add-call"),
     path("add_discord/", views.add_discord, name="hc-add-discord"),
     path("add_email/", views.add_email, name="hc-add-email"),
     path("add_matrix/", views.add_matrix, name="hc-add-matrix"),
diff --git a/hc/front/views.py b/hc/front/views.py
index 2df1777a..e892781c 100644
--- a/hc/front/views.py
+++ b/hc/front/views.py
@@ -269,6 +269,7 @@ def index(request):
         "enable_shell": settings.SHELL_ENABLED is True,
         "enable_slack_btn": settings.SLACK_CLIENT_ID is not None,
         "enable_sms": settings.TWILIO_AUTH is not None,
+        "enable_call": settings.TWILIO_AUTH is not None,
         "enable_telegram": settings.TELEGRAM_TOKEN is not None,
         "enable_trello": settings.TRELLO_APP_KEY is not None,
         "enable_whatsapp": settings.TWILIO_USE_WHATSAPP,
@@ -702,6 +703,7 @@ def channels(request, code):
         "enable_shell": settings.SHELL_ENABLED is True,
         "enable_slack_btn": settings.SLACK_CLIENT_ID is not None,
         "enable_sms": settings.TWILIO_AUTH is not None,
+        "enable_call": settings.TWILIO_AUTH is not None,
         "enable_telegram": settings.TELEGRAM_TOKEN is not None,
         "enable_trello": settings.TRELLO_APP_KEY is not None,
         "enable_whatsapp": settings.TWILIO_USE_WHATSAPP,
@@ -1515,6 +1517,32 @@ def add_sms(request, code):
     return render(request, "integrations/add_sms.html", ctx)
 
 
+@require_setting("TWILIO_AUTH")
+@login_required
+def add_call(request, code):
+    project = _get_project_for_user(request, code)
+    if request.method == "POST":
+        form = forms.AddSmsForm(request.POST)
+        if form.is_valid():
+            channel = Channel(project=project, kind="call")
+            channel.name = form.cleaned_data["label"]
+            channel.value = json.dumps({"value": form.cleaned_data["value"]})
+            channel.save()
+
+            channel.assign_all_checks()
+            return redirect("hc-p-channels", project.code)
+    else:
+        form = forms.AddSmsForm()
+
+    ctx = {
+        "page": "channels",
+        "project": project,
+        "form": form,
+        "profile": project.owner_profile,
+    }
+    return render(request, "integrations/add_call.html", ctx)
+
+
 @require_setting("TWILIO_USE_WHATSAPP")
 @login_required
 def add_whatsapp(request, code):
diff --git a/static/css/icomoon.css b/static/css/icomoon.css
index 0cb69798..d0897aa5 100644
--- a/static/css/icomoon.css
+++ b/static/css/icomoon.css
@@ -1,10 +1,10 @@
 @font-face {
   font-family: 'icomoon';
-  src:  url('../fonts/icomoon.eot?37tb6f');
-  src:  url('../fonts/icomoon.eot?37tb6f#iefix') format('embedded-opentype'),
-    url('../fonts/icomoon.ttf?37tb6f') format('truetype'),
-    url('../fonts/icomoon.woff?37tb6f') format('woff'),
-    url('../fonts/icomoon.svg?37tb6f#icomoon') format('svg');
+  src:  url('../fonts/icomoon.eot?e4bee3');
+  src:  url('../fonts/icomoon.eot?e4bee3#iefix') format('embedded-opentype'),
+    url('../fonts/icomoon.ttf?e4bee3') format('truetype'),
+    url('../fonts/icomoon.woff?e4bee3') format('woff'),
+    url('../fonts/icomoon.svg?e4bee3#icomoon') format('svg');
   font-weight: normal;
   font-style: normal;
 }
@@ -24,6 +24,10 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.icon-call:before {
+  content: "\e91a";
+  color: #e81a34;
+}
 .icon-spike:before {
   content: "\e919";
   color: #007bff;
diff --git a/static/fonts/icomoon.eot b/static/fonts/icomoon.eot
index 93b4cadcafd5e64aef7b44546d088d70213f1779..8eec81efefe9be3fdbab20f89d90fd1688716466 100644
GIT binary patch
delta 620
zcmZuu&1(}u6n}4bv%A^P#3Z|E5@SefLfbUSY}#F0)0$dA6hZ32da1f3g@B0(SZV1c
z2TSY0OW0l%@f5*>h)}#}4nfd^_#b%j5AdLeo;>KR)tkecH~il3V_@cy`?A3oEP#ik
z&)eME3fb@1w)8UqFr@o-z3p~)p7%edd+*j?eFMM|Kw;3_a2sPsAG!d=236TjIuK=U
zf#RnWPc++`+t2c%PBGQPi&m%Z4&T1s11L2qzTS4XyReAgDfaoyUAMjQ_;T<k#b4<i
zd)>~xO<*Yl#MftlWxYDqFyRew9TSHP)0ysZ0KY~Yup>AH7oY<N)R`4D6!;j4nrSqR
z3bC9ebnH1Yn=fKMH*S_KVj1&DNm@}O7UjpYxjdodpPHMs9U@qU&uU1HWo6s3Y&!9y
zwZB3tpQO<hKX3v61*Y*offeFCi6w5zh)nrXGL;XZ669q@&l<*JL6j76XiRW|CgHMr
zHWa>+EQ#`tESVgaQ1u7%sr!}6Qa}on_+0D_jmTIhB1s8R6$P1*VybpJ<!5-Sg+%WM
z3hB66n?#NYDgvLgqmeNI6;V_$!Up13%i*eVPE|=@l|e;mY5GZ#XCuL?Wo;#$J0`=P
z4@ASE=_KR(MLwQY<Pb;wLB;<G^c%oFSy{WKSC2rZ?@!m4i?!Y3ld0``2Qv;%d7ozn
TUaNRRGOkg^_e~vsD!#|xDGO~C

delta 248
zcmZ3J(v!&6W5B@hLVqHg8Oz$^Ja!Wu%K6P17#Q{daYAx#VnNlCiO1yXtI86>7#J82
zFfeHIWTYmhNFI*xV_?uZ15{;}0TkfiX0c>o&}9MgRWfo*DrTv3@B{f8K>m`P{N%)C
z85`Pwe31H(+{B6k1{=l?3=Db-K)ym=Vs7e8FV5dUz5~#Xwu1cP5(Z|V41@j&kURr3
z^W<bk2S&-sOBiDrB{wrM<!dW5g5(((?0Al^jpw)d%D@e>nt|cA9_MEmJy}QJoKbUf
WivE(xJO&|b3?MC<o3jiKF#-TfsXV&?

diff --git a/static/fonts/icomoon.svg b/static/fonts/icomoon.svg
index 56733477..a796fb5d 100644
--- a/static/fonts/icomoon.svg
+++ b/static/fonts/icomoon.svg
@@ -44,4 +44,5 @@
 <glyph unicode="&#xe917;" glyph-name="shell" d="M109.229 960c-60.512 0-109.229-48.717-109.229-109.229v-805.546c0-60.512 48.717-109.223 109.229-109.223h805.546c60.512 0 109.223 48.712 109.223 109.223v805.546c0 60.512-48.712 109.229-109.223 109.229h-805.546zM293.258 784.868h56.588v-76.746c21.22-2.829 40.317-8.607 57.293-17.33s31.36-20.161 43.149-34.308c12.025-13.911 21.217-30.412 27.583-49.51 6.602-18.862 9.905-40.082 9.905-63.66h-98.32c0 28.529-6.485 50.1-19.452 64.718-12.968 14.854-30.533 22.28-52.696 22.28-12.025 0-22.515-1.649-31.474-4.95-8.724-3.065-15.916-7.544-21.575-13.439-5.659-5.659-9.904-12.377-12.733-20.158-2.594-7.781-3.892-16.271-3.892-25.466s1.298-17.446 3.892-24.755c2.829-7.073 7.425-13.675 13.791-19.805 6.602-6.13 15.209-12.024 25.819-17.683 10.61-5.423 23.813-10.966 39.61-16.625 23.813-8.96 45.39-18.269 64.724-27.936 19.334-9.431 35.835-20.517 49.51-33.249 13.911-12.496 24.524-27.115 31.833-43.855 7.545-16.504 11.316-36.070 11.316-58.704 0-20.748-3.421-39.495-10.258-56.235-6.838-16.504-16.62-30.766-29.352-42.791s-28.058-21.696-45.977-29.005c-17.919-7.073-37.964-11.669-60.127-13.791v-69.315h-56.229v69.315c-20.041 1.886-39.495 6.248-58.357 13.086-18.862 7.073-35.603 17.213-50.221 30.416-14.382 13.204-25.931 29.827-34.655 49.868-8.724 20.277-13.086 44.561-13.086 72.854h98.673c0-16.976 2.474-31.243 7.425-42.796 4.951-11.317 11.319-20.393 19.1-27.23 8.016-6.602 17.092-11.315 27.23-14.144s20.512-4.244 31.122-4.244c25.228 0 44.326 5.894 57.293 17.683s19.452 26.992 19.452 45.619c0 9.903-1.532 18.627-4.597 26.172-2.829 7.781-7.542 14.856-14.144 21.222-6.366 6.366-14.856 12.143-25.466 17.33-10.374 5.423-22.987 10.726-37.841 15.914-23.813 8.488-45.507 17.446-65.076 26.877s-36.31 20.395-50.221 32.891c-13.675 12.496-24.282 26.998-31.827 43.502-7.545 16.74-11.316 36.545-11.316 59.415 0 20.041 3.415 38.314 10.253 54.818 6.838 16.74 16.509 31.241 29.005 43.502s27.583 22.16 45.266 29.705c17.683 7.545 37.371 12.38 59.063 14.502v76.040zM571.594 187.88h322.544v-76.746h-322.544v76.746z" />
 <glyph unicode="&#xe918;" glyph-name="zulip" d="M512.002 960c-0.001 0-0.001 0-0.001 0-282.77 0-512.001-229.23-512.001-512.001 0-0.001 0-0.001 0-0.002v0.001c0.002-282.769 229.231-511.998 512.001-511.998 0.001 0 0.001 0 0.002 0h-0.001c0.001 0 0.001 0 0.001 0 282.769 0 512 229.229 512.001 511.999v0c0 0.001 0 0.001 0 0.001 0 282.77-229.23 512.001-512.001 512.001-0.001 0-0.001 0-0.002 0h0.001zM284.075 714.286h394.776l58.098-119.923-268.809-280.809h209.963l63.314-131.839h-397.006l-61.825 131.839 276.205 279.32h-219.596z" />
 <glyph unicode="&#xe919;" glyph-name="spike" d="M109.229 960c-60.512 0-109.229-48.717-109.229-109.229v-805.546c0-60.512 48.717-109.223 109.229-109.223h805.546c60.512 0 109.223 48.712 109.223 109.223v805.546c0 60.512-48.712 109.229-109.223 109.229h-805.546zM519.994 785.921c26.731 0 48.899-9.736 66.504-29.225 18.255-19.486 27.384-43.496 27.384-72.027s-9.132-52.538-27.384-72.022c-17.605-19.486-39.773-29.231-66.504-29.231-27.386 0-50.206 9.74-68.461 29.231-17.605 19.484-26.403 43.49-26.403 72.022s8.804 52.541 26.403 72.027c18.255 19.484 41.075 29.225 68.461 29.225zM520.32 507.623c6.096-0.139 12.331-0.933 18.708-2.381l0.011 0.006c28.061-6.363 48.535-22.392 61.416-48.083 13.515-25.828 16.278-58.825 8.279-98.987-15.724-78.957-55.879-141.702-120.468-188.229-11.595-8.035-23.78-10.623-36.535-7.728s-22.963 10.188-30.631 21.894c-7.802 11.022-10.558 22.314-8.252 33.889 2.167 10.883 8.281 19.813 18.328 26.784 27.336 20.121 48.064 43.881 62.183 71.267-23.827 7.539-41.767 21.209-53.821 41.021-11.92 20.489-15.293 43.669-10.153 69.536 5.558 27.906 18.846 49.43 39.858 64.586 15.763 11.367 32.786 16.844 51.076 16.426z" />
+<glyph unicode="&#xe91a;" glyph-name="call" d="M511.999 960c-282.768-0.001-511.998-229.229-511.999-511.998v-0.001c0.001-282.768 229.229-511.998 511.998-511.999h0.001c282.768 0.001 511.998 229.229 511.999 511.998v0.001c-0.001 282.768-229.229 511.998-511.998 511.999h-0.001zM523.135 718.551c0.212 0.008 0.461 0.012 0.71 0.012 1.228 0 2.431-0.105 3.601-0.307l-0.125 0.018c63.598-9.762 111.38-29.198 148.064-60.881s61.269-74.421 82.321-127.903c0.921-2.278 1.455-4.919 1.455-7.686 0-11.609-9.411-21.019-21.019-21.019-8.842 0-16.409 5.46-19.514 13.192l-0.050 0.141c-19.763 50.209-41.118 85.954-70.69 111.495s-68.379 42.13-126.95 51.12c-10.294 1.472-18.121 10.229-18.121 20.815 0 11.361 9.015 20.616 20.281 21.002l0.035 0.001zM335.388 700.417c28.506 0 56.475-2.279 61.81-8.072 8.866-33.089 17.681-87.508 30.79-150.924-1.22-23.476-66.153-77.434-66.153-77.434 17.073-28.659 66.462-80.495 88.414-97.873s83.536-60.363 120.121-67.070c0 0 44.507 80.799 54.873 83.238 14.634 0 129.576 4.573 143.6-11.281s34.151-114.946 28.969-134.153c-5.183-19.207-24.828-41.032-43.121-51.398-19.512-9.147-126.82-15.236-202.43 9.459-37.805 12.347-128.683 52.31-196.289 119.12s-111.52 160.031-117.925 196.301c-12.811 72.538-31.148 153.47 32.323 184.453 7.47 3.354 36.513 5.634 65.019 5.634zM516.113 634.010c0.212 0.008 0.461 0.012 0.71 0.012 1.228 0 2.431-0.105 3.601-0.307l-0.125 0.018c42.287-6.491 74.931-19.61 100.057-41.311s41.701-50.751 55.633-86.146c1.134-2.501 1.795-5.423 1.795-8.499 0-11.606-9.409-21.015-21.015-21.015-9.145 0-16.925 5.841-19.814 13.996l-0.045 0.147c-12.644 32.122-26 54.166-44.014 69.725s-41.719 25.843-78.979 31.563c-10.294 1.472-18.121 10.229-18.121 20.815 0 11.361 9.015 20.616 20.281 21.002l0.035 0.001z" />
 </font></defs></svg>
\ No newline at end of file
diff --git a/static/fonts/icomoon.ttf b/static/fonts/icomoon.ttf
index 65a8141f6010609d61b19ec174260dae28e37c24..f1890ce83af31281fc62a2fc426843312aad1141 100644
GIT binary patch
delta 675
zcmZuv&ubG=5T4m=b~n45-<wUE#8}dr)Fw@`n>K4|TB8+;A`}(WOHxBx8){+#ty+7D
zV5ve+8ZSZ-gckIm6pBzZhg<~z2QMByh}1(*9(2|!cyO4<yl=j5zW3n0FSC!TZ9o8!
z;67L&GjlnuJ3ZV9>U3#cuQn>J)$Kd405D8=bD^@-qUs{NM^#v;-@Ea?^yVw!9zb%d
zHeZ?RJNQ7F)Ex1-8Z`uo9Vfg=c(B%3UU?oDoP<daFYC=}zS4cSvks81QR7OZveJSH
z+$U@b`fpVl^Uu!Peh~glhpe}nOUrao3a$2dZyJM7u!O<gGBy)!7T{-(1xpW(!dYm-
zQyPf!4&*tXruZZ1SF@UKOrnt+(?;VdjK>E28C}!WJQ7K%s6K@oh{oa?k-u|nG-qhM
zu9~a^wL@7ZXXrWVnAVOzLXx-1I%^t^<6pxF{>Lz@F|b%FZwygvluL{M?j=Mfb1oE)
zyHK`q661`j>O@iyWudDMvb;mY)Ao}t_k~bekX9wp&$2<g^Fcm*JDZ)1T19J`i}~J?
zN5AgzhD1cWz)OtivpbH3O_R>+M6mrG`AEQDJdP}5lX)(dQ@njV%7P%H*J2IKWZVVy
zl-;gbFES|0b%*naz*)Sug09~U88`im<&0HvyAmPBoENx2RF+&U&D&)2S<KHw@lcz(
zI_oSPfJCoC@oBoac37F>T4z6L;BaSXWUKRW<eH*hBF3B>#&6&;Rlsy!pm%pFwT-_3
D0)BWc

delta 281
zcmeB3ei2{Kz{tSBz|GLWz|3IaAFOZ0FT`dJ6xjpB3CX#M1yxJRRx&U!$^iLu(i4jd
zfV2RRzXM2fq~}zoRh1=#0r>|Q7_@mZQWH}o4@dYhFzB2C%9~{X1vt1_EEyPdS%7?%
zjNFonS?V18K)wc$za%F=*)nli#)dYa07yefZem3NgAL;c1_nI^AYUObF*kLl7w2yv
z-vMYzTS0zt3DBWHpnqcG4tGY$NsO_KlAGfg^R<;h{s00yp5trd`E9;3aD%L5V7RTv
r`58t}?$9%5)SP@kZ^`5g{SX1L*EJd6F$jTGGEH8{D7^Wx{!&H&Bh5jM

diff --git a/static/fonts/icomoon.woff b/static/fonts/icomoon.woff
index 68106e2a6452ccde3b8ca2df3a37c058c9ceac66..8a3cfe19483be7e1fda0466bec15cf97b6f01e2a 100644
GIT binary patch
delta 716
zcmZuv&rcIU6rQ);?rwLtzvy;b+FD7$w$Rdcx3Co~71UrfB#j=_OVOqx4YsxkRgg;$
z8Z_ZxuwG1zCrJE}7!vA5IrQQmV8YFRz=JVz;G_w@DHtxk%$J$@-uJ$l$-MTh-IB7D
zpPnW_FtlAFb?2w8Jy4!A?0VeQJYA|5>x4iVGp{ICHXpp5FD@d-u(%hF;FzyGyn~!f
zNPL6hbK%2}@?7yYA&D*27!<wxU+QHfk^7GO0SZB4$II2mG9gK<C2uHRM+AGNRzh7a
z*+$|T#m=X#)oO7W4^B~GUl$Yb>t3-shg=*lxk~Z!vgLQZw%EW2wb%dT!PlCB0{FJy
zK`qwAD<5=NV(O5S<N~RY7g!PEZNPJGP4NW5qoy@IlY@*gs*OYv5DE8tQo5$AV}MB<
zit1Ll{!logVX`|$M~sZd>nhFKKs%JBjErs|L#=H`LX;1pb($KE!#~3y{Kqh@wZ6uD
zO$mTWUGfJa4v;OJ#MncsIuRE{S=dnrSl%YWl=Y0mIpa?X(uyQ{Sk`B?KN<_%Pp5Nc
z(VXPM?vH5Er}w!0B7jxkB}Q~xZKnd%!_<jJ*JcX~3x(OWD8})65BQ+hGua#jma)h@
z7d8}EFAuUH$lx-Wz4??gtDd!5HS-k)WVvFqpAa~c%aYagC4c6whcTTqD^5qu&(L~-
z^M+)}!D79I{@h`=5%NSkfBmLCyH6zi6^w5eCm$cr2k+U|)UXait;X<1OG(^N)T@}K
VojL?RNe@*L20PWY{VcHwe*xiof8ziE

delta 318
zcmcbTyd^=T+~3WOfsp|S3``ifLA3sh$sZX-CNZ&0)Df;XPtHv&U|?X(07}dO;i@HN
zE7KE;fnrQ7Kt2Z)3#8{%rUAux7#Os{xT-86EF(2Bg@Hj=0;t9ege4D0_+<bEfnotb
zz6uC)aI;uu<d#$b#Y%wuB_KRYor6CoKN+abP7kCx1caAmY-r0(tN>c9mjmQ0fUynZ
zhrGnxRG?T7(2;E*JkyKwcR_wJ&@cm$iGTbVB`5nZ#xhE7Ud5QNtqk@k&{&@1YvcKC
zzA|uw{J_9)TaWWIjGlZ&&zw<nGLQa}$y@Y81i)dV$@q>z2&|F`7&gM2^$nIX0s!>W
BMalpG

diff --git a/static/img/integrations/call.png b/static/img/integrations/call.png
new file mode 100644
index 0000000000000000000000000000000000000000..94a30dcdba00447d2336b917ed76df761be0165c
GIT binary patch
literal 3499
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

literal 0
HcmV?d00001

diff --git a/templates/emails/sms-limit-subject.html b/templates/emails/sms-limit-subject.html
index a5c6e634..3a18059b 100644
--- a/templates/emails/sms-limit-subject.html
+++ b/templates/emails/sms-limit-subject.html
@@ -1 +1 @@
-Monthly {{ transport }} Limit Reached
\ No newline at end of file
+Monthly {% if transport == "phone call" %}Phone Call{% else %}{{ transport }}{% endif %} Limit Reached
\ No newline at end of file
diff --git a/templates/front/channels.html b/templates/front/channels.html
index 6c06b408..e8a331bd 100644
--- a/templates/front/channels.html
+++ b/templates/front/channels.html
@@ -68,6 +68,8 @@
                             {% endif %}
                         {% elif ch.kind == "sms" %}
                             SMS to <span>{{ ch.sms_number }}</span>
+                        {% elif ch.kind == "call" %}
+                            Phone call to <span>{{ ch.sms_number }}</span>
                         {% elif ch.kind == "trello" %}
                             Trello
                             board <span>{{ ch.trello_board_list|first }}</span>,
@@ -122,7 +124,7 @@
                 {% else %}
                 Never
                 {% endif %}
-                {% if ch.kind == "sms" or ch.kind == "whatsapp" %}
+                {% if ch.kind == "sms" or ch.kind == "whatsapp" or ch.kind == "call" %}
                     <p>Used {{ profile.sms_sent_this_month }} of {{ profile.sms_limit }} sends this month.</p>
                 {% endif %}
             </td>
@@ -191,6 +193,17 @@
             <a href="{% url 'hc-add-email' project.code %}" class="btn btn-primary">Add Integration</a>
         </li>
 
+        {% if enable_call %}
+        <li>
+            <img src="{% static 'img/integrations/call.png' %}"
+                class="icon" alt="Phone icon" />
+
+            <h2>Phone Call</h2>
+            <p>Get a phone call when a check goes down.</p>
+            <a href="{% url 'hc-add-call' project.code %}" class="btn btn-primary">Add Integration</a>
+        </li>
+        {% endif %}
+
         <li>
             <img src="{% static 'img/integrations/webhook.png' %}"
                 class="icon" alt="Webhook icon" />
@@ -199,6 +212,7 @@
             <p>Receive a HTTP callback when a check goes down.</p>
             <a href="{% url 'hc-add-webhook' project.code %}" class="btn btn-primary">Add Integration</a>
         </li>
+
         {% if enable_apprise %}
         <li>
             <img src="{% static 'img/integrations/apprise.png' %}"
diff --git a/templates/front/event_summary.html b/templates/front/event_summary.html
index f913c32d..e9f8a924 100644
--- a/templates/front/event_summary.html
+++ b/templates/front/event_summary.html
@@ -35,6 +35,11 @@
     {% if event.channel.name %}
         ({{ event.channel.name }})
     {% endif %}
+{% elif event.channel.kind == "call" %}
+    Made a phone call to {{ event.channel.sms_number }}
+    {% if event.channel.name %}
+        ({{ event.channel.name }})
+    {% endif %}
 {% else %}
     Sent alert to {{ event.channel.get_kind_display }}
     {% if event.channel.name %}
diff --git a/templates/front/welcome.html b/templates/front/welcome.html
index a6dc7a87..b85ab88e 100644
--- a/templates/front/welcome.html
+++ b/templates/front/welcome.html
@@ -507,6 +507,18 @@
             </div>
         </div>
 
+        {% if enable_call %}
+        <div class="col-lg-2 col-md-3 col-sm-4 col-xs-6">
+            <div class="integration">
+                <img src="{% static 'img/integrations/call.png' %}" class="icon" alt="" />
+                <h3>
+                    {% trans "Phone Call" %}<br>
+                    <small>&nbsp;</small>
+                </h3>
+            </div>
+        </div>
+        {% endif %}
+
         <div class="col-lg-2 col-md-3 col-sm-4 col-xs-6">
             <a href="{% url 'hc-serve-doc' 'configuring_prometheus' %}" class="integration">
                 <img src="{% static 'img/integrations/prometheus.png' %}" class="icon" alt="" />
@@ -565,7 +577,7 @@
         </div>
         {% endif %}
 
-	<div class="col-md-2 col-sm-4 col-xs-6">
+	   <div class="col-md-2 col-sm-4 col-xs-6">
             <div class="integration">
                 <img src="{% static 'img/integrations/spike.png' %}" class="icon" alt="Spike.sh icon" />
                 <h3>
diff --git a/templates/integrations/add_call.html b/templates/integrations/add_call.html
new file mode 100644
index 00000000..7f2b838f
--- /dev/null
+++ b/templates/integrations/add_call.html
@@ -0,0 +1,84 @@
+{% extends "base.html" %}
+{% load humanize static hc_extras %}
+
+{% block title %}Add Phone Call Integration - {{ site_name }}{% endblock %}
+
+
+{% block content %}
+<div class="row">
+<div class="col-sm-12">
+    <h1>Phone Call</h1>
+    <p>
+        Get a phone call when a check goes down. When you pick up the call,
+        a text-to-speech engine will read out a message and then hang up.
+    </p>
+
+    {% if show_pricing and profile.sms_limit == 0 %}
+    <p class="alert alert-info">
+        <strong>Paid plan required.</strong>
+        Phone call notifications are not available on the free plan–they
+        cost too much! Please upgrade to a
+        <a href="{% url 'hc-billing' %}">paid plan</a>
+        to enable phone call notifications.
+    </p>
+    {% endif %}
+
+    <h2>Integration Settings</h2>
+
+    <form method="post" class="form-horizontal">
+        {% csrf_token %}
+        <div class="form-group {{ form.label.css_classes }}">
+            <label for="id_label" class="col-sm-2 control-label">Label</label>
+            <div class="col-sm-6">
+                <input
+                    id="id_label"
+                    type="text"
+                    class="form-control"
+                    name="label"
+                    placeholder="Alice's Phone"
+                    value="{{ form.label.value|default:"" }}">
+
+                {% if form.label.errors %}
+                <div class="help-block">
+                    {{ form.label.errors|join:"" }}
+                </div>
+                {% else %}
+                <span class="help-block">
+                    Optional. If you add multiple phone numbers,
+                    the labels will help you tell them apart.
+                </span>
+                {% endif %}
+            </div>
+        </div>
+        <div class="form-group {{ form.value.css_classes }}">
+            <label for="id_number" class="col-sm-2 control-label">Phone Number</label>
+            <div class="col-sm-3">
+                <input
+                    id="id_number"
+                    type="tel"
+                    class="form-control"
+                    name="value"
+                    placeholder="+1234567890"
+                    value="{{ form.value.value|default:"" }}">
+
+                {% if form.value.errors %}
+                <div class="help-block">
+                    {{ form.value.errors|join:"" }}
+                </div>
+                {% else %}
+                <span class="help-block">
+                    Make sure the phone number starts with "+" and  has the
+                    country code.
+                </span>
+                {% endif %}
+            </div>
+        </div>
+        <div class="form-group">
+            <div class="col-sm-offset-2 col-sm-10">
+                <button type="submit" class="btn btn-primary">Save Integration</button>
+            </div>
+        </div>
+    </form>
+</div>
+</div>
+{% endblock %}
diff --git a/templates/integrations/call_message.html b/templates/integrations/call_message.html
new file mode 100644
index 00000000..0a0664b4
--- /dev/null
+++ b/templates/integrations/call_message.html
@@ -0,0 +1 @@
+<Response><Say>Hello! A message from {{ site_name }}: The check "{{ check.name_then_code }}" is down.</Say></Response>
\ No newline at end of file
diff --git a/templates/payments/pricing.html b/templates/payments/pricing.html
index 47cba7a6..692405d5 100644
--- a/templates/payments/pricing.html
+++ b/templates/payments/pricing.html
@@ -87,7 +87,7 @@
                         </li>
                         <li class="list-group-item">API access</li>
                         <li class="list-group-item">
-                            <span data-help="sms-help">5 SMS &amp; WhatsApp credits</span>
+                            <span data-help="sms-help">5 SMS, WhatsApp and call credits</span>
                         </li>
                         <li class="list-group-item">&nbsp;</li>
                     </ul>
@@ -120,7 +120,7 @@
                         </li>
                         <li class="list-group-item">API access</li>
                         <li class="list-group-item">
-                            <span data-help="sms-help">5 SMS &amp; WhatsApp credits</span>
+                            <span data-help="sms-help">5 SMS, WhatsApp and call credits</span>
                         </li>
                         <li class="list-group-item">Email support</li>
                     </ul>
@@ -156,7 +156,7 @@
                         </li>
                         <li class="list-group-item">API access</li>
                         <li class="list-group-item">
-                            <span data-help="sms-help">50 SMS &amp; WhatsApp credits</span>
+                            <span data-help="sms-help">50 SMS, WhatsApp and call credits</span>
                         </li>
                         <li class="list-group-item">Email support</li>
                     </ul>
@@ -192,7 +192,7 @@
                         </li>
                         <li class="list-group-item">API access</li>
                         <li class="list-group-item">
-                            <span data-help="sms-help">500 SMS &amp; WhatsApp credits</span>
+                            <span data-help="sms-help">500 SMS, WhatsApp and call credits</span>
                         </li>
                         <li class="list-group-item">Priority email support</li>
                     </ul>
@@ -303,10 +303,10 @@
 </div>
 
 <div id="sms-help" class="hidden">
-    <p>The maximum number of SMS &amp; WhatsApp notifications per month.</p>
+    <p>The maximum number of SMS, WhatsApp and phone call notifications per month.</p>
 
-    <p>The limit is applied to the combined number of sent SMS and
-    WhatsApp notifications. </p>
+    <p>The limit is applied to the combined number of sent SMS, WhatsApp and phone
+    call notifications. </p>
 </div>
 
 {% if not request.user.is_authenticated %}