Merge pull request #1674 from coreos-inc/new-quay-emails

New quay emails
This commit is contained in:
Ben Spoon 2016-08-09 09:12:54 -07:00 committed by GitHub
commit b0e34692cf
15 changed files with 353 additions and 75 deletions

View file

@ -11,7 +11,7 @@
</script>
{% endif %}
</head>
<body bgcolor="#FFFFFF" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; margin: 0; padding: 0;"><style type="text/css">
<body bgcolor="#F5F5F5" style="padding-left: 50px; padding-right: 50px; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; margin: 0; padding: 0;"><style type="text/css">
@media only screen and (max-width: 600px) {
a[class="btn"] {
display: block !important; margin-bottom: 10px !important; background-image: none !important; margin-right: 0 !important;
@ -26,26 +26,46 @@
</style>
<!-- HEADER -->
<table class="head-wrap" bgcolor="#FFFFFF" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; width: 100%; margin: 0; padding: 0;"><tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;"><td style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;"></td>
<table cell-padding="10" class="head-wrap" bgcolor="#F5F5F5" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; width: 100%; margin: 0; padding: 0;"><tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;"><td style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;"></td>
<td class="header container" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; display: block !important; max-width: 100% !important; clear: both !important; margin: 0; padding: 0;">
<div class="content" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; max-width: 100%; display: block; margin: 0; padding: 15px;">
<table bgcolor="#FFFFFF" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; width: 100%; margin: 0; padding: 0;"><tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;"><td style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;"><img src="{{ app_logo }}" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; max-width: 100%; margin: 0; padding: 0;" alt="{{ app_title }}" title="{{ app_title }}"/></td>
<table bgcolor="#F5F5F5" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; width: 100%; margin: 0; padding: 0;"><tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;"><td style="text-align: center; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;"><img src="{{ app_logo }}" width="100" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; max-width: 100%; margin: 0; padding: 0;" alt="{{ app_title }}" title="{{ app_title }}"/></td>
</tr></table></div>
</td>
<td style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;"></td>
</tr></table><!-- /HEADER --><!-- BODY --><table class="body-wrap" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; width: 100%; margin: 0; padding: 0;"><tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;"><td style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;"></td>
<td class="container" bgcolor="#FFFFFF" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; display: block !important; max-width: 100% !important; clear: both !important; margin: 0; padding: 0;">
</tr></table><!-- /HEADER --><!-- BODY --><table class="body-wrap" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0 auto; padding: 0; max-width: 640px; width: 100%;"><tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;"><td style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;"></td>
<td class="container" bgcolor="#FFFFFF" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; display: block !important; max-width: 100% !important; clear: both !important; margin: 0; padding: 0; box-shadow: 0px 2px 4px 0px #888;">
<div class="content" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; max-width: 100%; display: block; margin: 0; padding: 15px;">
<table style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; width: 100%; margin: 0; padding: 0;"><tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;"><td style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;">
{% block content %}{% endblock %}
<br>
<br>
<table style="font-size: 11px; font-weight: 200; font-style: italic; margin: 0 0 20px 0;">
<tr><td>If you have any questions, respond to this email and well be happy to help!</td></tr>
</table>
</td>
</tr></table></div><!-- /content -->
</td>
<td style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;"></td>
</tr></table><!-- /BODY -->
{% if hosted %}
<table style="text-align:center; margin:25px auto 0;">
<tr>
<td style="font-size: 13px; font-weight: 200">Quay [ builds, analyzes, distributes ] your container images</td>
</tr>
</table>
<table style="margin: 0 auto;">
<tr style="font-size: 11px;" >
<td><a style="color: #52A3D9;" href="{{app_url}}/user/{{username}}?tab=settings">Your Account</a></td>
<td><a style="color: #52A3D9;" href="https://docs.quay.io/">Documentation</a></td>
<td><a style="color: #52A3D9;" href="{{app_url}}">Quay.io</a></td>
</tr>
</table>
{% endif %}
</body>
</html>

View file

@ -2,12 +2,25 @@
{% block content %}
<h3>E-mail Address Change Requested</h3>
<h3 style="font-size: 20px; font-weight:400">E-mail Address Change Requested</h3>
<hr style="border:none; border-top: 1px solid #D9D9D9; margin: 25px 0">
<span style="font-size: 13px; margin: 25px 0;">This email address was added to the {{ app_title }} account <strong>{{ username }}</strong>.
This email address was recently asked to become the new e-mail address for user {{ username | user_reference }}.
<table style="margin: 25px 0;">
<tr>
<td style="background: #40B4E5; padding: 10px; border-radius: 3px; color: #fff; font-size: 20px; font-weight: 500"><a style="text-decoration: none; color: #ffffff;" href="{{ app_link('confirm?code=' + token) }}">Confirm Email</a></td>
</tr>
</table>
<table style="margin-bottom: 25px">
<tr>
<td>If you did not add this address to <strong>{{ username }}</strong>, you can safely ignore this message.</td>
</tr>
</table>
Best Regards,
<br>
The {{ app_title }} Team
<br>
<br>
To confirm this change, please click the following link:<br>
{{ app_link('confirm?code=' + token) }}
{% endblock %}

View file

@ -2,12 +2,29 @@
{% block content %}
<h3>Please Confirm E-mail Address</h3>
<h3 style="font-weight: 400">Confirm email for new user: <strong>{{ username }}</strong></h3>
<hr style="border:none; border-top: 1px solid #D9D9D9; margin: 25px 0">
This email address was recently used to register user {{ username | user_reference }}.
<br>
<br>
To confirm this email address, please click the following link:<br>
{{ app_link('confirm?code=' + token) }}
<table>
<tr>
<td style="font-size: 13px;">This email address was user to register user <strong>{{ username }}.</strong> </td>
</tr>
</table>
<table style="margin-top: 25px">
<tr>
<td style="font-size: 13px;">Once you confirm this email youll be able to access your {{ app_title }} account.</td>
</tr>
</table>
<table style="margin: 25px 0;">
<tr>
<td style="background: #40B4E5; padding: 10px; border-radius: 3px; color: #fff; font-size: 20px; font-weight: 500"><a style="text-decoration: none; color: #ffffff;" href="{{ app_link('confirm?code=' + token) }}">Confirm Email</a></td>
</tr>
</table>
<span style="font-size: 13px;">Welcome!</span><br>
<span style="font-size: 13px;">The {{ app_title }} Team</span><br>
{% endblock %}

View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title>Email Template Viewer</title>
</head>
<body>
<h1>Email Template Viewer</h1>
Here is a list of the templates available:
<ul>
{% for template in templates %}
{% if template != 'email-template-viewer' %}
<li><a href="{{template}}">{{template}}</a></li>
{% endif %}
{% endfor %}
</ul>
</body>
</html>

View file

@ -2,11 +2,28 @@
{% block content %}
<h3>Account E-mail Address Changed</h3>
<h3 style="font-weight: 400">Account password changed: <strong>{{ username }}</strong></h3>
<hr style="border:none; border-top: 1px solid #D9D9D9; margin: 25px 0">
The email address for user {{ username | user_reference }} has been changed from this e-mail address to {{ new_email }}.
<br>
<br>
If this change was not expected, please immediately log into your {{ username | admin_reference }} and reset your email address.
<table>
<tr>
<td style="font-size: 13px;">The password for user <strong>{{ username }}</strong> has been changed. </td>
</tr>
</table>
<table style="margin-top: 25px">
<tr>
<td style="font-size: 13px;">No action is required if you made this change.</td>
</tr>
</table>
<table style="margin: 25px 0 35px">
<tr>
<td style="font-size: 13px;">If you did not make this change, please <a href="https://quay.io/contact/">contact support</a></td>
</tr>
</table>
<span style="font-size: 13px;">Best wishes,</span><br>
<span style="font-size: 13px;">The {{ app_title }} Team</span><br>
{% endblock %}

View file

@ -2,19 +2,44 @@
{% block content %}
<h3>Organization {{ organization }} recovery</h3>
<h3 style="font-weight: 400">Organization recovery: <strong>{{ organization }}</strong></h3>
<hr style="border:none; border-top: 1px solid #D9D9D9; margin: 25px 0">
A user at {{ app_link() }} has attempted to recover organization {{ organization | user_reference }} via this email address.
<br>
<br>
Please login with one of the following user accounts to access this organization:
<ul>
{% for admin_user in admin_usernames %}
<li>{{ admin_user | user_reference }}</li>
{% endfor %}
</ul>
<br>
If you did not make this request, your organization has not been compromised and the user was
not given access. Please disregard this email.
<table>
<tr>
<td style="font-size: 13px;">A user at <a href="{{ app_link() }}">{{ app_link() }}</a> has attempted to recover access to organization <strong>{{ organization }}</strong> via this email address.</td>
</tr>
</table>
<table style="margin-top: 25px;">
<tr>
<td style="font-size: 13px;">Please login with one of the following user accounts to access this organization:</td>
</tr>
</table>
<table>
<tr>
<ul>
{% for admin_user in admin_usernames %}
<li style="font-weight: 500; font-size: 13px; margin-top: 15px;">{{ admin_user | user_reference }}</li>
{% endfor %}
</ul>
</tr>
</table>
<table style="">
<tr>
<td style="background: #40B4E5; padding: 10px; border-radius: 3px; color: #fff; font-size: 20px; font-weight: 500"><a style="text-decoration: none; color: #ffffff;" href="https://quay.io/signin/">Login to Recover</a></td>
</tr>
</table>
<table style="margin: 25px 0 35px">
<tr>
<td style="font-size: 13px;">If you did not make this request, your organization has not been compromised and the user was not given access. You can safely ignore this message.</td>
</tr>
</table>
<span style="font-size: 13px;">Best Wishes,</span><br>
<span style="font-size: 13px;">The {{ app_title }} Team</span><br>
{% endblock %}

View file

@ -2,12 +2,29 @@
{% block content %}
<h3>Account Password Changed</h3>
<h3 style="font-weight: 400">Account password changed: <strong>{{ username }}</strong></h3>
<hr style="border:none; border-top: 1px solid #D9D9D9; margin: 25px 0">
The password for user {{ username | user_reference }} has been updated.
<br>
<br>
If this change was not expected, please immediately log into your account settings and reset your email address,
or <a href="https://quay.io/contact">contact support</a>.
<table>
<tr>
<td style="font-size: 13px;">The password for user <strong>{{ username }}</strong> has been changed</td>
</tr>
</table>
<table style="margin-top: 25px">
<tr>
<td style="font-size: 13px;">No action is required if you made this change</td>
</tr>
</table>
<table style="margin: 25px 0 35px">
<tr>
<td style="font-size: 13px;">If you did not make this change, please <a href="https://quay.io/contact/">contact support</a> </td>
</tr>
</table>
<span style="font-size: 13px;">Best Wishes,</span><br>
<span style="font-size: 13px;">The {{ app_title }} Team</span><br>
{% endblock %}

View file

@ -2,12 +2,29 @@
{% block content %}
<h3>Subscription Payment Failure</h3>
<h3 style="font-weight: 400">Subscription payment failure: <strong>{{ username }}</strong></h3>
<hr style="border:none; border-top: 1px solid #D9D9D9; margin: 25px 0">
Your recent payment for account {{ username | user_reference }} failed, which usually results in our payments processor canceling
your subscription automatically. If you would like to continue to use {{ app_title }} without interruption,
please add a new card to {{ app_title }} and re-subscribe to your plan.<br>
<br>
You can find the card and subscription management features under your {{ username | admin_reference }}<br>
<table>
<tr>
<td style="font-size: 13px;">A recent payment for account <strong>{{ username }}</strong> failed.</td>
</tr>
</table>
<table style="margin: 25px 0 35px;">
<tr>
<td style="font-size: 13px;">If you would like to continue to use the account <strong>{{ username }}</strong> without interruption, update your payment information.</td>
</tr>
</table>
<table style="margin: 25px 0 35px">
<tr>
<td style="background: #40B4E5; padding: 8px 25px; border-radius: 3px; color: #fff; font-size: 20px; font-weight: 500"><a style="text-decoration: none; color: #ffffff;" href="https://quay.io/signin/">Log in to update payment info</a></td>
</tr>
</table>
<span style="font-size: 13px;">Thank you,</span><br>
<span style="font-size: 13px;">The {{ app_title }} Team</span><br>
{% endblock %}

View file

@ -2,17 +2,29 @@
{% block content %}
<h3>Account recovery</h3>
<h3 style="font-weight: 400">Account recovery</h3>
<hr style="border:none; border-top: 1px solid #D9D9D9; margin: 25px 0">
A user at {{ app_link() }} has attempted to recover their account
using this email address.
<br>
<br>
If you made this request, please click the following link to recover your account and
change your password:
{{ app_link('recovery?code=' + token) }}
<br><br>
If you did not make this request, your account has not been compromised and the user was
not given access. Please disregard this email.
<table>
<tr>
<td style="font-size: 13px;">A user at {{ app_title }} has attempted to recover their access to the account registered to this email address</td>
</tr>
</table>
<table style="margin: 25px 0;">
<tr>
<td style="background: #40B4E5; padding: 10px; border-radius: 3px; color: #fff; font-size: 20px; font-weight: 500"><a style="text-decoration: none; color: #ffffff;" href="{{ app_link('recovery?code=' + token) }}">Recover Account</a></td>
</tr>
</table>
<table style="margin: 25px 0 35px">
<tr>
<td style="font-size: 13px;">If you did not request this password reset, you can safely ignore this message and the account password and access will not change.</td>
</tr>
</table>
<span style="font-size: 13px;">Best Wishes,</span><br>
<span style="font-size: 13px;">The {{ app_title }} Team</span><br>
{% endblock %}

View file

@ -2,12 +2,29 @@
{% block content %}
<h3>Verify e-mail to receive repository notifications</h3>
<h3 style="font-weight: 400">Verify e-mail to recieve <strong>{{namespace}}/{{repository}}</strong> notifications</h3>
<hr style="border:none; border-top: 1px solid #D9D9D9; margin: 25px 0">
A request has been made to send <a href="http://docs.quay.io/guides/notifications.html">notifications</a> to this email address for repository {{ (namespace, repository) | repository_reference }}
<table>
<tr>
<td style="font-size: 13px;">A request has been made to send notifications to this email address for the repository <strong>{{namespace}}/{{repository}}</strong></td>
</tr>
</table>
<br><br>
To verify this email address, please click the following link:<br>
{{ app_link('authrepoemail?code=' + token) }}
<table style="margin: 25px 0;">
<tr>
<td style="background: #40B4E5; padding: 10px; border-radius: 3px; color: #fff; font-size: 20px; font-weight: 500"><a style="text-decoration: none; color: #ffffff;" href="{{ app_link('authrepoemail?code=' + token) }}">Confirm Email</a></td>
</tr>
</table>
<table style="margin: 25px 0 35px">
<tr>
<td style="font-size: 13px;">If you do not wish to receive notifications for <strong>{{namespace}}/{{repository}}</strong>, you can ignore this message.</td>
</tr>
</table>
<span style="font-size: 13px;">Thank you,</span><br>
<span style="font-size: 13px;">The {{ app_title }} Team</span><br>
{% endblock %}

View file

@ -2,16 +2,29 @@
{% block content %}
<h3>Invitation to join team: {{ teamname }}</h3>
<h3 style="font-weight: 400">Invitation to join team: <strong>{{ organization }}/{{ teamname }}</strong></h3>
<hr style="border:none; border-top: 1px solid #D9D9D9; margin: 25px 0">
{{ inviter | user_reference }} has invited you to join the team {{ teamname | team_reference }} under organization {{ organization | user_reference }}.
<table>
<tr>
<td style="font-size: 13px;">Youve been invited to join the team <strong>{{ teamname }}</strong> in the organization <strong>{{ organization }}</strong> by user <strong>{{ inviter | user_reference }}</strong>.</td>
</tr>
</table>
<br><br>
<table style="margin-top: 25px">
<tr>
<td style="background: #40B4E5; padding: 8px 25px; border-radius: 3px; color: #fff; font-size: 20px; font-weight: 500"><a style="text-decoration: none; color: #ffffff;" href="{{ app_link('confirminvite?code=' + token) }}">Join Team</a></td>
</tr>
</table>
To join the team, please click the following link:<br>
{{ app_link('confirminvite?code=' + token) }}
<table style="margin: 25px 0 35px;">
<tr>
<td style="font-size: 13px;">If you were not expecting this invitation, you can safely ignore this email.</td>
</tr>
</table>
<br><br>
If you were not expecting this invitation, you can ignore this email.
<span style="font-size: 13px;">Thank you,</span><br>
<span style="font-size: 13px;">The {{ app_title }} Team</span><br>
{% endblock %}

View file

@ -0,0 +1,89 @@
from flask import Flask, render_template
import datetime
import os
tmpl_dir = '../../emails'
app = Flask(__name__, template_folder=tmpl_dir)
@app.template_filter()
def user_reference_filter(value):
return value
@app.template_filter()
def admin_reference(value):
return value
@app.template_filter()
def repository_reference(value):
return value
@app.template_filter()
def team_reference(value):
return value
app.jinja_env.filters['user_reference'] = user_reference_filter
app.jinja_env.filters['admin_reference'] = admin_reference
app.jinja_env.filters['repository_reference'] = repository_reference
app.jinja_env.filters['team_reference'] = team_reference
app_title = 'Quay.io (local)'
def app_link_handler(url=None, title=None):
""" Just because it is in the original email tempaltes """
return 'http://example.com/example'
def render_with_options(template=None):
""" Pass a bunch of common variables when rendering templates """
return render_template(template, username="exampleuser", user_reference="testing",
app_logo="https://quay.io/static/img/quay-horizontal-color.svg", token="sdf8SdfKGRME9dse_dfdf",
app_link=app_link_handler, namespace="booboo", repository="foobar", organization="buynlarge",
admin_usernames=["lazercat", "booboocoreos"], teamname="creators", inviter="devtable",
hosted=False, app_title=app_title, app_url="https://quay.io")
def get_templates():
""" Return a list of the available templates """
return [t.replace('.html', '') for t in os.listdir('../../emails')]
@app.route("/")
def template_test():
return render_template('email-template-viewer.html', templates=get_templates())
@app.route("/changeemail")
def changeemail():
return render_with_options('changeemail.html');
@app.route("/confirmemail")
def confirmemail():
return render_with_options('confirmemail.html');
@app.route("/emailchanged")
def emailchanged():
return render_with_options('emailchanged.html');
@app.route("/orgrecovery")
def orgrecovery():
return render_with_options('orgrecovery.html');
@app.route("/passwordchanged")
def passwordchanged():
return render_with_options('passwordchanged.html');
@app.route("/paymentfailure")
def paymentfailure():
return render_with_options('paymentfailure.html');
@app.route("/recovery")
def recovery():
return render_with_options('recovery.html');
@app.route("/repoauthorizeemail")
def repoauthorizeemail():
return render_with_options('repoauthorizeemail.html');
@app.route("/teaminvite")
def teaminvite():
return render_with_options('teaminvite.html');
if __name__ == '__main__':
app.run(debug=True)

View file

@ -0,0 +1,6 @@
Flask==0.10.1
Jinja2==2.7.2
MarkupSafe==0.18
Werkzeug==0.9.4
itsdangerous==0.23
wsgiref==0.1.2

View file

@ -74,7 +74,7 @@ def admin_reference(username):
if user.organization:
return """
<a href="%s/organization/%s/admin">organization's admin setting</a>
<a href="%s/organization/%s?tab=settings">organization's admin setting</a>
""" % (get_app_url(), username)
else:
return """

View file

@ -1,6 +1,7 @@
import logging
import traceback
import json
import features
from flask.ext.mail import Message
@ -53,18 +54,15 @@ def send_email(recipient, subject, template_file, parameters, action=None):
app_title = app.config['REGISTRY_TITLE_SHORT']
app_url = get_app_url()
def app_link_handler(url=None, title=None):
real_url = app_url + '/' + url if url else app_url
if not title:
title = real_url if url else app_title
return '<a href="%s">%s</a>' % (real_url, title)
def app_link_handler(url=None):
return app_url + '/' + url if url else app_url
parameters.update({
'subject': subject,
'app_logo': 'https://quay.io/static/img/quay-logo.png', # TODO: make this pull from config
'app_url': app_url,
'app_title': app_title,
'hosted': features.BILLING,
'app_link': app_link_handler,
'action_metadata': json.dumps(action.metadata) if action else None
})