canaille-globuzma/canaille/forms.py

367 lines
10 KiB
Python
Raw Normal View History

import math
import wtforms.form
from flask import current_app
from flask import g
2020-10-28 14:49:14 +00:00
from flask_babel import lazy_gettext as _
2020-08-19 14:20:57 +00:00
from flask_wtf import FlaskForm
2021-12-20 22:57:27 +00:00
from flask_wtf.file import FileAllowed
from flask_wtf.file import FileField
from .i18n import native_language_name_from_code
2021-12-20 22:57:27 +00:00
from .models import Group
from .models import User
2020-08-19 14:20:57 +00:00
2021-12-01 11:19:28 +00:00
def unique_login(form, field):
if User.get(field.data) and (
not getattr(form, "user", None) or form.user.uid[0] != field.data
):
2021-12-01 11:19:28 +00:00
raise wtforms.ValidationError(
_("The login '{login}' already exists").format(login=field.data)
)
def unique_email(form, field):
if User.get(mail=field.data) and (
not getattr(form, "user", None) or form.user.mail[0] != field.data
):
2021-12-01 11:19:28 +00:00
raise wtforms.ValidationError(
2023-03-29 17:34:17 +00:00
_("The email '{email}' is already used").format(email=field.data)
2021-12-01 11:19:28 +00:00
)
2021-12-07 18:41:20 +00:00
def unique_group(form, field):
if Group.get(field.data):
raise wtforms.ValidationError(
_("The group '{group}' already exists").format(group=field.data)
)
def existing_login(form, field):
if not current_app.config.get("HIDE_INVALID_LOGINS", True) and not User.get(
2021-12-07 18:41:20 +00:00
field.data
):
raise wtforms.ValidationError(
_("The login '{login}' does not exist").format(login=field.data)
)
class TableForm(FlaskForm):
def __init__(self, cls=None, page_size=25, fields=None, filter=None, **kwargs):
filter = filter or {}
super().__init__(**kwargs)
2023-03-07 17:29:18 +00:00
if self.query.data:
self.items = cls.fuzzy(self.query.data, fields, **filter)
2023-03-07 17:29:18 +00:00
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)
2023-03-07 17:29:18 +00:00
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"))
2020-08-19 14:20:57 +00:00
class LoginForm(FlaskForm):
login = wtforms.StringField(
2020-10-20 09:44:45 +00:00
_("Login"),
2021-12-07 18:41:20 +00:00
validators=[wtforms.validators.DataRequired(), existing_login],
render_kw={
2020-10-22 15:37:01 +00:00
"placeholder": _("jane@doe.com"),
"spellcheck": "false",
"autocorrect": "off",
"inputmode": "email",
},
2020-08-19 14:20:57 +00:00
)
2020-10-20 09:44:45 +00:00
2021-01-23 21:30:43 +00:00
class PasswordForm(FlaskForm):
password = wtforms.PasswordField(
2021-10-29 12:20:06 +00:00
_("Password"),
validators=[wtforms.validators.DataRequired()],
2021-01-23 21:30:43 +00:00
)
class FullLoginForm(LoginForm, PasswordForm):
pass
2020-10-22 15:37:01 +00:00
class ForgottenPasswordForm(FlaskForm):
login = wtforms.StringField(
_("Login"),
2021-12-07 18:41:20 +00:00
validators=[wtforms.validators.DataRequired(), existing_login],
2020-10-22 15:37:01 +00:00
render_kw={
"placeholder": _("jane@doe.com"),
"spellcheck": "false",
"autocorrect": "off",
},
)
class PasswordResetForm(FlaskForm):
password = wtforms.PasswordField(
_("Password"),
validators=[wtforms.validators.DataRequired()],
render_kw={
"autocomplete": "new-password",
},
2020-10-22 15:37:01 +00:00
)
confirmation = wtforms.PasswordField(
_("Password confirmation"),
validators=[
wtforms.validators.EqualTo(
"password", _("Password and confirmation do not match.")
),
],
render_kw={
"autocomplete": "new-password",
},
2020-10-22 15:37:01 +00:00
)
2022-12-20 23:20:20 +00:00
class FirstLoginForm(FlaskForm):
pass
def available_language_choices():
languages = [
(lang_code, native_language_name_from_code(lang_code))
for lang_code in g.available_language_codes
]
languages.sort()
return [("auto", _("Automatic"))] + languages
PROFILE_FORM_FIELDS = dict(
uid=wtforms.StringField(
2020-10-20 09:44:45 +00:00
_("Username"),
2020-10-30 19:22:31 +00:00
render_kw={"placeholder": _("jdoe")},
validators=[wtforms.validators.DataRequired(), unique_login],
),
cn=wtforms.StringField(_("Name")),
2023-03-13 12:47:15 +00:00
title=wtforms.StringField(
_("Title"), render_kw={"placeholder": _("Vice president")}
),
givenName=wtforms.StringField(
_("Given name"),
render_kw={
"placeholder": _("John"),
"spellcheck": "false",
"autocorrect": "off",
},
),
sn=wtforms.StringField(
_("Family Name"),
validators=[wtforms.validators.DataRequired()],
render_kw={
"placeholder": _("Doe"),
"spellcheck": "false",
"autocorrect": "off",
},
),
displayName=wtforms.StringField(
_("Display Name"),
validators=[wtforms.validators.Optional()],
render_kw={
"placeholder": _("Johnny"),
"spellcheck": "false",
"autocorrect": "off",
},
),
mail=wtforms.EmailField(
2020-10-21 07:52:02 +00:00
_("Email address"),
validators=[
wtforms.validators.DataRequired(),
wtforms.validators.Email(),
unique_email,
],
2021-12-20 22:57:27 +00:00
description=_(
"This email will be used as a recovery address to reset the password if needed"
),
render_kw={
"placeholder": _("jane@doe.com"),
"spellcheck": "false",
"autocorrect": "off",
},
),
telephoneNumber=wtforms.TelField(
2020-10-21 07:52:02 +00:00
_("Phone number"), render_kw={"placeholder": _("555-000-555")}
),
postalAddress=wtforms.StringField(
_("Address"),
render_kw={
"placeholder": _("132, Foobar Street, Gotham City 12401, XX"),
},
),
street=wtforms.StringField(
_("Street"),
render_kw={
"placeholder": _("132, Foobar Street"),
},
),
postalCode=wtforms.StringField(
_("Postal Code"),
render_kw={
"placeholder": "12401",
},
),
l=wtforms.StringField(
_("Locality"),
render_kw={
"placeholder": _("Gotham City"),
},
),
st=wtforms.StringField(
_("Region"),
render_kw={
2023-03-11 21:37:53 +00:00
"placeholder": _("North Pole"),
},
),
2021-12-08 17:06:50 +00:00
jpegPhoto=FileField(
_("Photo"),
validators=[FileAllowed(["jpg", "jpeg"])],
render_kw={"accept": "image/jpg, image/jpeg"},
),
jpegPhoto_delete=wtforms.BooleanField(_("Delete the photo")),
password1=wtforms.PasswordField(
2020-10-21 08:26:31 +00:00
_("Password"),
validators=[wtforms.validators.Optional(), wtforms.validators.Length(min=8)],
render_kw={
"autocomplete": "new-password",
},
),
password2=wtforms.PasswordField(
2020-10-21 08:26:31 +00:00
_("Password confirmation"),
validators=[
wtforms.validators.EqualTo(
"password1", message=_("Password and confirmation do not match.")
)
],
render_kw={
"autocomplete": "new-password",
},
),
employeeNumber=wtforms.StringField(
2023-03-11 11:52:36 +00:00
_("Employee number"),
render_kw={
"placeholder": _("1234"),
},
),
departmentNumber=wtforms.StringField(
_("Department number"),
2021-10-29 12:20:06 +00:00
render_kw={
"placeholder": _("1234"),
},
),
2023-03-17 16:35:05 +00:00
o=wtforms.StringField(
_("Organization"),
render_kw={
"placeholder": _("Cogip LTD."),
},
),
2021-12-13 22:04:34 +00:00
labeledURI=wtforms.URLField(
_("Website"),
render_kw={
"placeholder": _("https://mywebsite.tld"),
},
),
preferredLanguage=wtforms.SelectField(
_("Preferred language"),
choices=available_language_choices,
),
2023-03-16 17:39:28 +00:00
groups=wtforms.SelectMultipleField(
_("Groups"),
choices=lambda: [(group.id, group.display_name) for group in Group.query()],
render_kw={"placeholder": _("users, admins …")},
),
)
def profile_form(write_field_names, readonly_field_names, user=None):
2021-12-02 17:23:14 +00:00
if "userPassword" in write_field_names:
write_field_names |= {"password1", "password2"}
2021-12-08 17:06:50 +00:00
if "jpegPhoto" in write_field_names:
write_field_names |= {"jpegPhoto_delete"}
fields = {
name: PROFILE_FORM_FIELDS.get(name)
2021-12-02 17:23:14 +00:00
for name in write_field_names | readonly_field_names
if PROFILE_FORM_FIELDS.get(name)
}
2021-12-02 17:23:14 +00:00
2023-03-16 17:39:28 +00:00
if "groups" in fields and not Group.query():
del fields["groups"]
2021-12-02 17:23:14 +00:00
form = wtforms.form.BaseForm(fields)
form.user = user
2021-12-02 17:23:14 +00:00
for field in form:
if field.name in readonly_field_names - write_field_names:
field.render_kw["readonly"] = "true"
2021-12-02 17:23:14 +00:00
return form
2021-07-01 16:21:20 +00:00
2022-12-27 20:32:21 +00:00
class CreateGroupForm(FlaskForm):
display_name = wtforms.StringField(
2021-07-01 16:21:20 +00:00
_("Name"),
2022-12-27 20:32:21 +00:00
validators=[wtforms.validators.DataRequired(), unique_group],
2021-10-29 12:20:06 +00:00
render_kw={
"placeholder": _("group"),
},
2021-07-01 16:21:20 +00:00
)
2021-12-10 16:08:43 +00:00
description = wtforms.StringField(
_("Description"),
validators=[wtforms.validators.Optional()],
)
2021-12-01 11:19:28 +00:00
2022-12-27 20:32:21 +00:00
class EditGroupForm(FlaskForm):
display_name = wtforms.StringField(
2022-12-27 20:32:21 +00:00
_("Name"),
validators=[wtforms.validators.DataRequired()],
render_kw={
"readonly": "true",
},
)
description = wtforms.StringField(
_("Description"),
validators=[wtforms.validators.Optional()],
)
2021-12-01 11:19:28 +00:00
class InvitationForm(FlaskForm):
uid = wtforms.StringField(
_("Username"),
render_kw={"placeholder": _("jdoe")},
validators=[wtforms.validators.DataRequired(), unique_login],
)
2022-01-01 17:41:04 +00:00
uid_editable = wtforms.BooleanField(_("Username editable by the invitee"))
2021-12-01 11:19:28 +00:00
mail = wtforms.EmailField(
_("Email address"),
validators=[
wtforms.validators.DataRequired(),
wtforms.validators.Email(),
unique_email,
],
render_kw={
"placeholder": _("jane@doe.com"),
"spellcheck": "false",
"autocorrect": "off",
},
)
groups = wtforms.SelectMultipleField(
_("Groups"),
choices=lambda: [(group.id, group.display_name) for group in Group.query()],
2021-12-01 11:19:28 +00:00
render_kw={},
)