Coverage for src/typedal/for_py4web.py: 100%
27 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-14 15:09 +0100
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-14 15:09 +0100
1"""
2ONLY USE IN COMBINATION WITH PY4WEB!
3"""
4import typing
5from datetime import datetime
6from typing import Any, Optional
8import json_fix # noqa: F401
9import threadsafevariable
10from py4web.core import ICECUBE
11from py4web.core import Fixture as _Fixture
12from pydal.validators import CRYPT, IS_EMAIL, IS_NOT_EMPTY, IS_NOT_IN_DB, IS_STRONG
14from .core import TypeDAL, TypedField, TypedTable
15from .fields import PasswordField
16from .types import Validator
19class Fixture(_Fixture): # type: ignore
20 """
21 Make mypy happy.
22 """
25class DAL(TypeDAL, Fixture): # pragma: no cover
26 """
27 Fixture similar to the py4web pydal fixture, but for typedal.
28 """
30 def on_request(self, _: dict[str, Any]) -> None:
31 """
32 Make sure there is a database connection when a request comes in.
33 """
34 self.get_connection_from_pool_or_new()
35 threadsafevariable.ThreadSafeVariable.restore(ICECUBE)
37 def on_error(self, _: dict[str, Any]) -> None:
38 """
39 Rollback db on error.
40 """
41 self.recycle_connection_in_pool_or_close("rollback")
43 def on_success(self, _: dict[str, Any]) -> None:
44 """
45 Commit db on success.
46 """
47 self.recycle_connection_in_pool_or_close("commit")
50class AuthUser(TypedTable):
51 """
52 Class for db.auth_user in py4web (probably not w2p).
53 """
55 redefine = True
56 migrate = False
58 # call db.define on this when ready
60 email: TypedField[str]
61 password = PasswordField(requires=[IS_STRONG(entropy=45), CRYPT()])
62 first_name: TypedField[Optional[str]]
63 last_name: TypedField[Optional[str]]
64 sso_id: TypedField[Optional[str]]
65 action_token: TypedField[Optional[str]]
66 last_password_change: TypedField[Optional[datetime]]
68 # past_passwords_hash: Optional[str]
69 # username: Optional[str]
70 # phone_number: Optional[str]
72 @classmethod
73 def __on_define__(cls, db: TypeDAL) -> None:
74 """
75 Add some requires= to the auth_user fields.
76 """
77 cls.email.requires = typing.cast(tuple[Validator, ...], (IS_EMAIL(), IS_NOT_IN_DB(db, "auth_user.email")))
78 cls.first_name.requires = IS_NOT_EMPTY()
79 cls.last_name.requires = IS_NOT_EMPTY()