# -*- coding: utf-8 -*-
import re
from flask import url_for
from flask_wtf import FlaskForm as Form
from flask_login import current_user
from wtforms import (
StringField,
PasswordField,
ValidationError,
BooleanField,
validators,
)
from wtforms.form import FormMeta
from markupsafe import Markup
from .utils import NotRegexp
from accounts.app import accounts_app
USERNAME_RE = re.compile(r"^[a-zA-Z][a-zA-Z0-9-]{1,15}$")
USERNAME_EXCLUDE_RE = re.compile(r"^(admin|root)")
class RegisterForm(Form):
username = StringField(
"Benutzername",
[
validators.Regexp(
USERNAME_RE,
message="Benutzername darf nur aus a-z, "
"Zahlen und - bestehen (2-16 Zeichen, am Anfang nur a-z).",
),
NotRegexp(
USERNAME_EXCLUDE_RE,
message="Dieser Benutzername ist nicht erlaubt.",
),
],
)
mail = StringField(
"E-Mail-Adresse",
[validators.Email(), validators.Length(min=6, max=50)],
)
question = StringField(
"Hauptstadt von Deutschland?",
[
validators.AnyOf(
("Berlin", "berlin"), message="Bitte beantworte die Frage."
)
],
)
def validate_username(self, field):
try:
accounts_app.user_backend.get_by_uid(field.data)
except accounts_app.user_backend.NoSuchUserError:
if accounts_app.username_blacklist:
if field.data.lower() in accounts_app.username_blacklist:
raise ValidationError(
Markup(
"Dieser Benutzername ist momentan nicht erlaubt. "
'Weitere Informationen'
% url_for("default.about")
)
)
else:
raise ValidationError("Dieser Benutzername ist schon vergeben.")
def validate_mail(self, field):
try:
accounts_app.user_backend.get_by_mail(field.data)
except accounts_app.user_backend.NoSuchUserError:
pass
else:
raise ValidationError(
Markup(
"Ein Benutzername mit dieser Adresse existiert bereits. "
"Falls du deinen Benutzernamen vergessen hast, kannst du "
'die Passwort-vergessen-Funktion benutzen.'
% url_for("default.lost_password")
)
)
class AdminCreateAccountForm(RegisterForm):
def validate_username(self, field):
try:
accounts_app.user_backend.get_by_uid(field.data)
except accounts_app.user_backend.NoSuchUserError:
return
else:
raise ValidationError("Dieser Benutzername ist schon vergeben")
question = None
class RegisterCompleteForm(Form):
password = PasswordField(
"Passwort",
[
validators.DataRequired(),
validators.EqualTo(
"password_confirm", message="Passwörter stimmen nicht überein"
),
],
)
password_confirm = PasswordField("Passwort bestätigen")
# n.b. this form is also used in lost_password_complete
class LostPasswordForm(Form):
username_or_mail = StringField("Benutzername oder E-Mail")
user = None
def validate_username_or_mail(self, field):
if "@" not in field.data:
try:
self.user = accounts_app.user_backend.get_by_uid(field.data)
except accounts_app.user_backend.NoSuchUserError:
raise ValidationError(
"Es gibt keinen Benutzer mit diesem Namen."
)
else:
try:
self.user = accounts_app.user_backend.get_by_mail(field.data)
except accounts_app.user_backend.NoSuchUserError:
raise ValidationError(
"Es gibt keinen Benutzer mit dieser Adresse."
)
class SettingsMeta(FormMeta):
def __call__(cls, *args, **kwargs):
for service in accounts_app.all_services:
setattr(
cls,
"password_%s" % service.id,
PasswordField(
"Passwort für %s" % service.name,
[
validators.Optional(),
validators.EqualTo(
"password_confirm_%s" % service.id,
message="Passwörter stimmen nicht überein",
),
],
),
)
setattr(
cls,
"password_confirm_%s" % service.id,
PasswordField("Passwort für %s (Bestätigung)" % service.name),
)
setattr(
cls,
"delete_%s" % service.id,
BooleanField("Passwort für %s löschen" % service.name),
)
return super(SettingsMeta, cls).__call__(*args, **kwargs)
class SettingsForm(Form, metaclass=SettingsMeta):
old_password = PasswordField("Altes Passwort")
password = PasswordField(
"Neues Passwort",
[
validators.Optional(),
validators.EqualTo(
"password_confirm", message="Passwörter stimmen nicht überein"
),
],
)
password_confirm = PasswordField("Passwort bestätigen")
mail = StringField(
"E-Mail-Adresse",
[
validators.Optional(),
validators.Email(),
validators.Length(min=6, max=50),
],
)
def validate_old_password(self, field):
if self.password.data:
if not field.data:
raise ValidationError(
"Gib bitte dein altes Passwort ein, um ein neues zu setzen."
)
if field.data != current_user.password:
raise ValidationError("Altes Passwort ist falsch.")
def validate_mail(self, field):
results = accounts_app.user_backend.find_by_mail(field.data)
for user in results:
if user.uid != current_user.uid:
raise ValidationError(
"Diese E-Mail-Adresse wird schon von einem anderen Account benutzt!"
)
def get_servicepassword(self, service_id: str):
return getattr(self, "password_%s" % service_id)
def get_servicepasswordconfirm(self, service_id: str):
return getattr(self, "password_confirm_%s" % service_id)
def get_servicedelete(self, service_id: str):
return getattr(self, "delete_%s" % service_id)
class AdminDisableAccountForm(Form):
username = StringField("Benutzername")
user = None
def validate_username(self, field):
try:
self.user = accounts_app.user_backend.get_by_uid(field.data)
except accounts_app.user_backend.NoSuchUserError:
raise ValidationError("Dieser Benutzername existiert nicht")