gitscope
https://dev.kronoz.win/r/marzneshin.git
app/models/user.py · v0.3.2
Source
1 12b255b Dawsh 2y ago import secrets
2 a47eb4c Dawsh 2y ago from datetime import datetime
3 a47eb4c Dawsh 2y ago from enum import Enum
4 d377c4c Dawsh 2y ago from typing import Annotated
5 a47eb4c Dawsh 2y ago
6 01cdf2e Dawsh 2y ago from pydantic import (
7 01cdf2e Dawsh 2y ago ConfigDict,
8 01cdf2e Dawsh 2y ago BaseModel,
9 01cdf2e Dawsh 2y ago Field,
10 01cdf2e Dawsh 2y ago computed_field,
11 01cdf2e Dawsh 2y ago StringConstraints,
12 857e289 Mrdn 2y ago model_validator,
13 01cdf2e Dawsh 2y ago )
14 a47eb4c Dawsh 2y ago
15 8111eb7 Dawsh 2y ago from app.config.env import SUBSCRIPTION_URL_PREFIX
16 a47eb4c Dawsh 2y ago
17 f446990 Dawsh 2y ago USERNAME_REGEXP = r"^\w{3,32}$"
18 a47eb4c Dawsh 2y ago
19 a47eb4c Dawsh 2y ago
20 a47eb4c Dawsh 2y ago class ReminderType(str, Enum):
21 a47eb4c Dawsh 2y ago expiration_date = "expiration_date"
22 a47eb4c Dawsh 2y ago data_usage = "data_usage"
23 a47eb4c Dawsh 2y ago
24 a47eb4c Dawsh 2y ago
25 a47eb4c Dawsh 2y ago class UserStatus(str, Enum):
26 d377c4c Dawsh 2y ago ACTIVE = "active"
27 d377c4c Dawsh 2y ago INACTIVE = "inactive"
28 a47eb4c Dawsh 2y ago
29 12b255b Dawsh 2y ago
30 d377c4c Dawsh 2y ago class UserDataUsageResetStrategy(str, Enum):
31 a47eb4c Dawsh 2y ago no_reset = "no_reset"
32 a47eb4c Dawsh 2y ago day = "day"
33 a47eb4c Dawsh 2y ago week = "week"
34 a47eb4c Dawsh 2y ago month = "month"
35 a47eb4c Dawsh 2y ago year = "year"
36 a47eb4c Dawsh 2y ago
37 a47eb4c Dawsh 2y ago
38 d377c4c Dawsh 2y ago class UserExpireStrategy(str, Enum):
39 d377c4c Dawsh 2y ago NEVER = "never"
40 d377c4c Dawsh 2y ago FIXED_DATE = "fixed_date"
41 d377c4c Dawsh 2y ago START_ON_FIRST_USE = "start_on_first_use"
42 d377c4c Dawsh 2y ago
43 d377c4c Dawsh 2y ago
44 db68a58 Dawsh 2y ago class User(BaseModel):
45 db68a58 Dawsh 2y ago id: int | None = None
46 f1ab16c Dawsh 2y ago username: Annotated[
47 f1ab16c Dawsh 2y ago str, StringConstraints(to_lower=True, pattern=USERNAME_REGEXP)
48 f1ab16c Dawsh 2y ago ]
49 d377c4c Dawsh 2y ago expire_strategy: UserExpireStrategy
50 d377c4c Dawsh 2y ago expire_date: datetime | None = Field(None)
51 d377c4c Dawsh 2y ago usage_duration: int | None = Field(None)
52 d377c4c Dawsh 2y ago activation_deadline: datetime | None = Field(None)
53 a47eb4c Dawsh 2y ago key: str = Field(default_factory=lambda: secrets.token_hex(16))
54 db68a58 Dawsh 2y ago data_limit: int | None = Field(
55 a47eb4c Dawsh 2y ago ge=0, default=None, description="data_limit can be 0 or greater"
56 a47eb4c Dawsh 2y ago )
57 d377c4c Dawsh 2y ago data_limit_reset_strategy: UserDataUsageResetStrategy = (
58 d377c4c Dawsh 2y ago UserDataUsageResetStrategy.no_reset
59 a47eb4c Dawsh 2y ago )
60 db68a58 Dawsh 2y ago note: Annotated[str, Field(max_length=500)] | None = None
61 db68a58 Dawsh 2y ago sub_updated_at: datetime | None = Field(None)
62 db68a58 Dawsh 2y ago sub_last_user_agent: str | None = Field(None)
63 db68a58 Dawsh 2y ago online_at: datetime | None = Field(None)
64 a47eb4c Dawsh 2y ago
65 a47eb4c Dawsh 2y ago model_config = ConfigDict(from_attributes=True)
66 a47eb4c Dawsh 2y ago
67 4d647dd Dawsh 2y ago
68 a47eb4c Dawsh 2y ago class UserCreate(User):
69 db68a58 Dawsh 2y ago service_ids: list[int] = Field([])
70 01cdf2e Dawsh 2y ago model_config = ConfigDict(
71 01cdf2e Dawsh 2y ago json_schema_extra={
72 01cdf2e Dawsh 2y ago "example": {
73 01cdf2e Dawsh 2y ago "username": "user1234",
74 01cdf2e Dawsh 2y ago "services": [1, 2, 3],
75 d377c4c Dawsh 2y ago "expire_strategy": "start_on_first_use",
76 d377c4c Dawsh 2y ago "usage_duration": 86400 * 14,
77 d377c4c Dawsh 2y ago "activation_deadline": "2024-11-03T20:30:00",
78 01cdf2e Dawsh 2y ago "data_limit": 0,
79 01cdf2e Dawsh 2y ago "data_limit_reset_strategy": "no_reset",
80 01cdf2e Dawsh 2y ago "note": "",
81 01cdf2e Dawsh 2y ago }
82 a47eb4c Dawsh 2y ago }
83 01cdf2e Dawsh 2y ago )
84 a47eb4c Dawsh 2y ago
85 857e289 Mrdn 2y ago @model_validator(mode="after")
86 857e289 Mrdn 2y ago def validate_expiry(self):
87 d377c4c Dawsh 2y ago if self.expire_strategy == UserExpireStrategy.START_ON_FIRST_USE:
88 d377c4c Dawsh 2y ago if not self.usage_duration:
89 01cdf2e Dawsh 2y ago raise ValueError(
90 d377c4c Dawsh 2y ago "User expire_strategy can not be start_on_first_use without a valid usage_duration."
91 01cdf2e Dawsh 2y ago )
92 d377c4c Dawsh 2y ago elif (
93 d377c4c Dawsh 2y ago self.expire_strategy == UserExpireStrategy.FIXED_DATE
94 d377c4c Dawsh 2y ago and not self.expire_date
95 5c78ce8 Dawsh 2y ago ):
96 f1ab16c Dawsh 2y ago raise ValueError(
97 d377c4c Dawsh 2y ago "User expire_strategy can not be fixed_date without a valid expire date."
98 f1ab16c Dawsh 2y ago )
99 857e289 Mrdn 2y ago return self
100 857e289 Mrdn 2y ago
101 a47eb4c Dawsh 2y ago
102 d377c4c Dawsh 2y ago class UserModify(UserCreate):
103 db68a58 Dawsh 2y ago service_ids: list[int] | None = Field(None)
104 d377c4c Dawsh 2y ago data_limit_reset_strategy: UserDataUsageResetStrategy | None = Field(None)
105 01cdf2e Dawsh 2y ago model_config = ConfigDict(
106 01cdf2e Dawsh 2y ago json_schema_extra={
107 01cdf2e Dawsh 2y ago "example": {
108 01cdf2e Dawsh 2y ago "username": "mammad1234",
109 d377c4c Dawsh 2y ago "service_ids": [1, 2, 3],
110 d377c4c Dawsh 2y ago "expire_strategy": "fixed_date",
111 d377c4c Dawsh 2y ago "expire_date": "2023-11-03T20:30:00",
112 01cdf2e Dawsh 2y ago "data_limit": 0,
113 01cdf2e Dawsh 2y ago "data_limit_reset_strategy": "no_reset",
114 01cdf2e Dawsh 2y ago "note": "",
115 01cdf2e Dawsh 2y ago }
116 a47eb4c Dawsh 2y ago }
117 01cdf2e Dawsh 2y ago )
118 a47eb4c Dawsh 2y ago
119 a47eb4c Dawsh 2y ago
120 a47eb4c Dawsh 2y ago class UserResponse(User):
121 a47eb4c Dawsh 2y ago id: int
122 d377c4c Dawsh 2y ago activated: bool
123 d377c4c Dawsh 2y ago is_active: bool
124 d377c4c Dawsh 2y ago expired: bool
125 d377c4c Dawsh 2y ago data_limit_reached: bool
126 d377c4c Dawsh 2y ago enabled: bool
127 a47eb4c Dawsh 2y ago used_traffic: int
128 d377c4c Dawsh 2y ago lifetime_used_traffic: int
129 a47eb4c Dawsh 2y ago created_at: datetime
130 db68a58 Dawsh 2y ago service_ids: list[int]
131 9bfa731 Dawsh 2y ago
132 a47eb4c Dawsh 2y ago model_config = ConfigDict(from_attributes=True)
133 9bfa731 Dawsh 2y ago
134 a47eb4c Dawsh 2y ago @computed_field
135 a47eb4c Dawsh 2y ago @property
136 a47eb4c Dawsh 2y ago def subscription_url(self) -> str:
137 a47eb4c Dawsh 2y ago salt = secrets.token_hex(8)
138 5c78ce8 Dawsh 2y ago url_prefix = SUBSCRIPTION_URL_PREFIX.replace("*", salt)
139 6a606d6 Dawsh 2y ago return f"{url_prefix}/sub/{self.username}/{self.key}"
140 a47eb4c Dawsh 2y ago
141 a47eb4c Dawsh 2y ago
142 a47eb4c Dawsh 2y ago class UserUsageResponse(BaseModel):
143 d377c4c Dawsh 2y ago node_id: int | None = None
144 a47eb4c Dawsh 2y ago node_name: str
145 a47eb4c Dawsh 2y ago used_traffic: int
146 a47eb4c Dawsh 2y ago
147 a47eb4c Dawsh 2y ago
148 a47eb4c Dawsh 2y ago class UserUsagesResponse(BaseModel):
149 a47eb4c Dawsh 2y ago username: str
150 d377c4c Dawsh 2y ago usages: list[UserUsageResponse]