-
-
Notifications
You must be signed in to change notification settings - Fork 50
Expand file tree
/
Copy pathusers.py
More file actions
72 lines (58 loc) · 1.87 KB
/
users.py
File metadata and controls
72 lines (58 loc) · 1.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import dataclasses
from enum import IntEnum
from typing import Annotated, Self
from pydantic import StringConstraints
from sqlalchemy import Connection, text
from config import load_configuration
# Enforces str is 32 hexadecimal characters, does not check validity.
api_key_pattern = r"^[0-9a-fA-F]{32}$"
if load_configuration()["development"].get("allow_test_api_keys"):
api_key_pattern = r"^([0-9a-fA-F]{32}|normaluser|normaluser2|abc)$"
APIKey = Annotated[
str,
StringConstraints(pattern=api_key_pattern),
]
class UserGroup(IntEnum):
ADMIN = (1,)
READ_WRITE = (2,)
READ_ONLY = (3,)
def get_user_id_for(*, api_key: APIKey, connection: Connection) -> int | None:
user = connection.execute(
text(
"""
SELECT *
FROM users
WHERE session_hash = :api_key
""",
),
parameters={"api_key": api_key},
).one_or_none()
return user.id if user else None
def get_user_groups_for(*, user_id: int, connection: Connection) -> list[UserGroup]:
row = connection.execute(
text(
"""
SELECT group_id
FROM users_groups
WHERE user_id = :user_id
""",
),
parameters={"user_id": user_id},
)
return [UserGroup(group) for (group,) in row]
@dataclasses.dataclass
class User:
user_id: int
_database: Connection
_groups: list[UserGroup] | None = None
@classmethod
def fetch(cls, api_key: APIKey, user_db: Connection) -> Self | None:
if user_id := get_user_id_for(api_key=api_key, connection=user_db):
return cls(user_id, _database=user_db)
return None
@property
def groups(self) -> list[UserGroup]:
if self._groups is None:
groups = get_user_groups_for(user_id=self.user_id, connection=self._database)
self._groups = [UserGroup(group_id) for group_id in groups]
return self._groups