Use existing form errors to flash error messages

This is nice because we can reuse the translated strings of form error
messages in another context.

Suggested by Glandos.
This commit is contained in:
Baptiste Jonglez 2021-07-17 13:26:33 +02:00 committed by zorun
parent 439282356c
commit c69b8d66eb
2 changed files with 29 additions and 8 deletions

View file

@ -15,6 +15,7 @@ from babel.numbers import get_currency_name, get_currency_symbol
from flask import current_app, escape, redirect, render_template from flask import current_app, escape, redirect, render_template
from flask_babel import get_locale, lazy_gettext as _ from flask_babel import get_locale, lazy_gettext as _
import jinja2 import jinja2
from markupsafe import Markup
from werkzeug.routing import HTTPException, RoutingException from werkzeug.routing import HTTPException, RoutingException
@ -394,3 +395,23 @@ def render_localized_template(template_name_prefix, **context):
] ]
# render_template() supports a list of templates to try in order # render_template() supports a list of templates to try in order
return render_template(templates, **context) return render_template(templates, **context)
def format_form_errors(form, prefix):
"""Format all form errors into a single string, with a string prefix in
front. Useful for flashing the result.
"""
if len(form.errors) == 0:
return ""
elif len(form.errors) == 1:
# I18N: Form error with only one error
return _("{prefix}: {error}").format(
prefix=prefix, error=form.errors.popitem()[1][0]
)
else:
error_list = "</li><li>".join(
str(error) for (field, errors) in form.errors.items() for error in errors
)
errors = f"<ul><li>{error_list}</li></ul>"
# I18N: Form error with a list of errors
return Markup(_("{prefix}:<br />{errors}").format(prefix=prefix, errors=errors))

View file

@ -55,6 +55,7 @@ from ihatemoney.models import Bill, LoggingMode, Person, Project, db
from ihatemoney.utils import ( from ihatemoney.utils import (
LoginThrottler, LoginThrottler,
Redirect303, Redirect303,
format_form_errors,
get_members, get_members,
list_of_dicts2csv, list_of_dicts2csv,
list_of_dicts2json, list_of_dicts2json,
@ -524,7 +525,7 @@ def delete_project():
return redirect(url_for(".home")) return redirect(url_for(".home"))
else: else:
flash( flash(
_("Error deleting project: wrong private code or wrong CSRF token"), format_form_errors(form, _("Error deleting project")),
category="danger", category="danger",
) )
return redirect(request.headers.get("Referer") or url_for(".home")) return redirect(request.headers.get("Referer") or url_for(".home"))
@ -619,6 +620,7 @@ def invite():
@main.route("/<project_id>/") @main.route("/<project_id>/")
def list_bills(): def list_bills():
bill_form = get_billform_for(g.project) bill_form = get_billform_for(g.project)
# Used for CSRF validation
csrf_form = EmptyForm() csrf_form = EmptyForm()
# set the last selected payer as default choice if exists # set the last selected payer as default choice if exists
if "last_selected_payer" in session: if "last_selected_payer" in session:
@ -660,7 +662,7 @@ def reactivate(member_id):
# Used for CSRF validation # Used for CSRF validation
form = EmptyForm() form = EmptyForm()
if not form.validate(): if not form.validate():
flash(_("CSRF Token: The CSRF token is invalid."), category="danger") flash(format_form_errors(form, _("Error activating member")), category="danger")
return redirect(url_for(".list_bills")) return redirect(url_for(".list_bills"))
person = ( person = (
@ -680,7 +682,7 @@ def remove_member(member_id):
# Used for CSRF validation # Used for CSRF validation
form = EmptyForm() form = EmptyForm()
if not form.validate(): if not form.validate():
flash(_("CSRF Token: The CSRF token is invalid."), category="danger") flash(format_form_errors(form, _("Error removing member")), category="danger")
return redirect(url_for(".list_bills")) return redirect(url_for(".list_bills"))
member = g.project.remove_member(member_id) member = g.project.remove_member(member_id)
@ -745,7 +747,7 @@ def delete_bill(bill_id):
# Used for CSRF validation # Used for CSRF validation
form = EmptyForm() form = EmptyForm()
if not form.validate(): if not form.validate():
flash(_("CSRF Token: The CSRF token is invalid."), category="danger") flash(format_form_errors(form, _("Error deleting bill")), category="danger")
return redirect(url_for(".list_bills")) return redirect(url_for(".list_bills"))
bill = Bill.query.get(g.project, bill_id) bill = Bill.query.get(g.project, bill_id)
@ -822,7 +824,7 @@ def erase_history():
form = DestructiveActionProjectForm(id=g.project.id) form = DestructiveActionProjectForm(id=g.project.id)
if not form.validate(): if not form.validate():
flash( flash(
_("Error deleting project history: wrong private code or wrong CSRF token"), format_form_errors(form, _("Error deleting project history")),
category="danger", category="danger",
) )
return redirect(url_for(".history")) return redirect(url_for(".history"))
@ -841,9 +843,7 @@ def strip_ip_addresses():
form = DestructiveActionProjectForm(id=g.project.id) form = DestructiveActionProjectForm(id=g.project.id)
if not form.validate(): if not form.validate():
flash( flash(
_( format_form_errors(form, _("Error deleting recorded IP addresses")),
"Error deleting recorded IP addresses: wrong private code or wrong CSRF token"
),
category="danger", category="danger",
) )
return redirect(url_for(".history")) return redirect(url_for(".history"))