Matrix integration WIP. cc: #175

This commit is contained in:
Pēteris Caune 2019-02-22 18:23:36 +02:00
parent 15a853bd8a
commit f539e99652
No known key found for this signature in database
GPG Key ID: E28D7679E9A9EDE2
11 changed files with 163 additions and 4 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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"),

View File

@ -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):

View File

@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -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" />

View 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 %}

View 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 %}

View 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 %}