108 lines
3.4 KiB
Python
108 lines
3.4 KiB
Python
|
from datetime import datetime, date
|
||
|
from abc import ABC
|
||
|
from typing import Optional
|
||
|
|
||
|
from pydantic import BaseModel, validator
|
||
|
|
||
|
from .models import Gender
|
||
|
|
||
|
|
||
|
class AbstractUserInfoValidation(BaseModel, ABC):
|
||
|
@validator('email', check_fields=False)
|
||
|
def assert_email_is_valid(cls, email):
|
||
|
if email is not None:
|
||
|
if not len(email):
|
||
|
raise ValueError("Email must not be empty.")
|
||
|
# TODO implement more robust check
|
||
|
return email
|
||
|
|
||
|
@validator('first_name', check_fields=False)
|
||
|
def assert_first_name_is_valid(cls, first_name):
|
||
|
if first_name is not None:
|
||
|
if not len(first_name):
|
||
|
raise ValueError("First Name must not be empty.")
|
||
|
return first_name
|
||
|
|
||
|
@validator('last_name', check_fields=False)
|
||
|
def assert_last_name_is_valid(cls, last_name):
|
||
|
if last_name is not None:
|
||
|
if not len(last_name):
|
||
|
raise ValueError("Last Name must not be empty.")
|
||
|
return last_name
|
||
|
|
||
|
@validator('date_of_birth', check_fields=False)
|
||
|
def assert_dob_is_valid(cls, dob):
|
||
|
if dob is not None:
|
||
|
if dob >= date.today():
|
||
|
raise ValueError("Date of birth cannot be in the future.")
|
||
|
return dob
|
||
|
|
||
|
class AbstractUser(AbstractUserInfoValidation, ABC):
|
||
|
email: str
|
||
|
first_name: str
|
||
|
last_name: str
|
||
|
|
||
|
gender: Optional[Gender]
|
||
|
date_of_birth: Optional[date]
|
||
|
is_patient: Optional[bool]
|
||
|
|
||
|
is_admin: Optional[bool]
|
||
|
|
||
|
@validator('is_admin')
|
||
|
def assert_tegridy(cls, is_admin, values):
|
||
|
if values['is_patient']:
|
||
|
if is_admin:
|
||
|
raise ValueError('User cannot be both patient and admin.')
|
||
|
for key in ['gender', 'date_of_birth']:
|
||
|
if key not in values or values[key] is None:
|
||
|
raise ValueError(f"Must specify key '{key}' for patients.")
|
||
|
if not values['is_patient'] and not is_admin:
|
||
|
raise ValueError(f'User must either be patient or admin.')
|
||
|
return is_admin
|
||
|
|
||
|
|
||
|
class UserCreate(AbstractUser):
|
||
|
password: str
|
||
|
password_confirmation: str
|
||
|
|
||
|
@validator('password_confirmation')
|
||
|
def assert_passwords_match(cls, password_confirmation, values):
|
||
|
if not password_confirmation == values['password']:
|
||
|
raise ValueError("Passwords do not match.")
|
||
|
if len(password_confirmation) < 1:
|
||
|
# TODO use more robust password rules
|
||
|
raise ValueError("Password must not be empty.")
|
||
|
return password_confirmation
|
||
|
|
||
|
|
||
|
class UserUpdate(AbstractUserInfoValidation):
|
||
|
email: Optional[str]
|
||
|
first_name: Optional[str]
|
||
|
last_name: Optional[str]
|
||
|
|
||
|
gender: Optional[Gender]
|
||
|
date_of_birth: Optional[date]
|
||
|
|
||
|
password: Optional[str] = None
|
||
|
password_confirmation: Optional[str] = None
|
||
|
|
||
|
@validator('password_confirmation')
|
||
|
def assert_passwords_match_or_are_both_none(cls, password_confirmation, values):
|
||
|
password = values.get('password')
|
||
|
if None not in [password, password_confirmation]:
|
||
|
if not password == password_confirmation:
|
||
|
raise ValueError("Passwords do not match.")
|
||
|
if len(password_confirmation) < 1:
|
||
|
# TODO use more robust password rules
|
||
|
raise ValueError("Password must not be empty.")
|
||
|
return password_confirmation
|
||
|
|
||
|
|
||
|
class User(AbstractUser):
|
||
|
id: int
|
||
|
created: datetime
|
||
|
updated: datetime
|
||
|
|
||
|
class Config:
|
||
|
orm_mode = True
|