Send welcome email to new Cloud subscribers
This commit is contained in:
@@ -85,10 +85,12 @@ class CloudExtension(PillarExtension):
|
||||
}
|
||||
|
||||
def setup_app(self, app):
|
||||
from . import routes, webhooks
|
||||
from . import routes, webhooks, eve_hooks, email
|
||||
|
||||
routes.setup_app(app)
|
||||
app.register_api_blueprint(webhooks.blueprint, '/webhooks')
|
||||
eve_hooks.setup_app(app)
|
||||
email.setup_app(app)
|
||||
|
||||
|
||||
def _get_current_cloud():
|
||||
|
33
cloud/email.py
Normal file
33
cloud/email.py
Normal file
@@ -0,0 +1,33 @@
|
||||
import functools
|
||||
import logging
|
||||
|
||||
import flask
|
||||
|
||||
from pillar.auth import UserClass
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def queue_welcome_mail(user: UserClass):
|
||||
"""Queue a welcome email for execution by Celery."""
|
||||
assert user.email
|
||||
log.info('queueing welcome email to %s', user.email)
|
||||
|
||||
subject = 'Welcome to Blender Cloud'
|
||||
render = functools.partial(flask.render_template, subject=subject, user=user)
|
||||
text = render('emails/welcome.txt')
|
||||
html = render('emails/welcome.html')
|
||||
|
||||
from pillar.celery import email_tasks
|
||||
email_tasks.send_email.delay(user.full_name, user.email, subject, text, html)
|
||||
|
||||
|
||||
def user_subscription_changed(user: UserClass, *, grant_roles: set, revoke_roles: set):
|
||||
if user.has_cap('subscriber') and 'has_subscription' in grant_roles:
|
||||
log.info('user %s just got a new subscription', user.email)
|
||||
queue_welcome_mail(user)
|
||||
|
||||
|
||||
def setup_app(app):
|
||||
from pillar.api.blender_cloud import subscription
|
||||
subscription.user_subscription_updated.connect(user_subscription_changed)
|
39
cloud/eve_hooks.py
Normal file
39
cloud/eve_hooks.py
Normal file
@@ -0,0 +1,39 @@
|
||||
import logging
|
||||
import typing
|
||||
|
||||
from pillar.auth import UserClass
|
||||
|
||||
from . import email
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def welcome_new_user(user_doc: dict):
|
||||
"""Sends a welcome email to a new user."""
|
||||
|
||||
user_email = user_doc.get('email')
|
||||
if not user_email:
|
||||
log.warning('user %s has no email address', user_doc.get('_id', '-no-id-'))
|
||||
return
|
||||
|
||||
# Only send mail to new users when they actually are subscribers.
|
||||
user = UserClass.construct('', user_doc)
|
||||
if not (user.has_cap('subscriber') or user.has_cap('can-renew-subscription')):
|
||||
log.debug('user %s is new, but not a subscriber, so no email for them.', user_email)
|
||||
return
|
||||
|
||||
email.queue_welcome_mail(user)
|
||||
|
||||
|
||||
def welcome_new_users(user_docs: typing.List[dict]):
|
||||
"""Sends a welcome email to new users."""
|
||||
|
||||
for user_doc in user_docs:
|
||||
try:
|
||||
welcome_new_user(user_doc)
|
||||
except Exception:
|
||||
log.exception('error sending welcome mail to user %s', user_doc)
|
||||
|
||||
|
||||
def setup_app(app):
|
||||
app.on_inserted_users += welcome_new_users
|
@@ -1,10 +1,10 @@
|
||||
import functools
|
||||
import itertools
|
||||
import json
|
||||
import logging
|
||||
import typing
|
||||
|
||||
from flask_login import current_user, login_required
|
||||
import flask
|
||||
from flask import Blueprint, render_template, redirect, session, url_for, abort, flash
|
||||
from pillarsdk import Node, Project, User, exceptions as sdk_exceptions, Group
|
||||
from pillarsdk.exceptions import ResourceNotFound
|
||||
@@ -372,6 +372,31 @@ def privacy():
|
||||
return render_template('privacy.html')
|
||||
|
||||
|
||||
@blueprint.route('/emails/welcome.send')
|
||||
@login_required
|
||||
def emails_welcome_send():
|
||||
from cloud import email
|
||||
email.queue_welcome_mail(current_user)
|
||||
return f'queued mail to {current_user.email}'
|
||||
|
||||
|
||||
@blueprint.route('/emails/welcome.html')
|
||||
@login_required
|
||||
def emails_welcome_html():
|
||||
return render_template('emails/welcome.html',
|
||||
subject='Welcome to Blender Cloud',
|
||||
user=current_user)
|
||||
|
||||
|
||||
@blueprint.route('/emails/welcome.txt')
|
||||
@login_required
|
||||
def emails_welcome_txt():
|
||||
txt = render_template('emails/welcome.txt',
|
||||
subject='Welcome to Blender Cloud',
|
||||
user=current_user)
|
||||
return flask.Response(txt, content_type='text/plain; charset=utf-8')
|
||||
|
||||
|
||||
def setup_app(app):
|
||||
global _homepage_context
|
||||
cached = app.cache.cached(timeout=300)
|
||||
|
@@ -126,11 +126,14 @@ def insert_or_fetch_user(wh_payload: dict) -> typing.Optional[dict]:
|
||||
provider='blender-id',
|
||||
full_name=wh_payload['full_name'])
|
||||
|
||||
user_doc['roles'] = [subscription.ROLES_BID_TO_PILLAR[r]
|
||||
for r in wh_payload.get('roles', [])
|
||||
if r in subscription.ROLES_BID_TO_PILLAR]
|
||||
|
||||
# Figure out the user's eventual roles. These aren't stored in the document yet,
|
||||
# because that's handled by the badger service.
|
||||
eventual_roles = [subscription.ROLES_BID_TO_PILLAR[r]
|
||||
for r in wh_payload.get('roles', [])
|
||||
if r in subscription.ROLES_BID_TO_PILLAR]
|
||||
user_ob = UserClass.construct('', user_doc)
|
||||
user_ob.roles = eventual_roles
|
||||
user_ob.collect_capabilities()
|
||||
create = (user_ob.has_cap('subscriber') or
|
||||
user_ob.has_cap('can-renew-subscription') or
|
||||
current_app.org_manager.user_is_unknown_member(email))
|
||||
@@ -179,19 +182,23 @@ def user_modified():
|
||||
return '', 204
|
||||
|
||||
# Use direct database updates to change the email and full name.
|
||||
# Also updates the db_user dict so that local_user below will have
|
||||
# the updated information.
|
||||
updates = {}
|
||||
if db_user['email'] != payload['email']:
|
||||
my_log.info('User changed email from %s to %s', payload['old_email'], payload['email'])
|
||||
updates['email'] = payload['email']
|
||||
db_user['email'] = payload['email']
|
||||
|
||||
if payload['full_name'] != db_user['full_name']:
|
||||
if db_user['full_name'] != payload['full_name']:
|
||||
my_log.info('User changed full name from %r to %r',
|
||||
payload['full_name'], db_user['full_name'])
|
||||
db_user['full_name'], payload['full_name'])
|
||||
if payload['full_name']:
|
||||
updates['full_name'] = payload['full_name']
|
||||
else:
|
||||
# Fall back to the username when the full name was erased.
|
||||
updates['full_name'] = db_user['username']
|
||||
db_user['full_name'] = updates['full_name']
|
||||
|
||||
if updates:
|
||||
users_coll = current_app.db('users')
|
||||
|
Reference in New Issue
Block a user