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 CHANGED
@@ -9,7 +9,6 @@
9
9
 
10
10
  Modules
11
11
  -------
12
- radmin : Admin methods.
13
12
  rall : All methods.
14
13
  rauth : Authentication methods.
15
14
  rbase : Base methods.
reyserver/rall.py CHANGED
@@ -9,7 +9,6 @@
9
9
  """
10
10
 
11
11
 
12
- from .radmin import *
13
12
  from .rauth import *
14
13
  from .rbase import *
15
14
  from .rclient import *
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 HTTPBearer, HTTPAuthorizationCredentials
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
- 'build_auth_db',
33
- 'auth_router'
32
+ 'build_db_auth',
33
+ 'router_auth'
34
34
  )
35
35
 
36
36
 
37
37
  UserInfo = TypedDict(
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
- Token = TypedDict(
54
- 'Token',
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 build_auth_db(engine: DatabaseEngine | DatabaseEngineAsync) -> None:
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
- auth_router = APIRouter()
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
- @auth_router.post('/sessions')
409
+ @router_auth.post('/token')
340
410
  async def create_sessions(
341
- account: str = Bind.i.body,
342
- password: str = Bind.i.body,
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
- ) -> dict:
415
+ ) -> ResponseToken:
347
416
  """
348
417
  Create session.
349
418
 
350
419
  Parameters
351
420
  ----------
352
- account : User account.
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, account, account_type)
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
- # JWT.
443
+ # Response.
379
444
  now_timestamp_s = now('timestamp_s')
380
445
  user_id = info.pop('user_id')
381
- data: Token = {
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 = {'token': token}
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.create_session(username, password)
56
+ self.token = self.get_token(username, password)
57
57
 
58
58
 
59
- def create_session(
59
+ def get_token(
60
60
  self,
61
61
  username: str,
62
62
  password: str
63
63
  ) -> str:
64
64
  """
65
- Create session.
65
+ Get token.
66
66
 
67
67
  Parameters
68
68
  ----------
69
- account : User name.
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, 'sessions')
80
- json = {
81
- 'account': username,
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, json=json, check=True)
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
- 'build_file_db',
24
- 'file_router'
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 build_file_db(engine: DatabaseEngine | DatabaseEngineAsync) -> None:
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
- file_router = APIRouter()
180
+ router_file = APIRouter()
181
181
 
182
182
 
183
- @file_router.get('/files/{file_id}')
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
- @file_router.post('/files')
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
- @file_router.get('/files/{file_id}/download')
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.__add_default_middleware()
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 __add_default_middleware(self) -> None:
181
+ def __add_base_middleware(self) -> None:
189
182
  """
190
- Add default handle middleware.
183
+ Add base middleware.
191
184
  """
192
185
 
193
186
  # Add.
194
187
  @self.wrap_middleware
195
- async def middleware(
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
- Default handle middleware.
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
- def add_api_admin(self) -> None:
283
- """
284
- Add admin API.
285
- """
286
-
287
- # Add.
288
- self.admin = radmin.ServerAdmin(self)
289
-
290
-
291
- def add_admin_model(
292
- self,
293
- model: Type['radmin.ServerAdminModel'] | type[rorm.Model],
294
- engine: DatabaseEngineAsync | str = None,
295
- label: str | None = None,
296
- name: str | None = None,
297
- column: str | Sequence[str] | None = None,
298
- **attrs: Any
299
- ) -> None:
300
- """
301
- Add admin model type.
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
- build_auth_db(engine)
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(auth_router, tags=['auth'])
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 .rfile import (
381
- build_file_db,
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
- build_file_db(engine)
348
+ build_db_file(engine)
392
349
 
393
350
  # Add.
394
351
  self.api_file_dir = file_dir
395
- self.app.include_router(file_router, tags=['file'])
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'])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reyserver
3
- Version: 1.1.60
3
+ Version: 1.1.61
4
4
  Summary: Backend server method set.
5
5
  Project-URL: homepage, https://github.com/reyxbo/reyserver/
6
6
  Author-email: Rey <reyxbo@163.com>
@@ -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,,