diff --git a/mo/web/fields.py b/mo/web/fields.py new file mode 100644 index 0000000000000000000000000000000000000000..e6f21da098528f367c161d9421dc366ee78b8135 --- /dev/null +++ b/mo/web/fields.py @@ -0,0 +1,140 @@ +from typing import Optional +import wtforms +from wtforms.widgets.html5 import NumberInput + +import mo +import mo.users +import mo.db as db + + +class OptionalInt(wtforms.IntegerField): + widget = NumberInput() + + def process_formdata(self, valuelist): + self.data = None + if valuelist: + if valuelist[0]: + try: + self.data = int(valuelist[0]) + except ValueError: + raise wtforms.ValidationError('Nejedná se o číslo.') + + +class Email(wtforms.StringField): + def __init__(self, label="E-mail", validators=None, **kwargs): + super().__init__(label, validators, **kwargs) + + def pre_validate(field, form): + if field.data: + try: + field.data = mo.users.normalize_email(field.data) + except mo.CheckError as e: + raise wtforms.ValidationError(str(e)) + + +class Grade(wtforms.StringField): + """Pro validaci hledá ve formuláři form.school a podle ní rozlišuje SŠ a ZŠ """ + default_description = "Pro základní školy je to číslo od 1 do 9, pro <var>k</var>-tý ročník <var>r</var>-leté střední školy má formát <var>k</var>/<var>r</var>." + validate_grade = True + + def __init__(self, label="Ročník", validators=None, description=default_description, **kwargs): + super().__init__(label, validators, description=description, **kwargs) + + def pre_validate(field, form): + if field.data: + if field.validate_grade: + school_place = form.school.get_place() + if school_place is not None: + try: + field.data = mo.users.normalize_grade(field.data, school_place.school) + except mo.CheckError as e: + raise wtforms.ValidationError(str(e)) + + +class BirthYear(OptionalInt): + def __init__(self, label="Rok narození", validators=None, **kwargs): + super().__init__(label, validators, **kwargs) + + def pre_validate(field, form): + if field.data is not None: + r: int = field.data + try: + mo.users.validate_born_year(r) + except mo.CheckError as e: + raise wtforms.ValidationError(str(e)) + + +class Name(wtforms.StringField): + def pre_validate(field, form): + # XXX: Tato kontrola úmyslně není striktní, aby prošla i jména jako 'de Beer' + if field.data: + if field.data == field.data.lower(): + raise wtforms.ValidationError('Ve jméně nejsou velká písmena.') + if field.data == field.data.upper(): + raise wtforms.ValidationError('Ve jméně nejsou malá písmena.') + + +class FirstName(Name): + def __init__(self, label="Jméno", validators=None, **kwargs): + super().__init__(label, validators, **kwargs) + + +class LastName(Name): + def __init__(self, label="Příjmení", validators=None, **kwargs): + super().__init__(label, validators, **kwargs) + + +class Place(wtforms.StringField): + def __init__(self, label="Místo", validators=None, **kwargs): + super().__init__(label, validators, **kwargs) + + place_loaded: bool = False + place: Optional[db.Place] = None + place_error: str + + def load_place(field) -> None: + field.place = None + field.place_error = "" + if field.data: + field.place = db.get_place_by_code(field.data) + if field.place is None: + field.place_error = "Zadané místo nenalezeno." + + def get_place(field) -> Optional[db.Place]: + """ Kešuje výsledek v field.place""" + if not field.place_loaded: + field.place_loaded = True + field.load_place() + return field.place + + def pre_validate(field, form): + if field.get_place() is None and field.place_error: + raise wtforms.ValidationError(field.place_error) + + def get_place_id(field) -> int: + p = field.get_place() + if p is None: + return 0 + return p.place_id + + def populate_obj(field, obj, name): + setattr(obj, name, field.get_place_id()) + + def process_data(field, obj: Optional[int]): + if obj is not None: + field.data = db.get_place_by_id(obj).get_code() + else: + field.data = "" + + +class School(Place): + def __init__(self, label="Škola", validators=None, **kwargs): + super().__init__(label, validators, **kwargs) + + def load_place(field) -> None: + field.place = None + if field.data: + try: + field.place = mo.users.validate_and_find_school(field.data) + except mo.CheckError as e: + field.place_error = str(e)