Add mattermost notifications

This commit is contained in:
crepe 2017-09-09 22:00:31 -07:00
parent 2fb9b6cf25
commit bb0e968704
7 changed files with 9456 additions and 6 deletions

View File

@ -157,7 +157,7 @@ class Migration(migrations.Migration):
('status', models.CharField(default=b'pending', max_length=20, editable=False, choices=[(b'pending', 'Pending'), (b'successful', 'Successful'), (b'failed', 'Failed')])),
('error', models.TextField(default=b'', editable=False, blank=True)),
('notifications_sent', models.IntegerField(default=0, editable=False)),
('notification_type', models.CharField(max_length=32, choices=[(b'email', 'Email'), (b'slack', 'Slack'), (b'twilio', 'Twilio'), (b'pagerduty', 'Pagerduty'), (b'hipchat', 'HipChat'), (b'webhook', 'Webhook'), (b'irc', 'IRC')])),
('notification_type', models.CharField(max_length=32, choices=[(b'email', 'Email'), (b'slack', 'Slack'), (b'twilio', 'Twilio'), (b'pagerduty', 'Pagerduty'), (b'hipchat', 'HipChat'), (b'webhook', 'Webhook'), (b'mattermost', 'Mattermost'), (b'irc', 'IRC')])),
('recipients', models.TextField(default=b'', editable=False, blank=True)),
('subject', models.TextField(default=b'', editable=False, blank=True)),
('body', jsonfield.fields.JSONField(default=dict, blank=True)),
@ -174,7 +174,7 @@ class Migration(migrations.Migration):
('modified', models.DateTimeField(default=None, editable=False)),
('description', models.TextField(default=b'', blank=True)),
('name', models.CharField(unique=True, max_length=512)),
('notification_type', models.CharField(max_length=32, choices=[(b'email', 'Email'), (b'slack', 'Slack'), (b'twilio', 'Twilio'), (b'pagerduty', 'Pagerduty'), (b'hipchat', 'HipChat'), (b'webhook', 'Webhook'), (b'irc', 'IRC')])),
('notification_type', models.CharField(max_length=32, choices=[(b'email', 'Email'), (b'slack', 'Slack'), (b'twilio', 'Twilio'), (b'pagerduty', 'Pagerduty'), (b'hipchat', 'HipChat'), (b'webhook', 'Webhook'), (b'mattermost', 'Mattermost'), (b'irc', 'IRC')])),
('notification_configuration', jsonfield.fields.JSONField(default=dict)),
('created_by', models.ForeignKey(related_name="{u'class': 'notificationtemplate', u'app_label': 'main'}(class)s_created+", on_delete=django.db.models.deletion.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)),
('modified_by', models.ForeignKey(related_name="{u'class': 'notificationtemplate', u'app_label': 'main'}(class)s_modified+", on_delete=django.db.models.deletion.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)),

View File

@ -19,6 +19,7 @@ from awx.main.notifications.twilio_backend import TwilioBackend
from awx.main.notifications.pagerduty_backend import PagerDutyBackend
from awx.main.notifications.hipchat_backend import HipChatBackend
from awx.main.notifications.webhook_backend import WebhookBackend
from awx.main.notifications.mattermost_backend import MattermostBackend
from awx.main.notifications.irc_backend import IrcBackend
from awx.main.fields import JSONField
@ -36,6 +37,7 @@ class NotificationTemplate(CommonModelNameNotUnique):
('pagerduty', _('Pagerduty'), PagerDutyBackend),
('hipchat', _('HipChat'), HipChatBackend),
('webhook', _('Webhook'), WebhookBackend),
('mattermost', _('Mattermost'), MattermostBackend),
('irc', _('IRC'), IrcBackend)]
NOTIFICATION_TYPE_CHOICES = [(x[0], x[1]) for x in NOTIFICATION_TYPES]
CLASS_FOR_NOTIFICATION_TYPE = dict([(x[0], x[2]) for x in NOTIFICATION_TYPES])

View File

@ -0,0 +1,55 @@
# Copyright (c) 2016 Ansible, Inc.
# All Rights Reserved.
import logging
import requests
import json
from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
from awx.main.notifications.base import AWXBaseEmailBackend
from awx.main.utils import get_awx_version
logger = logging.getLogger('awx.main.notifications.mattermost_backend')
class MattermostBackend(AWXBaseEmailBackend):
init_parameters = {"mattermost_url": {"label": "Target URL", "type": "string"}}
#"mattermost_channel": {"label": "Channel", "type": "string"},
#"mattermost_username": {"label": "Username", "type": "string"},
#"mattermost_icon_url": {"label": "Icon URL", "type": "string"}}
recipient_parameter = "mattermost_url"
sender_parameter = None
def __init__(self, mattermost_channel=None, mattermost_username=None,
mattermost_icon_url=None, fail_silently=False, **kwargs):
super(MattermostBackend, self).__init__(fail_silently=fail_silently)
self.mattermost_channel = mattermost_channel
self.mattermost_username = mattermost_username
self.mattermost_icon_url = mattermost_icon_url
def format_body(self, body):
return body
def send_messages(self, messages):
sent_messages = 0
for m in messages:
payload = {}
for opt, optval in {'mattermost_icon_url':'icon_url',
'mattermost_channel': 'channel', 'mattermost_username': 'username'}.iteritems():
optvalue = getattr(self, opt)
if optvalue is not None:
payload[optval] = optvalue.strip()
payload['text'] = m.subject
r = requests.post("{}".format(m.recipients()[0]),
data=json.dumps(payload))
if r.status_code >= 400:
logger.error(smart_text(_("Error sending notification mattermost: {}").format(r.text)))
logger.error(smart_text(_("Error sending notification mattermost: {}").format(payload)))
if not self.fail_silently:
raise Exception(smart_text(_("Error sending notification mattermost: {}").format(r.text)))
sent_messages += 1
return sent_messages

View File

@ -333,6 +333,50 @@ export default ['i18n', function(i18n) {
subForm: 'typeSubForm',
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
},
mattermost_url: {
label: i18n._('Target URL'),
type: 'text',
awRequiredWhen: {
reqExpression: "mattermost_required",
init: "false"
},
ngShow: "notification_type.value == 'mattermost' ",
subForm: 'typeSubForm',
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
},
mattermost_username: {
label: i18n._('Username'),
type: 'text',
awRequiredWhen: {
reqExpression: "mattermost_username_required",
init: "false"
},
ngShow: "notification_type.value == 'mattermost' ",
subForm: 'typeSubForm',
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
},
mattermost_channel: {
label: i18n._('Channel'),
type: 'text',
awRequiredWhen: {
reqExpression: "mattermost_channel_required",
init: "false"
},
ngShow: "notification_type.value == 'mattermost' ",
subForm: 'typeSubForm',
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
},
mattermost_icon_url: {
label: i18n._('Icon URL'),
type: 'text',
awRequiredWhen: {
reqExpression: "mattermost_icon_url_required",
init: "false"
},
ngShow: "notification_type.value == 'mattermost' ",
subForm: 'typeSubForm',
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
},
server: {
label: i18n._('IRC Server Address'),
type: 'text',

View File

@ -17,6 +17,7 @@ function (i18n) {
obj.irc_required = false;
obj.twilio_required = false;
obj.webhook_required = false;
obj.mattermost_required = false;
obj.token_required = false;
obj.port_required = false;
obj.password_required = false;
@ -48,6 +49,12 @@ function (i18n) {
case 'webhook':
obj.webhook_required = true;
break;
case 'mattermost':
obj.mattermost_required = true;
obj.mattermost_username_required = false;
obj.mattermost_channel_required = false;
obj.mattermost_icon_url_required = false;
break;
case 'pagerduty':
obj.tokenLabel = ' ' + i18n._('API Token');
obj.pagerduty_required = true;

9342
awx/ui/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -9,14 +9,14 @@
<title ng-bind="tabTitle"></title>
<script>var $basePath = '{{ STATIC_URL }}'</script>
<link href="{{ STATIC_URL }}css/vendor.f283b4795bc6921b48e5.css" rel="stylesheet" />
<link href="{{ STATIC_URL }}css/vendor.60b270d4310f8d01aab3.css" rel="stylesheet" />
<link href="{{ STATIC_URL }}css/app.f283b4795bc6921b48e5.css" rel="stylesheet" />
<link href="{{ STATIC_URL }}css/app.60b270d4310f8d01aab3.css" rel="stylesheet" />
<script src="{{ STATIC_URL }}js/vendor.f283b4795bc6921b48e5.js"></script>
<script src="{{ STATIC_URL }}js/vendor.60b270d4310f8d01aab3.js"></script>
<script src="{{ STATIC_URL }}js/app.f283b4795bc6921b48e5.js"></script>
<script src="{{ STATIC_URL }}js/app.60b270d4310f8d01aab3.js"></script>
</head>