Add e-mail authorization to the repository notification flow. Also validates the creation of the other notification methods.

This commit is contained in:
Joseph Schorr 2014-07-28 14:58:12 -04:00
parent 56fec63fcd
commit 34fc279092
15 changed files with 483 additions and 34 deletions

View file

@ -14,6 +14,10 @@ logger = logging.getLogger(__name__)
class InvalidNotificationMethodException(Exception):
pass
class CannotValidateNotificationMethodException(Exception):
pass
class NotificationMethod(object):
def __init__(self):
pass
@ -25,6 +29,13 @@ class NotificationMethod(object):
"""
raise NotImplementedError
def validate(self, repository, config_data):
"""
Validates that the notification can be created with the given data. Throws
a CannotValidateNotificationMethodException on failure.
"""
raise NotImplementedError
def perform(self, notification, event_handler, notification_data):
"""
Performs the notification method.
@ -49,36 +60,32 @@ class QuayNotificationMethod(NotificationMethod):
def method_name(cls):
return 'quay_notification'
def perform(self, notification, event_handler, notification_data):
config_data = json.loads(notification.config_json)
repository_id = notification_data['repository_id']
repository = model.lookup_repository(repository_id)
if not repository:
# Probably deleted.
return True
# Lookup the target user or team to which we'll send the notification.
def validate(self, repository, config_data):
status, err_message, target_users = self.find_targets(repository, config_data)
if err_message:
raise CannotValidateNotificationMethodException(err_message)
def find_targets(self, repository, config_data):
target_info = config_data['target']
target_users = []
if target_info['kind'] == 'user':
target = model.get_user(target_info['name'])
if not target:
# Just to be safe.
return True
return (True, 'Unknown user %s' % target_info['name'], [])
target_users.append(target)
return (True, None, [target])
elif target_info['kind'] == 'org':
target = model.get_organization(target_info['name'])
if not target:
# Just to be safe.
return True
return (True, 'Unknown organization %s' % target_info['name'], None)
# Only repositories under the organization can cause notifications to that org.
if target_info['name'] != repository.namespace:
return False
return (False, 'Organization name must match repository namespace')
target_users.append(target)
return (True, None, [target])
elif target_info['kind'] == 'team':
# Lookup the team.
team = None
@ -86,13 +93,27 @@ class QuayNotificationMethod(NotificationMethod):
team = model.get_organization_team(repository.namespace, target_info['name'])
except model.InvalidTeamException:
# Probably deleted.
return True
return (True, 'Unknown team %s' % target_info['name'], None)
# Lookup the team's members
target_users = model.get_organization_team_members(team.id)
return (True, None, model.get_organization_team_members(team.id))
def perform(self, notification, event_handler, notification_data):
repository_id = notification_data['repository_id']
repository = model.lookup_repository(repository_id)
if not repository:
# Probably deleted.
return True
# Lookup the target user or team to which we'll send the notification.
config_data = json.loads(notification.config_json)
status, err_message, target_users = self.find_targets(repository, config_data)
if not status:
return False
# For each of the target users, create a notification.
for target_user in set(target_users):
for target_user in set(target_users or []):
model.create_notification(event_handler.event_name(), target_user,
metadata=notification_data['event_data'])
return True
@ -103,6 +124,18 @@ class EmailMethod(NotificationMethod):
def method_name(cls):
return 'email'
def validate(self, repository, config_data):
email = config_data.get('email', '')
if not email:
raise CannotValidateNotificationMethodException('Missing e-mail address')
record = model.get_email_authorized_for_repo(repository.namespace, repository.name, email)
if not record or not record.confirmed:
raise CannotValidateNotificationMethodException('The specified e-mail address '
'is not authorized to receive '
'notifications for this repository')
def perform(self, notification, event_handler, notification_data):
config_data = json.loads(notification.config_json)
email = config_data.get('email', '')
@ -129,6 +162,11 @@ class WebhookMethod(NotificationMethod):
def method_name(cls):
return 'webhook'
def validate(self, repository, config_data):
url = config_data.get('url', '')
if not url:
raise CannotValidateNotificationMethodException('Missing webhook URL')
def perform(self, notification, event_handler, notification_data):
config_data = json.loads(notification.config_json)
url = config_data.get('url', '')