Add better (jinja-based) messaging to the notifications and add some fixes for the email templates
This commit is contained in:
parent
ea96dbb2ad
commit
5db9cd948b
13 changed files with 216 additions and 128 deletions
|
@ -579,6 +579,13 @@ def get_user(username):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_namespace_user(username):
|
||||||
|
try:
|
||||||
|
return User.get(User.username == username)
|
||||||
|
except User.DoesNotExist:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_user_or_org(username):
|
def get_user_or_org(username):
|
||||||
try:
|
try:
|
||||||
return User.get(User.username == username, User.robot == False)
|
return User.get(User.username == username, User.robot == False)
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from notificationhelper import build_event_data
|
from notificationhelper import build_event_data
|
||||||
|
from util.jinjautil import get_template_env
|
||||||
|
|
||||||
|
template_env = get_template_env("events")
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class InvalidNotificationEventException(Exception):
|
class InvalidNotificationEventException(Exception):
|
||||||
|
@ -14,7 +16,7 @@ class NotificationEvent(object):
|
||||||
def get_level(self, event_data, notification_data):
|
def get_level(self, event_data, notification_data):
|
||||||
"""
|
"""
|
||||||
Returns a 'level' representing the severity of the event.
|
Returns a 'level' representing the severity of the event.
|
||||||
Valid values are: 'info', 'warning', 'error', 'primary'
|
Valid values are: 'info', 'warning', 'error', 'primary', 'success'
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@ -28,7 +30,10 @@ class NotificationEvent(object):
|
||||||
"""
|
"""
|
||||||
Returns a human readable HTML message for the given notification data.
|
Returns a human readable HTML message for the given notification data.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
return template_env.get_template(self.event_name() + '.html').render({
|
||||||
|
'event_data': event_data,
|
||||||
|
'notification_data': notification_data
|
||||||
|
})
|
||||||
|
|
||||||
def get_sample_data(self, repository=None):
|
def get_sample_data(self, repository=None):
|
||||||
"""
|
"""
|
||||||
|
@ -59,28 +64,11 @@ class RepoPushEvent(NotificationEvent):
|
||||||
return 'repo_push'
|
return 'repo_push'
|
||||||
|
|
||||||
def get_level(self, event_data, notification_data):
|
def get_level(self, event_data, notification_data):
|
||||||
return 'info'
|
return 'primary'
|
||||||
|
|
||||||
def get_summary(self, event_data, notification_data):
|
def get_summary(self, event_data, notification_data):
|
||||||
return 'Repository %s updated' % (event_data['repository'])
|
return 'Repository %s updated' % (event_data['repository'])
|
||||||
|
|
||||||
def get_message(self, event_data, notification_data):
|
|
||||||
if not event_data.get('updated_tags', {}).keys():
|
|
||||||
html = """
|
|
||||||
Repository <a href="%s">%s</a> has been updated via a push.
|
|
||||||
""" % (event_data['homepage'],
|
|
||||||
event_data['repository'])
|
|
||||||
else:
|
|
||||||
html = """
|
|
||||||
Repository <a href="%s">%s</a> has been updated via a push.
|
|
||||||
<br><br>
|
|
||||||
Tags Updated: %s
|
|
||||||
""" % (event_data['homepage'],
|
|
||||||
event_data['repository'],
|
|
||||||
', '.join(event_data['updated_tags'].keys()))
|
|
||||||
|
|
||||||
return html
|
|
||||||
|
|
||||||
def get_sample_data(self, repository):
|
def get_sample_data(self, repository):
|
||||||
return build_event_data(repository, {
|
return build_event_data(repository, {
|
||||||
'updated_tags': {'latest': 'someimageid', 'foo': 'anotherimage'},
|
'updated_tags': {'latest': 'someimageid', 'foo': 'anotherimage'},
|
||||||
|
@ -108,26 +96,7 @@ class BuildQueueEvent(NotificationEvent):
|
||||||
}, subpage='/build?current=%s' % build_uuid)
|
}, subpage='/build?current=%s' % build_uuid)
|
||||||
|
|
||||||
def get_summary(self, event_data, notification_data):
|
def get_summary(self, event_data, notification_data):
|
||||||
return 'Build queued for repository %s' % (event_data['repository'])
|
return 'Build queued for repository %s' % (event_data['repository'])
|
||||||
|
|
||||||
def get_message(self, event_data, notification_data):
|
|
||||||
is_manual = event_data['is_manual']
|
|
||||||
if is_manual:
|
|
||||||
html = """
|
|
||||||
A <a href="%s">new build</a> has been manually queued to start on repository %s.
|
|
||||||
<br><br>
|
|
||||||
Build ID: %s
|
|
||||||
""" % (event_data['homepage'], event_data['repository'], event_data['build_id'])
|
|
||||||
else:
|
|
||||||
html = """
|
|
||||||
A <a href="%s">new build</a> has been queued via a %s trigger to start on repository %s.
|
|
||||||
<br><br>
|
|
||||||
Build ID: %s
|
|
||||||
""" % (event_data['homepage'], event_data['trigger_kind'],
|
|
||||||
event_data['repository'], event_data['build_id'])
|
|
||||||
|
|
||||||
return html
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BuildStartEvent(NotificationEvent):
|
class BuildStartEvent(NotificationEvent):
|
||||||
|
@ -151,15 +120,6 @@ class BuildStartEvent(NotificationEvent):
|
||||||
def get_summary(self, event_data, notification_data):
|
def get_summary(self, event_data, notification_data):
|
||||||
return 'Build started for repository %s' % (event_data['repository'])
|
return 'Build started for repository %s' % (event_data['repository'])
|
||||||
|
|
||||||
def get_message(self, event_data, notification_data):
|
|
||||||
html = """
|
|
||||||
A <a href="%s">new build</a> has started on repository %s.
|
|
||||||
<br><br>
|
|
||||||
Build ID: %s
|
|
||||||
""" % (event_data['homepage'], event_data['repository'], event_data['build_id'])
|
|
||||||
|
|
||||||
return html
|
|
||||||
|
|
||||||
|
|
||||||
class BuildSuccessEvent(NotificationEvent):
|
class BuildSuccessEvent(NotificationEvent):
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -167,7 +127,7 @@ class BuildSuccessEvent(NotificationEvent):
|
||||||
return 'build_success'
|
return 'build_success'
|
||||||
|
|
||||||
def get_level(self, event_data, notification_data):
|
def get_level(self, event_data, notification_data):
|
||||||
return 'primary'
|
return 'success'
|
||||||
|
|
||||||
def get_sample_data(self, repository):
|
def get_sample_data(self, repository):
|
||||||
build_uuid = 'fake-build-id'
|
build_uuid = 'fake-build-id'
|
||||||
|
@ -182,15 +142,6 @@ class BuildSuccessEvent(NotificationEvent):
|
||||||
def get_summary(self, event_data, notification_data):
|
def get_summary(self, event_data, notification_data):
|
||||||
return 'Build succeeded for repository %s' % (event_data['repository'])
|
return 'Build succeeded for repository %s' % (event_data['repository'])
|
||||||
|
|
||||||
def get_message(self, event_data, notification_data):
|
|
||||||
html = """
|
|
||||||
A <a href="%s">build</a> has finished on repository %s.
|
|
||||||
<br><br>
|
|
||||||
Build ID: %s
|
|
||||||
""" % (event_data['homepage'], event_data['repository'], event_data['build_id'])
|
|
||||||
|
|
||||||
return html
|
|
||||||
|
|
||||||
|
|
||||||
class BuildFailureEvent(NotificationEvent):
|
class BuildFailureEvent(NotificationEvent):
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -214,13 +165,3 @@ class BuildFailureEvent(NotificationEvent):
|
||||||
def get_summary(self, event_data, notification_data):
|
def get_summary(self, event_data, notification_data):
|
||||||
return 'Build failure for repository %s' % (event_data['repository'])
|
return 'Build failure for repository %s' % (event_data['repository'])
|
||||||
|
|
||||||
def get_message(self, event_data, notification_data):
|
|
||||||
html = """
|
|
||||||
A <a href="%s">build</a> has failed on repository %s.
|
|
||||||
<br><br>
|
|
||||||
Reason: %s<br>
|
|
||||||
Build ID: %s<br>
|
|
||||||
""" % (event_data['homepage'], event_data['repository'],
|
|
||||||
event_data['error_message'], event_data['build_id'])
|
|
||||||
|
|
||||||
return html
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from app import app, notification_queue
|
from app import app, notification_queue
|
||||||
from data import model
|
from data import model
|
||||||
|
from auth.auth_context import get_authenticated_user, get_validated_oauth_token
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
@ -27,21 +28,37 @@ def build_event_data(repo, extra_data={}, subpage=None):
|
||||||
event_data.update(extra_data)
|
event_data.update(extra_data)
|
||||||
return event_data
|
return event_data
|
||||||
|
|
||||||
def build_notification_data(notification, event_data):
|
def build_notification_data(notification, event_data, performer_data=None):
|
||||||
|
if not performer_data:
|
||||||
|
performer_data = {}
|
||||||
|
|
||||||
|
oauth_token = get_validated_oauth_token()
|
||||||
|
if oauth_token:
|
||||||
|
performer_data['oauth_token_id'] = oauth_token.id
|
||||||
|
performer_data['oauth_token_application_id'] = oauth_token.application.client_id
|
||||||
|
performer_data['oauth_token_application'] = oauth_token.application.name
|
||||||
|
|
||||||
|
performer_user = get_authenticated_user()
|
||||||
|
if performer_user:
|
||||||
|
performer_data['entity_id'] = performer_user.id
|
||||||
|
performer_data['entity_name'] = performer_user.username
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'notification_uuid': notification.uuid,
|
'notification_uuid': notification.uuid,
|
||||||
'repository_namespace': notification.repository.namespace_user.username,
|
'repository_namespace': notification.repository.namespace_user.username,
|
||||||
'repository_name': notification.repository.name,
|
'repository_name': notification.repository.name,
|
||||||
'event_data': event_data
|
'event_data': event_data,
|
||||||
|
'performer_data': performer_data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def spawn_notification(repo, event_name, extra_data={}, subpage=None, pathargs=[]):
|
def spawn_notification(repo, event_name, extra_data={}, subpage=None, pathargs=[],
|
||||||
|
performer_data=None):
|
||||||
event_data = build_event_data(repo, extra_data=extra_data, subpage=subpage)
|
event_data = build_event_data(repo, extra_data=extra_data, subpage=subpage)
|
||||||
|
|
||||||
notifications = model.list_repo_notifications(repo.namespace_user.username, repo.name,
|
notifications = model.list_repo_notifications(repo.namespace_user.username, repo.name,
|
||||||
event_name=event_name)
|
event_name=event_name)
|
||||||
for notification in notifications:
|
for notification in list(notifications):
|
||||||
notification_data = build_notification_data(notification, event_data)
|
notification_data = build_notification_data(notification, event_data, performer_data)
|
||||||
path = [repo.namespace_user.username, repo.name, event_name] + pathargs
|
path = [repo.namespace_user.username, repo.name, event_name] + pathargs
|
||||||
notification_queue.put(path, json.dumps(notification_data))
|
notification_queue.put(path, json.dumps(notification_data))
|
||||||
|
|
|
@ -279,6 +279,7 @@ class HipchatMethod(NotificationMethod):
|
||||||
'info': 'gray',
|
'info': 'gray',
|
||||||
'warning': 'yellow',
|
'warning': 'yellow',
|
||||||
'error': 'red',
|
'error': 'red',
|
||||||
|
'success': 'green',
|
||||||
'primary': 'purple'
|
'primary': 'purple'
|
||||||
}.get(level, 'gray')
|
}.get(level, 'gray')
|
||||||
|
|
||||||
|
@ -303,6 +304,56 @@ class HipchatMethod(NotificationMethod):
|
||||||
raise NotificationMethodPerformException(ex.message)
|
raise NotificationMethodPerformException(ex.message)
|
||||||
|
|
||||||
|
|
||||||
|
from HTMLParser import HTMLParser
|
||||||
|
|
||||||
|
class SlackAdjuster(HTMLParser):
|
||||||
|
def __init__(self):
|
||||||
|
self.reset()
|
||||||
|
self.result = []
|
||||||
|
|
||||||
|
def handle_data(self, d):
|
||||||
|
self.result.append(d)
|
||||||
|
|
||||||
|
def get_attr(self, attrs, name):
|
||||||
|
for attr in attrs:
|
||||||
|
if attr[0] == name:
|
||||||
|
return attr[1]
|
||||||
|
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def handle_starttag(self, tag, attrs):
|
||||||
|
if tag == 'a':
|
||||||
|
self.result.append('<%s|' % (self.get_attr(attrs, 'href'), ))
|
||||||
|
|
||||||
|
if tag == 'i':
|
||||||
|
self.result.append('_')
|
||||||
|
|
||||||
|
if tag == 'b' or tag == 'strong':
|
||||||
|
self.result.append('*')
|
||||||
|
|
||||||
|
if tag == 'img':
|
||||||
|
self.result.append(self.get_attr(attrs, 'alt'))
|
||||||
|
self.result.append(' ')
|
||||||
|
|
||||||
|
def handle_endtag(self, tag):
|
||||||
|
if tag == 'a':
|
||||||
|
self.result.append('>')
|
||||||
|
|
||||||
|
if tag == 'b' or tag == 'strong':
|
||||||
|
self.result.append('*')
|
||||||
|
|
||||||
|
if tag == 'i':
|
||||||
|
self.result.append('_')
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
return ''.join(self.result)
|
||||||
|
|
||||||
|
def adjust_tags(html):
|
||||||
|
s = SlackAdjuster()
|
||||||
|
s.feed(html)
|
||||||
|
return s.get_data()
|
||||||
|
|
||||||
|
|
||||||
class SlackMethod(NotificationMethod):
|
class SlackMethod(NotificationMethod):
|
||||||
""" Method for sending notifications to Slack via the API:
|
""" Method for sending notifications to Slack via the API:
|
||||||
https://api.slack.com/docs/attachments
|
https://api.slack.com/docs/attachments
|
||||||
|
@ -318,12 +369,11 @@ class SlackMethod(NotificationMethod):
|
||||||
if not config_data.get('subdomain', '').isalnum():
|
if not config_data.get('subdomain', '').isalnum():
|
||||||
raise CannotValidateNotificationMethodException('Missing Slack Subdomain Name')
|
raise CannotValidateNotificationMethodException('Missing Slack Subdomain Name')
|
||||||
|
|
||||||
def formatForSlack(self, message):
|
def format_for_slack(self, message):
|
||||||
message = message.replace('\n', '')
|
message = message.replace('\n', '')
|
||||||
message = re.sub(r'\s+', ' ', message)
|
message = re.sub(r'\s+', ' ', message)
|
||||||
message = message.replace('<br>', '\n')
|
message = message.replace('<br>', '\n')
|
||||||
message = re.sub(r'<a href="(.+)">(.+)</a>', '<\\1|\\2>', message)
|
return adjust_tags(message)
|
||||||
return message
|
|
||||||
|
|
||||||
def perform(self, notification, event_handler, notification_data):
|
def perform(self, notification, event_handler, notification_data):
|
||||||
config_data = json.loads(notification.config_json)
|
config_data = json.loads(notification.config_json)
|
||||||
|
@ -346,6 +396,7 @@ class SlackMethod(NotificationMethod):
|
||||||
'info': '#ffffff',
|
'info': '#ffffff',
|
||||||
'warning': 'warning',
|
'warning': 'warning',
|
||||||
'error': 'danger',
|
'error': 'danger',
|
||||||
|
'success': 'good',
|
||||||
'primary': 'good'
|
'primary': 'good'
|
||||||
}.get(level, '#ffffff')
|
}.get(level, '#ffffff')
|
||||||
|
|
||||||
|
@ -359,8 +410,9 @@ class SlackMethod(NotificationMethod):
|
||||||
'attachments': [
|
'attachments': [
|
||||||
{
|
{
|
||||||
'fallback': summary,
|
'fallback': summary,
|
||||||
'text': self.formatForSlack(message),
|
'text': self.format_for_slack(message),
|
||||||
'color': color
|
'color': color,
|
||||||
|
'mrkdwn_in': ["text"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
2
events/build_failure.html
Normal file
2
events/build_failure.html
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<a href="{{ event_data.homepage }}">Build</a> failed for repository
|
||||||
|
{{ event_data.repository | repository_reference }} ({{ event_data.build_id }}): {{ event_data.error_message }}
|
9
events/build_queued.html
Normal file
9
events/build_queued.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{% if event_data.is_manual and notification_data.performer_data.entity_name %}
|
||||||
|
{{ notification_data.performer_data.entity_name | user_reference }} queued a
|
||||||
|
<a href="{{ event_data.homepage }}">build</a>
|
||||||
|
{% elif event_data.trigger_kind %}
|
||||||
|
<a href="{{ event_data.homepage }}">Build</a> queued via a {{ event_data.trigger_kind }} trigger
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ event_data.homepage }}">Build</a> queued
|
||||||
|
{% endif %}
|
||||||
|
for repository {{ event_data.repository | repository_reference }} ({{ event_data.build_id }})
|
2
events/build_start.html
Normal file
2
events/build_start.html
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<a href="{{ event_data.homepage }}">Build</a> started for repository
|
||||||
|
{{ event_data.repository | repository_reference }} ({{ event_data.build_id }})
|
2
events/build_success.html
Normal file
2
events/build_success.html
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<a href="{{ event_data.homepage }}">Build</a> completed for repository
|
||||||
|
{{ event_data.repository | repository_reference }} ({{ event_data.build_id }})
|
12
events/repo_push.html
Normal file
12
events/repo_push.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{% if notification_data.performer_data.entity_name %}
|
||||||
|
{{ notification_data.performer_data.entity_name | user_reference }} pushed
|
||||||
|
{% else %}
|
||||||
|
Push of
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if event_data.updated_tags %}
|
||||||
|
{{ 'tags' | icon_image }}
|
||||||
|
{% for tag in event_data.updated_tags %}{%if loop.index > 1 %}, {% endif %}{{ (event_data.repository, tag) | repository_tag_reference }}{% endfor %} in
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
repository {{ event_data.repository | repository_reference }}
|
BIN
static/img/icons/tags.png
Normal file
BIN
static/img/icons/tags.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 294 B |
BIN
static/img/icons/wrench.png
Normal file
BIN
static/img/icons/wrench.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 379 B |
91
util/jinjautil.py
Normal file
91
util/jinjautil.py
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
from app import get_app_url
|
||||||
|
from data import model
|
||||||
|
from util.gravatar import compute_hash
|
||||||
|
from util.names import parse_robot_username
|
||||||
|
from jinja2 import Template, Environment, FileSystemLoader, contextfilter
|
||||||
|
|
||||||
|
def icon_path(icon_name):
|
||||||
|
return '%s/static/img/icons/%s.png' % (get_app_url(), icon_name)
|
||||||
|
|
||||||
|
def icon_image(icon_name):
|
||||||
|
return '<img src="%s" alt="%s">' % (icon_path(icon_name), icon_name)
|
||||||
|
|
||||||
|
def user_reference(username):
|
||||||
|
user = model.get_namespace_user(username)
|
||||||
|
if not user:
|
||||||
|
return username
|
||||||
|
|
||||||
|
is_robot = False
|
||||||
|
if user.robot:
|
||||||
|
parts = parse_robot_username(username)
|
||||||
|
user = model.get_namespace_user(parts[0])
|
||||||
|
|
||||||
|
return """<span><img src="%s" alt="Robot"> <b>%s</b></span>""" % (icon_path('wrench'), username)
|
||||||
|
|
||||||
|
alt = 'Organization' if user.organization else 'User'
|
||||||
|
return """
|
||||||
|
<span>
|
||||||
|
<img src="http://www.gravatar.com/avatar/%s?s=16&d=identicon"
|
||||||
|
style="vertical-align: middle; margin-left: 6px; margin-right: 4px;" alt="%s">
|
||||||
|
<b>%s</b>
|
||||||
|
</span>""" % (compute_hash(user.email), alt, username)
|
||||||
|
|
||||||
|
|
||||||
|
def repository_tag_reference(repository_path_and_tag):
|
||||||
|
(repository_path, tag) = repository_path_and_tag
|
||||||
|
(namespace, repository) = repository_path.split('/')
|
||||||
|
owner = model.get_namespace_user(namespace)
|
||||||
|
if not owner:
|
||||||
|
return tag
|
||||||
|
|
||||||
|
return """<a href="%s/repository/%s/%s?tag=%s">%s</a>""" % (get_app_url(), namespace, repository,
|
||||||
|
tag, tag)
|
||||||
|
|
||||||
|
def repository_reference(pair):
|
||||||
|
if isinstance(pair, tuple):
|
||||||
|
(namespace, repository) = pair
|
||||||
|
else:
|
||||||
|
pair = pair.split('/')
|
||||||
|
namespace = pair[0]
|
||||||
|
repository = pair[1]
|
||||||
|
|
||||||
|
owner = model.get_namespace_user(namespace)
|
||||||
|
if not owner:
|
||||||
|
return "%s/%s" % (namespace, repository)
|
||||||
|
|
||||||
|
return """
|
||||||
|
<span style="white-space: nowrap;">
|
||||||
|
<img src="http://www.gravatar.com/avatar/%s?s=16&d=identicon" style="vertical-align: middle; margin-left: 6px; margin-right: 4px;">
|
||||||
|
<a href="%s/repository/%s/%s">%s/%s</a>
|
||||||
|
</span>
|
||||||
|
""" % (compute_hash(owner.email), get_app_url(), namespace, repository, namespace, repository)
|
||||||
|
|
||||||
|
|
||||||
|
def admin_reference(username):
|
||||||
|
user = model.get_user_or_org(username)
|
||||||
|
if not user:
|
||||||
|
return 'account settings'
|
||||||
|
|
||||||
|
if user.organization:
|
||||||
|
return """
|
||||||
|
<a href="%s/organization/%s/admin">organization's admin setting</a>
|
||||||
|
""" % (get_app_url(), username)
|
||||||
|
else:
|
||||||
|
return """
|
||||||
|
<a href="%s/user/">account settings</a>
|
||||||
|
""" % (get_app_url())
|
||||||
|
|
||||||
|
|
||||||
|
def get_template_env(searchpath):
|
||||||
|
template_loader = FileSystemLoader(searchpath=searchpath)
|
||||||
|
template_env = Environment(loader=template_loader)
|
||||||
|
add_filters(template_env)
|
||||||
|
return template_env
|
||||||
|
|
||||||
|
|
||||||
|
def add_filters(template_env):
|
||||||
|
template_env.filters['icon_image'] = icon_image
|
||||||
|
template_env.filters['user_reference'] = user_reference
|
||||||
|
template_env.filters['admin_reference'] = admin_reference
|
||||||
|
template_env.filters['repository_reference'] = repository_reference
|
||||||
|
template_env.filters['repository_tag_reference'] = repository_tag_reference
|
|
@ -1,58 +1,11 @@
|
||||||
from flask.ext.mail import Message
|
from flask.ext.mail import Message
|
||||||
|
|
||||||
from app import mail, app, get_app_url
|
from app import mail, app, get_app_url
|
||||||
from jinja2 import Template, Environment, FileSystemLoader, contextfilter
|
|
||||||
from data import model
|
from data import model
|
||||||
from util.gravatar import compute_hash
|
from util.gravatar import compute_hash
|
||||||
|
from util.jinjautil import get_template_env
|
||||||
|
|
||||||
def user_reference(username):
|
template_env = get_template_env("emails")
|
||||||
user = model.get_user_or_org(username)
|
|
||||||
if not user:
|
|
||||||
return username
|
|
||||||
|
|
||||||
return """
|
|
||||||
<span>
|
|
||||||
<img src="http://www.gravatar.com/avatar/%s?s=16&d=identicon" style="vertical-align: middle; margin-left: 6px; margin-right: 4px;">
|
|
||||||
<b>%s</b>
|
|
||||||
</span>""" % (compute_hash(user.email), username)
|
|
||||||
|
|
||||||
|
|
||||||
def repository_reference(pair):
|
|
||||||
(namespace, repository) = pair
|
|
||||||
|
|
||||||
owner = model.get_user(namespace)
|
|
||||||
if not owner:
|
|
||||||
return "%s/%s" % (namespace, repository)
|
|
||||||
|
|
||||||
return """
|
|
||||||
<span style="white-space: nowrap;">
|
|
||||||
<img src="http://www.gravatar.com/avatar/%s?s=16&d=identicon" style="vertical-align: middle; margin-left: 6px; margin-right: 4px;">
|
|
||||||
<a href="%s/repository/%s/%s">%s/%s</a>
|
|
||||||
</span>
|
|
||||||
""" % (compute_hash(owner.email), get_app_url(), namespace, repository, namespace, repository)
|
|
||||||
|
|
||||||
|
|
||||||
def admin_reference(username):
|
|
||||||
user = model.get_user(username)
|
|
||||||
if not user:
|
|
||||||
return 'account settings'
|
|
||||||
|
|
||||||
if user.organization:
|
|
||||||
return """
|
|
||||||
<a href="%s/organization/%s/admin">organization's admin setting</a>
|
|
||||||
""" % (get_app_url(), username)
|
|
||||||
else:
|
|
||||||
return """
|
|
||||||
<a href="%s/user/">account settings</a>
|
|
||||||
""" % (get_app_url())
|
|
||||||
|
|
||||||
|
|
||||||
template_loader = FileSystemLoader(searchpath="emails")
|
|
||||||
template_env = Environment(loader=template_loader)
|
|
||||||
template_env.filters['user_reference'] = user_reference
|
|
||||||
template_env.filters['admin_reference'] = admin_reference
|
|
||||||
template_env.filters['repository_reference'] = repository_reference
|
|
||||||
|
|
||||||
|
|
||||||
def send_email(recipient, subject, template_file, parameters):
|
def send_email(recipient, subject, template_file, parameters):
|
||||||
app_title = app.config['REGISTRY_TITLE_SHORT']
|
app_title = app.config['REGISTRY_TITLE_SHORT']
|
||||||
|
|
Reference in a new issue