From c2b1d00422db971d4d1f758ef4191b65adfb1c9d Mon Sep 17 00:00:00 2001 From: Chris Caron Date: Wed, 7 Aug 2019 19:10:47 -0400 Subject: [PATCH] Apprise Integration --- hc/api/models.py | 3 ++ hc/api/transports.py | 17 +++++- hc/front/forms.py | 5 ++ hc/front/tests/test_add_apprise.py | 21 ++++++++ hc/front/urls.py | 1 + hc/front/views.py | 24 +++++++++ hc/settings.py | 1 + requirements.txt | 1 + static/img/integrations/apprise.png | Bin 0 -> 28702 bytes templates/front/channels.html | 11 ++++ templates/front/welcome.html | 6 +++ templates/integrations/add_apprise.html | 49 ++++++++++++++++++ .../integrations/apprise_description.html | 5 ++ templates/integrations/apprise_title.html | 1 + 14 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 hc/front/tests/test_add_apprise.py create mode 100644 static/img/integrations/apprise.png create mode 100644 templates/integrations/add_apprise.html create mode 100644 templates/integrations/apprise_description.html create mode 100644 templates/integrations/apprise_title.html diff --git a/hc/api/models.py b/hc/api/models.py index 32313aa3..dd2f9245 100644 --- a/hc/api/models.py +++ b/hc/api/models.py @@ -41,6 +41,7 @@ CHANNEL_KINDS = ( ("trello", "Trello"), ("matrix", "Matrix"), ("whatsapp", "WhatsApp"), + ("apprise", "Apprise"), ) PO_PRIORITIES = {-2: "lowest", -1: "low", 0: "normal", 1: "high", 2: "emergency"} @@ -392,6 +393,8 @@ class Channel(models.Model): return transports.Matrix(self) elif self.kind == "whatsapp": return transports.WhatsApp(self) + elif self.kind == "apprise": + return transports.Apprise(self) else: raise NotImplementedError("Unknown channel kind: %s" % self.kind) diff --git a/hc/api/transports.py b/hc/api/transports.py index 9475a89f..41e54ced 100644 --- a/hc/api/transports.py +++ b/hc/api/transports.py @@ -3,6 +3,7 @@ from django.template.loader import render_to_string from django.utils import timezone import json import requests +import apprise from urllib.parse import quote, urlencode from hc.accounts.models import Profile @@ -273,7 +274,7 @@ class PagerTree(HttpTransport): class PagerTeam(HttpTransport): def notify(self, check): url = self.channel.value - headers = {"Conent-Type": "application/json"} + headers = {"Content-Type": "application/json"} payload = { "incident_key": str(check.code), "event_type": "trigger" if check.status == "down" else "resolve", @@ -461,3 +462,17 @@ class Trello(HttpTransport): } return self.post(self.URL, params=params) + +class Apprise(HttpTransport): + def notify(self, check): + a = apprise.Apprise() + title = tmpl("apprise_title.html", check=check) + body = tmpl("apprise_description.html", check=check) + + a.add(self.channel.value) + + notify_type = apprise.NotifyType.SUCCESS \ + if check.status == "up" else apprise.NotifyType.FAILURE + + return "Failed" if not \ + a.notify(body=body, title=title, notify_type=notify_type) else None diff --git a/hc/front/forms.py b/hc/front/forms.py index 30494ade..4e01e49a 100644 --- a/hc/front/forms.py +++ b/hc/front/forms.py @@ -159,3 +159,8 @@ class AddMatrixForm(forms.Form): self.cleaned_data["room_id"] = doc["room_id"] return v + + +class AddAppriseForm(forms.Form): + error_css_class = "has-error" + url = forms.CharField(max_length=512) diff --git a/hc/front/tests/test_add_apprise.py b/hc/front/tests/test_add_apprise.py new file mode 100644 index 00000000..cd1cb30b --- /dev/null +++ b/hc/front/tests/test_add_apprise.py @@ -0,0 +1,21 @@ +from hc.api.models import Channel +from hc.test import BaseTestCase + + +class AddSlackTestCase(BaseTestCase): + def test_instructions_work(self): + self.client.login(username="alice@example.org", password="password") + r = self.client.get("/integrations/add_apprise/") + self.assertContains(r, "Integration Settings", status_code=200) + + def test_it_works(self): + form = {"url": "json://example.org"} + + self.client.login(username="alice@example.org", password="password") + r = self.client.post("/integrations/add_apprise/", form) + self.assertRedirects(r, "/integrations/") + + c = Channel.objects.get() + self.assertEqual(c.kind, "apprise") + self.assertEqual(c.value, "json://example.org") + self.assertEqual(c.project, self.project) diff --git a/hc/front/urls.py b/hc/front/urls.py index d3643d4f..e23ba45a 100644 --- a/hc/front/urls.py +++ b/hc/front/urls.py @@ -43,6 +43,7 @@ channel_urls = [ path("add_trello/", views.add_trello, name="hc-add-trello"), path("add_trello/settings/", views.trello_settings, name="hc-trello-settings"), path("add_matrix/", views.add_matrix, name="hc-add-matrix"), + path("add_apprise/", views.add_apprise, name="hc-add-apprise"), path("/checks/", views.channel_checks, name="hc-channel-checks"), path("/name/", views.update_channel_name, name="hc-channel-name"), path("/test/", views.send_test_notification, name="hc-channel-test"), diff --git a/hc/front/views.py b/hc/front/views.py index 398cc1db..c02025d1 100644 --- a/hc/front/views.py +++ b/hc/front/views.py @@ -44,6 +44,7 @@ from hc.front.forms import ( ChannelNameForm, EmailSettingsForm, AddMatrixForm, + AddAppriseForm, ) from hc.front.schemas import telegram_callback from hc.front.templatetags.hc_extras import num_down_title, down_title, sortchecks @@ -1325,6 +1326,29 @@ def add_matrix(request): return render(request, "integrations/add_matrix.html", ctx) +@login_required +def add_apprise(request): + if request.method == "POST": + form = AddAppriseForm(request.POST) + if form.is_valid(): + channel = Channel(project=request.project, kind="apprise") + channel.value = form.cleaned_data["url"] + channel.save() + + channel.assign_all_checks() + messages.success(request, "The Apprise integration has been added!") + return redirect("hc-channels") + else: + form = AddAppriseForm() + + ctx = { + "page": "channels", + "project": request.project, + "form": form, + } + return render(request, "integrations/add_apprise.html", ctx) + + @login_required @require_POST def trello_settings(request): diff --git a/hc/settings.py b/hc/settings.py index 612811f1..6f31a3bf 100644 --- a/hc/settings.py +++ b/hc/settings.py @@ -204,6 +204,7 @@ MATRIX_HOMESERVER = os.getenv("MATRIX_HOMESERVER") MATRIX_USER_ID = os.getenv("MATRIX_USER_ID") MATRIX_ACCESS_TOKEN = os.getenv("MATRIX_ACCESS_TOKEN") + if os.path.exists(os.path.join(BASE_DIR, "hc/local_settings.py")): from .local_settings import * else: diff --git a/requirements.txt b/requirements.txt index 88ba406c..027adb1a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ django_compressor==2.2 psycopg2==2.7.5 pytz==2019.1 requests==2.22.0 +apprise==0.7.9 diff --git a/static/img/integrations/apprise.png b/static/img/integrations/apprise.png new file mode 100644 index 0000000000000000000000000000000000000000..46533dc8cdde139593ccb40422bcf00072aebba6 GIT binary patch literal 28702 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 Integration +
  • + Pushover icon + +

    Apprise

    +

    Receive instant push notifications using Apprise; see all of the supported services here.

    + + Add Integration +
  • {% if enable_pushover %}
  • {% endif %} +
    +
    + Apprise icon +

    WhatsApp
    Chat

    +
    +
    diff --git a/templates/integrations/add_apprise.html b/templates/integrations/add_apprise.html new file mode 100644 index 00000000..e079ccfa --- /dev/null +++ b/templates/integrations/add_apprise.html @@ -0,0 +1,49 @@ +{% extends "base.html" %} +{% load humanize static hc_extras %} + +{% block title %}Add Apprise - {% site_name %}{% endblock %} + +{% block content %} +
    +
    +

    Apprise

    + +

    + Identify as many Apprise URLs as you wish. You can use a comma (,) to identify + more than on URL if you wish to. + + For a detailed list of all supported Apprise Notification URLs simply + click here. +

    + +

    Integration Settings

    + +
    + {% csrf_token %} + +
    + +
    + + + {% if form.url.errors %} +
    + {{ form.url.errors|join:"" }} +
    + {% endif %} +
    +
    +
    +
    + +
    +
    +
    +
    +
    +{% endblock %} diff --git a/templates/integrations/apprise_description.html b/templates/integrations/apprise_description.html new file mode 100644 index 00000000..22c9e800 --- /dev/null +++ b/templates/integrations/apprise_description.html @@ -0,0 +1,5 @@ +{% load humanize %} +{{ check.name_then_code }} is {{ check.status|upper }}. +{% if check.status == "down" %} +Last ping was {{ check.last_ping|naturaltime }}. +{% endif %} diff --git a/templates/integrations/apprise_title.html b/templates/integrations/apprise_title.html new file mode 100644 index 00000000..29274284 --- /dev/null +++ b/templates/integrations/apprise_title.html @@ -0,0 +1 @@ +{{ check.name_then_code }} is {{ check.status|upper }}