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