mirror of
https://github.com/YunoHost-Apps/ihatemoney_ynh.git
synced 2024-09-03 19:26:15 +02:00
Fix #24 on Authentication and New project forms usability.
- Do not display anymore the identifier field in home. - Let the user enter the id if the slug generated from project name already exists as a project id. - Moved get_billform_for from 'utils' to 'forms', to avoid issue (was 'from forms import ...' into utils, and 'from utils import ...' into forms, which causeed an error).
This commit is contained in:
parent
f48fc22335
commit
88cd2f8675
5 changed files with 62 additions and 29 deletions
|
@ -2,6 +2,8 @@ from flaskext.wtf import *
|
||||||
from wtforms.widgets import html_params
|
from wtforms.widgets import html_params
|
||||||
from models import Project, Person, Bill
|
from models import Project, Person, Bill
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from jinja2 import Markup
|
||||||
|
from utils import slugify
|
||||||
|
|
||||||
|
|
||||||
def select_multi_checkbox(field, ul_class='', **kwargs):
|
def select_multi_checkbox(field, ul_class='', **kwargs):
|
||||||
|
@ -18,16 +20,41 @@ def select_multi_checkbox(field, ul_class='', **kwargs):
|
||||||
return u''.join(html)
|
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):
|
class ProjectForm(Form):
|
||||||
name = TextField("Project name", validators=[Required()])
|
name = TextField("Project name", validators=[Required()])
|
||||||
id = TextField("Project identifier", 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()])
|
contact_email = TextField("Email", validators=[Required(), Email()])
|
||||||
submit = SubmitField("Create the project")
|
submit = SubmitField("Create the project")
|
||||||
|
|
||||||
def validate_id(form, field):
|
def validate_id(form, field):
|
||||||
if Project.query.get(field.data):
|
form.id.data = slugify(field.data)
|
||||||
raise ValidationError("This project id is already used")
|
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.
|
||||||
|
<br />
|
||||||
|
We tried to generate an identifier for you but
|
||||||
|
a projet with this identifier already exists.
|
||||||
|
<br />
|
||||||
|
Please create a new identifier you will be able
|
||||||
|
to remember.
|
||||||
|
"""))
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""Create a new project with the information given by this form.
|
"""Create a new project with the information given by this form.
|
||||||
|
@ -42,7 +69,7 @@ class ProjectForm(Form):
|
||||||
|
|
||||||
class AuthenticationForm(Form):
|
class AuthenticationForm(Form):
|
||||||
id = TextField("Project identifier", validators=[Required()])
|
id = TextField("Project identifier", validators=[Required()])
|
||||||
password = PasswordField("Password", validators=[Required()])
|
password = PasswordField("Private code", validators=[Required()])
|
||||||
submit = SubmitField("Get in")
|
submit = SubmitField("Get in")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from web import main, db, mail
|
from web import main, db, mail
|
||||||
import api
|
#import api
|
||||||
|
|
||||||
from flask import *
|
from flask import *
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,11 @@
|
||||||
</div> <!-- /clearfix -->
|
</div> <!-- /clearfix -->
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro submit(field, cancel=False) -%}
|
{% macro submit(field, cancel=False, home=False) -%}
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
|
{% if home %}
|
||||||
|
<a href="{{ url_for(".home") }}" class="btn">Back Home</a>
|
||||||
|
{% endif %}
|
||||||
<button type="submit" class="btn primary">{{ field.name }}</button>
|
<button type="submit" class="btn primary">{{ field.name }}</button>
|
||||||
{% if cancel %}
|
{% if cancel %}
|
||||||
<button id="cancel-form" type="reset" class="btn">Cancel</button>
|
<button id="cancel-form" type="reset" class="btn">Cancel</button>
|
||||||
|
@ -42,12 +45,14 @@
|
||||||
|
|
||||||
{% include "display_errors.html" %}
|
{% include "display_errors.html" %}
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
{{ input(form.name) }}
|
{% if not home %}
|
||||||
{{ input(form.id) }}
|
{{ input(form.id) }}
|
||||||
|
{% endif %}
|
||||||
|
{{ input(form.name) }}
|
||||||
{{ input(form.password) }}
|
{{ input(form.password) }}
|
||||||
{{ input(form.contact_email) }}
|
{{ input(form.contact_email) }}
|
||||||
{% if not home %}
|
{% if not home %}
|
||||||
{{ submit(form.submit) }}
|
{{ submit(form.submit, home=True) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
|
@ -1,24 +1,19 @@
|
||||||
|
import re
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from flask import redirect, url_for, session, request
|
from flask import redirect, url_for, session, request
|
||||||
from werkzeug.routing import HTTPException, RoutingException
|
from werkzeug.routing import HTTPException, RoutingException
|
||||||
|
|
||||||
from models import Bill, Project
|
def slugify(value):
|
||||||
from forms import BillForm
|
"""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()
|
if type(value) == unicode:
|
||||||
form.payed_for.choices = form.payer.choices = [(str(m.id), m.name) for m in project.active_members]
|
import unicodedata
|
||||||
form.payed_for.default = [str(m.id) for m in project.active_members]
|
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
|
||||||
|
value = unicode(re.sub('[^\w\s-]', '', value).strip().lower())
|
||||||
if set_default and request.method == "GET":
|
return re.sub('[-\s]+', '-', value)
|
||||||
form.set_default()
|
|
||||||
return form
|
|
||||||
|
|
||||||
class Redirect303(HTTPException, RoutingException):
|
class Redirect303(HTTPException, RoutingException):
|
||||||
"""Raise if the map requests a redirect. This is for example the case if
|
"""Raise if the map requests a redirect. This is for example the case if
|
||||||
|
|
|
@ -5,9 +5,9 @@ from flaskext.mail import Mail, Message
|
||||||
|
|
||||||
# local modules
|
# local modules
|
||||||
from models import db, Project, Person, Bill
|
from models import db, Project, Person, Bill
|
||||||
from forms import (ProjectForm, AuthenticationForm, BillForm, MemberForm,
|
from forms import (get_billform_for, ProjectForm, AuthenticationForm, BillForm,
|
||||||
InviteForm, CreateArchiveForm)
|
MemberForm, InviteForm, CreateArchiveForm)
|
||||||
from utils import get_billform_for, Redirect303
|
from utils import Redirect303
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The blueprint for the web interface.
|
The blueprint for the web interface.
|
||||||
|
@ -111,6 +111,12 @@ def create_project():
|
||||||
form.name.data = request.values['project_id']
|
form.name.data = request.values['project_id']
|
||||||
|
|
||||||
if request.method == "POST":
|
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():
|
if form.validate():
|
||||||
# save the object in the db
|
# save the object in the db
|
||||||
project = form.save()
|
project = form.save()
|
||||||
|
@ -178,7 +184,7 @@ def list_bills():
|
||||||
bills = g.project.get_bills()
|
bills = g.project.get_bills()
|
||||||
return render_template("list_bills.html",
|
return render_template("list_bills.html",
|
||||||
bills=bills, member_form=MemberForm(g.project),
|
bills=bills, member_form=MemberForm(g.project),
|
||||||
bill_form=get_billform_for(g.project)
|
bill_form=get_billform_for(request, g.project)
|
||||||
)
|
)
|
||||||
|
|
||||||
@main.route("/<project_id>/members/add", methods=["GET", "POST"])
|
@main.route("/<project_id>/members/add", methods=["GET", "POST"])
|
||||||
|
@ -224,7 +230,7 @@ def remove_member(member_id):
|
||||||
|
|
||||||
@main.route("/<project_id>/add", methods=["GET", "POST"])
|
@main.route("/<project_id>/add", methods=["GET", "POST"])
|
||||||
def add_bill():
|
def add_bill():
|
||||||
form = get_billform_for(g.project)
|
form = get_billform_for(request, g.project)
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
if form.validate():
|
if form.validate():
|
||||||
bill = Bill()
|
bill = Bill()
|
||||||
|
@ -250,7 +256,7 @@ def delete_bill(bill_id):
|
||||||
@main.route("/<project_id>/edit/<int:bill_id>", methods=["GET", "POST"])
|
@main.route("/<project_id>/edit/<int:bill_id>", methods=["GET", "POST"])
|
||||||
def edit_bill(bill_id):
|
def edit_bill(bill_id):
|
||||||
bill = Bill.query.get_or_404(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():
|
if request.method == 'POST' and form.validate():
|
||||||
form.save(bill)
|
form.save(bill)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
Loading…
Reference in a new issue