aboutsummaryrefslogtreecommitdiff
path: root/budget
diff options
context:
space:
mode:
Diffstat (limited to 'budget')
-rw-r--r--budget/default_settings.py2
-rw-r--r--budget/forms.py10
-rw-r--r--budget/templates/display_errors.html5
-rw-r--r--budget/templates/invitation_mail10
-rw-r--r--budget/templates/send_invites.html14
-rw-r--r--budget/web.py36
6 files changed, 72 insertions, 5 deletions
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 %}
+ <p class="error">{{error}}</p>
+ {% 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 %}
+<h2>Invite people to join this project</h2>
+<p>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.</p>
+<p>If you prefer, you can <a href="{{ url_for("list_bills", project_id=project.id) }}">skip this step</a> and notify them yourself</p>
+
+{% include "display_errors.html" %}
+<form method="post" accept-charset="utf-8">
+ {{ form.hidden_tag() }}
+ <p>{{ form.emails.label }}<br /> {{ form.emails }}</p>
+ <p>{{ form.submit }} <a href="{{ url_for("list_bills", project_id=project.id) }}">No, thanks</a></p>
+</form>
+{% 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("/<string:project_id>/invite")
+@app.route("/<string:project_id>/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("/<string:project_id>/")
@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__':