2020-11-26 14:29:14 +00:00
|
|
|
import wtforms.form
|
2023-11-21 17:34:59 +00:00
|
|
|
import wtforms.validators
|
2024-03-15 18:58:06 +00:00
|
|
|
from flask import current_app
|
|
|
|
from flask import g
|
|
|
|
from flask_wtf.file import FileAllowed
|
|
|
|
from flask_wtf.file import FileField
|
|
|
|
|
2023-04-09 09:37:04 +00:00
|
|
|
from canaille.app import models
|
2023-07-21 12:50:04 +00:00
|
|
|
from canaille.app.forms import BaseForm
|
2023-05-29 18:16:59 +00:00
|
|
|
from canaille.app.forms import DateTimeUTCField
|
2023-07-21 12:50:04 +00:00
|
|
|
from canaille.app.forms import Form
|
2023-11-22 10:30:30 +00:00
|
|
|
from canaille.app.forms import IDToModel
|
2024-11-05 14:43:15 +00:00
|
|
|
from canaille.app.forms import compromised_password_validator
|
2024-03-15 18:58:06 +00:00
|
|
|
from canaille.app.forms import email_validator
|
2023-04-09 13:52:55 +00:00
|
|
|
from canaille.app.forms import is_uri
|
2024-10-28 21:17:47 +00:00
|
|
|
from canaille.app.forms import password_length_validator
|
|
|
|
from canaille.app.forms import password_too_long_validator
|
2023-08-03 16:48:51 +00:00
|
|
|
from canaille.app.forms import phone_number
|
2023-07-24 16:07:35 +00:00
|
|
|
from canaille.app.forms import set_readonly
|
2023-06-22 14:54:05 +00:00
|
|
|
from canaille.app.forms import unique_values
|
2023-09-01 08:46:56 +00:00
|
|
|
from canaille.app.i18n import lazy_gettext as _
|
2023-04-09 13:52:55 +00:00
|
|
|
from canaille.app.i18n import native_language_name_from_code
|
2024-04-16 20:42:29 +00:00
|
|
|
from canaille.backends import Backend
|
2024-11-29 09:32:17 +00:00
|
|
|
from canaille.core.models import OTP_DIGITS
|
2024-12-16 17:17:42 +00:00
|
|
|
from canaille.core.validators import existing_group_member
|
|
|
|
from canaille.core.validators import existing_login
|
|
|
|
from canaille.core.validators import non_empty_groups
|
|
|
|
from canaille.core.validators import unique_email
|
|
|
|
from canaille.core.validators import unique_group
|
|
|
|
from canaille.core.validators import unique_user_name
|
2024-04-08 12:37:59 +00:00
|
|
|
|
|
|
|
|
2023-07-21 12:50:04 +00:00
|
|
|
class LoginForm(Form):
|
2020-08-19 14:20:57 +00:00
|
|
|
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],
|
2020-10-21 10:05:21 +00:00
|
|
|
render_kw={
|
2024-11-20 22:42:58 +00:00
|
|
|
"placeholder": _("jane.doe@example.com"),
|
2020-10-21 10:05:21 +00:00
|
|
|
"spellcheck": "false",
|
|
|
|
"autocorrect": "off",
|
|
|
|
"inputmode": "email",
|
|
|
|
},
|
2020-08-19 14:20:57 +00:00
|
|
|
)
|
2020-10-20 09:44:45 +00:00
|
|
|
|
|
|
|
|
2023-07-21 12:50:04 +00:00
|
|
|
class PasswordForm(Form):
|
2021-01-23 21:30:43 +00:00
|
|
|
password = wtforms.PasswordField(
|
2021-10-29 12:20:06 +00:00
|
|
|
_("Password"),
|
|
|
|
validators=[wtforms.validators.DataRequired()],
|
2024-04-17 10:36:39 +00:00
|
|
|
render_kw={
|
|
|
|
"autocomplete": "current-password",
|
|
|
|
},
|
2021-01-23 21:30:43 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2023-07-21 12:50:04 +00:00
|
|
|
class ForgottenPasswordForm(Form):
|
2020-10-22 15:37:01 +00:00
|
|
|
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={
|
2024-11-20 22:42:58 +00:00
|
|
|
"placeholder": _("jane.doe@example.com"),
|
2020-10-22 15:37:01 +00:00
|
|
|
"spellcheck": "false",
|
|
|
|
"autocorrect": "off",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2023-07-21 12:50:04 +00:00
|
|
|
class PasswordResetForm(Form):
|
2020-10-22 15:37:01 +00:00
|
|
|
password = wtforms.PasswordField(
|
2023-03-29 17:03:28 +00:00
|
|
|
_("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.")
|
|
|
|
),
|
|
|
|
],
|
2023-03-29 17:03:28 +00:00
|
|
|
render_kw={
|
|
|
|
"autocomplete": "new-password",
|
|
|
|
},
|
2020-10-22 15:37:01 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2023-07-21 12:50:04 +00:00
|
|
|
class FirstLoginForm(Form):
|
2022-12-20 23:20:20 +00:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
2022-11-20 21:12:18 +00:00
|
|
|
def available_language_choices():
|
2023-03-12 15:55:28 +00:00
|
|
|
languages = [
|
2022-11-20 21:12:18 +00:00
|
|
|
(lang_code, native_language_name_from_code(lang_code))
|
|
|
|
for lang_code in g.available_language_codes
|
|
|
|
]
|
2023-03-12 15:55:28 +00:00
|
|
|
languages.sort()
|
|
|
|
return [("auto", _("Automatic"))] + languages
|
2022-11-20 21:12:18 +00:00
|
|
|
|
|
|
|
|
2020-11-26 14:29:14 +00:00
|
|
|
PROFILE_FORM_FIELDS = dict(
|
2023-02-05 17:57:18 +00:00
|
|
|
user_name=wtforms.StringField(
|
2020-10-20 09:44:45 +00:00
|
|
|
_("Username"),
|
2020-10-30 19:22:31 +00:00
|
|
|
render_kw={"placeholder": _("jdoe")},
|
2024-04-07 17:50:26 +00:00
|
|
|
validators=[wtforms.validators.DataRequired(), unique_user_name],
|
2020-11-26 14:29:14 +00:00
|
|
|
),
|
2023-02-05 17:57:18 +00:00
|
|
|
formatted_name=wtforms.StringField(_("Name")),
|
2023-03-13 12:47:15 +00:00
|
|
|
title=wtforms.StringField(
|
|
|
|
_("Title"), render_kw={"placeholder": _("Vice president")}
|
|
|
|
),
|
2023-02-05 17:57:18 +00:00
|
|
|
given_name=wtforms.StringField(
|
2020-10-21 10:05:21 +00:00
|
|
|
_("Given name"),
|
|
|
|
render_kw={
|
|
|
|
"placeholder": _("John"),
|
|
|
|
"spellcheck": "false",
|
|
|
|
"autocorrect": "off",
|
|
|
|
},
|
2020-11-26 14:29:14 +00:00
|
|
|
),
|
2023-02-05 17:57:18 +00:00
|
|
|
family_name=wtforms.StringField(
|
2020-10-21 10:05:21 +00:00
|
|
|
_("Family Name"),
|
2022-01-07 14:19:05 +00:00
|
|
|
validators=[wtforms.validators.DataRequired()],
|
2020-10-21 10:05:21 +00:00
|
|
|
render_kw={
|
|
|
|
"placeholder": _("Doe"),
|
|
|
|
"spellcheck": "false",
|
|
|
|
"autocorrect": "off",
|
|
|
|
},
|
2020-11-26 14:29:14 +00:00
|
|
|
),
|
2023-02-05 17:57:18 +00:00
|
|
|
display_name=wtforms.StringField(
|
2022-12-02 17:47:16 +00:00
|
|
|
_("Display Name"),
|
|
|
|
validators=[wtforms.validators.Optional()],
|
|
|
|
render_kw={
|
|
|
|
"placeholder": _("Johnny"),
|
|
|
|
"spellcheck": "false",
|
|
|
|
"autocorrect": "off",
|
|
|
|
},
|
|
|
|
),
|
2023-06-22 14:54:05 +00:00
|
|
|
emails=wtforms.FieldList(
|
|
|
|
wtforms.EmailField(
|
2023-06-30 15:39:35 +00:00
|
|
|
_("Email addresses"),
|
2023-06-22 14:54:05 +00:00
|
|
|
validators=[
|
|
|
|
wtforms.validators.DataRequired(),
|
2023-08-16 15:14:11 +00:00
|
|
|
email_validator,
|
2023-06-22 14:54:05 +00:00
|
|
|
unique_email,
|
|
|
|
],
|
|
|
|
description=_(
|
|
|
|
"This email will be used as a recovery address to reset the password if needed"
|
|
|
|
),
|
|
|
|
render_kw={
|
2024-11-20 22:42:58 +00:00
|
|
|
"placeholder": _("jane.doe@example.com"),
|
2023-06-22 14:54:05 +00:00
|
|
|
"spellcheck": "false",
|
|
|
|
"autocorrect": "off",
|
|
|
|
},
|
2021-12-20 22:57:27 +00:00
|
|
|
),
|
2023-06-22 14:54:05 +00:00
|
|
|
min_entries=1,
|
|
|
|
validators=[unique_values],
|
2020-11-26 14:29:14 +00:00
|
|
|
),
|
2023-06-22 14:54:05 +00:00
|
|
|
phone_numbers=wtforms.FieldList(
|
|
|
|
wtforms.TelField(
|
2023-08-03 16:48:51 +00:00
|
|
|
_("Phone numbers"),
|
|
|
|
render_kw={"placeholder": _("555-000-555")},
|
|
|
|
validators=[wtforms.validators.Optional(), phone_number],
|
2023-06-22 14:54:05 +00:00
|
|
|
),
|
|
|
|
min_entries=1,
|
|
|
|
validators=[unique_values],
|
2020-11-26 14:29:14 +00:00
|
|
|
),
|
2023-02-05 17:57:18 +00:00
|
|
|
formatted_address=wtforms.StringField(
|
2022-07-07 12:35:17 +00:00
|
|
|
_("Address"),
|
|
|
|
render_kw={
|
2023-03-11 19:11:55 +00:00
|
|
|
"placeholder": _("132, Foobar Street, Gotham City 12401, XX"),
|
|
|
|
},
|
|
|
|
),
|
|
|
|
street=wtforms.StringField(
|
|
|
|
_("Street"),
|
|
|
|
render_kw={
|
|
|
|
"placeholder": _("132, Foobar Street"),
|
|
|
|
},
|
|
|
|
),
|
2023-02-05 17:57:18 +00:00
|
|
|
postal_code=wtforms.StringField(
|
2023-03-11 19:11:55 +00:00
|
|
|
_("Postal Code"),
|
|
|
|
render_kw={
|
|
|
|
"placeholder": "12401",
|
|
|
|
},
|
|
|
|
),
|
2023-02-05 17:57:18 +00:00
|
|
|
locality=wtforms.StringField(
|
2023-03-11 19:11:55 +00:00
|
|
|
_("Locality"),
|
|
|
|
render_kw={
|
|
|
|
"placeholder": _("Gotham City"),
|
|
|
|
},
|
|
|
|
),
|
2023-02-05 17:57:18 +00:00
|
|
|
region=wtforms.StringField(
|
2023-03-11 19:11:55 +00:00
|
|
|
_("Region"),
|
|
|
|
render_kw={
|
2023-03-11 21:37:53 +00:00
|
|
|
"placeholder": _("North Pole"),
|
2022-07-07 12:35:17 +00:00
|
|
|
},
|
|
|
|
),
|
2023-02-05 17:57:18 +00:00
|
|
|
photo=FileField(
|
2021-12-08 17:06:50 +00:00
|
|
|
_("Photo"),
|
|
|
|
validators=[FileAllowed(["jpg", "jpeg"])],
|
|
|
|
render_kw={"accept": "image/jpg, image/jpeg"},
|
|
|
|
),
|
2023-02-05 17:57:18 +00:00
|
|
|
photo_delete=wtforms.BooleanField(_("Delete the photo")),
|
2020-11-26 14:29:14 +00:00
|
|
|
password1=wtforms.PasswordField(
|
2020-10-21 08:26:31 +00:00
|
|
|
_("Password"),
|
2023-05-20 18:46:39 +00:00
|
|
|
validators=[
|
|
|
|
wtforms.validators.Optional(),
|
2024-10-28 21:17:47 +00:00
|
|
|
password_length_validator,
|
|
|
|
password_too_long_validator,
|
2024-11-05 14:43:15 +00:00
|
|
|
compromised_password_validator,
|
2023-05-20 18:46:39 +00:00
|
|
|
],
|
2023-03-29 17:03:28 +00:00
|
|
|
render_kw={
|
|
|
|
"autocomplete": "new-password",
|
|
|
|
},
|
2020-11-26 14:29:14 +00:00
|
|
|
),
|
|
|
|
password2=wtforms.PasswordField(
|
2020-10-21 08:26:31 +00:00
|
|
|
_("Password confirmation"),
|
2020-11-25 19:21:18 +00:00
|
|
|
validators=[
|
|
|
|
wtforms.validators.EqualTo(
|
|
|
|
"password1", message=_("Password and confirmation do not match.")
|
|
|
|
)
|
|
|
|
],
|
2023-03-29 17:03:28 +00:00
|
|
|
render_kw={
|
|
|
|
"autocomplete": "new-password",
|
|
|
|
},
|
2020-11-26 14:29:14 +00:00
|
|
|
),
|
2023-02-05 17:57:18 +00:00
|
|
|
employee_number=wtforms.StringField(
|
2023-03-29 21:01:02 +00:00
|
|
|
_("User number"),
|
2023-03-11 11:52:36 +00:00
|
|
|
render_kw={
|
|
|
|
"placeholder": _("1234"),
|
|
|
|
},
|
|
|
|
),
|
2023-02-05 17:57:18 +00:00
|
|
|
department=wtforms.StringField(
|
|
|
|
_("Department"),
|
2021-10-29 12:20:06 +00:00
|
|
|
render_kw={
|
|
|
|
"placeholder": _("1234"),
|
|
|
|
},
|
2020-11-26 14:29:14 +00:00
|
|
|
),
|
2023-02-05 17:57:18 +00:00
|
|
|
organization=wtforms.StringField(
|
2023-03-17 16:35:05 +00:00
|
|
|
_("Organization"),
|
|
|
|
render_kw={
|
|
|
|
"placeholder": _("Cogip LTD."),
|
|
|
|
},
|
|
|
|
),
|
2023-02-05 17:57:18 +00:00
|
|
|
profile_url=wtforms.URLField(
|
2021-12-13 22:04:34 +00:00
|
|
|
_("Website"),
|
|
|
|
render_kw={
|
|
|
|
"placeholder": _("https://mywebsite.tld"),
|
|
|
|
},
|
2023-03-29 18:14:28 +00:00
|
|
|
validators=[wtforms.validators.Optional(), is_uri],
|
2021-12-13 22:04:34 +00:00
|
|
|
),
|
2023-02-05 17:57:18 +00:00
|
|
|
preferred_language=wtforms.SelectField(
|
2022-11-20 21:12:18 +00:00
|
|
|
_("Preferred language"),
|
|
|
|
choices=available_language_choices,
|
|
|
|
),
|
2023-03-16 17:39:28 +00:00
|
|
|
groups=wtforms.SelectMultipleField(
|
|
|
|
_("Groups"),
|
2023-12-24 11:05:18 +00:00
|
|
|
default=[],
|
2024-04-10 13:44:11 +00:00
|
|
|
choices=lambda: [
|
|
|
|
(group, group.display_name)
|
2024-04-16 20:42:29 +00:00
|
|
|
for group in Backend.instance.query(models.Group)
|
2024-04-10 13:44:11 +00:00
|
|
|
],
|
2023-03-16 17:39:28 +00:00
|
|
|
render_kw={"placeholder": _("users, admins …")},
|
2023-11-22 10:30:30 +00:00
|
|
|
coerce=IDToModel("Group"),
|
2024-04-08 12:37:59 +00:00
|
|
|
validators=[non_empty_groups],
|
2023-03-16 17:39:28 +00:00
|
|
|
),
|
2020-11-26 14:29:14 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2023-07-20 16:43:28 +00:00
|
|
|
def build_profile_form(write_field_names, readonly_field_names, user=None):
|
2023-02-05 17:57:18 +00:00
|
|
|
if "password" in write_field_names:
|
2021-12-02 17:23:14 +00:00
|
|
|
write_field_names |= {"password1", "password2"}
|
|
|
|
|
2023-02-05 17:57:18 +00:00
|
|
|
if "photo" in write_field_names:
|
|
|
|
write_field_names |= {"photo_delete"}
|
2021-12-08 17:06:50 +00:00
|
|
|
|
2020-11-26 14:29:14 +00:00
|
|
|
fields = {
|
|
|
|
name: PROFILE_FORM_FIELDS.get(name)
|
2021-12-02 17:23:14 +00:00
|
|
|
for name in write_field_names | readonly_field_names
|
2020-11-26 14:29:14 +00:00
|
|
|
if PROFILE_FORM_FIELDS.get(name)
|
|
|
|
}
|
2021-12-02 17:23:14 +00:00
|
|
|
|
2024-04-16 20:42:29 +00:00
|
|
|
if "groups" in fields and not Backend.instance.query(models.Group):
|
2023-03-16 17:39:28 +00:00
|
|
|
del fields["groups"]
|
2021-12-02 17:23:14 +00:00
|
|
|
|
2024-05-14 20:53:47 +00:00
|
|
|
if current_app.features.has_account_lockability: # pragma: no branch
|
2023-05-29 18:16:59 +00:00
|
|
|
fields["lock_date"] = DateTimeUTCField(
|
2023-05-26 15:44:15 +00:00
|
|
|
_("Account expiration"),
|
|
|
|
validators=[wtforms.validators.Optional()],
|
|
|
|
format=[
|
|
|
|
"%Y-%m-%d %H:%M",
|
|
|
|
"%Y-%m-%dT%H:%M",
|
|
|
|
"%Y-%m-%d %H:%M:%S",
|
|
|
|
"%Y-%m-%dT%H:%M:%S",
|
|
|
|
],
|
|
|
|
)
|
2022-11-01 11:25:21 +00:00
|
|
|
|
2023-07-21 12:50:04 +00:00
|
|
|
form = BaseForm(fields)
|
2023-03-27 21:16:32 +00:00
|
|
|
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:
|
2023-07-24 16:07:35 +00:00
|
|
|
set_readonly(field)
|
2021-12-02 17:23:14 +00:00
|
|
|
|
|
|
|
return form
|
2021-07-01 16:21:20 +00:00
|
|
|
|
|
|
|
|
2023-07-21 12:50:04 +00:00
|
|
|
class CreateGroupForm(Form):
|
2024-12-16 17:17:42 +00:00
|
|
|
"""The group creation form."""
|
|
|
|
|
2023-02-05 18:39:52 +00:00
|
|
|
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-07-29 14:00:21 +00:00
|
|
|
|
2021-12-01 11:19:28 +00:00
|
|
|
|
2023-07-21 12:50:04 +00:00
|
|
|
class EditGroupForm(Form):
|
2024-12-16 17:17:42 +00:00
|
|
|
"""The group edition form."""
|
|
|
|
|
2023-02-05 18:39:52 +00:00
|
|
|
display_name = wtforms.StringField(
|
2022-12-27 20:32:21 +00:00
|
|
|
_("Name"),
|
2023-07-24 16:07:35 +00:00
|
|
|
validators=[
|
|
|
|
wtforms.validators.DataRequired(),
|
2023-11-21 17:34:59 +00:00
|
|
|
wtforms.validators.ReadOnly(),
|
2023-07-24 16:07:35 +00:00
|
|
|
],
|
2022-12-27 20:32:21 +00:00
|
|
|
render_kw={
|
|
|
|
"readonly": "true",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
description = wtforms.StringField(
|
|
|
|
_("Description"),
|
|
|
|
validators=[wtforms.validators.Optional()],
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2024-04-28 14:13:01 +00:00
|
|
|
class DeleteGroupMemberForm(Form):
|
|
|
|
member = wtforms.StringField(
|
|
|
|
filters=[IDToModel("User", raise_on_errors=False)],
|
|
|
|
validators=[existing_group_member],
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2023-08-14 22:48:49 +00:00
|
|
|
class JoinForm(Form):
|
2023-05-08 09:44:21 +00:00
|
|
|
email = wtforms.EmailField(
|
|
|
|
_("Email address"),
|
|
|
|
validators=[
|
|
|
|
wtforms.validators.DataRequired(),
|
2023-08-16 15:14:11 +00:00
|
|
|
email_validator,
|
2023-05-08 09:44:21 +00:00
|
|
|
],
|
|
|
|
render_kw={
|
2024-11-20 22:42:58 +00:00
|
|
|
"placeholder": _("jane.doe@example.com"),
|
2023-05-08 09:44:21 +00:00
|
|
|
"spellcheck": "false",
|
|
|
|
"autocorrect": "off",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
2023-08-16 15:45:39 +00:00
|
|
|
def validate_email(form, field):
|
2023-12-18 17:06:03 +00:00
|
|
|
if not current_app.config["CANAILLE"]["HIDE_INVALID_LOGINS"]:
|
2023-08-16 15:45:39 +00:00
|
|
|
unique_email(form, field)
|
|
|
|
|
2023-05-08 09:44:21 +00:00
|
|
|
|
2023-07-21 12:50:04 +00:00
|
|
|
class InvitationForm(Form):
|
2024-12-16 17:17:42 +00:00
|
|
|
"""The user invitation form."""
|
|
|
|
|
2023-02-05 17:57:18 +00:00
|
|
|
user_name = wtforms.StringField(
|
2024-04-07 17:50:26 +00:00
|
|
|
_("User name"),
|
2021-12-01 11:19:28 +00:00
|
|
|
render_kw={"placeholder": _("jdoe")},
|
2024-04-07 17:50:26 +00:00
|
|
|
validators=[wtforms.validators.DataRequired(), unique_user_name],
|
2021-12-01 11:19:28 +00:00
|
|
|
)
|
2023-02-05 17:57:18 +00:00
|
|
|
user_name_editable = wtforms.BooleanField(_("Username editable by the invitee"))
|
|
|
|
email = wtforms.EmailField(
|
2021-12-01 11:19:28 +00:00
|
|
|
_("Email address"),
|
|
|
|
validators=[
|
|
|
|
wtforms.validators.DataRequired(),
|
2023-08-16 15:14:11 +00:00
|
|
|
email_validator,
|
2021-12-01 11:19:28 +00:00
|
|
|
unique_email,
|
|
|
|
],
|
|
|
|
render_kw={
|
2024-11-20 22:42:58 +00:00
|
|
|
"placeholder": _("jane.doe@example.com"),
|
2021-12-01 11:19:28 +00:00
|
|
|
"spellcheck": "false",
|
|
|
|
"autocorrect": "off",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
groups = wtforms.SelectMultipleField(
|
|
|
|
_("Groups"),
|
2024-04-10 13:44:11 +00:00
|
|
|
choices=lambda: [
|
|
|
|
(group, group.display_name)
|
2024-04-16 20:42:29 +00:00
|
|
|
for group in Backend.instance.query(models.Group)
|
2024-04-10 13:44:11 +00:00
|
|
|
],
|
2021-12-01 11:19:28 +00:00
|
|
|
render_kw={},
|
2023-11-22 10:30:30 +00:00
|
|
|
coerce=IDToModel("Group"),
|
2021-12-01 11:19:28 +00:00
|
|
|
)
|
2023-07-20 16:43:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
class EmailConfirmationForm(Form):
|
|
|
|
old_emails = wtforms.FieldList(
|
|
|
|
wtforms.EmailField(
|
2023-11-21 17:34:59 +00:00
|
|
|
validators=[wtforms.validators.ReadOnly()],
|
2023-07-20 16:43:28 +00:00
|
|
|
description=_(
|
|
|
|
"This email will be used as a recovery address to reset the password if needed"
|
|
|
|
),
|
|
|
|
render_kw={
|
2024-11-20 22:42:58 +00:00
|
|
|
"placeholder": _("jane.doe@example.com"),
|
2023-07-20 16:43:28 +00:00
|
|
|
"spellcheck": "false",
|
|
|
|
"autocorrect": "off",
|
|
|
|
"readonly": "true",
|
|
|
|
},
|
|
|
|
),
|
2023-08-08 12:26:46 +00:00
|
|
|
label=_("Email addresses"),
|
2023-07-20 16:43:28 +00:00
|
|
|
)
|
|
|
|
new_email = wtforms.EmailField(
|
|
|
|
_("New email address"),
|
|
|
|
validators=[
|
|
|
|
wtforms.validators.DataRequired(),
|
2023-08-16 15:14:11 +00:00
|
|
|
email_validator,
|
2023-07-20 16:43:28 +00:00
|
|
|
unique_email,
|
|
|
|
],
|
|
|
|
render_kw={
|
2024-11-20 22:42:58 +00:00
|
|
|
"placeholder": _("jane.doe@example.com"),
|
2023-07-20 16:43:28 +00:00
|
|
|
"spellcheck": "false",
|
|
|
|
"autocorrect": "off",
|
|
|
|
},
|
|
|
|
)
|
2024-10-25 07:51:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
class TwoFactorForm(Form):
|
|
|
|
otp = wtforms.StringField(
|
|
|
|
_("One-time password"),
|
|
|
|
validators=[
|
|
|
|
wtforms.validators.DataRequired(),
|
2024-11-29 09:32:17 +00:00
|
|
|
wtforms.validators.Length(min=OTP_DIGITS, max=OTP_DIGITS),
|
2024-10-25 07:51:01 +00:00
|
|
|
],
|
|
|
|
render_kw={
|
|
|
|
"placeholder": _("123456"),
|
|
|
|
"spellcheck": "false",
|
|
|
|
"autocorrect": "off",
|
|
|
|
},
|
|
|
|
)
|