diff --git a/budget/forms.py b/budget/forms.py
index 7ac48cc..3ab5f45 100644
--- a/budget/forms.py
+++ b/budget/forms.py
@@ -2,6 +2,8 @@ from flaskext.wtf import *
from wtforms.widgets import html_params
from models import Project, Person, Bill
from datetime import datetime
+from jinja2 import Markup
+from utils import slugify
def select_multi_checkbox(field, ul_class='', **kwargs):
@@ -18,16 +20,41 @@ def select_multi_checkbox(field, ul_class='', **kwargs):
return u''.join(html)
+def get_billform_for(request, project, set_default=True):
+ """Return an instance of BillForm configured for a particular project.
+
+ :set_default: if set to True, on GET methods (usually when we want to
+ display the default form, it will call set_default on it.
+
+ """
+ form = BillForm()
+ form.payed_for.choices = form.payer.choices = [(str(m.id), m.name) for m in project.active_members]
+ form.payed_for.default = [str(m.id) for m in project.active_members]
+
+ if set_default and request.method == "GET":
+ form.set_default()
+ return form
+
+
class ProjectForm(Form):
name = TextField("Project name", validators=[Required()])
id = TextField("Project identifier", validators=[Required()])
- password = PasswordField("Password", validators=[Required()])
+ password = PasswordField("Private code", validators=[Required()])
contact_email = TextField("Email", validators=[Required(), Email()])
submit = SubmitField("Create the project")
def validate_id(form, field):
- if Project.query.get(field.data):
- raise ValidationError("This project id is already used")
+ form.id.data = slugify(field.data)
+ if Project.query.get(form.id.data):
+ raise ValidationError(Markup("""The project identifier is used
+ to log in and for the URL of the project.
+
+ We tried to generate an identifier for you but
+ a projet with this identifier already exists.
+
+ Please create a new identifier you will be able
+ to remember.
+ """))
def save(self):
"""Create a new project with the information given by this form.
@@ -42,7 +69,7 @@ class ProjectForm(Form):
class AuthenticationForm(Form):
id = TextField("Project identifier", validators=[Required()])
- password = PasswordField("Password", validators=[Required()])
+ password = PasswordField("Private code", validators=[Required()])
submit = SubmitField("Get in")
diff --git a/budget/run.py b/budget/run.py
index b1fad19..c01dcdb 100644
--- a/budget/run.py
+++ b/budget/run.py
@@ -1,5 +1,5 @@
from web import main, db, mail
-import api
+#import api
from flask import *
diff --git a/budget/templates/forms.html b/budget/templates/forms.html
index b027763..ba915e8 100644
--- a/budget/templates/forms.html
+++ b/budget/templates/forms.html
@@ -17,8 +17,11 @@
{% endmacro %}
-{% macro submit(field, cancel=False) -%}
+{% macro submit(field, cancel=False, home=False) -%}
+ {% if home %}
+ Back Home
+ {% endif %}
{% if cancel %}
@@ -42,12 +45,14 @@
{% include "display_errors.html" %}
{{ form.hidden_tag() }}
- {{ input(form.name) }}
+ {% if not home %}
{{ input(form.id) }}
+ {% endif %}
+ {{ input(form.name) }}
{{ input(form.password) }}
{{ input(form.contact_email) }}
{% if not home %}
- {{ submit(form.submit) }}
+ {{ submit(form.submit, home=True) }}
{% endif %}
{% endmacro %}
diff --git a/budget/utils.py b/budget/utils.py
index 262ebfe..f4003eb 100644
--- a/budget/utils.py
+++ b/budget/utils.py
@@ -1,24 +1,19 @@
+import re
from functools import wraps
from flask import redirect, url_for, session, request
from werkzeug.routing import HTTPException, RoutingException
-from models import Bill, Project
-from forms import BillForm
+def slugify(value):
+ """Normalizes string, converts to lowercase, removes non-alpha characters,
+ and converts spaces to hyphens.
-def get_billform_for(project, set_default=True):
- """Return an instance of BillForm configured for a particular project.
-
- :set_default: if set to True, on GET methods (usually when we want to
- display the default form, it will call set_default on it.
-
+ Copy/Pasted from ametaireau/pelican/utils itself took from django sources.
"""
- form = BillForm()
- form.payed_for.choices = form.payer.choices = [(str(m.id), m.name) for m in project.active_members]
- form.payed_for.default = [str(m.id) for m in project.active_members]
-
- if set_default and request.method == "GET":
- form.set_default()
- return form
+ if type(value) == unicode:
+ import unicodedata
+ value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
+ value = unicode(re.sub('[^\w\s-]', '', value).strip().lower())
+ return re.sub('[-\s]+', '-', value)
class Redirect303(HTTPException, RoutingException):
"""Raise if the map requests a redirect. This is for example the case if
diff --git a/budget/web.py b/budget/web.py
index f72a686..cb8c4ac 100644
--- a/budget/web.py
+++ b/budget/web.py
@@ -5,9 +5,9 @@ from flaskext.mail import Mail, Message
# local modules
from models import db, Project, Person, Bill
-from forms import (ProjectForm, AuthenticationForm, BillForm, MemberForm,
- InviteForm, CreateArchiveForm)
-from utils import get_billform_for, Redirect303
+from forms import (get_billform_for, ProjectForm, AuthenticationForm, BillForm,
+ MemberForm, InviteForm, CreateArchiveForm)
+from utils import Redirect303
"""
The blueprint for the web interface.
@@ -111,6 +111,12 @@ def create_project():
form.name.data = request.values['project_id']
if request.method == "POST":
+ # At first, we don't want the user to bother with the identifier
+ # so it will automatically be missing because not displayed into the form
+ # Thus we fill it with the same value as the filled name, the validation will
+ # take care of the slug
+ if not form.id.data:
+ form.id.data = form.name.data
if form.validate():
# save the object in the db
project = form.save()
@@ -178,7 +184,7 @@ def list_bills():
bills = g.project.get_bills()
return render_template("list_bills.html",
bills=bills, member_form=MemberForm(g.project),
- bill_form=get_billform_for(g.project)
+ bill_form=get_billform_for(request, g.project)
)
@main.route("//members/add", methods=["GET", "POST"])
@@ -224,7 +230,7 @@ def remove_member(member_id):
@main.route("//add", methods=["GET", "POST"])
def add_bill():
- form = get_billform_for(g.project)
+ form = get_billform_for(request, g.project)
if request.method == 'POST':
if form.validate():
bill = Bill()
@@ -250,7 +256,7 @@ def delete_bill(bill_id):
@main.route("//edit/", methods=["GET", "POST"])
def edit_bill(bill_id):
bill = Bill.query.get_or_404(bill_id)
- form = get_billform_for(g.project, set_default=False)
+ form = get_billform_for(request, g.project, set_default=False)
if request.method == 'POST' and form.validate():
form.save(bill)
db.session.commit()