supernote 0.13.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- supernote/__init__.py +28 -0
- supernote/alembic/__init__.py +0 -0
- supernote/alembic/env.py +121 -0
- supernote/alembic/script.py.mako +28 -0
- supernote/alembic/versions/0543a383957b_initial_schema.py +312 -0
- supernote/alembic.ini +149 -0
- supernote/cli/__init__.py +1 -0
- supernote/cli/admin.py +178 -0
- supernote/cli/client.py +434 -0
- supernote/cli/main.py +61 -0
- supernote/cli/notebook.py +313 -0
- supernote/cli/server.py +89 -0
- supernote/client/__init__.py +28 -0
- supernote/client/admin.py +76 -0
- supernote/client/api.py +135 -0
- supernote/client/api_model.py +231 -0
- supernote/client/auth.py +84 -0
- supernote/client/client.py +365 -0
- supernote/client/device.py +361 -0
- supernote/client/exceptions.py +33 -0
- supernote/client/extended.py +20 -0
- supernote/client/hashing.py +50 -0
- supernote/client/login_client.py +154 -0
- supernote/client/schedule.py +149 -0
- supernote/client/summary.py +156 -0
- supernote/client/web.py +213 -0
- supernote/models/__init__.py +14 -0
- supernote/models/auth.py +380 -0
- supernote/models/base.py +266 -0
- supernote/models/equipment.py +276 -0
- supernote/models/extended.py +124 -0
- supernote/models/file_common.py +95 -0
- supernote/models/file_device.py +571 -0
- supernote/models/file_web.py +602 -0
- supernote/models/schedule.py +663 -0
- supernote/models/summary.py +830 -0
- supernote/models/system.py +431 -0
- supernote/models/user.py +638 -0
- supernote/notebook/__init__.py +67 -0
- supernote/notebook/color.py +93 -0
- supernote/notebook/converter.py +560 -0
- supernote/notebook/decoder.py +398 -0
- supernote/notebook/exceptions.py +43 -0
- supernote/notebook/fileformat.py +463 -0
- supernote/notebook/manipulator.py +420 -0
- supernote/notebook/parser.py +737 -0
- supernote/notebook/utils.py +49 -0
- supernote/py.typed +0 -0
- supernote/server/__init__.py +12 -0
- supernote/server/app.py +428 -0
- supernote/server/config.py +265 -0
- supernote/server/constants.py +26 -0
- supernote/server/db/__init__.py +9 -0
- supernote/server/db/base.py +8 -0
- supernote/server/db/migrations.py +44 -0
- supernote/server/db/models/__init__.py +23 -0
- supernote/server/db/models/device.py +17 -0
- supernote/server/db/models/file.py +107 -0
- supernote/server/db/models/kv.py +17 -0
- supernote/server/db/models/login_record.py +22 -0
- supernote/server/db/models/note_processing.py +100 -0
- supernote/server/db/models/schedule.py +83 -0
- supernote/server/db/models/summary.py +122 -0
- supernote/server/db/models/user.py +30 -0
- supernote/server/db/session.py +88 -0
- supernote/server/events.py +63 -0
- supernote/server/exceptions.py +153 -0
- supernote/server/mcp/__init__.py +1 -0
- supernote/server/mcp/models.py +109 -0
- supernote/server/mcp/server.py +176 -0
- supernote/server/resources/__init__.py +0 -0
- supernote/server/resources/prompts/__init__.py +0 -0
- supernote/server/resources/prompts/ocr/common/context.md +19 -0
- supernote/server/resources/prompts/ocr/common/legend.md +11 -0
- supernote/server/resources/prompts/ocr/daily/prompt.md +12 -0
- supernote/server/resources/prompts/ocr/default/system.md +14 -0
- supernote/server/resources/prompts/ocr/monthly/prompt.md +22 -0
- supernote/server/resources/prompts/ocr/weekly/prompt.md +16 -0
- supernote/server/resources/prompts/summary/common/instruction.md +8 -0
- supernote/server/resources/prompts/summary/daily/prompt.md +6 -0
- supernote/server/resources/prompts/summary/default/prompt.md +4 -0
- supernote/server/resources/prompts/summary/monthly/prompt.md +6 -0
- supernote/server/resources/prompts/summary/weekly/prompt.md +6 -0
- supernote/server/routes/admin.py +109 -0
- supernote/server/routes/auth.py +337 -0
- supernote/server/routes/decorators.py +13 -0
- supernote/server/routes/extended.py +139 -0
- supernote/server/routes/file_device.py +593 -0
- supernote/server/routes/file_web.py +597 -0
- supernote/server/routes/oss.py +317 -0
- supernote/server/routes/schedule.py +223 -0
- supernote/server/routes/summary.py +390 -0
- supernote/server/routes/system.py +57 -0
- supernote/server/services/__init__.py +15 -0
- supernote/server/services/blob.py +214 -0
- supernote/server/services/coordination.py +171 -0
- supernote/server/services/file.py +970 -0
- supernote/server/services/gemini.py +66 -0
- supernote/server/services/integrity.py +112 -0
- supernote/server/services/processor.py +331 -0
- supernote/server/services/processor_modules/__init__.py +145 -0
- supernote/server/services/processor_modules/gemini_embedding.py +112 -0
- supernote/server/services/processor_modules/gemini_ocr.py +149 -0
- supernote/server/services/processor_modules/page_hashing.py +220 -0
- supernote/server/services/processor_modules/png_conversion.py +107 -0
- supernote/server/services/processor_modules/summary.py +302 -0
- supernote/server/services/prompt_loader.py +133 -0
- supernote/server/services/schedule.py +161 -0
- supernote/server/services/search.py +250 -0
- supernote/server/services/summary.py +419 -0
- supernote/server/services/user.py +480 -0
- supernote/server/services/vfs.py +476 -0
- supernote/server/static/favicon.ico +0 -0
- supernote/server/static/index.html +186 -0
- supernote/server/static/js/api/client.js +463 -0
- supernote/server/static/js/components/FileCard.js +55 -0
- supernote/server/static/js/components/FileViewer.js +137 -0
- supernote/server/static/js/components/LoginCard.js +64 -0
- supernote/server/static/js/components/MoveModal.js +74 -0
- supernote/server/static/js/components/RenameModal.js +39 -0
- supernote/server/static/js/components/SummaryPanel.js +101 -0
- supernote/server/static/js/components/SystemPanel.js +158 -0
- supernote/server/static/js/composables/useFileSystem.js +116 -0
- supernote/server/static/js/main.js +241 -0
- supernote/server/static/style.css +14 -0
- supernote/server/utils/hashing.py +18 -0
- supernote/server/utils/note_content.py +76 -0
- supernote/server/utils/paths.py +58 -0
- supernote/server/utils/rate_limit.py +52 -0
- supernote/server/utils/tasks.py +71 -0
- supernote/server/utils/unique_id.py +48 -0
- supernote/server/utils/url_signer.py +218 -0
- supernote-0.13.6.dist-info/METADATA +183 -0
- supernote-0.13.6.dist-info/RECORD +138 -0
- supernote-0.13.6.dist-info/WHEEL +5 -0
- supernote-0.13.6.dist-info/entry_points.txt +3 -0
- supernote-0.13.6.dist-info/licenses/LICENSE +201 -0
- supernote-0.13.6.dist-info/top_level.txt +1 -0
supernote/models/auth.py
ADDED
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
"""Module for authentication API data models.
|
|
2
|
+
|
|
3
|
+
The following endpoints are supported:
|
|
4
|
+
- /api/official/user/account/login/equipment
|
|
5
|
+
- /api/official/user/account/login/new
|
|
6
|
+
- /api/official/user/query/random/code
|
|
7
|
+
- /api/official/user/sms/login
|
|
8
|
+
- /api/user/sms/validcode/send
|
|
9
|
+
- /api/user/query/token
|
|
10
|
+
- /api/user/validcode/pre-auth
|
|
11
|
+
- /api/user/logout (empty body)
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
|
|
16
|
+
from mashumaro import field_options
|
|
17
|
+
from mashumaro.config import BaseConfig
|
|
18
|
+
from mashumaro.mixins.json import DataClassJSONMixin
|
|
19
|
+
|
|
20
|
+
from .base import BaseEnum, BaseResponse
|
|
21
|
+
|
|
22
|
+
COUNTRY_CODE = 1
|
|
23
|
+
BROWSER = "Chrome142"
|
|
24
|
+
LANGUAGE = "en"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Equipment(BaseEnum):
|
|
28
|
+
"""Device type."""
|
|
29
|
+
|
|
30
|
+
WEB = 1
|
|
31
|
+
APP = 2
|
|
32
|
+
TERMINAL = 3
|
|
33
|
+
USER_PLATFORM = 4
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _deserialize_int_equipment(value: str) -> Equipment:
|
|
37
|
+
return Equipment(int(value))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class UserCheckDTO(DataClassJSONMixin):
|
|
42
|
+
"""Request to check user existence."""
|
|
43
|
+
|
|
44
|
+
email: str
|
|
45
|
+
country_code: str = field(metadata=field_options(alias="countryCode"), default="")
|
|
46
|
+
telephone: str = ""
|
|
47
|
+
user_name: str = field(metadata=field_options(alias="userName"), default="")
|
|
48
|
+
domain: str = ""
|
|
49
|
+
|
|
50
|
+
class Config(BaseConfig):
|
|
51
|
+
serialize_by_alias = True
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class LoginMethod(str, BaseEnum):
|
|
55
|
+
"""Method for logging in to account."""
|
|
56
|
+
|
|
57
|
+
PHONE = "1"
|
|
58
|
+
EMAIL = "2"
|
|
59
|
+
WECHAT = "3"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass
|
|
63
|
+
class LoginDTO(DataClassJSONMixin):
|
|
64
|
+
"""Request to login.
|
|
65
|
+
|
|
66
|
+
This is used by the following POST endpoints:
|
|
67
|
+
/api/official/user/account/login/equipment
|
|
68
|
+
/api/official/user/account/login/new
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
account: str
|
|
72
|
+
"""User account (must be an email address)."""
|
|
73
|
+
|
|
74
|
+
password: str
|
|
75
|
+
"""Hashed password. Schema: SHA256(MD5(pwd) + randomCode)) or MD5(pwd + randomCode)."""
|
|
76
|
+
|
|
77
|
+
timestamp: str
|
|
78
|
+
"""Client timestamp in milliseconds."""
|
|
79
|
+
|
|
80
|
+
login_method: LoginMethod = field(metadata=field_options(alias="loginMethod"))
|
|
81
|
+
"""Login method."""
|
|
82
|
+
|
|
83
|
+
language: str = LANGUAGE
|
|
84
|
+
"""Language code."""
|
|
85
|
+
|
|
86
|
+
country_code: int | None = field(
|
|
87
|
+
metadata=field_options(alias="countryCode"), default=None
|
|
88
|
+
)
|
|
89
|
+
"""Country code."""
|
|
90
|
+
|
|
91
|
+
browser: str = BROWSER
|
|
92
|
+
"""Browser name (user agent info)."""
|
|
93
|
+
|
|
94
|
+
equipment: Equipment = field(
|
|
95
|
+
metadata=field_options(deserialize=_deserialize_int_equipment),
|
|
96
|
+
default=Equipment.WEB,
|
|
97
|
+
)
|
|
98
|
+
"""Device type."""
|
|
99
|
+
|
|
100
|
+
equipment_no: str | None = field(
|
|
101
|
+
metadata=field_options(alias="equipmentNo"), default=None
|
|
102
|
+
)
|
|
103
|
+
"""Device serial number (SN12345678) or other client identifier (WEB)."""
|
|
104
|
+
|
|
105
|
+
class Config(BaseConfig):
|
|
106
|
+
serialize_by_alias = True
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@dataclass(kw_only=True)
|
|
110
|
+
class LoginVO(BaseResponse):
|
|
111
|
+
"""Response from login endpoints."""
|
|
112
|
+
|
|
113
|
+
token: str
|
|
114
|
+
"""JWT Access Token."""
|
|
115
|
+
|
|
116
|
+
counts: str
|
|
117
|
+
"""Error count."""
|
|
118
|
+
|
|
119
|
+
user_name: str | None = field(
|
|
120
|
+
metadata=field_options(alias="userName"), default=None
|
|
121
|
+
)
|
|
122
|
+
"""User nickname."""
|
|
123
|
+
|
|
124
|
+
is_bind: str = field(metadata=field_options(alias="isBind"), default="N")
|
|
125
|
+
"""Is account bound."""
|
|
126
|
+
|
|
127
|
+
is_bind_equipment: str = field(
|
|
128
|
+
metadata=field_options(alias="isBindEquipment"), default="N"
|
|
129
|
+
)
|
|
130
|
+
"""Is device bound (Terminal only)."""
|
|
131
|
+
|
|
132
|
+
sold_out_count: int = field(metadata=field_options(alias="soldOutCount"), default=0)
|
|
133
|
+
"""Logout count."""
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@dataclass
|
|
137
|
+
class RandomCodeDTO(DataClassJSONMixin):
|
|
138
|
+
"""Request to get a random code.
|
|
139
|
+
|
|
140
|
+
This is used by the following POST endpoint:
|
|
141
|
+
/api/official/user/query/random/code
|
|
142
|
+
"""
|
|
143
|
+
|
|
144
|
+
account: str
|
|
145
|
+
"""User account (must be an email address)."""
|
|
146
|
+
|
|
147
|
+
country_code: int | None = field(
|
|
148
|
+
metadata=field_options(alias="countryCode"), default=None
|
|
149
|
+
)
|
|
150
|
+
"""Country code."""
|
|
151
|
+
|
|
152
|
+
version: str | None = None
|
|
153
|
+
"""Version."""
|
|
154
|
+
|
|
155
|
+
class Config(BaseConfig):
|
|
156
|
+
serialize_by_alias = True
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@dataclass(kw_only=True)
|
|
160
|
+
class RandomCodeVO(BaseResponse):
|
|
161
|
+
"""Response from random code endpoint."""
|
|
162
|
+
|
|
163
|
+
random_code: str = field(metadata=field_options(alias="randomCode"), default="")
|
|
164
|
+
"""Server-side nonce (salt) used for password hashing."""
|
|
165
|
+
|
|
166
|
+
timestamp: str = ""
|
|
167
|
+
"""Client timestamp in milliseconds."""
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@dataclass
|
|
171
|
+
class QueryTokenDTO(DataClassJSONMixin):
|
|
172
|
+
"""Request to token endpoint.
|
|
173
|
+
|
|
174
|
+
This is used by the following POST endpoint:
|
|
175
|
+
/api/user/query/token
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@dataclass(kw_only=True)
|
|
180
|
+
class QueryTokenVO(BaseResponse):
|
|
181
|
+
"""Response from token endpoint."""
|
|
182
|
+
|
|
183
|
+
token: str | None = None
|
|
184
|
+
"""JWT Access Token."""
|
|
185
|
+
|
|
186
|
+
class Config(BaseConfig):
|
|
187
|
+
serialize_by_alias = True
|
|
188
|
+
omit_none = False
|
|
189
|
+
code_generation_options = ["TO_DICT_ADD_OMIT_NONE_FLAG"]
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class OSType(str, BaseEnum):
|
|
193
|
+
"""OS Type."""
|
|
194
|
+
|
|
195
|
+
WINDOWS = "WINDOWS"
|
|
196
|
+
MACOS = "MACOS"
|
|
197
|
+
LINUX = "LINUX"
|
|
198
|
+
ANDROID = "ANDROID"
|
|
199
|
+
IOS = "IOS"
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@dataclass
|
|
203
|
+
class UserVO(DataClassJSONMixin):
|
|
204
|
+
"""User profile VO."""
|
|
205
|
+
|
|
206
|
+
user_name: str | None = field(
|
|
207
|
+
metadata=field_options(alias="userName"), default=None
|
|
208
|
+
)
|
|
209
|
+
email: str | None = None
|
|
210
|
+
phone: str | None = None
|
|
211
|
+
country_code: str | None = field(
|
|
212
|
+
metadata=field_options(alias="countryCode"), default=None
|
|
213
|
+
)
|
|
214
|
+
total_capacity: str = field(
|
|
215
|
+
metadata=field_options(alias="totalCapacity"), default="0"
|
|
216
|
+
)
|
|
217
|
+
file_server: str = field(metadata=field_options(alias="fileServer"), default="0")
|
|
218
|
+
avatars_url: str | None = field(
|
|
219
|
+
metadata=field_options(alias="avatarsUrl"), default=None
|
|
220
|
+
)
|
|
221
|
+
birthday: str | None = None
|
|
222
|
+
sex: str | None = None
|
|
223
|
+
|
|
224
|
+
class Config(BaseConfig):
|
|
225
|
+
serialize_by_alias = True
|
|
226
|
+
omit_none = True
|
|
227
|
+
code_generation_options = ["TO_DICT_ADD_OMIT_NONE_FLAG"]
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
@dataclass
|
|
231
|
+
class UserQueryByIdVO(BaseResponse):
|
|
232
|
+
"""User query response."""
|
|
233
|
+
|
|
234
|
+
user: UserVO | None = None
|
|
235
|
+
is_user: bool = field(metadata=field_options(alias="isUser"), default=False)
|
|
236
|
+
equipment_no: str | None = field(
|
|
237
|
+
metadata=field_options(alias="equipmentNo"), default=None
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
@dataclass
|
|
242
|
+
class SmsLoginDTO(DataClassJSONMixin):
|
|
243
|
+
"""Request to login via sms.
|
|
244
|
+
|
|
245
|
+
This is used by the following POST endpoint:
|
|
246
|
+
/api/user/sms/login
|
|
247
|
+
"""
|
|
248
|
+
|
|
249
|
+
valid_code: str = field(metadata=field_options(alias="validCode"))
|
|
250
|
+
"""SMS/Email verification code."""
|
|
251
|
+
|
|
252
|
+
valid_code_key: str = field(metadata=field_options(alias="validCodeKey"))
|
|
253
|
+
"""Redis session key for the code (e.g., '{email}_validCode')."""
|
|
254
|
+
|
|
255
|
+
country_code: int = field(
|
|
256
|
+
metadata=field_options(alias="countryCode"), default=COUNTRY_CODE
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
telephone: str | None = None
|
|
260
|
+
"""User phone number."""
|
|
261
|
+
|
|
262
|
+
timestamp: str | None = None
|
|
263
|
+
"""Client timestamp in milliseconds."""
|
|
264
|
+
|
|
265
|
+
email: str | None = None
|
|
266
|
+
"""User email."""
|
|
267
|
+
|
|
268
|
+
browser: str = BROWSER
|
|
269
|
+
"""Browser name (user agent info)."""
|
|
270
|
+
|
|
271
|
+
equipment: Equipment = Equipment.WEB
|
|
272
|
+
"""Device type."""
|
|
273
|
+
|
|
274
|
+
devices: OSType | None = OSType.WINDOWS
|
|
275
|
+
"""OS Type: WINDOWS, MACOS, LINUX, ANDROID, IOS."""
|
|
276
|
+
|
|
277
|
+
class Config(BaseConfig):
|
|
278
|
+
serialize_by_alias = True
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
@dataclass(kw_only=True)
|
|
282
|
+
class SmsLoginVO(BaseResponse):
|
|
283
|
+
"""Response from access token call."""
|
|
284
|
+
|
|
285
|
+
token: str
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
@dataclass
|
|
289
|
+
class UserPreAuthRequest(DataClassJSONMixin):
|
|
290
|
+
"""Request for pre-auth.
|
|
291
|
+
|
|
292
|
+
This is used by the following POST endpoint:
|
|
293
|
+
/api/user/validcode/pre-auth
|
|
294
|
+
"""
|
|
295
|
+
|
|
296
|
+
account: str
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
@dataclass
|
|
300
|
+
class UserPreAuthResponse(BaseResponse):
|
|
301
|
+
"""Response from pre-auth."""
|
|
302
|
+
|
|
303
|
+
token: str = ""
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
@dataclass
|
|
307
|
+
class SendSmsDTO(DataClassJSONMixin):
|
|
308
|
+
"""Request to send SMS code.
|
|
309
|
+
|
|
310
|
+
This is used by the following POST endpoint:
|
|
311
|
+
/api/user/sms/validcode/send
|
|
312
|
+
"""
|
|
313
|
+
|
|
314
|
+
telephone: str
|
|
315
|
+
"""User phone number."""
|
|
316
|
+
|
|
317
|
+
timestamp: str
|
|
318
|
+
"""Client timestamp in milliseconds."""
|
|
319
|
+
|
|
320
|
+
token: str
|
|
321
|
+
"""JWT Access Token."""
|
|
322
|
+
|
|
323
|
+
sign: str
|
|
324
|
+
"""JWT Signature."""
|
|
325
|
+
|
|
326
|
+
extend: str | None = None
|
|
327
|
+
"""JWT Extension."""
|
|
328
|
+
|
|
329
|
+
nationcode: int = field(
|
|
330
|
+
metadata=field_options(alias="nationcode"), default=COUNTRY_CODE
|
|
331
|
+
)
|
|
332
|
+
"""Country code."""
|
|
333
|
+
|
|
334
|
+
class Config(BaseConfig):
|
|
335
|
+
serialize_by_alias = True
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
@dataclass
|
|
339
|
+
class SendSmsVO(BaseResponse):
|
|
340
|
+
"""Response from send SMS."""
|
|
341
|
+
|
|
342
|
+
valid_code_key: str = field(
|
|
343
|
+
metadata=field_options(alias="validCodeKey"), default=""
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
@dataclass
|
|
348
|
+
class EmailDTO(DataClassJSONMixin):
|
|
349
|
+
"""Request to send email code.
|
|
350
|
+
|
|
351
|
+
Used by:
|
|
352
|
+
/api/user/mail/validcode (POST)
|
|
353
|
+
"""
|
|
354
|
+
|
|
355
|
+
email: str
|
|
356
|
+
"""User email."""
|
|
357
|
+
|
|
358
|
+
language: str | None = None
|
|
359
|
+
"""Language code."""
|
|
360
|
+
|
|
361
|
+
class Config(BaseConfig):
|
|
362
|
+
serialize_by_alias = True
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
@dataclass
|
|
366
|
+
class ValidCodeDTO(DataClassJSONMixin):
|
|
367
|
+
"""Request to check validation code.
|
|
368
|
+
|
|
369
|
+
Used by:
|
|
370
|
+
/api/user/check/validcode (POST)
|
|
371
|
+
"""
|
|
372
|
+
|
|
373
|
+
valid_code_key: str = field(metadata=field_options(alias="validCodeKey"))
|
|
374
|
+
"""Key for the validation code."""
|
|
375
|
+
|
|
376
|
+
valid_code: str = field(metadata=field_options(alias="validCode"))
|
|
377
|
+
"""The validation code."""
|
|
378
|
+
|
|
379
|
+
class Config(BaseConfig):
|
|
380
|
+
serialize_by_alias = True
|
supernote/models/base.py
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"""Module for API base classes."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Any, Self
|
|
6
|
+
|
|
7
|
+
from mashumaro import field_options
|
|
8
|
+
from mashumaro.config import BaseConfig
|
|
9
|
+
from mashumaro.mixins.json import DataClassJSONMixin
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class BaseResponse(DataClassJSONMixin):
|
|
14
|
+
"""Base response class."""
|
|
15
|
+
|
|
16
|
+
success: bool = True
|
|
17
|
+
"""Whether the request was successful."""
|
|
18
|
+
|
|
19
|
+
error_code: str | None = field(
|
|
20
|
+
metadata=field_options(alias="errorCode"), default=None
|
|
21
|
+
)
|
|
22
|
+
"""Error code."""
|
|
23
|
+
|
|
24
|
+
error_msg: str | None = field(
|
|
25
|
+
metadata=field_options(alias="errorMsg"), default=None
|
|
26
|
+
)
|
|
27
|
+
"""Error message."""
|
|
28
|
+
|
|
29
|
+
class Config(BaseConfig):
|
|
30
|
+
serialize_by_alias = True
|
|
31
|
+
omit_none = True
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class BaseEnum(Enum):
|
|
35
|
+
"""Base enum class."""
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def from_value(cls, value: int) -> Self:
|
|
39
|
+
for member in cls:
|
|
40
|
+
if member.value == value:
|
|
41
|
+
return member
|
|
42
|
+
raise ValueError(f"Invalid {cls.__name__} value: {value}")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class BooleanEnum(str, BaseEnum):
|
|
46
|
+
"""Boolean enum."""
|
|
47
|
+
|
|
48
|
+
YES = "Y"
|
|
49
|
+
NO = "N"
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def of(cls, value: bool) -> Self:
|
|
53
|
+
return cls.YES if value else cls.NO
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class ProcessingStatus(str, BaseEnum):
|
|
57
|
+
"""Processing status for system tasks."""
|
|
58
|
+
|
|
59
|
+
PENDING = "PENDING"
|
|
60
|
+
PROCESSING = "PROCESSING"
|
|
61
|
+
COMPLETED = "COMPLETED"
|
|
62
|
+
FAILED = "FAILED"
|
|
63
|
+
NONE = "NONE" # Used in view aggregation
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass
|
|
67
|
+
class CommonList(BaseResponse):
|
|
68
|
+
"""Common list response class."""
|
|
69
|
+
|
|
70
|
+
total: int = 0
|
|
71
|
+
"""Total count of items."""
|
|
72
|
+
|
|
73
|
+
pages: int = 0
|
|
74
|
+
"""Total pages."""
|
|
75
|
+
|
|
76
|
+
size: int = field(metadata=field_options(alias="size"), default=20)
|
|
77
|
+
"""Current page size."""
|
|
78
|
+
|
|
79
|
+
vo_list: list[Any] = field(
|
|
80
|
+
metadata=field_options(alias="voList"), default_factory=list
|
|
81
|
+
)
|
|
82
|
+
"""List of items."""
|
|
83
|
+
|
|
84
|
+
class Config(BaseConfig):
|
|
85
|
+
serialize_by_alias = True
|
|
86
|
+
omit_none = True
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class ErrorCode(str, Enum):
|
|
90
|
+
"""API Error Codes."""
|
|
91
|
+
|
|
92
|
+
description: str
|
|
93
|
+
|
|
94
|
+
def __new__(cls, code: str, message: str) -> "ErrorCode":
|
|
95
|
+
obj = str.__new__(cls, code)
|
|
96
|
+
obj._value_ = code
|
|
97
|
+
setattr(obj, "description", message)
|
|
98
|
+
return obj
|
|
99
|
+
|
|
100
|
+
SUCCESS = ("200", "Success")
|
|
101
|
+
BAD_REQUEST = ("400", "Bad Request")
|
|
102
|
+
UNAUTHORIZED = ("401", "Unauthorized")
|
|
103
|
+
FORBIDDEN = ("403", "Forbidden")
|
|
104
|
+
NOT_FOUND = ("404", "Not Found")
|
|
105
|
+
CONFLICT = ("409", "Conflict")
|
|
106
|
+
INTERNAL_ERROR = ("500", "Internal Server Error")
|
|
107
|
+
|
|
108
|
+
# Specific Error Codes from legacy system
|
|
109
|
+
OPERATION_FAILED = ("E0701", "Operation failed!")
|
|
110
|
+
DELETION_FAILED = ("E0702", "Deletion failed!")
|
|
111
|
+
DELETE_CHILDREN_FIRST = (
|
|
112
|
+
"E0703",
|
|
113
|
+
"Please delete the child nodes first before deleting the current node!",
|
|
114
|
+
)
|
|
115
|
+
ID_EMPTY = ("E0704", "ID cannot be empty!")
|
|
116
|
+
MODIFICATION_FAILED = ("E0705", "Modification failed!")
|
|
117
|
+
SYSTEM_ERROR = ("E0706", "System error!")
|
|
118
|
+
ROLE_DELETION_FAILED_USERS_EXIST = (
|
|
119
|
+
"E0707",
|
|
120
|
+
"There are still users under this role, deletion is not allowed!",
|
|
121
|
+
)
|
|
122
|
+
INVALID_CREDENTIALS = ("E0708", "Incorrect username or password!")
|
|
123
|
+
USER_DISABLED = (
|
|
124
|
+
"E0709",
|
|
125
|
+
"The current user is in a disabled state. Please contact the administrator!",
|
|
126
|
+
)
|
|
127
|
+
USER_LOCKED = (
|
|
128
|
+
"E0710",
|
|
129
|
+
"The user is locked. Please contact the administrator or try logging in later!",
|
|
130
|
+
)
|
|
131
|
+
LOGIN_ATTEMPTS_REMAINING = (
|
|
132
|
+
"E0711",
|
|
133
|
+
"Incorrect username or password. Remaining login attempts",
|
|
134
|
+
)
|
|
135
|
+
LOGIN_EXPIRED = (
|
|
136
|
+
"E0712",
|
|
137
|
+
"You are not logged in or your login has expired. Please log in again!",
|
|
138
|
+
)
|
|
139
|
+
PASSWORD_RECENTLY_USED = (
|
|
140
|
+
"E0713",
|
|
141
|
+
"The password cannot be the same as the recent ones!",
|
|
142
|
+
)
|
|
143
|
+
ORIGINAL_PASSWORD_INCORRECT = (
|
|
144
|
+
"E0714",
|
|
145
|
+
"The original password entered is incorrect!",
|
|
146
|
+
)
|
|
147
|
+
ENABLEMENT_FAILED = ("E0715", "Enablement failed!")
|
|
148
|
+
CANNOT_ENABLE_SELF = ("E0716", "A user cannot enable themselves!")
|
|
149
|
+
CANNOT_DISABLE_SELF = ("E0717", "A user cannot disable themselves!")
|
|
150
|
+
DISABLE_FAILED = ("E0718", "Disabling failed!")
|
|
151
|
+
USER_HAS_RECORDS_CANNOT_DELETE = (
|
|
152
|
+
"E0719",
|
|
153
|
+
"This user already has operation records and cannot be deleted!",
|
|
154
|
+
)
|
|
155
|
+
CANNOT_DELETE_SELF = ("E0720", "A user cannot delete themselves!")
|
|
156
|
+
ONLY_LOCKED_CAN_UNLOCK = ("E0721", "Only locked users can be unlocked!")
|
|
157
|
+
USER_INFO_NOT_FOUND = ("E0722", "No information found for this user!")
|
|
158
|
+
CANNOT_AUTHORIZE_SELF = ("E0723", "A user cannot authorize themselves!")
|
|
159
|
+
AUTHORIZATION_FAILED = ("E0724", "Authorization failed!")
|
|
160
|
+
TASK_DISABLE_FAILED = ("E0725", "Scheduled task disabling failed!")
|
|
161
|
+
TASK_ENABLE_FAILED = ("E0726", "Scheduled task enabling failed!")
|
|
162
|
+
TASK_RUNNING = ("E0727", "The task is running!")
|
|
163
|
+
QUOTA_EXCEEDED = ("E0728", "Data cleanup exception!")
|
|
164
|
+
TASK_EXECUTION_EXCEPTION = (
|
|
165
|
+
"E0729",
|
|
166
|
+
"Scheduled task execution exception. Please stop the task and restart it!",
|
|
167
|
+
)
|
|
168
|
+
DUPLICATE_BUSINESS_CODE = (
|
|
169
|
+
"E0730",
|
|
170
|
+
"Identical codes are not allowed under the same business code!",
|
|
171
|
+
)
|
|
172
|
+
PARAMETER_EXISTS = ("E0731", "The parameter already exists!")
|
|
173
|
+
ALREADY_ENABLED = ("E0732", "Normal users are not allowed to be enabled again!")
|
|
174
|
+
USER_ALREADY_EXISTS = ("E0733", "The user already exists!")
|
|
175
|
+
ALREADY_DISABLED = ("E0734", "Disabled users are not allowed to be disabled again!")
|
|
176
|
+
CANNOT_UNLOCK_SELF = ("E0735", "A user cannot unlock themselves!")
|
|
177
|
+
ALL_ENABLED = (
|
|
178
|
+
"E0736",
|
|
179
|
+
"All data is in the enabled state. Please select a task that is not enabled!",
|
|
180
|
+
)
|
|
181
|
+
ALL_DISABLED = (
|
|
182
|
+
"E0737",
|
|
183
|
+
"All data is in the disabled state. Please select a task that is not disabled!",
|
|
184
|
+
)
|
|
185
|
+
ENABLE_TASK_FIRST = ("E0738", "Please enable the task first!")
|
|
186
|
+
REQUEST_DATA_EMPTY = ("E0739", "The request data is empty!")
|
|
187
|
+
ROLE_DELETION_FAILED_CHILDREN_EXIST = (
|
|
188
|
+
"E0740",
|
|
189
|
+
"Please delete all child roles under this role first!",
|
|
190
|
+
)
|
|
191
|
+
USER_DELETION_FAILED_CHILDREN_EXIST = (
|
|
192
|
+
"E0741",
|
|
193
|
+
"Please delete all child users under this user first!",
|
|
194
|
+
)
|
|
195
|
+
SUPERIOR_RESOURCES_MISMATCH = (
|
|
196
|
+
"E0742",
|
|
197
|
+
"The system does not match the superior resources!",
|
|
198
|
+
)
|
|
199
|
+
ACCOUNT_CANCELLED = ("E0061", "The account has been cancelled!")
|
|
200
|
+
PHONE_EMPTY = ("E0062", "The phone number is empty!")
|
|
201
|
+
TOO_MANY_SMS = ("E0064", "Too many SMS messages have been sent!")
|
|
202
|
+
FAILED_TO_SEND_SMS = ("E0065", "Failed to send SMS!")
|
|
203
|
+
INVALID_PHONE_FORMAT = ("E0066", "The phone number format is incorrect!")
|
|
204
|
+
AVATAR_UPLOAD_FAILED = ("E0067", "Failed to upload the avatar!")
|
|
205
|
+
COPY_LIMIT_EXCEEDED = ("E0068", "The number of copied files exceeds the limit!")
|
|
206
|
+
INVALID_DEVICE = ("E0069", "The device is invalid!")
|
|
207
|
+
NO_NEED_TO_UPDATE = ("E0070", "No need to update!")
|
|
208
|
+
NO_COMPRESSED_PACKAGE = ("E0071", "There is no compressed package!")
|
|
209
|
+
ACCESS_DENIED_SYSTEM = (
|
|
210
|
+
"E0072",
|
|
211
|
+
"No operations are allowed under the supernote directory!",
|
|
212
|
+
)
|
|
213
|
+
NICKNAME_EMPTY = ("E0073", "The nickname cannot be empty!")
|
|
214
|
+
NICKNAME_EXISTS = ("E0074", "The nickname already exists. Please choose a new one!")
|
|
215
|
+
DEVICE_ALREADY_BOUND = (
|
|
216
|
+
"E0075",
|
|
217
|
+
"The device is already bound to this account. No need to bind again!",
|
|
218
|
+
)
|
|
219
|
+
BINDING_ACCOUNT_MISMATCH = (
|
|
220
|
+
"E0077",
|
|
221
|
+
"The logged-in account is not the same as the one bound to the device!",
|
|
222
|
+
)
|
|
223
|
+
ANOTHER_DEVICE_SYNCING = (
|
|
224
|
+
"E0078",
|
|
225
|
+
"A device is currently synchronizing. Please wait until it's finished before synchronizing again!",
|
|
226
|
+
)
|
|
227
|
+
SYNC_IN_PROGRESS = (
|
|
228
|
+
"E0079",
|
|
229
|
+
"Synchronization is in progress. Please wait until it's finished before performing other operations!",
|
|
230
|
+
)
|
|
231
|
+
PATH_NOT_FOUND = ("E0081", "The path does not exist!")
|
|
232
|
+
HASH_EXITS = (
|
|
233
|
+
"E0082",
|
|
234
|
+
"There is a file with the same MD5 value. No need to upload!",
|
|
235
|
+
)
|
|
236
|
+
DEVICE_BOUND_OTHER_ACCOUNT = (
|
|
237
|
+
"E0083",
|
|
238
|
+
"The device is already bound to another account. It cannot be bound to a new account!",
|
|
239
|
+
)
|
|
240
|
+
INVALID_VERSION_NUMBER = ("E0084", "The published version number is incorrect!")
|
|
241
|
+
INVALID_TOKEN = ("E0085", "The token is invalid!")
|
|
242
|
+
COUNTRY_CODE_EMPTY = ("E0086", "The country code is empty!")
|
|
243
|
+
NO_LATEST_VERSION = ("E0087", "There is no latest version. No need to update.")
|
|
244
|
+
RESOURCE_IN_USE_BY_ROLE = (
|
|
245
|
+
"E0088",
|
|
246
|
+
"This resource is already in use by a role and cannot be deleted",
|
|
247
|
+
)
|
|
248
|
+
CONFLICT_EXISTS = ("E0322", "File or directory already exists!")
|
|
249
|
+
TIMEZONE_NOT_OBTAINED = (
|
|
250
|
+
"E0844",
|
|
251
|
+
"The time zone information for this area was not obtained",
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
@property
|
|
255
|
+
def message(self) -> str:
|
|
256
|
+
"""Get the default message for the error code."""
|
|
257
|
+
return str(getattr(self, "description", "An error occurred"))
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def create_error_response(
|
|
261
|
+
error_msg: str, error_code: str | ErrorCode | None = None
|
|
262
|
+
) -> BaseResponse:
|
|
263
|
+
"""Create an error response."""
|
|
264
|
+
if isinstance(error_code, ErrorCode):
|
|
265
|
+
error_code = error_code.value
|
|
266
|
+
return BaseResponse(success=False, error_code=error_code, error_msg=error_msg)
|