Project 'mj/mo-submit' was moved to 'mo-p/osmo'. Please update any links and bookmarks that may still have the old path.
Select Git revision
Jiří Kalvoda authored
fields.py 7.25 KiB
import decimal
from typing import Optional
import wtforms
from wtforms.fields.html5 import EmailField
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 Decimal(wtforms.DecimalField):
"""Upravený DecimalField, který formátuje číslo podle jeho skutečného počtu
desetinných míst a zadané `places` používá jen jako maximální počet desetinných míst."""
def _value(self):
if self.data is not None:
# Spočítání počtu desetinných míst, zbytek necháme na původní implementaci
max_places = self.places
self.places = 0
d = decimal.Decimal(1)
while self.data % d != 0 and self.places < max_places:
self.places += 1
d /= 10
return super(Decimal, self)._value()
class IntList(wtforms.StringField):
list = None
def __init__(self, label="", validators=None, **kwargs):
super().__init__(label, validators, **kwargs)
def pre_validate(field, form):
field.list = None
if field.data:
try:
field.list = mo.util.parse_int_list(field.data)
except mo.CheckError as e:
raise wtforms.ValidationError(str(e))
class Points(Decimal):
def __init__(self, label="Body", validators=None, **kwargs):
super().__init__(label, validators, **kwargs)
class Email(EmailField):
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)
self.render_kw = {"placeholder": "Kód"}
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
field.place_error = ""
if field.data:
try:
field.place = mo.users.validate_and_find_school(field.data)
except mo.CheckError as e:
field.place_error = str(e)
class NewPassword(wtforms.PasswordField):
def __init__(self, label="Nové heslo", validators=None, **kwargs):
super().__init__(label, validators, **kwargs)
def pre_validate(field, form):
if field.data:
if not mo.users.validate_password(field.data):
raise wtforms.ValidationError(mo.users.password_help)
class RepeatPassword(wtforms.PasswordField):
"""Pro validaci hledá ve formuláři form.new_passwd a s ním porovnává."""
def __init__(self, label="Zopakujte heslo", validators=None, **kwargs):
super().__init__(label, validators, **kwargs)
def pre_validate(field, form):
if field.data != form.new_passwd.data:
raise wtforms.ValidationError('Hesla se neshodují.')
class DateTime(wtforms.DateTimeField):
def __init__(self, label, format='%Y-%m-%d %H:%M', description='Ve formátu 2000-01-01 12:34', **kwargs):
super().__init__(label, format=format, description=description, **kwargs)
def process_data(self, valuelist):
super().process_data(valuelist)
if self.data is not None:
self.data = self.data.astimezone()
def process_formdata(self, valuelist):
super().process_formdata(valuelist)
if self.data is not None:
self.data = self.data.astimezone()