canaille-globuzma/canaille/app/forms.py

84 lines
2.6 KiB
Python
Raw Normal View History

2023-04-01 22:30:39 +00:00
import math
import wtforms
2023-04-09 13:52:55 +00:00
from canaille.app.i18n import DEFAULT_LANGUAGE_CODE
from canaille.app.i18n import locale_selector
2023-04-01 22:30:39 +00:00
from flask import abort
from flask import current_app
from flask import make_response
from flask import request
from flask_babel import gettext as _
from flask_wtf import FlaskForm
2023-04-02 11:24:06 +00:00
from wtforms.meta import DefaultMeta
2023-04-01 22:30:39 +00:00
from . import validate_uri
from .flask import request_is_htmx
def is_uri(form, field):
if not validate_uri(field.data):
raise wtforms.ValidationError(_("This is not a valid URL"))
2023-04-02 11:24:06 +00:00
meta = DefaultMeta()
class I18NFormMixin:
def __init__(self, *args, **kwargs):
preferred_locale = locale_selector()
meta.locales = (
[preferred_locale, DEFAULT_LANGUAGE_CODE] if preferred_locale else False
)
super().__init__(*args, meta=meta, **kwargs)
2023-04-01 22:30:39 +00:00
class HTMXFormMixin:
def validate(self, *args, **kwargs):
"""
If the request is a HTMX request, this will only render the field
that triggered the request (after having validated the form). This
uses the Flask abort method to interrupt the flow with an exception.
"""
if not request_is_htmx():
return super().validate(*args, **kwargs)
field = self[request.headers.get("HX-Trigger-Name")]
field.widget.hide_value = False
self.process(request.form)
super().validate(*args, **kwargs)
form_macro = current_app.jinja_env.get_template("macro/form.html")
response = make_response(form_macro.module.render_field(field))
abort(response)
2023-04-02 11:24:06 +00:00
class HTMXForm(HTMXFormMixin, I18NFormMixin, FlaskForm):
2023-04-01 22:30:39 +00:00
pass
2023-04-02 11:24:06 +00:00
class HTMXBaseForm(HTMXFormMixin, I18NFormMixin, wtforms.form.BaseForm):
2023-04-01 22:30:39 +00:00
pass
class TableForm(I18NFormMixin, FlaskForm):
2023-04-01 22:30:39 +00:00
def __init__(self, cls=None, page_size=25, fields=None, filter=None, **kwargs):
filter = filter or {}
super().__init__(**kwargs)
if self.query.data:
self.items = cls.fuzzy(self.query.data, fields, **filter)
else:
self.items = cls.query(**filter)
self.page_size = page_size
self.nb_items = len(self.items)
self.page_max = max(1, math.ceil(self.nb_items / self.page_size))
first_item = (self.page.data - 1) * self.page_size
last_item = min((self.page.data) * self.page_size, self.nb_items)
self.items_slice = self.items[first_item:last_item]
page = wtforms.IntegerField(default=1)
query = wtforms.StringField(default="")
def validate_page(self, field):
if field.data < 1 or field.data > self.page_max:
raise wtforms.validators.ValidationError(_("The page number is not valid"))