reyserver 1.1.60__py3-none-any.whl → 1.1.61__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.
Potentially problematic release.
This version of reyserver might be problematic. Click here for more details.
- reyserver/__init__.py +0 -1
- reyserver/rall.py +0 -1
- reyserver/rauth.py +104 -95
- reyserver/rclient.py +8 -9
- reyserver/rfile.py +7 -7
- reyserver/rserver.py +42 -89
- {reyserver-1.1.60.dist-info → reyserver-1.1.61.dist-info}/METADATA +1 -1
- reyserver-1.1.61.dist-info/RECORD +11 -0
- reyserver/radmin.py +0 -171
- reyserver-1.1.60.dist-info/RECORD +0 -12
- {reyserver-1.1.60.dist-info → reyserver-1.1.61.dist-info}/WHEEL +0 -0
- {reyserver-1.1.60.dist-info → reyserver-1.1.61.dist-info}/licenses/LICENSE +0 -0
reyserver/__init__.py
CHANGED
reyserver/rall.py
CHANGED
reyserver/rauth.py
CHANGED
|
@@ -14,7 +14,7 @@ from datetime import datetime as Datetime
|
|
|
14
14
|
from re import PatternError
|
|
15
15
|
from fastapi import APIRouter, Request
|
|
16
16
|
from fastapi.params import Depends
|
|
17
|
-
from fastapi.security import
|
|
17
|
+
from fastapi.security import OAuth2PasswordBearer
|
|
18
18
|
from reydb import rorm, DatabaseEngine, DatabaseEngineAsync
|
|
19
19
|
from reykit.rdata import encode_jwt, decode_jwt, is_hash_bcrypt
|
|
20
20
|
from reykit.rre import search_batch
|
|
@@ -29,29 +29,29 @@ __all__ = (
|
|
|
29
29
|
'DatabaseORMTablePerm',
|
|
30
30
|
'DatabaseORMTableUserRole',
|
|
31
31
|
'DatabaseORMTableRolePerm',
|
|
32
|
-
'
|
|
33
|
-
'
|
|
32
|
+
'build_db_auth',
|
|
33
|
+
'router_auth'
|
|
34
34
|
)
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
UserInfo = TypedDict(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
'
|
|
38
|
+
'UserInfo',
|
|
39
|
+
{
|
|
40
|
+
'create_time': float,
|
|
41
|
+
'udpate_time': float,
|
|
42
|
+
'user_id': int,
|
|
43
|
+
'user_name': str,
|
|
44
|
+
'role_names': list[str],
|
|
45
|
+
'perm_names': list[str],
|
|
46
|
+
'perm_apis': list[str],
|
|
47
|
+
'email': str | None,
|
|
48
|
+
'phone': str | None,
|
|
49
|
+
'avatar': int | None,
|
|
50
|
+
'password': NotRequired[str]
|
|
51
|
+
}
|
|
52
|
+
)
|
|
53
|
+
TokenInfo = TypedDict(
|
|
54
|
+
'TokenInfo',
|
|
55
55
|
{
|
|
56
56
|
'sub': int,
|
|
57
57
|
'iat': int,
|
|
@@ -60,6 +60,14 @@ Token = TypedDict(
|
|
|
60
60
|
'user': UserInfo
|
|
61
61
|
}
|
|
62
62
|
)
|
|
63
|
+
Token = str
|
|
64
|
+
ResponseToken = TypedDict(
|
|
65
|
+
'ResponseToken',
|
|
66
|
+
{
|
|
67
|
+
'access_token': Token,
|
|
68
|
+
'token_type': Literal['Bearer']
|
|
69
|
+
}
|
|
70
|
+
)
|
|
63
71
|
|
|
64
72
|
|
|
65
73
|
class DatabaseORMTableUser(rorm.Table):
|
|
@@ -138,7 +146,7 @@ class DatabaseORMTableRolePerm(rorm.Table):
|
|
|
138
146
|
perm_id: int = rorm.Field(rorm.types_mysql.SMALLINT(unsigned=True), key=True, comment='Permission ID.')
|
|
139
147
|
|
|
140
148
|
|
|
141
|
-
def
|
|
149
|
+
def build_db_auth(engine: DatabaseEngine | DatabaseEngineAsync) -> None:
|
|
142
150
|
"""
|
|
143
151
|
Check and build `auth` database tables.
|
|
144
152
|
|
|
@@ -231,7 +239,69 @@ def build_auth_db(engine: DatabaseEngine | DatabaseEngineAsync) -> None:
|
|
|
231
239
|
engine.sync_engine.build.build(tables=tables, views_stats=views_stats, skip=True)
|
|
232
240
|
|
|
233
241
|
|
|
234
|
-
|
|
242
|
+
bearer = OAuth2PasswordBearer(
|
|
243
|
+
tokenUrl='/token',
|
|
244
|
+
scheme_name='RBACBearer',
|
|
245
|
+
description='Global authentication of based on RBAC model and Bearer framework.',
|
|
246
|
+
auto_error=False
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
async def depend_auth(
|
|
251
|
+
request: Request,
|
|
252
|
+
server: Bind.Server = Bind.server,
|
|
253
|
+
token: Token | None = Depends(bearer)
|
|
254
|
+
) -> UserInfo:
|
|
255
|
+
"""
|
|
256
|
+
Dependencie function of authentication.
|
|
257
|
+
If the verification fails, then response status code is 401 or 403.
|
|
258
|
+
|
|
259
|
+
Parameters
|
|
260
|
+
----------
|
|
261
|
+
request : Request.
|
|
262
|
+
server : Server.
|
|
263
|
+
token : Authentication token.
|
|
264
|
+
|
|
265
|
+
Returns
|
|
266
|
+
-------
|
|
267
|
+
User information
|
|
268
|
+
"""
|
|
269
|
+
|
|
270
|
+
# Check.
|
|
271
|
+
if not server.is_started_auth:
|
|
272
|
+
return
|
|
273
|
+
if bearer is None:
|
|
274
|
+
exit_api(401)
|
|
275
|
+
|
|
276
|
+
# Parameter.
|
|
277
|
+
key = server.api_auth_key
|
|
278
|
+
api_path = f'{request.method} {request.url.path}'
|
|
279
|
+
|
|
280
|
+
# Cache.
|
|
281
|
+
user: UserInfo | None = getattr(request.state, 'user', None)
|
|
282
|
+
|
|
283
|
+
# Decode.
|
|
284
|
+
if user is None:
|
|
285
|
+
json: TokenInfo | None = decode_jwt(token, key)
|
|
286
|
+
if json is None:
|
|
287
|
+
exit_api(401)
|
|
288
|
+
user = json['user']
|
|
289
|
+
request.state.user = user
|
|
290
|
+
|
|
291
|
+
# Authentication.
|
|
292
|
+
perm_apis = json['user']['perm_apis']
|
|
293
|
+
perm_apis = [
|
|
294
|
+
f'^{pattern}$'
|
|
295
|
+
for pattern in perm_apis
|
|
296
|
+
]
|
|
297
|
+
result = search_batch(api_path, *perm_apis)
|
|
298
|
+
if result is None:
|
|
299
|
+
exit_api(403)
|
|
300
|
+
|
|
301
|
+
return user
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
router_auth = APIRouter()
|
|
235
305
|
|
|
236
306
|
|
|
237
307
|
async def get_user_info(
|
|
@@ -336,25 +406,20 @@ async def get_user_info(
|
|
|
336
406
|
return info
|
|
337
407
|
|
|
338
408
|
|
|
339
|
-
@
|
|
409
|
+
@router_auth.post('/token')
|
|
340
410
|
async def create_sessions(
|
|
341
|
-
|
|
342
|
-
password: str = Bind.i.
|
|
343
|
-
account_type: Literal['name', 'email', 'phone'] = Bind.Body('name'),
|
|
411
|
+
username: str = Bind.i.form,
|
|
412
|
+
password: str = Bind.i.form,
|
|
344
413
|
conn: Bind.Conn = Bind.conn.auth,
|
|
345
414
|
server: Bind.Server = Bind.server
|
|
346
|
-
) ->
|
|
415
|
+
) -> ResponseToken:
|
|
347
416
|
"""
|
|
348
417
|
Create session.
|
|
349
418
|
|
|
350
419
|
Parameters
|
|
351
420
|
----------
|
|
352
|
-
|
|
421
|
+
username : User name.
|
|
353
422
|
password : User password.
|
|
354
|
-
account_type : User account type.
|
|
355
|
-
- `Literal['name']`: User name.
|
|
356
|
-
- `Literal['email']`: User Email.
|
|
357
|
-
- `Literal['phone']`: User phone mumber.
|
|
358
423
|
|
|
359
424
|
Returns
|
|
360
425
|
-------
|
|
@@ -366,7 +431,7 @@ async def create_sessions(
|
|
|
366
431
|
sess_seconds = server.api_auth_sess_seconds
|
|
367
432
|
|
|
368
433
|
# User information.
|
|
369
|
-
info = await get_user_info(conn,
|
|
434
|
+
info = await get_user_info(conn, username)
|
|
370
435
|
|
|
371
436
|
# Check.
|
|
372
437
|
if info is None:
|
|
@@ -375,10 +440,10 @@ async def create_sessions(
|
|
|
375
440
|
if not is_hash_bcrypt(password, password_hash):
|
|
376
441
|
exit_api(401)
|
|
377
442
|
|
|
378
|
-
#
|
|
443
|
+
# Response.
|
|
379
444
|
now_timestamp_s = now('timestamp_s')
|
|
380
445
|
user_id = info.pop('user_id')
|
|
381
|
-
data:
|
|
446
|
+
data: TokenInfo = {
|
|
382
447
|
'sub': str(user_id),
|
|
383
448
|
'iat': now_timestamp_s,
|
|
384
449
|
'nbf': now_timestamp_s,
|
|
@@ -386,65 +451,9 @@ async def create_sessions(
|
|
|
386
451
|
'user': info
|
|
387
452
|
}
|
|
388
453
|
token = encode_jwt(data, key)
|
|
389
|
-
response = {
|
|
454
|
+
response = {
|
|
455
|
+
'access_token': token,
|
|
456
|
+
'token_type': 'Bearer'
|
|
457
|
+
}
|
|
390
458
|
|
|
391
459
|
return response
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
bearer = HTTPBearer(
|
|
395
|
-
scheme_name='RBACBearer',
|
|
396
|
-
description='Global authentication of based on RBAC model and Bearer framework.',
|
|
397
|
-
bearerFormat='JWT standard.',
|
|
398
|
-
auto_error=False
|
|
399
|
-
)
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
async def depend_auth(
|
|
403
|
-
request: Request,
|
|
404
|
-
server: Bind.Server = Bind.server,
|
|
405
|
-
auth: HTTPAuthorizationCredentials | None = Depends(bearer)
|
|
406
|
-
) -> None:
|
|
407
|
-
"""
|
|
408
|
-
Dependencie function of authentication.
|
|
409
|
-
|
|
410
|
-
Parameters
|
|
411
|
-
----------
|
|
412
|
-
request : Request.
|
|
413
|
-
server : Server.
|
|
414
|
-
auth : Authentication.
|
|
415
|
-
"""
|
|
416
|
-
|
|
417
|
-
# Check.
|
|
418
|
-
print(11111111111111111)
|
|
419
|
-
api_path = f'{request.method} {request.url.path}'
|
|
420
|
-
if (
|
|
421
|
-
not server.is_started_auth
|
|
422
|
-
or api_path == 'POST /sessions'
|
|
423
|
-
):
|
|
424
|
-
return
|
|
425
|
-
if auth is None:
|
|
426
|
-
exit_api(401)
|
|
427
|
-
|
|
428
|
-
# Parameter.
|
|
429
|
-
key = server.api_auth_key
|
|
430
|
-
token = auth.credentials
|
|
431
|
-
|
|
432
|
-
# Decode.
|
|
433
|
-
json = decode_jwt(token, key)
|
|
434
|
-
if json is None:
|
|
435
|
-
exit_api(401)
|
|
436
|
-
json: Token
|
|
437
|
-
request.state.user = json['user']
|
|
438
|
-
|
|
439
|
-
# Check.
|
|
440
|
-
perm_apis = json['user']['perm_apis']
|
|
441
|
-
perm_apis = [
|
|
442
|
-
f'^{pattern}$'
|
|
443
|
-
for pattern in perm_apis
|
|
444
|
-
]
|
|
445
|
-
try:
|
|
446
|
-
result = search_batch(api_path, *perm_apis)
|
|
447
|
-
except PatternError:
|
|
448
|
-
exit_api(403)
|
|
449
|
-
if result is None:
|
|
450
|
-
exit_api(403)
|
reyserver/rclient.py
CHANGED
|
@@ -53,22 +53,21 @@ class ServerClient(ServerBase):
|
|
|
53
53
|
self.username = username
|
|
54
54
|
self.password = password
|
|
55
55
|
self.url = url
|
|
56
|
-
self.token = self.
|
|
56
|
+
self.token = self.get_token(username, password)
|
|
57
57
|
|
|
58
58
|
|
|
59
|
-
def
|
|
59
|
+
def get_token(
|
|
60
60
|
self,
|
|
61
61
|
username: str,
|
|
62
62
|
password: str
|
|
63
63
|
) -> str:
|
|
64
64
|
"""
|
|
65
|
-
|
|
65
|
+
Get token.
|
|
66
66
|
|
|
67
67
|
Parameters
|
|
68
68
|
----------
|
|
69
|
-
|
|
69
|
+
username : User name.
|
|
70
70
|
password : User password.
|
|
71
|
-
account_type : User account type.
|
|
72
71
|
|
|
73
72
|
Returns
|
|
74
73
|
-------
|
|
@@ -76,14 +75,14 @@ class ServerClient(ServerBase):
|
|
|
76
75
|
"""
|
|
77
76
|
|
|
78
77
|
# Parameter.
|
|
79
|
-
url = join_url(self.url, '
|
|
80
|
-
|
|
81
|
-
'
|
|
78
|
+
url = join_url(self.url, 'token')
|
|
79
|
+
data = {
|
|
80
|
+
'username': username,
|
|
82
81
|
'password': password
|
|
83
82
|
}
|
|
84
83
|
|
|
85
84
|
# Request.
|
|
86
|
-
response = request(url,
|
|
85
|
+
response = request(url, data=data, check=True)
|
|
87
86
|
response_dict = response.json()
|
|
88
87
|
token = response_dict['token']
|
|
89
88
|
|
reyserver/rfile.py
CHANGED
|
@@ -20,8 +20,8 @@ from .rbase import Bind, exit_api
|
|
|
20
20
|
__all__ = (
|
|
21
21
|
'DatabaseORMTableInfo',
|
|
22
22
|
'DatabaseORMTableData',
|
|
23
|
-
'
|
|
24
|
-
'
|
|
23
|
+
'build_db_file',
|
|
24
|
+
'router_file'
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
|
|
@@ -51,7 +51,7 @@ class DatabaseORMTableData(rorm.Table):
|
|
|
51
51
|
path: str = rorm.Field(rorm.types.VARCHAR(4095), not_null=True, comment='File disk storage path.')
|
|
52
52
|
|
|
53
53
|
|
|
54
|
-
def
|
|
54
|
+
def build_db_file(engine: DatabaseEngine | DatabaseEngineAsync) -> None:
|
|
55
55
|
"""
|
|
56
56
|
Check and build `file` database tables.
|
|
57
57
|
|
|
@@ -177,10 +177,10 @@ def build_file_db(engine: DatabaseEngine | DatabaseEngineAsync) -> None:
|
|
|
177
177
|
engine.sync_engine.build.build(tables=tables, views=views, views_stats=views_stats, skip=True)
|
|
178
178
|
|
|
179
179
|
|
|
180
|
-
|
|
180
|
+
router_file = APIRouter()
|
|
181
181
|
|
|
182
182
|
|
|
183
|
-
@
|
|
183
|
+
@router_file.get('/files/{file_id}')
|
|
184
184
|
async def get_file_info(
|
|
185
185
|
file_id: int = Bind.i.path,
|
|
186
186
|
sess: Bind.Sess = Bind.sess.file
|
|
@@ -207,7 +207,7 @@ async def get_file_info(
|
|
|
207
207
|
return table_info
|
|
208
208
|
|
|
209
209
|
|
|
210
|
-
@
|
|
210
|
+
@router_file.post('/files')
|
|
211
211
|
async def upload_file(
|
|
212
212
|
file: Bind.File = Bind.i.forms,
|
|
213
213
|
name: str = Bind.i.forms_n,
|
|
@@ -262,7 +262,7 @@ async def upload_file(
|
|
|
262
262
|
return table_info
|
|
263
263
|
|
|
264
264
|
|
|
265
|
-
@
|
|
265
|
+
@router_file.get('/files/{file_id}/download')
|
|
266
266
|
async def download_file(
|
|
267
267
|
file_id: int = Bind.i.path,
|
|
268
268
|
conn: Bind.Conn = Bind.conn.file
|
reyserver/rserver.py
CHANGED
|
@@ -16,7 +16,6 @@ from contextlib import asynccontextmanager, _AsyncGeneratorContextManager
|
|
|
16
16
|
from uvicorn import run as uvicorn_run
|
|
17
17
|
from starlette.middleware.base import _StreamingResponse
|
|
18
18
|
from fastapi import FastAPI, Request
|
|
19
|
-
from fastapi.params import Depends
|
|
20
19
|
from fastapi.staticfiles import StaticFiles
|
|
21
20
|
from fastapi.middleware.gzip import GZipMiddleware
|
|
22
21
|
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
|
|
@@ -25,7 +24,6 @@ from reykit.rbase import CoroutineFunctionSimple, Singleton, throw
|
|
|
25
24
|
from reykit.rrand import randchar
|
|
26
25
|
|
|
27
26
|
from .rbase import ServerBase, Bind
|
|
28
|
-
from . import radmin
|
|
29
27
|
|
|
30
28
|
|
|
31
29
|
__all__ = (
|
|
@@ -69,8 +67,6 @@ class Server(ServerBase, Singleton):
|
|
|
69
67
|
debug : Whether use development mode debug server.
|
|
70
68
|
"""
|
|
71
69
|
|
|
72
|
-
from .rauth import depend_auth
|
|
73
|
-
|
|
74
70
|
# Parameter.
|
|
75
71
|
if type(ssl_cert) != type(ssl_key):
|
|
76
72
|
throw(AssertionError, ssl_cert, ssl_key)
|
|
@@ -79,8 +75,6 @@ class Server(ServerBase, Singleton):
|
|
|
79
75
|
elif iscoroutinefunction(depend):
|
|
80
76
|
depend = (depend,)
|
|
81
77
|
depend = [
|
|
82
|
-
Bind.Depend(depend_auth)
|
|
83
|
-
] + [
|
|
84
78
|
Bind.Depend(task)
|
|
85
79
|
for task in depend
|
|
86
80
|
]
|
|
@@ -90,8 +84,6 @@ class Server(ServerBase, Singleton):
|
|
|
90
84
|
self.db = db
|
|
91
85
|
self.ssl_cert = ssl_cert
|
|
92
86
|
self.ssl_key = ssl_key
|
|
93
|
-
|
|
94
|
-
## App.
|
|
95
87
|
self.app = FastAPI(
|
|
96
88
|
dependencies=depend,
|
|
97
89
|
lifespan=lifespan,
|
|
@@ -99,17 +91,18 @@ class Server(ServerBase, Singleton):
|
|
|
99
91
|
server=self
|
|
100
92
|
)
|
|
101
93
|
|
|
94
|
+
# Public file.
|
|
102
95
|
if public is not None:
|
|
103
96
|
subapp = StaticFiles(directory=public, html=True)
|
|
104
97
|
self.app.mount('/', subapp)
|
|
105
|
-
self.wrap_middleware = self.app.middleware('http')
|
|
106
|
-
'Decorator, add middleware to APP.'
|
|
107
98
|
|
|
108
99
|
# Middleware
|
|
100
|
+
self.wrap_middleware = self.app.middleware('http')
|
|
101
|
+
'Decorator, add middleware to APP.'
|
|
109
102
|
self.app.add_middleware(GZipMiddleware)
|
|
110
103
|
if not debug:
|
|
111
104
|
self.app.add_middleware(HTTPSRedirectMiddleware)
|
|
112
|
-
self.
|
|
105
|
+
self.__add_base_middleware()
|
|
113
106
|
|
|
114
107
|
# API.
|
|
115
108
|
self.is_started_auth: bool = False
|
|
@@ -185,19 +178,19 @@ class Server(ServerBase, Singleton):
|
|
|
185
178
|
return lifespan
|
|
186
179
|
|
|
187
180
|
|
|
188
|
-
def
|
|
181
|
+
def __add_base_middleware(self) -> None:
|
|
189
182
|
"""
|
|
190
|
-
Add
|
|
183
|
+
Add base middleware.
|
|
191
184
|
"""
|
|
192
185
|
|
|
193
186
|
# Add.
|
|
194
187
|
@self.wrap_middleware
|
|
195
|
-
async def
|
|
188
|
+
async def base_middleware(
|
|
196
189
|
request: Request,
|
|
197
190
|
call_next: Callable[[Request], Coroutine[None, None, _StreamingResponse]]
|
|
198
191
|
) -> _StreamingResponse:
|
|
199
192
|
"""
|
|
200
|
-
|
|
193
|
+
Base middleware.
|
|
201
194
|
|
|
202
195
|
Parameters
|
|
203
196
|
----------
|
|
@@ -217,6 +210,8 @@ class Server(ServerBase, Singleton):
|
|
|
217
210
|
and request.method == 'POST'
|
|
218
211
|
):
|
|
219
212
|
response.status_code = 201
|
|
213
|
+
elif response.status_code == 401:
|
|
214
|
+
response.headers.setdefault('WWW-Authenticate', 'Bearer')
|
|
220
215
|
|
|
221
216
|
return response
|
|
222
217
|
|
|
@@ -234,6 +229,9 @@ class Server(ServerBase, Singleton):
|
|
|
234
229
|
)
|
|
235
230
|
|
|
236
231
|
|
|
232
|
+
__call__ = run
|
|
233
|
+
|
|
234
|
+
|
|
237
235
|
def set_doc(
|
|
238
236
|
self,
|
|
239
237
|
version: str | None = None,
|
|
@@ -273,50 +271,30 @@ class Server(ServerBase, Singleton):
|
|
|
273
271
|
"""
|
|
274
272
|
Add base API.
|
|
275
273
|
"""
|
|
276
|
-
from fastapi import Request
|
|
277
|
-
@self.app.get('/test')
|
|
278
|
-
async def test(request: Request) -> str:
|
|
279
|
-
return 'test'
|
|
280
274
|
|
|
275
|
+
from fastapi import Depends, Form
|
|
276
|
+
from time import time
|
|
281
277
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
Parameters
|
|
304
|
-
----------
|
|
305
|
-
model : Model type.
|
|
306
|
-
- `type[rorm.Model]`: Define as `ServerAdminModel`.
|
|
307
|
-
engine : Database engine or name.
|
|
308
|
-
label : Admin model class label.
|
|
309
|
-
name : Admin model name.
|
|
310
|
-
column : Admin model display column names.
|
|
311
|
-
attrs : Other admin model attributes.
|
|
312
|
-
"""
|
|
313
|
-
|
|
314
|
-
# Check.
|
|
315
|
-
if not hasattr(self, 'admin'):
|
|
316
|
-
return
|
|
317
|
-
|
|
318
|
-
# Add.
|
|
319
|
-
self.admin.add_model(model, engine, label, name, column, **attrs)
|
|
278
|
+
form = Form()
|
|
279
|
+
def func():
|
|
280
|
+
return int(time())
|
|
281
|
+
depend = Depends(func)
|
|
282
|
+
@self.app.get('/test')
|
|
283
|
+
async def test(a: int = form, b: int = form) -> str:
|
|
284
|
+
print(a, b)
|
|
285
|
+
return 'test'
|
|
286
|
+
@self.app.get('/test1')
|
|
287
|
+
async def test1(a: int = depend, b: int = depend) -> str:
|
|
288
|
+
print(a, b)
|
|
289
|
+
return 'test'
|
|
290
|
+
@self.app.get('/test2')
|
|
291
|
+
async def test2(a: int = form, b: int = depend) -> str:
|
|
292
|
+
print(a, b)
|
|
293
|
+
return 'test'
|
|
294
|
+
@self.app.get('/test3')
|
|
295
|
+
async def test3(a: int = form, b: int = depend) -> str:
|
|
296
|
+
print(a, b)
|
|
297
|
+
return 'test'
|
|
320
298
|
|
|
321
299
|
|
|
322
300
|
def add_api_auth(self, key: str | None = None, sess_seconds: int = 28800) -> None:
|
|
@@ -331,16 +309,7 @@ class Server(ServerBase, Singleton):
|
|
|
331
309
|
sess_seconds : Session valid seconds.
|
|
332
310
|
"""
|
|
333
311
|
|
|
334
|
-
from .rauth import
|
|
335
|
-
DatabaseORMTableUser,
|
|
336
|
-
DatabaseORMTableRole,
|
|
337
|
-
DatabaseORMTablePerm,
|
|
338
|
-
DatabaseORMTableUserRole,
|
|
339
|
-
DatabaseORMTableRolePerm,
|
|
340
|
-
build_auth_db,
|
|
341
|
-
auth_router,
|
|
342
|
-
depend_auth
|
|
343
|
-
)
|
|
312
|
+
from .rauth import build_db_auth, router_auth
|
|
344
313
|
|
|
345
314
|
# Parameter.
|
|
346
315
|
if key is None:
|
|
@@ -350,21 +319,14 @@ class Server(ServerBase, Singleton):
|
|
|
350
319
|
if 'auth' not in self.db:
|
|
351
320
|
throw(AssertionError, self.db)
|
|
352
321
|
engine = self.db.auth
|
|
353
|
-
|
|
322
|
+
build_db_auth(engine)
|
|
354
323
|
|
|
355
324
|
# Add.
|
|
356
325
|
self.api_auth_key = key
|
|
357
326
|
self.api_auth_sess_seconds = sess_seconds
|
|
358
|
-
self.app.include_router(
|
|
327
|
+
self.app.include_router(router_auth, tags=['auth'])
|
|
359
328
|
self.is_started_auth = True
|
|
360
329
|
|
|
361
|
-
## Admin.
|
|
362
|
-
self.add_admin_model(DatabaseORMTableUser, engine, category='auth', name='User', column_list=['user_id', 'name'])
|
|
363
|
-
self.add_admin_model(DatabaseORMTableRole, engine, category='auth', name='Role', column_list=['role_id', 'name'])
|
|
364
|
-
self.add_admin_model(DatabaseORMTablePerm, engine, category='auth', name='Perm', column_list=['perm_id', 'name'])
|
|
365
|
-
self.add_admin_model(DatabaseORMTableUserRole, engine, category='auth', name='User Role')
|
|
366
|
-
self.add_admin_model(DatabaseORMTableRolePerm, engine, category='auth', name='Role Perm')
|
|
367
|
-
|
|
368
330
|
|
|
369
331
|
def add_api_file(self, file_dir: str = 'file') -> None:
|
|
370
332
|
"""
|
|
@@ -374,26 +336,17 @@ class Server(ServerBase, Singleton):
|
|
|
374
336
|
Parameters
|
|
375
337
|
----------
|
|
376
338
|
file_dir : File API store directory path.
|
|
377
|
-
prefix : File API path prefix.
|
|
378
339
|
"""
|
|
379
340
|
|
|
380
|
-
from .
|
|
381
|
-
|
|
382
|
-
file_router,
|
|
383
|
-
DatabaseORMTableInfo,
|
|
384
|
-
DatabaseORMTableData
|
|
385
|
-
)
|
|
341
|
+
from .rauth import depend_auth
|
|
342
|
+
from .rfile import build_db_file, router_file
|
|
386
343
|
|
|
387
344
|
# Database.
|
|
388
345
|
if 'file' not in self.db:
|
|
389
346
|
throw(AssertionError, self.db)
|
|
390
347
|
engine = self.db.file
|
|
391
|
-
|
|
348
|
+
build_db_file(engine)
|
|
392
349
|
|
|
393
350
|
# Add.
|
|
394
351
|
self.api_file_dir = file_dir
|
|
395
|
-
self.app.include_router(
|
|
396
|
-
|
|
397
|
-
## Admin.
|
|
398
|
-
self.add_admin_model(DatabaseORMTableInfo, engine, category='file', name='Info', column_list=['file_id', 'name'])
|
|
399
|
-
self.add_admin_model(DatabaseORMTableData, engine, category='file', name='Data')
|
|
352
|
+
self.app.include_router(router_file, tags=['file'])
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
reyserver/__init__.py,sha256=7GX64p7uI2eetJH9NJ-DTg-8iyQwOsGcviADFJCPxVA,373
|
|
2
|
+
reyserver/rall.py,sha256=riyDRTUsigco_Bee1H4aZFb8IgvjnxdX9qcnVb9i9mE,270
|
|
3
|
+
reyserver/rauth.py,sha256=hXI21VrZ_sDrFZzd982ENymFJfPWi6U1XHmGmiglez0,15103
|
|
4
|
+
reyserver/rbase.py,sha256=kzSbo6yoPlWquR6XiseTKi5hEbllaG3qVmmwnnKKac0,6898
|
|
5
|
+
reyserver/rclient.py,sha256=a07zHDUH4Y3f-WdAXMX7Wq9PocwvlrDfdIl2s-M4IWo,6222
|
|
6
|
+
reyserver/rfile.py,sha256=6H5_7B9aiA3F56VToQDI9Trarkrl9gcIuFqYyCVCiCU,8877
|
|
7
|
+
reyserver/rserver.py,sha256=mrtsYu8wsxJmctmh2qWfwD9l70gOZq57UrKcDJ9EAVM,9856
|
|
8
|
+
reyserver-1.1.61.dist-info/METADATA,sha256=IghNj6ce-pWACkbexwa3jvtkMx0lc8hto2XGWhWtWyo,1666
|
|
9
|
+
reyserver-1.1.61.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
10
|
+
reyserver-1.1.61.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
|
|
11
|
+
reyserver-1.1.61.dist-info/RECORD,,
|
reyserver/radmin.py
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
# !/usr/bin/env python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
"""
|
|
5
|
-
@Time : 2025-10-14
|
|
6
|
-
@Author : Rey
|
|
7
|
-
@Contact : reyxbo@163.com
|
|
8
|
-
@Explain : Admin methods.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
from typing import Any, Type
|
|
13
|
-
from collections.abc import Sequence
|
|
14
|
-
from sqlalchemy.ext.asyncio import async_sessionmaker
|
|
15
|
-
from fastapi import Request
|
|
16
|
-
from sqladmin import Admin, ModelView
|
|
17
|
-
from sqladmin.authentication import AuthenticationBackend
|
|
18
|
-
from reydb import DatabaseEngineAsync, rorm
|
|
19
|
-
from reykit.rbase import Singleton
|
|
20
|
-
|
|
21
|
-
from .rbase import ServerBase
|
|
22
|
-
from . import rserver
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
__all__ = (
|
|
26
|
-
'ServerAdminModel',
|
|
27
|
-
'ServerAdminModelView',
|
|
28
|
-
'ServerAdminModelViewStats',
|
|
29
|
-
'ServerAdmin'
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class ServerAdminModel(ServerBase, ModelView):
|
|
34
|
-
"""
|
|
35
|
-
Server admin model type.
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class ServerAdminModelView(ServerAdminModel):
|
|
40
|
-
"""
|
|
41
|
-
Server admin view model type.
|
|
42
|
-
"""
|
|
43
|
-
|
|
44
|
-
category = 'View'
|
|
45
|
-
can_view_details = can_edit = can_create = can_delete = False
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class ServerAdminModelViewStats(ServerAdminModelView):
|
|
49
|
-
"""
|
|
50
|
-
Server admin stats view model type.
|
|
51
|
-
"""
|
|
52
|
-
|
|
53
|
-
column_list = ['item', 'value', 'comment']
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
# class ServerAdminAuthentication(ServerAdmin, AuthenticationBackend):
|
|
57
|
-
# """
|
|
58
|
-
# Server admin authentication type.
|
|
59
|
-
# """
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
# async def authenticate(self, request: Request) -> bool:
|
|
63
|
-
# """
|
|
64
|
-
# Authenticate request.
|
|
65
|
-
|
|
66
|
-
# Parameters
|
|
67
|
-
# ----------
|
|
68
|
-
# request : Request.
|
|
69
|
-
# """
|
|
70
|
-
|
|
71
|
-
# #
|
|
72
|
-
# ...
|
|
73
|
-
# request.session['token']
|
|
74
|
-
# ...
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
# async def login(self, request: Request) -> bool:
|
|
78
|
-
# form = await request.form()
|
|
79
|
-
# form['username']
|
|
80
|
-
# form['password']
|
|
81
|
-
# ...
|
|
82
|
-
# request.session['token'] = ...
|
|
83
|
-
# ...
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
# async def logout(self, request: Request) -> None:
|
|
87
|
-
# request.session.clear()
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
class ServerAdmin(ServerBase, Singleton):
|
|
91
|
-
"""
|
|
92
|
-
Server admin type, singleton mode.
|
|
93
|
-
"""
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
def __init__(self, server: 'rserver.Server') -> None:
|
|
97
|
-
"""
|
|
98
|
-
Build instance attributes.
|
|
99
|
-
|
|
100
|
-
Parameters
|
|
101
|
-
----------
|
|
102
|
-
server : Server.
|
|
103
|
-
"""
|
|
104
|
-
|
|
105
|
-
# Build.
|
|
106
|
-
self.server = server
|
|
107
|
-
|
|
108
|
-
## Admin.
|
|
109
|
-
self.api_admin_binds: dict[ServerAdminModel, DatabaseEngineAsync] = {}
|
|
110
|
-
'Admin API model bind database engine dictionary.'
|
|
111
|
-
Session = async_sessionmaker()
|
|
112
|
-
Session.configure(binds=self.api_admin_binds)
|
|
113
|
-
auth = self.__create_auth()
|
|
114
|
-
self.admin = Admin(
|
|
115
|
-
self.server.app,
|
|
116
|
-
session_maker=Session,
|
|
117
|
-
authentication_backend=auth
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def add_model(
|
|
123
|
-
self,
|
|
124
|
-
model: Type[ServerAdminModel] | type[rorm.Model],
|
|
125
|
-
engine: DatabaseEngineAsync | str = None,
|
|
126
|
-
label: str | None = None,
|
|
127
|
-
name: str | None = None,
|
|
128
|
-
column: str | Sequence[str] | None = None,
|
|
129
|
-
**attrs: Any
|
|
130
|
-
) -> None:
|
|
131
|
-
"""
|
|
132
|
-
Add admin model type.
|
|
133
|
-
|
|
134
|
-
Parameters
|
|
135
|
-
----------
|
|
136
|
-
model : Model type.
|
|
137
|
-
- `type[rorm.Model]`: Define as `ServerAdminModel`.
|
|
138
|
-
engine : Database engine or name.
|
|
139
|
-
label : Admin model class label.
|
|
140
|
-
name : Admin model name.
|
|
141
|
-
column : Admin model display column names.
|
|
142
|
-
attrs : Other admin model attributes.
|
|
143
|
-
"""
|
|
144
|
-
|
|
145
|
-
# Parameter.
|
|
146
|
-
if issubclass(model, rorm.Model):
|
|
147
|
-
class ServerAdminModel_(ServerAdminModel, model=model): ...
|
|
148
|
-
model = ServerAdminModel_
|
|
149
|
-
if type(engine) == str:
|
|
150
|
-
engine = self.server.db[engine]
|
|
151
|
-
if label is not None:
|
|
152
|
-
model.category = label
|
|
153
|
-
if name is not None:
|
|
154
|
-
model.name = model.name_plural = name
|
|
155
|
-
if type(column) == str:
|
|
156
|
-
column = [column]
|
|
157
|
-
if column is not None:
|
|
158
|
-
model.column_list = list(column)
|
|
159
|
-
for key, value in attrs.items():
|
|
160
|
-
setattr(model, key, value)
|
|
161
|
-
|
|
162
|
-
# Add.
|
|
163
|
-
self.api_admin_binds[model.model] = engine.engine
|
|
164
|
-
self.admin.add_view(model)
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
# Simple path.
|
|
168
|
-
|
|
169
|
-
## Server admin model type.
|
|
170
|
-
View = ServerAdminModelView
|
|
171
|
-
ViewStats = ServerAdminModelViewStats
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
reyserver/__init__.py,sha256=Oq-lOcQInzhgKt1_4OB2jNx0OO2d9qZg9iZqUx6YRr8,398
|
|
2
|
-
reyserver/radmin.py,sha256=0nOEBd1vFDn0annjiGXi3TN9C6Vofpb8W_UfXj5TuhM,4257
|
|
3
|
-
reyserver/rall.py,sha256=MI1NnqUpq22CK9w3XPPBS0K8lNuf0BnbI0pn4MGMx38,293
|
|
4
|
-
reyserver/rauth.py,sha256=KgHWuRmqmxMoeNFCvCpdxb0S5uv7VH75M0vuMrZTOt8,15111
|
|
5
|
-
reyserver/rbase.py,sha256=kzSbo6yoPlWquR6XiseTKi5hEbllaG3qVmmwnnKKac0,6898
|
|
6
|
-
reyserver/rclient.py,sha256=VDUqQMVUTGzmZ8kjiMet2_zEt0_Siw0gyQkqHRIZ594,6281
|
|
7
|
-
reyserver/rfile.py,sha256=0wS-ohsAOGcSCg07U66wpqJlxnCLWN6gkEQJK4qavWQ,8877
|
|
8
|
-
reyserver/rserver.py,sha256=mjc-SeE2RZZwB5Z1nUSMo_VMign3VcftIK1Kv7XIne8,11484
|
|
9
|
-
reyserver-1.1.60.dist-info/METADATA,sha256=JuZnt-TPamZk_dtV07w4aEm6cT5fZa3Js146QUa6wNI,1666
|
|
10
|
-
reyserver-1.1.60.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
11
|
-
reyserver-1.1.60.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
|
|
12
|
-
reyserver-1.1.60.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|