From 87ea04505924a0869e3c806cdf4de3defc1c034c Mon Sep 17 00:00:00 2001 From: Alexis Metaireau Date: Sat, 30 Jul 2011 15:46:53 +0200 Subject: [PATCH] Invite people after project creation. Uses the flask-mail extension. --- budget/default_settings.py | 2 ++ budget/forms.py | 10 ++++++++ budget/templates/display_errors.html | 5 ++++ budget/templates/invitation_mail | 10 ++++++++ budget/templates/send_invites.html | 14 +++++++++++ budget/web.py | 36 ++++++++++++++++++++++++---- 6 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 budget/templates/display_errors.html create mode 100644 budget/templates/invitation_mail create mode 100644 budget/templates/send_invites.html diff --git a/budget/default_settings.py b/budget/default_settings.py index 208f859..ff61010 100644 --- a/budget/default_settings.py +++ b/budget/default_settings.py @@ -2,3 +2,5 @@ DEBUG = True SQLALCHEMY_DATABASE_URI = 'sqlite:///budget.db' SQLACHEMY_ECHO = DEBUG SECRET_KEY = "tralala" + +DEFAULT_MAIL_SENDER = ("Budget manager", "budget@notmyidea.org") diff --git a/budget/forms.py b/budget/forms.py index 45da1f3..0d9dae5 100644 --- a/budget/forms.py +++ b/budget/forms.py @@ -47,3 +47,13 @@ class MemberForm(Form): if Person.query.filter(Person.name == field.data)\ .filter(Person.project == form.project).all(): raise ValidationError("This project already have this member") + +class InviteForm(Form): + emails = TextAreaField("People to notify") + submit = SubmitField("Send invites") + + def validate_emails(form, field): + validator = Email() + for email in [email.strip() for email in form.emails.data.split(",")]: + if not validator.regex.match(email): + raise ValidationError("The email %s is not valid" % email) diff --git a/budget/templates/display_errors.html b/budget/templates/display_errors.html new file mode 100644 index 0000000..15039a2 --- /dev/null +++ b/budget/templates/display_errors.html @@ -0,0 +1,5 @@ +{% for errors in form.errors.values() %} + {% for error in errors %} +

{{error}}

+ {% endfor %} +{% endfor %} diff --git a/budget/templates/invitation_mail b/budget/templates/invitation_mail new file mode 100644 index 0000000..53991ed --- /dev/null +++ b/budget/templates/invitation_mail @@ -0,0 +1,10 @@ +Hi, + +Someone using the email adress {{ email }} invited you to share your expenses for {{ project.name }} on our application. + +It's as simple as saying what did you paid for, for who, and how much did it cost you, we are caring about the rest. + +You can access it here: {{ SITE_URL }}{{ url_for("list_bills", project_id=project.id) }}, the password is "{{ project.password }}". + +Enjoy, +Some weird guys diff --git a/budget/templates/send_invites.html b/budget/templates/send_invites.html new file mode 100644 index 0000000..f618803 --- /dev/null +++ b/budget/templates/send_invites.html @@ -0,0 +1,14 @@ +{% extends "layout.html" %} +{% block content %} +

Invite people to join this project

+

Specify a (coma separated) list of email adresses you want to notify about the +creation of this budget management project and we will send them an email for you.

+

If you prefer, you can skip this step and notify them yourself

+ +{% include "display_errors.html" %} +
+ {{ form.hidden_tag() }} +

{{ form.emails.label }}
{{ form.emails }}

+

{{ form.submit }} No, thanks

+
+{% endblock %} diff --git a/budget/web.py b/budget/web.py index 0f5a28b..10b2d4a 100644 --- a/budget/web.py +++ b/budget/web.py @@ -1,12 +1,15 @@ -from flask import Flask, session, request, redirect, url_for, render_template +from flask import (Flask, session, request, redirect, url_for, render_template, + flash) +from flaskext.mail import Mail, Message # local modules from models import db, Project, Person, Bill -from forms import ProjectForm, AuthenticationForm, BillForm, MemberForm +from forms import ProjectForm, AuthenticationForm, BillForm, MemberForm, InviteForm from utils import get_billform_for, requires_auth # create the application, initialize stuff app = Flask(__name__) +mail = Mail() @app.route("/") def home(): @@ -23,6 +26,7 @@ def authenticate(redirect_url=None): redirect_url = redirect_url or url_for("list_bills", project_id=project_id) project = Project.query.get(project_id) if not project: + flash("This project doesn't exist (yet). You can create it by filling this form") return redirect(url_for("create_project", project_id=project_id)) # if credentials are already in session, redirect @@ -35,6 +39,8 @@ def authenticate(redirect_url=None): if not form.password.data == project.password: form.errors['password'] = ["The password is not the right one"] else: + # maintain a list of visited projects + session["projects"].append(project_id) session[project_id] = form.password.data session.update() return redirect(redirect_url) @@ -69,11 +75,27 @@ def quit(): session.clear() return redirect(url_for("home")) -@app.route("//invite") +@app.route("//invite", methods=["GET", "POST"]) @requires_auth def invite(project): - # FIXME create a real page: form + send emails - return "invite ppl" + + form = InviteForm() + + if request.method == "POST": + if form.validate(): + # send the email + + message_body = render_template("invitation_mail", + email=project.contact_email, project=project) + + message_title = "You have been invited to share your expenses for %s" % project.name + msg = Message(message_title, + body=message_body, + recipients=[email.strip() for email in form.emails.data.split(",")]) + mail.send(msg) + return redirect(url_for("list_bills", project_id=project.id)) + + return render_template("send_invites.html", form=form, project=project) @app.route("//") @requires_auth @@ -173,10 +195,14 @@ def debug(): def main(): app.config.from_object("default_settings") + # db db.init_app(app) db.app = app db.create_all() + # mail + mail.init_app(app) + app.run(host="0.0.0.0", debug=True) if __name__ == '__main__':