forked from GithubBackups/healthchecks
Matrix integration WIP. cc: #175
This commit is contained in:
parent
15a853bd8a
commit
f539e99652
@ -43,7 +43,8 @@ CHANNEL_KINDS = (("email", "Email"),
|
||||
("telegram", "Telegram"),
|
||||
("sms", "SMS"),
|
||||
("zendesk", "Zendesk"),
|
||||
("trello", "Trello"))
|
||||
("trello", "Trello"),
|
||||
("matrix", "Matrix"))
|
||||
|
||||
PO_PRIORITIES = {
|
||||
-2: "lowest",
|
||||
@ -339,6 +340,8 @@ class Channel(models.Model):
|
||||
return transports.Sms(self)
|
||||
elif self.kind == "trello":
|
||||
return transports.Trello(self)
|
||||
elif self.kind == "matrix":
|
||||
return transports.Matrix(self)
|
||||
else:
|
||||
raise NotImplementedError("Unknown channel kind: %s" % self.kind)
|
||||
|
||||
|
@ -3,7 +3,7 @@ from django.template.loader import render_to_string
|
||||
from django.utils import timezone
|
||||
import json
|
||||
import requests
|
||||
from urllib.parse import quote
|
||||
from urllib.parse import quote, urlencode
|
||||
|
||||
from hc.accounts.models import Profile
|
||||
from hc.lib import emails
|
||||
@ -343,6 +343,28 @@ class VictorOps(HttpTransport):
|
||||
return self.post(self.channel.value, json=payload)
|
||||
|
||||
|
||||
class Matrix(HttpTransport):
|
||||
def get_url(self):
|
||||
s = quote(self.channel.value)
|
||||
|
||||
url = settings.MATRIX_HOMESERVER
|
||||
url += "/_matrix/client/r0/rooms/%s/send/m.room.message?" % s
|
||||
url += urlencode({"access_token": settings.MATRIX_ACCESS_TOKEN})
|
||||
return url
|
||||
|
||||
def notify(self, check):
|
||||
plain = tmpl("matrix_description.html", check=check)
|
||||
formatted = tmpl("matrix_description_formatted.html", check=check)
|
||||
payload = {
|
||||
"msgtype": "m.text",
|
||||
"body": plain,
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": formatted
|
||||
}
|
||||
|
||||
return self.post(self.get_url(), json=payload)
|
||||
|
||||
|
||||
class Discord(HttpTransport):
|
||||
def notify(self, check):
|
||||
text = tmpl("slack_message.json", check=check)
|
||||
|
@ -1,11 +1,14 @@
|
||||
from datetime import timedelta as td
|
||||
import json
|
||||
import re
|
||||
from urllib.parse import quote, urlencode
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.core.validators import RegexValidator
|
||||
from hc.front.validators import (CronExpressionValidator, TimezoneValidator,
|
||||
WebhookValidator)
|
||||
import requests
|
||||
|
||||
|
||||
class NameTagsForm(forms.Form):
|
||||
@ -116,3 +119,24 @@ class AddSmsForm(forms.Form):
|
||||
|
||||
class ChannelNameForm(forms.Form):
|
||||
name = forms.CharField(max_length=100, required=False)
|
||||
|
||||
|
||||
class AddMatrixForm(forms.Form):
|
||||
error_css_class = "has-error"
|
||||
alias = forms.CharField(max_length=40)
|
||||
|
||||
def clean_alias(self):
|
||||
v = self.cleaned_data["alias"]
|
||||
|
||||
# validate it by trying to join
|
||||
url = settings.MATRIX_HOMESERVER
|
||||
url += "/_matrix/client/r0/join/%s?" % quote(v)
|
||||
url += urlencode({"access_token": settings.MATRIX_ACCESS_TOKEN})
|
||||
doc = requests.post(url, {}).json()
|
||||
if "error" in doc:
|
||||
raise forms.ValidationError(
|
||||
"Response from Matrix: %s" % doc["error"])
|
||||
|
||||
self.cleaned_data["room_id"] = doc["room_id"]
|
||||
|
||||
return v
|
||||
|
@ -38,6 +38,7 @@ channel_urls = [
|
||||
path('add_sms/', views.add_sms, name="hc-add-sms"),
|
||||
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('<uuid:code>/checks/', views.channel_checks, name="hc-channel-checks"),
|
||||
path('<uuid:code>/name/', views.update_channel_name, name="hc-channel-name"),
|
||||
path('<uuid:code>/remove/', views.remove_channel, name="hc-remove-channel"),
|
||||
|
@ -1,6 +1,6 @@
|
||||
from datetime import datetime, timedelta as td
|
||||
import json
|
||||
from urllib.parse import urlencode
|
||||
from urllib.parse import urlencode, quote
|
||||
|
||||
from croniter import croniter
|
||||
from django.conf import settings
|
||||
@ -24,7 +24,7 @@ from hc.api.transports import Telegram
|
||||
from hc.front.forms import (AddWebhookForm, NameTagsForm,
|
||||
TimeoutForm, AddUrlForm, AddEmailForm,
|
||||
AddOpsGenieForm, CronForm, AddSmsForm,
|
||||
ChannelNameForm, EmailSettingsForm)
|
||||
ChannelNameForm, EmailSettingsForm, AddMatrixForm)
|
||||
from hc.front.schemas import telegram_callback
|
||||
from hc.front.templatetags.hc_extras import (num_down_title, down_title,
|
||||
sortchecks)
|
||||
@ -550,6 +550,7 @@ def channels(request):
|
||||
"enable_sms": settings.TWILIO_AUTH is not None,
|
||||
"enable_pd": settings.PD_VENDOR_KEY is not None,
|
||||
"enable_trello": settings.TRELLO_APP_KEY is not None,
|
||||
"enable_matrix": settings.MATRIX_ACCESS_TOKEN is not None,
|
||||
"use_payments": settings.USE_PAYMENTS
|
||||
}
|
||||
|
||||
@ -1144,6 +1145,37 @@ def add_trello(request):
|
||||
return render(request, "integrations/add_trello.html", ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
def add_matrix(request):
|
||||
if settings.MATRIX_ACCESS_TOKEN is None:
|
||||
raise Http404("matrix integration is not available")
|
||||
|
||||
if request.method == "POST":
|
||||
form = AddMatrixForm(request.POST)
|
||||
if form.is_valid():
|
||||
channel = Channel(project=request.project, kind="matrix")
|
||||
channel.value = form.cleaned_data["room_id"]
|
||||
|
||||
# If user supplied room alias instead of ID, use it as channel name
|
||||
alias = form.cleaned_data["alias"]
|
||||
if not alias.startswith("!"):
|
||||
channel.name = alias
|
||||
|
||||
channel.save()
|
||||
|
||||
channel.assign_all_checks()
|
||||
messages.success(request, "The Matrix integration has been added!")
|
||||
return redirect("hc-channels")
|
||||
else:
|
||||
form = AddMatrixForm()
|
||||
|
||||
ctx = {
|
||||
"page": "channels",
|
||||
"form": form
|
||||
}
|
||||
return render(request, "integrations/add_matrix.html", ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
def trello_settings(request):
|
||||
|
@ -196,6 +196,10 @@ PD_VENDOR_KEY = os.getenv("PD_VENDOR_KEY")
|
||||
# Trello
|
||||
TRELLO_APP_KEY = os.getenv("TRELLO_APP_KEY")
|
||||
|
||||
# Matrix
|
||||
MATRIX_HOMESERVER = os.getenv("MATRIX_HOMESERVER")
|
||||
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:
|
||||
|
BIN
static/img/integrations/matrix.png
Normal file
BIN
static/img/integrations/matrix.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
@ -80,6 +80,8 @@
|
||||
Trello
|
||||
board <span>{{ ch.trello_board_list|first }}</span>,
|
||||
list <span>{{ ch.trello_board_list|last }}</span>
|
||||
{% elif ch.kind == "matrix" %}
|
||||
Matrix <span>{{ ch.value }}</span>
|
||||
{% else %}
|
||||
{{ ch.kind }}
|
||||
{% endif %}
|
||||
@ -279,6 +281,17 @@
|
||||
<a href="{% url 'hc-add-trello' %}" class="btn btn-primary">Add Integration</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if enable_matrix %}
|
||||
<li>
|
||||
<img src="{% static 'img/integrations/matrix.png' %}"
|
||||
class="icon" alt="Matrix icon" />
|
||||
|
||||
<h2>Matrix</h2>
|
||||
<p>Post notifications to a Matrix room.</p>
|
||||
|
||||
<a href="{% url 'hc-add-matrix' %}" class="btn btn-primary">Add Integration</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="link-to-github">
|
||||
<img src="{% static 'img/integrations/missing.png' %}"
|
||||
class="icon" alt="Suggest New Integration" />
|
||||
|
48
templates/integrations/add_matrix.html
Normal file
48
templates/integrations/add_matrix.html
Normal file
@ -0,0 +1,48 @@
|
||||
{% extends "base.html" %}
|
||||
{% load humanize static hc_extras %}
|
||||
|
||||
{% block title %}Add Matrix - {% site_name %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<h1>Matrix</h1>
|
||||
|
||||
<p>
|
||||
If your team uses <a href="https://matrix.org/">Matrix</a>,
|
||||
you can set up {% site_name %} to post notifications
|
||||
to an appropriate Matrix room.
|
||||
</p>
|
||||
|
||||
<h2>Integration Settings</h2>
|
||||
|
||||
<form method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="form-group {{ form.room_id.css_classes }}">
|
||||
<label for="alias" class="col-sm-2 control-label">Room Alias or ID</label>
|
||||
<div class="col-sm-6">
|
||||
<input
|
||||
id="alias"
|
||||
type="text"
|
||||
class="form-control"
|
||||
name="alias"
|
||||
placeholder="!abc:matrix.org"
|
||||
value="{{ form.alias.value|default:"" }}">
|
||||
|
||||
{% if form.alias.errors %}
|
||||
<div class="help-block">
|
||||
{{ form.alias.errors|join:"" }}
|
||||
</div>
|
||||
{% 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 %}
|
6
templates/integrations/matrix_description.html
Normal file
6
templates/integrations/matrix_description.html
Normal file
@ -0,0 +1,6 @@
|
||||
{% load humanize %}
|
||||
{% if check.status == "down" %}
|
||||
{{ check.name_then_code }} is DOWN. Last ping was {{ check.last_ping|naturaltime }}.
|
||||
{% else %}
|
||||
{{ check.name_then_code }} is now UP.
|
||||
{% endif %}
|
6
templates/integrations/matrix_description_formatted.html
Normal file
6
templates/integrations/matrix_description_formatted.html
Normal file
@ -0,0 +1,6 @@
|
||||
{% load humanize %}
|
||||
{% if check.status == "down" %}
|
||||
<b>{{ check.name_then_code }}</b> is <b>DOWN</b>. Last ping was {{ check.last_ping|naturaltime }}.
|
||||
{% else %}
|
||||
<b>{{ check.name_then_code }}</b> is now <b>UP</b>.
|
||||
{% endif %}
|
Loading…
x
Reference in New Issue
Block a user