diff --git a/TODO b/TODO index e69de29..a759652 100644 --- a/TODO +++ b/TODO @@ -0,0 +1,7 @@ +* use flask.instance_path to get/store configuration. See http://flask.pocoo.org/docs/config/#instance-folders +* Attach the current projec to g and modify the url_for to use it. http://flask.pocoo.org/docs/patterns/urlprocessors/ +* Use class based views to factorize the code if there is some code to factorize, see http://flask.pocoo.org/docs/views/ +* Use request.args.get('next') to redirect when authenticating +* Move the flask app to __init__.py (http://flask.pocoo.org/docs/patterns/packages/) +* Eventually move the url definition into a specific section +* Render templates automatically using a decorator. see http://stackoverflow.com/questions/7054099/using-flask-blueprint-for-some-static-pages/7056374#7056374 diff --git a/budget/templates/add_bill.html b/budget/templates/add_bill.html index d844b6a..5b3a768 100644 --- a/budget/templates/add_bill.html +++ b/budget/templates/add_bill.html @@ -1,14 +1,14 @@ {% extends "layout.html" %} {% block top_menu %} -Back to the list +Back to the list {% endblock %} {% block content %}

Add a new bill

-
+ {{ forms.add_bill(form) }}
diff --git a/budget/templates/add_member.html b/budget/templates/add_member.html index 8d24aee..5739791 100644 --- a/budget/templates/add_member.html +++ b/budget/templates/add_member.html @@ -1,6 +1,6 @@ {% extends "layout.html" %} {% block content %} -
+ {{ forms.add_member(form) }}
{% endblock %} diff --git a/budget/templates/edit_bill.html b/budget/templates/edit_bill.html index c78eb09..03a1a26 100644 --- a/budget/templates/edit_bill.html +++ b/budget/templates/edit_bill.html @@ -1,14 +1,14 @@ {% extends "layout.html" %} {% block top_menu %} -Back to the list +Back to the list {% endblock %} {% block content %}

Edit a bill

-
+ {{ forms.add_bill(form) }}
diff --git a/budget/templates/invitation_mail b/budget/templates/invitation_mail index 53991ed..83a7840 100644 --- a/budget/templates/invitation_mail +++ b/budget/templates/invitation_mail @@ -1,10 +1,10 @@ Hi, -Someone using the email adress {{ email }} invited you to share your expenses for {{ project.name }} on our application. +Someone using the email adress {{ g.project.contact_email }} invited you to share your expenses for {{ g.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 }}". +You can access it here: {{ SITE_URL }}{{ url_for("list_bills") }}, the password is "{{ g.project.password }}". Enjoy, Some weird guys diff --git a/budget/templates/list_bills.html b/budget/templates/list_bills.html index fe564e1..94b0f8f 100644 --- a/budget/templates/list_bills.html +++ b/budget/templates/list_bills.html @@ -42,24 +42,24 @@ $('.members li').hover(function(){ {% block content %}
-
+ {{ forms.add_member(member_form) }}
- Add a bill + Add a bill - + {% if bills.count() > 0 %} @@ -72,15 +72,15 @@ $('.members li').hover(function(){ - + {% endfor %}
{{ bill.what }} {% for ower in bill.owers %}{{ ower.name }} {% endfor %} {{ bill.amount }} ({{ bill.pay_each() }} each)edit - deleteedit + delete
{% else %} -

Nothing to list yet. You probably want to add a bill ?

+

Nothing to list yet. You probably want to add a bill ?

{% endif %}
{% endblock %} diff --git a/budget/templates/send_invites.html b/budget/templates/send_invites.html index f618803..fa46c81 100644 --- a/budget/templates/send_invites.html +++ b/budget/templates/send_invites.html @@ -3,12 +3,12 @@

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

+

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

+

{{ form.submit }} No, thanks

{% endblock %} diff --git a/budget/web.py b/budget/web.py index e952109..14e058c 100644 --- a/budget/web.py +++ b/budget/web.py @@ -1,8 +1,8 @@ from collections import defaultdict -from flask import (Flask, session, request, redirect, url_for, render_template, - flash) +from flask import * from flaskext.mail import Mail, Message +from werkzeug.routing import RequestRedirect # local modules from models import db, Project, Person, Bill @@ -35,8 +35,6 @@ def authenticate(redirect_url=None): form = AuthenticationForm() project_id = form.id.data - - redirect_url = redirect_url or url_for("list_bills", project_id=project_id) project = Project.query.get(project_id) create_project = False # We don't want to create the project by default if not project: @@ -47,6 +45,7 @@ def authenticate(redirect_url=None): else: # if credentials are already in session, redirect if project_id in session and project.password == session[project_id]: + redirect_url = redirect_url or url_for("list_bills") return redirect(redirect_url) # else process the form @@ -62,6 +61,8 @@ def authenticate(redirect_url=None): session["projects"].insert(0, (project_id, project.name)) session[project_id] = form.password.data session.update() + setattr(g, 'project', project) + redirect_url = redirect_url or url_for("list_bills") return redirect(redirect_url) return render_template("authenticate.html", form=form, @@ -95,9 +96,32 @@ def exit(): session.clear() return redirect(url_for("home")) -@app.route("//invite", methods=["GET", "POST"]) -@requires_auth -def invite(project): +@app.url_defaults +def add_project_id(endpoint, values): + if 'project_id' in values or not hasattr(g, 'project'): + return + if app.url_map.is_endpoint_expecting(endpoint, 'project_id'): + values['project_id'] = g.project.id + +@app.url_value_preprocessor +def pull_project(endpoint, values): + if not values: + values = {} + project_id = values.pop('project_id', None) + if project_id: + project = Project.query.get(project_id) + if not project: + raise RequestRedirect(url_for("create_project")) + if project.id in session and session[project.id] == project.password: + # add project into kwargs and call the original function + g.project = project + else: + # redirect to authentication page + raise RequestRedirect( + url_for("authenticate", redirect_url=request.url)) + +@app.route("//invite", methods=["GET", "POST"]) +def invite(): form = InviteForm() @@ -105,51 +129,46 @@ def invite(project): if form.validate(): # send the email - message_body = render_template("invitation_mail", - email=project.contact_email, project=project) + message_body = render_template("invitation_mail") message_title = "You have been invited to share your"\ - + " expenses for %s" % project.name + + " expenses for %s" % g.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 redirect(url_for("list_bills")) - return render_template("send_invites.html", form=form, project=project) + return render_template("send_invites.html", form=form) -@app.route("//") -@requires_auth -def list_bills(project): +@app.route("//") +def list_bills(): bills = Bill.query.join(Person, Project)\ .filter(Bill.payer_id == Person.id)\ .filter(Person.project_id == Project.id)\ - .filter(Project.id == project.id)\ + .filter(Project.id == g.project.id)\ .order_by(Bill.date.desc()) return render_template("list_bills.html", - bills=bills, project=project, - member_form=MemberForm(project), - bill_form=get_billform_for(project) + bills=bills, member_form=MemberForm(g.project), + bill_form=get_billform_for(g.project) ) -@app.route("//members/add", methods=["GET", "POST"]) -@requires_auth -def add_member(project): +@app.route("//members/add", methods=["GET", "POST"]) +def add_member(): # FIXME manage form errors on the list_bills page - form = MemberForm(project) + form = MemberForm(g.project) if request.method == "POST": if form.validate(): - db.session.add(Person(name=form.name.data, project=project)) + db.session.add(Person(name=form.name.data, project=g.project)) db.session.commit() - return redirect(url_for("list_bills", project_id=project.id)) - return render_template("add_member.html", form=form, project=project) + return redirect(url_for("list_bills")) + return render_template("add_member.html", form=form) -@app.route("//members//delete", methods=["GET", "POST"]) -@requires_auth -def remove_member(project, member_id): +@app.route("//members//delete", methods=["GET", "POST"]) +def remove_member(member_id): person = Person.query.get_or_404(member_id) - if person.project == project: + if person.project == g.project: if not person.has_bills(): db.session.delete(person) db.session.commit() @@ -158,12 +177,11 @@ def remove_member(project, member_id): person.activated = False db.session.commit() flash("User '%s' has been desactivated" % person.name) - return redirect(url_for("list_bills", project_id=project.id)) + return redirect(url_for("list_bills")) -@app.route("//add", methods=["GET", "POST"]) -@requires_auth -def add_bill(project): - form = get_billform_for(project) +@app.route("//add", methods=["GET", "POST"]) +def add_bill(): + form = get_billform_for(g.project) if request.method == 'POST': if form.validate(): bill = Bill() @@ -171,47 +189,43 @@ def add_bill(project): db.session.commit() flash("The bill has been added") - return redirect(url_for('list_bills', project_id=project.id)) + return redirect(url_for('list_bills')) - return render_template("add_bill.html", form=form, project=project) + return render_template("add_bill.html", form=form) -@app.route("//delete/") -@requires_auth -def delete_bill(project, bill_id): +@app.route("//delete/") +def delete_bill(bill_id): bill = Bill.query.get_or_404(bill_id) db.session.delete(bill) db.session.commit() flash("The bill has been deleted") - return redirect(url_for('list_bills', project_id=project.id)) + return redirect(url_for('list_bills')) -@app.route("//edit/", methods=["GET", "POST"]) -@requires_auth -def edit_bill(project, bill_id): +@app.route("//edit/", methods=["GET", "POST"]) +def edit_bill(bill_id): bill = Bill.query.get_or_404(bill_id) - form = get_billform_for(project, set_default=False) + form = get_billform_for(g.project, set_default=False) if request.method == 'POST' and form.validate(): form.save(bill) db.session.commit() flash("The bill has been modified") - return redirect(url_for('list_bills', project_id=project.id)) + return redirect(url_for('list_bills')) form.fill(bill) - return render_template("edit_bill.html", form=form, project=project, bill_id=bill_id) + return render_template("edit_bill.html", form=form, bill_id=bill_id) -@app.route("//compute") -@requires_auth -def compute_bills(project): +@app.route("//compute") +def compute_bills(): """Compute the sum each one have to pay to each other and display it""" - return render_template("compute_bills.html", project=project) + return render_template("compute_bills.html") -@app.route("//reset") -@requires_auth -def reset_bills(project): +@app.route("//reset") +def reset_bills(): """Reset the list of bills""" # FIXME replace with the archive feature # get all the bills which are not processed