Fix Slack notification setup to support the new slack web hook format and convert all existing data to use the new format (so we only have one code path)

This commit is contained in:
Joseph Schorr 2014-12-16 14:34:43 +02:00
parent 79b61e7709
commit 107847a4bb
5 changed files with 97 additions and 22 deletions

View file

@ -0,0 +1,24 @@
"""Convert slack webhook data
Revision ID: 5b84373e5db
Revises: 1c5b738283a5
Create Date: 2014-12-16 12:02:55.167744
"""
# revision identifiers, used by Alembic.
revision = '5b84373e5db'
down_revision = '1c5b738283a5'
from alembic import op
import sqlalchemy as sa
from tools.migrateslackwebhook import run_slackwebhook_migration
def upgrade(tables):
run_slackwebhook_migration()
def downgrade(tables):
pass

View file

@ -363,11 +363,8 @@ class SlackMethod(NotificationMethod):
return 'slack'
def validate(self, repository, config_data):
if not config_data.get('token', ''):
raise CannotValidateNotificationMethodException('Missing Slack Token')
if not config_data.get('subdomain', '').isalnum():
raise CannotValidateNotificationMethodException('Missing Slack Subdomain Name')
if not config_data.get('url', ''):
raise CannotValidateNotificationMethodException('Missing Slack Callback URL')
def format_for_slack(self, message):
message = message.replace('\n', '')
@ -378,10 +375,8 @@ class SlackMethod(NotificationMethod):
def perform(self, notification, event_handler, notification_data):
config_data = json.loads(notification.config_json)
token = config_data.get('token', '')
subdomain = config_data.get('subdomain', '')
if not token or not subdomain:
url = config_data.get('url', '')
if not url:
return
owner = model.get_user_or_org(notification.repository.namespace_user.username)
@ -389,8 +384,6 @@ class SlackMethod(NotificationMethod):
# Something went wrong.
return
url = 'https://%s.slack.com/services/hooks/incoming-webhook?token=%s' % (subdomain, token)
level = event_handler.get_level(notification_data['event_data'], notification_data)
color = {
'info': '#ffffff',
@ -426,5 +419,5 @@ class SlackMethod(NotificationMethod):
raise NotificationMethodPerformException(error_message)
except requests.exceptions.RequestException as ex:
logger.exception('Slack method was unable to be sent: %s' % ex.message)
logger.exception('Slack method was unable to be sent: %s', ex.message)
raise NotificationMethodPerformException(ex.message)

View file

@ -73,7 +73,7 @@
<tr ng-if="currentMethod.fields.length"><td colspan="2"><hr></td></tr>
<tr ng-repeat="field in currentMethod.fields">
<td valign="top">{{ field.title }}:</td>
<td valign="top" style="padding-top: 10px">{{ field.title }}:</td>
<td>
<div ng-switch on="field.type">
<span ng-switch-when="email">
@ -81,6 +81,9 @@
</span>
<input type="url" class="form-control" ng-model="currentConfig[field.name]" ng-switch-when="url" required>
<input type="text" class="form-control" ng-model="currentConfig[field.name]" ng-switch-when="string" required>
<input type="text" class="form-control" ng-model="currentConfig[field.name]" ng-switch-when="regex" required
ng-pattern="getPattern(field)"
placeholder="{{ field.placeholder }}">
<div class="entity-search" namespace="repository.namespace"
placeholder="''"
current-entity="currentConfig[field.name]"

View file

@ -1484,15 +1484,12 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
'icon': 'slack-icon',
'fields': [
{
'name': 'subdomain',
'type': 'string',
'title': 'Slack Subdomain'
},
{
'name': 'token',
'type': 'string',
'title': 'Token',
'help_url': 'https://{subdomain}.slack.com/services/new/incoming-webhook'
'name': 'url',
'type': 'regex',
'title': 'Webhook URL',
'regex': '^https://hooks\\.slack\\.com/services/[A-Z0-9]+/[A-Z0-9]+/[a-zA-Z0-9]+$',
'help_url': 'https://slack.com/services/new/incoming-webhook',
'placeholder': 'https://hooks.slack.com/service/{some}/{token}/{here}'
}
]
}
@ -5905,6 +5902,10 @@ quayApp.directive('createExternalNotificationDialog', function () {
$scope.events = ExternalNotificationData.getSupportedEvents();
$scope.methods = ExternalNotificationData.getSupportedMethods();
$scope.getPattern = function(field) {
return new RegExp(field.regex);
};
$scope.setEvent = function(event) {
$scope.currentEvent = event;
};

View file

@ -0,0 +1,54 @@
import argparse
import logging
import json
from app import app
from data import model
from data.database import configure, RepositoryNotification, ExternalNotificationMethod
configure(app.config)
logger = logging.getLogger(__name__)
def run_slackwebhook_migration():
slack_method = ExternalNotificationMethod.get(ExternalNotificationMethod.name == "slack")
encountered = set()
while True:
found = list(RepositoryNotification.select().where(
RepositoryNotification.method == slack_method,
RepositoryNotification.config_json ** "%subdomain%",
~(RepositoryNotification.config_json ** "%url%")))
found = [f for f in found if not f.uuid in encountered]
if not found:
logger.debug('No additional records found')
return
logger.debug('Found %s records to be changed', len(found))
for notification in found:
encountered.add(notification.uuid)
try:
config = json.loads(notification.config_json)
except:
logging.error("Cannot parse config for noticification %s", notification.uuid)
continue
logger.debug("Checking notification %s", notification.uuid)
if 'subdomain' in config and 'token' in config:
subdomain = config['subdomain']
token = config['token']
new_url = 'https://%s.slack.com/services/hooks/incoming-webhook?token=%s' % (subdomain, token)
config['url'] = new_url
logger.debug("Updating notification %s to URL: %s", notification.uuid, new_url)
notification.config_json = json.dumps(config)
notification.save()
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
logging.getLogger('boto').setLevel(logging.CRITICAL)
run_slackwebhook_migration()