From 76ece294dbbfdb38038f74472cab72f9e6cdf132 Mon Sep 17 00:00:00 2001 From: Francesco Siddi Date: Wed, 16 Jul 2014 14:38:26 +0200 Subject: [PATCH] Email framework Notifications will be sent when someone submits an application. --- blender-bfct/application/__init__.py | 2 ++ blender-bfct/application/controllers/main.py | 14 ++++---- blender-bfct/application/decorators.py | 7 ++++ blender-bfct/application/emails.py | 34 +++++++++++++++++++ blender-bfct/application/helpers.py | 8 +++++ blender-bfct/application/models/users.py | 2 +- blender-bfct/application/templates/apply.html | 3 +- .../templates/email/new_submission.html | 4 +++ .../templates/email/new_submission.txt | 4 +++ 9 files changed, 70 insertions(+), 8 deletions(-) create mode 100644 blender-bfct/application/decorators.py create mode 100644 blender-bfct/application/emails.py create mode 100644 blender-bfct/application/templates/email/new_submission.html create mode 100644 blender-bfct/application/templates/email/new_submission.txt diff --git a/blender-bfct/application/__init__.py b/blender-bfct/application/__init__.py index fa147d9..a192228 100644 --- a/blender-bfct/application/__init__.py +++ b/blender-bfct/application/__init__.py @@ -1,5 +1,6 @@ from flask import Flask from flask.ext.sqlalchemy import SQLAlchemy +from flask.ext.mail import Mail # Create app app = Flask(__name__) @@ -8,6 +9,7 @@ app.config.from_object(config.Development) # Create database connection object db = SQLAlchemy(app) +mail = Mail(app) from controllers import main from controllers import admin diff --git a/blender-bfct/application/controllers/main.py b/blender-bfct/application/controllers/main.py index 8af89d0..796939f 100644 --- a/blender-bfct/application/controllers/main.py +++ b/blender-bfct/application/controllers/main.py @@ -1,11 +1,12 @@ from application import app, db +from application.emails import send_email_notification_new_submission from application.models.users import * from application.models.applications import Application, Skill from flask import render_template, redirect, url_for, request, flash from flask.ext.security import login_required from flask.ext.security.core import current_user -from sqlalchemy.orm.exc import MultipleResultsFound +from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound from flask_wtf import Form from wtforms import TextField, TextAreaField, BooleanField, SelectMultipleField from wtforms.validators import DataRequired @@ -46,9 +47,9 @@ def apply(): form = ApplicationForm() form.skills.choices = [(s.id, s.name) for s in Skill.query.all()] if form.validate_on_submit(): - print 'validating' application = Application( blender_id=current_user.id, + network_profile=form.website.data, website=form.website.data, city_country=form.city_country.data, institution_name=form.institution_name.data, @@ -62,6 +63,7 @@ def apply(): application.skills.append(s) db.session.add(application) db.session.commit() + send_email_notification_new_submission(application) return redirect(url_for('my_application')) # print form.errors return render_template('apply.html', @@ -77,8 +79,8 @@ def my_application(): except MultipleResultsFound: flash('You have submitted more than one application. Get in touch with support@blendernetwork.org.') return render_template('index.html') - if not application: + except NoResultFound: return redirect(url_for('apply')) - else: - return render_template('my_application.html', - application=application) + + return render_template('my_application.html', + application=application) diff --git a/blender-bfct/application/decorators.py b/blender-bfct/application/decorators.py new file mode 100644 index 0000000..720faa7 --- /dev/null +++ b/blender-bfct/application/decorators.py @@ -0,0 +1,7 @@ +from threading import Thread + +def async(f): + def wrapper(*args, **kwargs): + thr = Thread(target = f, args = args, kwargs = kwargs) + thr.start() + return wrapper diff --git a/blender-bfct/application/emails.py b/blender-bfct/application/emails.py new file mode 100644 index 0000000..39bef94 --- /dev/null +++ b/blender-bfct/application/emails.py @@ -0,0 +1,34 @@ +from flask import render_template +from flask.ext.mail import Message +from application import mail +from application import app +from decorators import async + +from application.models.users import user_datastore +from application.helpers import get_board_members_emails + +from flask.ext.security import current_user + + +@async +def send_async_email(msg): + with app.app_context(): + mail.send(msg) + + +def send_email(subject, sender, recipients, text_body, html_body): + msg = Message(subject, sender = sender, recipients = recipients) + msg.body = text_body + msg.html = html_body + send_async_email(msg) + + +def send_email_notification_new_submission(application): + board_members = get_board_members_emails() + send_email("[BFCT] New BFCT application submitted", + 'bfct-robot@blender.org', + board_members, + render_template("email/new_submission.txt", + application=application), + render_template("email/new_submission.html", + application=application)) diff --git a/blender-bfct/application/helpers.py b/blender-bfct/application/helpers.py index 85d298e..6cc4003 100644 --- a/blender-bfct/application/helpers.py +++ b/blender-bfct/application/helpers.py @@ -1,3 +1,5 @@ +from application.models.users import User, Role + def pretty_date(time=False): """ Get a datetime object or a int() Epoch timestamp and return a @@ -40,3 +42,9 @@ def pretty_date(time=False): if day_diff <= 365: return str(day_diff/30) + " months ago" return str(day_diff/365) + " years ago" + + +def get_board_members_emails(): + board_members = User.query.join(Role, User.roles).filter(Role.name == 'bfct_board').all() + board_members_emails = [member.email for member in board_members] + return board_members_emails diff --git a/blender-bfct/application/models/users.py b/blender-bfct/application/models/users.py index 7f4e264..a2bdbd4 100644 --- a/blender-bfct/application/models/users.py +++ b/blender-bfct/application/models/users.py @@ -31,7 +31,7 @@ class Role(db.Model, RoleMixin): # Define models roles_users = db.Table('roles_users', db.Column('user_id', db.Integer(), db.ForeignKey(User.id)), - db.Column('role_id', db.Integer(), db.ForeignKey('role.id')), + db.Column('role_id', db.Integer(), db.ForeignKey(Role.id)), info={'bind_key': 'users'}) # Setup Flask-Security diff --git a/blender-bfct/application/templates/apply.html b/blender-bfct/application/templates/apply.html index b3d131f..6ec9350 100755 --- a/blender-bfct/application/templates/apply.html +++ b/blender-bfct/application/templates/apply.html @@ -108,8 +108,9 @@
- {{ form.bio_message(class='form-control', id='editor1', placeholder='Tell us a bit about yourself and why you want to be a BFCT') }} + {{ form.bio_message(class='form-control', id='editor1', placeholder='Tell us a bit about yourself and why you want to be a BFCT') }} +

diff --git a/blender-bfct/application/templates/email/new_submission.html b/blender-bfct/application/templates/email/new_submission.html new file mode 100644 index 0000000..3e25f1e --- /dev/null +++ b/blender-bfct/application/templates/email/new_submission.html @@ -0,0 +1,4 @@ +

Hello!

+

A new BFCT application awaits your review! Check it out at the BFCT portal.

+ +

The BFCT robot

diff --git a/blender-bfct/application/templates/email/new_submission.txt b/blender-bfct/application/templates/email/new_submission.txt new file mode 100644 index 0000000..759e8fb --- /dev/null +++ b/blender-bfct/application/templates/email/new_submission.txt @@ -0,0 +1,4 @@ +Hello! +A new BFCT application awaits your review! Check it out at http://www.blender.org/certification{{url_for('applications.view', id=application.id)}}. + +The BFCT robot