Coverage for bc/kwai-bc-identity/src/kwai_bc_identity/users/user_account.py: 96%
28 statements
« prev ^ index » next coverage.py v7.11.0, created at 2024-01-01 00:00 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2024-01-01 00:00 +0000
1"""Module that implements a user account entity."""
3from dataclasses import dataclass, field, replace
4from typing import ClassVar, Self, Type
6from kwai_core.domain.entity import DataclassEntity
7from kwai_core.domain.value_objects.identifier import IntIdentifier
8from kwai_core.domain.value_objects.password import Password
9from kwai_core.domain.value_objects.timestamp import Timestamp
11from kwai_bc_identity.exceptions import NotAllowedException
12from kwai_bc_identity.users.user import UserEntity
15class UserAccountIdentifier(IntIdentifier):
16 """Identifier for a user account."""
19@dataclass(kw_only=True, eq=False, slots=True, frozen=True)
20class UserAccountEntity(DataclassEntity):
21 """A user account entity.
23 Attributes:
24 user: The associated user entity.
25 password: The password of the user.
26 logged_in: Whether the user is logged in.
27 last_login: Timestamp of the last login.
28 last_unsuccessful_login: Timestamp of the last unsuccessful login.
29 revoked: Whether the user is revoked.
30 admin: Whether the user is an administrator.
31 """
33 ID: ClassVar[Type] = UserAccountIdentifier
35 user: UserEntity
36 password: Password
37 logged_in: bool = False
38 last_login: Timestamp = field(default_factory=Timestamp)
39 last_unsuccessful_login: Timestamp = field(default_factory=Timestamp)
40 revoked: bool = False
42 def login(self, password: str | None = None) -> Self:
43 """Check if the given password is correct.
45 When login succeeds, last_login will be updated.
46 When login fails, last_unsuccessful_login will be updated.
47 Use None for password, when the user logs in using OIDC.
49 Args:
50 password: The password.
51 """
52 if password and not self.password.verify(password):
53 return replace(
54 self, last_unsuccessful_login=Timestamp.create_now(), logged_in=False
55 )
57 return replace(self, last_login=Timestamp.create_now(), logged_in=True)
59 def reset_password(self, password: Password) -> Self:
60 """Reset the password of the user account.
62 Args:
63 password: The new password.
64 """
65 if self.revoked:
66 raise NotAllowedException()
68 return replace(
69 self,
70 password=password,
71 traceable_time=self.traceable_time.mark_for_update(),
72 )
74 def revoke(self) -> Self:
75 """Revoke a user account."""
76 return replace(
77 self, revoked=True, traceable_time=self.traceable_time.mark_for_update()
78 )
80 def enact(self) -> Self:
81 """Reactivate a user account."""
82 return replace(
83 self, revoked=False, traceable_time=self.traceable_time.mark_for_update()
84 )