From 4409462cab9543e74b0a30486e897b1b1fdf28be Mon Sep 17 00:00:00 2001 From: davidmukiibi Date: Wed, 31 May 2017 14:20:17 +0300 Subject: [PATCH 1/8] [Feature #145028655] Add sms notification when cron job is up or down. - Twilio integration for sending sms alerts. - Added sms integration option to the integrations page. --- __init__.py | 0 hc/api/models.py | 4 +- hc/api/transports.py | 14 +++++++ hc/front/urls.py | 1 + hc/front/views.py | 4 ++ hc/settings.py | 7 +++- static/img/integrations/sms.png | Bin 0 -> 4617 bytes static/js/channels.js | 1 + templates/front/channels.html | 9 +++++ templates/integrations/add_sms.html | 58 ++++++++++++++++++++++++++++ 10 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 __init__.py create mode 100644 static/img/integrations/sms.png create mode 100644 templates/integrations/add_sms.html diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hc/api/models.py b/hc/api/models.py index a1cdd7d..d119885 100644 --- a/hc/api/models.py +++ b/hc/api/models.py @@ -21,7 +21,7 @@ ) DEFAULT_TIMEOUT = td(days=1) DEFAULT_GRACE = td(hours=1) -CHANNEL_KINDS = (("email", "Email"), ("webhook", "Webhook"), +CHANNEL_KINDS = (("sms", "SMS"), ("email", "Email"), ("webhook", "Webhook"), ("hipchat", "HipChat"), ("slack", "Slack"), ("pd", "PagerDuty"), ("po", "Pushover"), ("victorops", "VictorOps")) @@ -167,6 +167,8 @@ def send_verify_link(self): @property def transport(self): + if self.kind == 'sms': + return transports.SMS(self) if self.kind == "email": return transports.Email(self) elif self.kind == "webhook": diff --git a/hc/api/transports.py b/hc/api/transports.py index 0dd5a72..1408f80 100644 --- a/hc/api/transports.py +++ b/hc/api/transports.py @@ -4,6 +4,7 @@ import json import requests from six.moves.urllib.parse import quote +from twilio.rest import Client from hc.lib import emails @@ -89,6 +90,19 @@ def post(self, url, json, **kwargs): def post_form(self, url, data): return self.request("post", url, data=data) +class SMS(Transport): + + def notify(self, check): + if check.status in ["up", "down"]: + message = "Hullo, your {} check is {}!".format(check.name, check.status) + for value in self.channel.value: + to = value + client = Client(settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN) + response = client.messages.create(body=message, to=to, from_='(256) 998-9594') + + if response.error_message: + return response.error_message + class Webhook(HttpTransport): def notify(self, check): diff --git a/hc/front/urls.py b/hc/front/urls.py index 53befc6..90614cd 100644 --- a/hc/front/urls.py +++ b/hc/front/urls.py @@ -13,6 +13,7 @@ channel_urls = [ url(r'^$', views.channels, name="hc-channels"), url(r'^add/$', views.add_channel, name="hc-add-channel"), + url(r'^add_sms/$', views.add_sms, name="hc-add-sms"), url(r'^add_email/$', views.add_email, name="hc-add-email"), url(r'^add_webhook/$', views.add_webhook, name="hc-add-webhook"), url(r'^add_pd/$', views.add_pd, name="hc-add-pd"), diff --git a/hc/front/views.py b/hc/front/views.py index 4601505..0a413f2 100644 --- a/hc/front/views.py +++ b/hc/front/views.py @@ -358,6 +358,10 @@ def remove_channel(request, code): return redirect("hc-channels") +@login_required +def add_sms(request): + ctx = {"page": "channels"} + return render(request, "integrations/add_sms.html", ctx) @login_required def add_email(request): diff --git a/hc/settings.py b/hc/settings.py index adecc23..1ca1a40 100644 --- a/hc/settings.py +++ b/hc/settings.py @@ -35,9 +35,10 @@ 'djmail', 'hc.accounts', + 'django_twilio', 'hc.api', 'hc.front', - 'hc.payments' + 'hc.payments', ) MIDDLEWARE = ( @@ -139,6 +140,10 @@ SLACK_CLIENT_ID = None SLACK_CLIENT_SECRET = None +# sms integration +TWILIO_ACCOUNT_SID = 'ACacce7eab5f5f5018d1c78ba0bfc36aa7' +TWILIO_AUTH_TOKEN = '4b813e4109fe5f91e91568d202de0463' + # Pushover integration -- override these in local_settings PUSHOVER_API_TOKEN = None PUSHOVER_SUBSCRIPTION_URL = None diff --git a/static/img/integrations/sms.png b/static/img/integrations/sms.png new file mode 100644 index 0000000000000000000000000000000000000000..f0ea9b3dbfeaaaf560490f29185829dd3a4ef6a0 GIT binary patch literal 4617 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 literal 0 HcmV?d00001 diff --git a/static/js/channels.js b/static/js/channels.js index 0417f84..88c5045 100644 --- a/static/js/channels.js +++ b/static/js/channels.js @@ -4,6 +4,7 @@ $(function() { webhook: "http://", slack: "https://hooks.slack.com/...", hipchat: "https://api.hipchat.com/...", + sms: "+2547793222", pd: "service key" } diff --git a/templates/front/channels.html b/templates/front/channels.html index ef0daa4..826200a 100644 --- a/templates/front/channels.html +++ b/templates/front/channels.html @@ -27,6 +27,7 @@ {% for ch in channels %} + {% if ch.kind == "sms" %} SMS {% endif %} {% if ch.kind == "email" %} Email {% endif %} {% if ch.kind == "webhook" %} Webhook {% endif %} {% if ch.kind == "slack" %} Slack {% endif %} @@ -126,6 +127,14 @@

Add More

    +
  • + SMS icon + +

    SMS

    +

    Receive an sms when check goes up or down.

    + Add Integration +
  • Slack icon diff --git a/templates/integrations/add_sms.html b/templates/integrations/add_sms.html new file mode 100644 index 0000000..6eaf26d --- /dev/null +++ b/templates/integrations/add_sms.html @@ -0,0 +1,58 @@ +{% extends "base.html" %} +{% load compress humanize staticfiles hc_extras %} + +{% block title %}Add mobile numbers to send your notifications to - healthchecks.io{% endblock %} + + +{% block content %} +
    +
    +

    SMS

    + +

    Get an sms message when your check goes up or down.

    + +

    + Tip: + Add multiple phone numbers, to notify multiple team members. +

    + +

    + Confirmation needed. + After entering a phone number(s), healthchecks.io will send out a confirmation link. + Only confirmed numbers will receive notifications. +

    + +

    Integration Settings

    + +
    + {% csrf_token %} + +
    + +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    + + +{% endblock %} + +{% block scripts %} +{% compress js %} + + +{% endcompress %} +{% endblock %} From 2c47ff9ae727df0d8be4774a47a4584d31022fe8 Mon Sep 17 00:00:00 2001 From: victoriaaoka Date: Wed, 31 May 2017 15:04:45 +0300 Subject: [PATCH 2/8] [Feature #145028655 ] Update requirements.txt. --- requirements.txt | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index c21bee1..79c5261 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,47 @@ +appnope==0.1.0 +Babel==2.4.0 +backports.shutil-get-terminal-size==1.0.0 +boto==2.46.1 +coverage==4.4.1 +cssselect==1.0.1 +cssutils==1.0.2 +decorator==4.0.11 +Django==1.10 django-appconf==1.0.1 +django-compressor==2.1 +django-phonenumber-field==1.3.0 django-ses-backend==0.1.1 -Django==1.10 -django_compressor==2.1 +django-twilio==0.8.0 djmail==0.11.0 +enum34==1.1.6 +funcsigs==1.0.2 futures==3.0.3 +ipdb==0.10.3 +ipython==5.3.0 +ipython-genutils==0.2.0 +lxml==3.7.3 +mock==2.0.0 +pathlib2==2.2.1 +pbr==3.0.1 +pep8==1.7.0 +pexpect==4.2.1 +phonenumberslite==8.5.0 +pickleshare==0.7.4 premailer==2.9.6 +prompt-toolkit==1.0.14 psycopg2==2.6.1 +ptyprocess==0.5.1 +Pygments==2.2.0 +PyJWT==1.5.0 +PySocks==1.6.7 +pytz==2017.2 +rcssmin==1.0.6 requests==2.9.1 +rjsmin==1.0.12 +scandir==1.5 +simplegeneric==0.8.1 +six==1.10.0 +traitlets==4.3.2 +twilio==6.3.0 +virtualenv==15.1.0 +wcwidth==0.1.7 From 1349a0536f4e2fa813c7f10c1c7dfa1d6f9467a3 Mon Sep 17 00:00:00 2001 From: victoriaaoka Date: Wed, 31 May 2017 15:47:02 +0300 Subject: [PATCH 3/8] [Feature #145028655 ] Update requirements.txt. --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 79c5261..d3f0f96 100644 --- a/requirements.txt +++ b/requirements.txt @@ -45,3 +45,4 @@ traitlets==4.3.2 twilio==6.3.0 virtualenv==15.1.0 wcwidth==0.1.7 + From 79c20f3e9fe7704e2d8632a53d83c80075e20c0c Mon Sep 17 00:00:00 2001 From: victoriaaoka Date: Wed, 31 May 2017 15:54:59 +0300 Subject: [PATCH 4/8] [Feature #145028655 ] Update requirements.txt. --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d3f0f96..746d33f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,7 +16,6 @@ djmail==0.11.0 enum34==1.1.6 funcsigs==1.0.2 futures==3.0.3 -ipdb==0.10.3 ipython==5.3.0 ipython-genutils==0.2.0 lxml==3.7.3 From 28aba4823beec094f498fdd5884667e22ac17666 Mon Sep 17 00:00:00 2001 From: davidmukiibi Date: Fri, 2 Jun 2017 09:08:26 +0300 Subject: [PATCH 5/8] [Chore #145028655 ] Update requirements.txt file. - Adding the latest requirements to the requirements file. --- requirements.txt | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index c21bee1..c5eb36a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,32 @@ +appdirs==1.4.3 +Babel==2.4.0 +boto==2.46.1 +cssselect==1.0.1 +cssutils==1.0.2 +Django==1.10 django-appconf==1.0.1 +django-compressor==2.1 +django-phonenumber-field==1.3.0 +django-sendsms==0.2.3 django-ses-backend==0.1.1 -Django==1.10 -django_compressor==2.1 +django-twilio==0.8.0 djmail==0.11.0 +funcsigs==1.0.2 futures==3.0.3 +lxml==3.7.3 +mock==2.0.0 +packaging==16.8 +patch==1.16 +pbr==3.0.0 +phonenumberslite==8.5.0 premailer==2.9.6 psycopg2==2.6.1 +PyJWT==1.5.0 +pyparsing==2.2.0 +PySocks==1.6.7 +pytz==2017.2 +rcssmin==1.0.6 requests==2.9.1 +rjsmin==1.0.12 +six==1.10.0 +twilio==6.3.0 From 982391f04970d4cd05666abb11d67ceadf9bf4c3 Mon Sep 17 00:00:00 2001 From: davidmukiibi Date: Fri, 2 Jun 2017 09:15:32 +0300 Subject: [PATCH 6/8] [Chore #145028655 ] Update requirements.txt file. - Adding the latest requirements to the requirements file. --- requirements.txt | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c5eb36a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,32 @@ +appdirs==1.4.3 +Babel==2.4.0 +boto==2.46.1 +cssselect==1.0.1 +cssutils==1.0.2 +Django==1.10 +django-appconf==1.0.1 +django-compressor==2.1 +django-phonenumber-field==1.3.0 +django-sendsms==0.2.3 +django-ses-backend==0.1.1 +django-twilio==0.8.0 +djmail==0.11.0 +funcsigs==1.0.2 +futures==3.0.3 +lxml==3.7.3 +mock==2.0.0 +packaging==16.8 +patch==1.16 +pbr==3.0.0 +phonenumberslite==8.5.0 +premailer==2.9.6 +psycopg2==2.6.1 +PyJWT==1.5.0 +pyparsing==2.2.0 +PySocks==1.6.7 +pytz==2017.2 +rcssmin==1.0.6 +requests==2.9.1 +rjsmin==1.0.12 +six==1.10.0 +twilio==6.3.0 From 0f6f373eaaa0f14e641e44822807f087b270c7c8 Mon Sep 17 00:00:00 2001 From: davidmukiibi Date: Fri, 2 Jun 2017 09:16:50 +0300 Subject: [PATCH 7/8] [Feature #145028655] Refactor sms alerts when cron jobs are up or down. - Did some refactoring in the sms alerts configuration to fix the number to send to error that was apparent before. --- hc/api/transports.py | 7 +++---- templates/integrations/add_sms.html | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/hc/api/transports.py b/hc/api/transports.py index 1408f80..63e15c1 100644 --- a/hc/api/transports.py +++ b/hc/api/transports.py @@ -95,10 +95,9 @@ class SMS(Transport): def notify(self, check): if check.status in ["up", "down"]: message = "Hullo, your {} check is {}!".format(check.name, check.status) - for value in self.channel.value: - to = value - client = Client(settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN) - response = client.messages.create(body=message, to=to, from_='(256) 998-9594') + to = self.channel.value + client = Client(settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN) + response = client.messages.create(body=message, to=to, from_='+12569989594') if response.error_message: return response.error_message diff --git a/templates/integrations/add_sms.html b/templates/integrations/add_sms.html index 6eaf26d..d6b6165 100644 --- a/templates/integrations/add_sms.html +++ b/templates/integrations/add_sms.html @@ -32,7 +32,7 @@

    Integration Settings

    From 3f0e19d75b7891c7543e4446db545436327064b6 Mon Sep 17 00:00:00 2001 From: victoriaaoka Date: Wed, 7 Jun 2017 10:57:12 +0300 Subject: [PATCH 8/8] Update requirements.txt --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1cdd6b2..60a0028 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,6 @@ django-appconf==1.0.1 django-compressor==2.1 django-phonenumber-field==1.3.0 django-sendsms==0.2.3 -django-ses-backend==0.1.1 django-twilio==0.8.0 coverage==4.4.1 dj-database-url==0.4.2