import os
import json
import logging
from flask_mail import Message
import features
from _init import ROOT_DIR
from app import mail, app, get_app_url
from util.jinjautil import get_template_env
from util.html import html2text
logger = logging.getLogger(__name__)
template_env = get_template_env(os.path.join(ROOT_DIR, "emails"))
class CannotSendEmailException(Exception):
pass
class GmailAction(object):
""" Represents an action that can be taken in Gmail in response to the email. """
def __init__(self, metadata):
self.metadata = metadata
@staticmethod
def confirm(name, url, description):
return GmailAction({
"@context": "http://schema.org",
"@type": "EmailMessage",
"action": {
"@type": 'ConfirmAction',
"name": name,
"handler": {
"@type": "HttpActionHandler",
"url": get_app_url() + '/' + url
}
},
"description": description
})
@staticmethod
def view(name, url, description):
return GmailAction({
"@context": "http://schema.org",
"@type": "EmailMessage",
"action": {
"@type": 'ViewAction',
"name": name,
"url": get_app_url() + '/' + url
},
"description": description
})
def send_email(recipient, subject, template_file, parameters, action=None):
app_title = app.config['REGISTRY_TITLE_SHORT']
app_url = get_app_url()
html, plain = render_email(app_title, app_url, recipient, subject, template_file, parameters,
action=None)
msg = Message('[%s] %s' % (app_title, subject), recipients=[recipient])
msg.html = html
msg.body = plain
try:
mail.send(msg)
except Exception as ex:
logger.exception('Error while trying to send email to %s', recipient)
raise CannotSendEmailException(ex.message)
def render_email(app_title, app_url, recipient, subject, template_file, parameters, action=None):
def app_link_handler(url=None):
return app_url + '/' + url if url else app_url
app_logo = app.config.get('ENTERPRISE_LOGO_URL', 'https://quay.io/static/img/quay-logo.png')
parameters.update({
'subject': subject,
'app_logo': app_logo,
'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,
'with_base_template': True,
})
rendered_html = template_env.get_template(template_file + '.html').render(parameters)
parameters.update({
'with_base_template': False,
})
rendered_for_plain = template_env.get_template(template_file + '.html').render(parameters)
return rendered_html, html2text(rendered_for_plain)
def send_password_changed(username, email):
send_email(email, 'Account password changed', 'passwordchanged', {
'username': username
})
def send_email_changed(username, old_email, new_email):
send_email(old_email, 'Account e-mail address changed', 'emailchanged', {
'username': username,
'new_email': new_email
})
def send_change_email(username, email, token):
send_email(email, 'E-mail address change requested', 'changeemail', {
'username': username,
'token': token
})
def send_confirmation_email(username, email, token):
action = GmailAction.confirm('Confirm E-mail', 'confirm?code=' + token,
'Verification of e-mail address')
send_email(email, 'Please confirm your e-mail address', 'confirmemail', {
'username': username,
'token': token
}, action=action)
def send_repo_authorization_email(namespace, repository, email, token):
action = GmailAction.confirm('Verify E-mail', 'authrepoemail?code=' + token,
'Verification of e-mail address')
subject = 'Please verify your e-mail address for repository %s/%s' % (namespace, repository)
send_email(email, subject, 'repoauthorizeemail', {
'namespace': namespace,
'repository': repository,
'token': token
}, action=action)
def send_org_recovery_email(org, admin_users):
subject = 'Organization %s recovery' % (org.username)
send_email(org.email, subject, 'orgrecovery', {
'organization': org.username,
'admin_usernames': [user.username for user in admin_users],
})
def send_recovery_email(email, token):
action = GmailAction.view('Recover Account', 'recovery?code=' + token,
'Recovery of an account')
subject = 'Account recovery'
send_email(email, subject, 'recovery', {
'email': email,
'token': token
}, action=action)
def send_payment_failed(email, username):
send_email(email, 'Subscription Payment Failure', 'paymentfailure', {
'username': username
})
def send_org_invite_email(member_name, member_email, orgname, team, adder, code):
action = GmailAction.view('Join %s' % team, 'confirminvite?code=' + code,
'Invitation to join a team')
send_email(member_email, 'Invitation to join team', 'teaminvite', {
'inviter': adder,
'token': code,
'organization': orgname,
'teamname': team
}, action=action)
def send_invoice_email(email, contents):
# Note: This completely generates the contents of the email, so we don't use the
# normal template here.
msg = Message('Quay payment received - Thank you!', recipients=[email])
msg.html = contents
mail.send(msg)
def send_logs_exported_email(email, export_id, status, exported_data_url=None,
exported_data_expiration=None):
send_email(email, 'Export Action Logs Complete', 'logsexported', {
'status': status,
'export_id': export_id,
'exported_data_url': exported_data_url,
'exported_data_expiration': exported_data_expiration,
})
# INTERNAL EMAILS BELOW
def send_subscription_change(change_description, customer_id, customer_email, quay_username):
SUBSCRIPTION_CHANGE_TITLE = 'Subscription Change - {0} {1}'
SUBSCRIPTION_CHANGE = """
Change: {0}
Customer id: {1}
Customer email: {2}
Quay user or org name: {3}
"""
title = SUBSCRIPTION_CHANGE_TITLE.format(quay_username, change_description)
msg = Message(title, recipients=['stripe@quay.io'])
msg.html = SUBSCRIPTION_CHANGE.format(change_description, customer_id, customer_email,
quay_username)
mail.send(msg)