reyserver 1.1.49__py3-none-any.whl → 1.1.51__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.
- reyserver/rauth.py +146 -72
- reyserver/rbase.py +166 -30
- reyserver/rclient.py +38 -1
- reyserver/rfile.py +39 -36
- reyserver/rserver.py +32 -7
- {reyserver-1.1.49.dist-info → reyserver-1.1.51.dist-info}/METADATA +1 -1
- reyserver-1.1.51.dist-info/RECORD +11 -0
- reyserver-1.1.49.dist-info/RECORD +0 -11
- {reyserver-1.1.49.dist-info → reyserver-1.1.51.dist-info}/WHEEL +0 -0
- {reyserver-1.1.49.dist-info → reyserver-1.1.51.dist-info}/licenses/LICENSE +0 -0
reyserver/rauth.py
CHANGED
@@ -9,17 +9,23 @@
|
|
9
9
|
"""
|
10
10
|
|
11
11
|
|
12
|
+
from typing import Literal
|
12
13
|
from fastapi import APIRouter
|
13
|
-
from reydb import rorm
|
14
|
+
from reydb import rorm, DatabaseEngine, DatabaseEngineAsync
|
15
|
+
# from reykit.rdata import encode_jwt, is_hash_bcrypt
|
16
|
+
# from reykit.rtime import now
|
14
17
|
|
15
18
|
from .rbase import ServerConfig, Bind, exit_api
|
16
19
|
|
17
20
|
|
18
21
|
__all__ = (
|
19
|
-
'
|
20
|
-
'
|
21
|
-
'
|
22
|
-
'
|
22
|
+
'DatabaseORMTableUser',
|
23
|
+
'DatabaseORMTableRole',
|
24
|
+
'DatabaseORMTablePerm',
|
25
|
+
'DatabaseORMTableUserRole',
|
26
|
+
'DatabaseORMTableRolePerm',
|
27
|
+
'build_auth_db',
|
28
|
+
'auth_router'
|
23
29
|
)
|
24
30
|
|
25
31
|
|
@@ -34,10 +40,10 @@ class DatabaseORMTableUser(rorm.Model, table=True):
|
|
34
40
|
update_time: rorm.Datetime = rorm.Field(field_default=':update_time', not_null=True, index_n=True, comment='Record update time.')
|
35
41
|
user_id: int = rorm.Field(rorm.types_mysql.MEDIUMINT(unsigned=True), key_auto=True, comment='User ID.')
|
36
42
|
name: str = rorm.Field(rorm.types.VARCHAR(50), not_null=True, index_u=True, comment='User name.')
|
37
|
-
password: str
|
38
|
-
email: rorm.Email
|
39
|
-
phone:
|
40
|
-
|
43
|
+
password: str = rorm.Field(rorm.types.CHAR(60), not_null=True, comment='User password, encrypted with "bcrypt".')
|
44
|
+
email: rorm.Email = rorm.Field(rorm.types.VARCHAR(255), index_u=True, comment='User email.')
|
45
|
+
phone: str = rorm.Field(rorm.types.CHAR(11), index_u=True, comment='User phone.')
|
46
|
+
avatar: int = rorm.Field(rorm.types_mysql.MEDIUMINT(unsigned=True), comment='User avatar file ID.')
|
41
47
|
is_valid: bool = rorm.Field(rorm.types_mysql.TINYINT(unsigned=True), field_default='1', not_null=True, comment='Is the valid.')
|
42
48
|
|
43
49
|
|
@@ -61,13 +67,13 @@ class DatabaseORMTablePerm(rorm.Model, table=True):
|
|
61
67
|
"""
|
62
68
|
|
63
69
|
__name__ = 'perm'
|
64
|
-
__comment__ = '
|
70
|
+
__comment__ = 'API permission information table.'
|
65
71
|
create_time: rorm.Datetime = rorm.Field(field_default=':create_time', not_null=True, index_n=True, comment='Record create time.')
|
66
72
|
update_time: rorm.Datetime = rorm.Field(field_default=':update_time', not_null=True, index_n=True, comment='Record update time.')
|
67
73
|
perm_id: int = rorm.Field(rorm.types_mysql.SMALLINT(unsigned=True), key_auto=True, comment='Permission ID.')
|
68
74
|
name: str = rorm.Field(rorm.types.VARCHAR(50), not_null=True, index_u=True, comment='Permission name.')
|
69
75
|
desc: str = rorm.Field(rorm.types.VARCHAR(500), comment='Permission description.')
|
70
|
-
|
76
|
+
api: str = rorm.Field(rorm.types.VARCHAR(1000), comment='API resource path regular expression "match" pattern.')
|
71
77
|
|
72
78
|
|
73
79
|
class DatabaseORMTableUserRole(rorm.Model, table=True):
|
@@ -96,13 +102,16 @@ class DatabaseORMTableRolePerm(rorm.Model, table=True):
|
|
96
102
|
perm_id: int = rorm.Field(rorm.types_mysql.SMALLINT(unsigned=True), key=True, comment='Permission ID.')
|
97
103
|
|
98
104
|
|
99
|
-
def
|
105
|
+
def build_auth_db(engine: DatabaseEngine | DatabaseEngineAsync) -> None:
|
100
106
|
"""
|
101
|
-
Check and build `
|
107
|
+
Check and build `auth` database tables.
|
108
|
+
|
109
|
+
Parameters
|
110
|
+
----------
|
111
|
+
db : Database engine instance.
|
102
112
|
"""
|
103
113
|
|
104
114
|
# Set parameter.
|
105
|
-
engine = ServerConfig.server.db.file
|
106
115
|
database = engine.database
|
107
116
|
|
108
117
|
## Table.
|
@@ -120,110 +129,175 @@ def build_file_db() -> None:
|
|
120
129
|
'path': 'stats',
|
121
130
|
'items': [
|
122
131
|
{
|
123
|
-
'name': '
|
132
|
+
'name': 'user_count',
|
124
133
|
'select': (
|
125
134
|
'SELECT COUNT(1)\n'
|
126
|
-
f'FROM `{database}`.`
|
135
|
+
f'FROM `{database}`.`user`'
|
127
136
|
),
|
128
|
-
'comment': '
|
137
|
+
'comment': 'User information count.'
|
129
138
|
},
|
130
139
|
{
|
131
|
-
'name': '
|
140
|
+
'name': 'role_count',
|
132
141
|
'select': (
|
133
142
|
'SELECT COUNT(1)\n'
|
134
|
-
f'FROM `{database}`.`
|
135
|
-
'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) = 0'
|
143
|
+
f'FROM `{database}`.`role`'
|
136
144
|
),
|
137
|
-
'comment': '
|
145
|
+
'comment': 'Role information count.'
|
138
146
|
},
|
139
147
|
{
|
140
|
-
'name': '
|
148
|
+
'name': 'perm_count',
|
141
149
|
'select': (
|
142
150
|
'SELECT COUNT(1)\n'
|
143
|
-
f'FROM `{database}`.`
|
144
|
-
'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) <= 6'
|
151
|
+
f'FROM `{database}`.`perm`'
|
145
152
|
),
|
146
|
-
'comment': '
|
153
|
+
'comment': 'Permission information count.'
|
147
154
|
},
|
148
155
|
{
|
149
|
-
'name': '
|
156
|
+
'name': 'user_day_count',
|
150
157
|
'select': (
|
151
158
|
'SELECT COUNT(1)\n'
|
152
|
-
f'FROM `{database}`.`
|
153
|
-
'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW())
|
159
|
+
f'FROM `{database}`.`user`\n'
|
160
|
+
'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) = 0'
|
154
161
|
),
|
155
|
-
'comment': '
|
162
|
+
'comment': 'User information count in the past day.'
|
156
163
|
},
|
157
164
|
{
|
158
|
-
'name': '
|
165
|
+
'name': 'user_week_count',
|
159
166
|
'select': (
|
160
167
|
'SELECT COUNT(1)\n'
|
161
|
-
f'FROM `{database}`.`
|
162
|
-
|
163
|
-
'comment': 'File data unique count.'
|
164
|
-
},
|
165
|
-
{
|
166
|
-
'name': 'total_size',
|
167
|
-
'select': (
|
168
|
-
'SELECT FORMAT(SUM(`size`), 0)\n'
|
169
|
-
f'FROM `{database}`.`data`'
|
170
|
-
),
|
171
|
-
'comment': 'File total byte size.'
|
172
|
-
},
|
173
|
-
{
|
174
|
-
'name': 'avg_size',
|
175
|
-
'select': (
|
176
|
-
'SELECT FORMAT(AVG(`size`), 0)\n'
|
177
|
-
f'FROM `{database}`.`data`'
|
168
|
+
f'FROM `{database}`.`user`\n'
|
169
|
+
'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) <= 6'
|
178
170
|
),
|
179
|
-
'comment': '
|
171
|
+
'comment': 'User information count in the past week.'
|
180
172
|
},
|
181
173
|
{
|
182
|
-
'name': '
|
174
|
+
'name': 'user_month_count',
|
183
175
|
'select': (
|
184
|
-
'SELECT
|
185
|
-
f'FROM `{database}`.`
|
176
|
+
'SELECT COUNT(1)\n'
|
177
|
+
f'FROM `{database}`.`user`\n'
|
178
|
+
'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) <= 29'
|
186
179
|
),
|
187
|
-
'comment': '
|
180
|
+
'comment': 'User information count in the past month.'
|
188
181
|
},
|
189
182
|
{
|
190
|
-
'name': '
|
183
|
+
'name': 'user_last_time',
|
191
184
|
'select': (
|
192
185
|
'SELECT MAX(`create_time`)\n'
|
193
|
-
f'FROM `{database}`.`
|
186
|
+
f'FROM `{database}`.`user`'
|
194
187
|
),
|
195
|
-
'comment': '
|
188
|
+
'comment': 'User last record create time.'
|
196
189
|
}
|
197
190
|
]
|
198
191
|
}
|
199
192
|
]
|
200
193
|
|
201
194
|
# Build.
|
202
|
-
engine.sync_engine.build.build(tables=tables,
|
195
|
+
engine.sync_engine.build.build(tables=tables, views_stats=views_stats, skip=True)
|
203
196
|
|
204
197
|
|
205
|
-
|
206
|
-
|
207
|
-
|
198
|
+
auth_router = APIRouter()
|
199
|
+
depend_auth_sess = Bind.create_depend_db('auth', 'sess')
|
200
|
+
depend_auth_conn = Bind.create_depend_db('auth', 'conn')
|
208
201
|
|
209
202
|
|
210
|
-
@
|
211
|
-
async def
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
) ->
|
203
|
+
@auth_router.post('/sessions')
|
204
|
+
async def create_sessions(
|
205
|
+
account: str = Bind.i.body,
|
206
|
+
password: str = Bind.i.body,
|
207
|
+
account_type: Literal['name', 'email', 'phone'] = Bind.Body('name'),
|
208
|
+
conn: Bind.Conn = depend_auth_conn
|
209
|
+
) -> dict:
|
217
210
|
"""
|
218
|
-
|
211
|
+
Create session.
|
219
212
|
|
220
213
|
Parameters
|
221
214
|
----------
|
222
|
-
|
223
|
-
|
224
|
-
|
215
|
+
account : User account, name or email or phone.
|
216
|
+
password : User password.
|
217
|
+
account_type : User account type.
|
225
218
|
|
226
219
|
Returns
|
227
220
|
-------
|
228
|
-
|
229
|
-
"""
|
221
|
+
JSON with `token`.
|
222
|
+
"""
|
223
|
+
|
224
|
+
# Parameter.
|
225
|
+
key = ServerConfig.server.api_auth_key
|
226
|
+
sess_seconds = ServerConfig.server.api_auth_sess_seconds
|
227
|
+
|
228
|
+
# Check.
|
229
|
+
sql = (
|
230
|
+
'SELECT ANY_VALUE(`create_time`) AS `create_time`,\n'
|
231
|
+
' ANY_VALUE(`update_time`) AS `update_time`,\n'
|
232
|
+
' ANY_VALUE(`user`.`user_id`) AS `user_id`,\n'
|
233
|
+
' ANY_VALUE(`user`.`name`) AS `user_name`,\n'
|
234
|
+
' ANY_VALUE(`password`) AS `password`,\n'
|
235
|
+
' ANY_VALUE(`email`) AS `email`,\n'
|
236
|
+
' ANY_VALUE(`phone`) AS `phone`,\n'
|
237
|
+
' ANY_VALUE(`avatar`) AS `avatar`,\n'
|
238
|
+
" GROUP_CONCAT(DISTINCT `role`.`name` SEPARATOR ';') AS `role_names`,\n"
|
239
|
+
" GROUP_CONCAT(DISTINCT `perm`.`name` SEPARATOR ';') AS `perm_names`,\n"
|
240
|
+
" GROUP_CONCAT(DISTINCT `perm`.`api` SEPARATOR ';') AS `perm_apis`\n"
|
241
|
+
'FROM (\n'
|
242
|
+
' SELECT `create_time`, `update_time`, `user_id`, `password`, `name`, `email`, `phone`, `avatar`\n'
|
243
|
+
' FROM `test`.`user`\n'
|
244
|
+
f' WHERE `{account_type}` = :account\n'
|
245
|
+
' LIMIT 1\n'
|
246
|
+
') as `user`\n'
|
247
|
+
'LEFT JOIN (\n'
|
248
|
+
' SELECT `user_id`, `role_id`\n'
|
249
|
+
' FROM `test`.`user_role`\n'
|
250
|
+
') as `user_role`\n'
|
251
|
+
'ON `user_role`.`user_id` = `user`.`user_id`\n'
|
252
|
+
'LEFT JOIN (\n'
|
253
|
+
' SELECT `role_id`, `name`\n'
|
254
|
+
' FROM `test`.`role`\n'
|
255
|
+
') AS `role`\n'
|
256
|
+
'ON `user_role`.`role_id` = `role`.`role_id`\n'
|
257
|
+
'LEFT JOIN (\n'
|
258
|
+
' SELECT `role_id`, `perm_id`\n'
|
259
|
+
' FROM `test`.`role_perm`\n'
|
260
|
+
') as `role_perm`\n'
|
261
|
+
'ON `role_perm`.`role_id` = `role`.`role_id`\n'
|
262
|
+
'LEFT JOIN (\n'
|
263
|
+
" SELECT `perm_id`, `name`, CONCAT(`method`, ':', `path`) as `api`\n"
|
264
|
+
' FROM `test`.`perm`\n'
|
265
|
+
') AS `perm`\n'
|
266
|
+
'ON `role_perm`.`perm_id` = `perm`.`perm_id`'
|
267
|
+
)
|
268
|
+
print(1111111111111)
|
269
|
+
result = await conn.execute(
|
270
|
+
sql,
|
271
|
+
account=account
|
272
|
+
)
|
273
|
+
print(result.fetchall())
|
274
|
+
return {'message': 'ok'}
|
275
|
+
|
276
|
+
# # Check.
|
277
|
+
# table = result.to_table()
|
278
|
+
# print(table)
|
279
|
+
# if table == []:
|
280
|
+
# exit_api(401)
|
281
|
+
# json = table[0]
|
282
|
+
# if not is_hash_bcrypt(password, json['password']):
|
283
|
+
# exit_api(401)
|
284
|
+
|
285
|
+
# # JWT.
|
286
|
+
# now_timestamp_s = now('timestamp_s')
|
287
|
+
# json['sub'] = json.pop('user_id')
|
288
|
+
# json['iat'] = now_timestamp_s
|
289
|
+
# json['nbf'] = now_timestamp_s
|
290
|
+
# json['exp'] = now_timestamp_s + sess_seconds
|
291
|
+
# json['role_names'] = json['role_names'].split(';')
|
292
|
+
# json['perm_names'] = json['perm_names'].split(';')
|
293
|
+
# perm_apis: list[str] = json['perm_apis'].split(';')
|
294
|
+
# perm_api_dict = {}
|
295
|
+
# for perm_api in perm_apis:
|
296
|
+
# for method, path in perm_api.split(':', 1):
|
297
|
+
# paths: list = perm_api_dict.setdefault(method, [])
|
298
|
+
# paths.append(path)
|
299
|
+
# json['perm_apis'] = perm_api_dict
|
300
|
+
# token = encode_jwt(json, key)
|
301
|
+
# data = {'token': token}
|
302
|
+
# print(111111, data)
|
303
|
+
# return data
|
reyserver/rbase.py
CHANGED
@@ -26,8 +26,7 @@ from fastapi.params import (
|
|
26
26
|
)
|
27
27
|
from reydb.rconn import DatabaseConnectionAsync
|
28
28
|
from reydb.rorm import DatabaseORMModel, DatabaseORMSessionAsync
|
29
|
-
from reykit.
|
30
|
-
from reykit.rbase import CoroutineFunctionSimple, Base, Exit, StaticMeta, ConfigMeta, throw
|
29
|
+
from reykit.rbase import CoroutineFunctionSimple, Base, Exit, StaticMeta, ConfigMeta, Singleton, throw
|
31
30
|
|
32
31
|
from . import rserver
|
33
32
|
|
@@ -38,7 +37,8 @@ __all__ = (
|
|
38
37
|
'ServerExit',
|
39
38
|
'ServerExitAPI',
|
40
39
|
'exit_api',
|
41
|
-
'ServerBind'
|
40
|
+
'ServerBind',
|
41
|
+
'Bind'
|
42
42
|
)
|
43
43
|
|
44
44
|
|
@@ -91,6 +91,168 @@ def exit_api(code: int = 400, text: str | None = None) -> NoReturn:
|
|
91
91
|
raise ServerExitAPI(code, text)
|
92
92
|
|
93
93
|
|
94
|
+
class ServerBindInstance(ServerBase, Singleton):
|
95
|
+
"""
|
96
|
+
Server API bind parameter build instance type.
|
97
|
+
"""
|
98
|
+
|
99
|
+
|
100
|
+
@property
|
101
|
+
def path(self) -> Path:
|
102
|
+
"""
|
103
|
+
Path instance.
|
104
|
+
"""
|
105
|
+
|
106
|
+
# Build.
|
107
|
+
path = Path()
|
108
|
+
|
109
|
+
return path
|
110
|
+
|
111
|
+
|
112
|
+
@property
|
113
|
+
def query(self) -> Query:
|
114
|
+
"""
|
115
|
+
Query instance.
|
116
|
+
"""
|
117
|
+
|
118
|
+
# Build.
|
119
|
+
query = Query()
|
120
|
+
|
121
|
+
return query
|
122
|
+
|
123
|
+
|
124
|
+
@property
|
125
|
+
def header(self) -> Header:
|
126
|
+
"""
|
127
|
+
Header instance.
|
128
|
+
"""
|
129
|
+
|
130
|
+
# Build.
|
131
|
+
header = Header()
|
132
|
+
|
133
|
+
return header
|
134
|
+
|
135
|
+
|
136
|
+
@property
|
137
|
+
def cookie(self) -> Cookie:
|
138
|
+
"""
|
139
|
+
Cookie instance.
|
140
|
+
"""
|
141
|
+
|
142
|
+
# Build.
|
143
|
+
cookie = Cookie()
|
144
|
+
|
145
|
+
return cookie
|
146
|
+
|
147
|
+
|
148
|
+
@property
|
149
|
+
def body(self) -> Body:
|
150
|
+
"""
|
151
|
+
Body instance.
|
152
|
+
"""
|
153
|
+
|
154
|
+
# Build.
|
155
|
+
body = Body()
|
156
|
+
|
157
|
+
return body
|
158
|
+
|
159
|
+
|
160
|
+
@property
|
161
|
+
def form(self) -> Form:
|
162
|
+
"""
|
163
|
+
Form instance.
|
164
|
+
"""
|
165
|
+
|
166
|
+
# Build.
|
167
|
+
form = Form()
|
168
|
+
|
169
|
+
return form
|
170
|
+
|
171
|
+
|
172
|
+
@property
|
173
|
+
def forms(self) -> Forms:
|
174
|
+
"""
|
175
|
+
Forms instance.
|
176
|
+
"""
|
177
|
+
|
178
|
+
# Build.
|
179
|
+
forms = Forms()
|
180
|
+
|
181
|
+
return forms
|
182
|
+
|
183
|
+
|
184
|
+
@property
|
185
|
+
def query_n(self) -> Query:
|
186
|
+
"""
|
187
|
+
Query instance, default `None`.
|
188
|
+
"""
|
189
|
+
|
190
|
+
# Build.
|
191
|
+
query = Query(None)
|
192
|
+
|
193
|
+
return query
|
194
|
+
|
195
|
+
|
196
|
+
@property
|
197
|
+
def header_n(self) -> Header:
|
198
|
+
"""
|
199
|
+
Header instance, default `None`.
|
200
|
+
"""
|
201
|
+
|
202
|
+
# Build.
|
203
|
+
header = Header(None)
|
204
|
+
|
205
|
+
return header
|
206
|
+
|
207
|
+
|
208
|
+
@property
|
209
|
+
def cookie_n(self) -> Cookie:
|
210
|
+
"""
|
211
|
+
Cookie instance, default `None`.
|
212
|
+
"""
|
213
|
+
|
214
|
+
# Build.
|
215
|
+
cookie = Cookie(None)
|
216
|
+
|
217
|
+
return cookie
|
218
|
+
|
219
|
+
|
220
|
+
@property
|
221
|
+
def body_n(self) -> Body:
|
222
|
+
"""
|
223
|
+
Body instance, default `None`.
|
224
|
+
"""
|
225
|
+
|
226
|
+
# Build.
|
227
|
+
body = Body(None)
|
228
|
+
|
229
|
+
return body
|
230
|
+
|
231
|
+
|
232
|
+
@property
|
233
|
+
def form_n(self) -> Form:
|
234
|
+
"""
|
235
|
+
Form instance, default `None`.
|
236
|
+
"""
|
237
|
+
|
238
|
+
# Build.
|
239
|
+
form = Form(None)
|
240
|
+
|
241
|
+
return form
|
242
|
+
|
243
|
+
|
244
|
+
@property
|
245
|
+
def forms_n(self) -> Forms:
|
246
|
+
"""
|
247
|
+
Forms instance, default `None`.
|
248
|
+
"""
|
249
|
+
|
250
|
+
# Build.
|
251
|
+
forms = Forms(None)
|
252
|
+
|
253
|
+
return forms
|
254
|
+
|
255
|
+
|
94
256
|
class ServerBind(ServerBase, metaclass=StaticMeta):
|
95
257
|
"""
|
96
258
|
Server API bind parameter type.
|
@@ -148,7 +310,6 @@ class ServerBind(ServerBase, metaclass=StaticMeta):
|
|
148
310
|
return lifespan
|
149
311
|
|
150
312
|
|
151
|
-
@wrap_cache
|
152
313
|
def create_depend_db(database: str, mode: Literal['sess', 'conn']) -> Depends:
|
153
314
|
"""
|
154
315
|
Create dependencie type of asynchronous database.
|
@@ -201,32 +362,7 @@ class ServerBind(ServerBase, metaclass=StaticMeta):
|
|
201
362
|
JSON = DatabaseORMModel
|
202
363
|
Conn = DatabaseConnectionAsync
|
203
364
|
Sess = DatabaseORMSessionAsync
|
204
|
-
|
205
|
-
'Path instance.'
|
206
|
-
query = Query()
|
207
|
-
'Query instance.'
|
208
|
-
header = Header()
|
209
|
-
'Header instance.'
|
210
|
-
cookie = Cookie()
|
211
|
-
'Cookie instance.'
|
212
|
-
body = Body()
|
213
|
-
'Body instance.'
|
214
|
-
form = Form()
|
215
|
-
'Form instance.'
|
216
|
-
forms = Forms()
|
217
|
-
'Forms instance.'
|
218
|
-
query_n = Query(None)
|
219
|
-
'Query instance, default `None`.'
|
220
|
-
header_n = Header(None)
|
221
|
-
'Header instance, default `None`.'
|
222
|
-
cookie_n = Cookie(None)
|
223
|
-
'Cookie instance, default `None`.'
|
224
|
-
body_n = Body(None)
|
225
|
-
'Body instance, default `None`.'
|
226
|
-
form_n = Form(None)
|
227
|
-
'Form instance, default `None`.'
|
228
|
-
forms_n = Forms(None)
|
229
|
-
'Forms instance, default `None`.'
|
365
|
+
i = ServerBindInstance()
|
230
366
|
|
231
367
|
|
232
368
|
Bind = ServerBind
|
reyserver/rclient.py
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
"""
|
10
10
|
|
11
11
|
|
12
|
-
from typing import TypedDict
|
12
|
+
from typing import TypedDict, Literal
|
13
13
|
from datetime import datetime as Datetime
|
14
14
|
from reykit.ros import File, Folder, overload
|
15
15
|
from reykit.rnet import join_url, request, get_response_file_name
|
@@ -44,6 +44,43 @@ class ServerClient(ServerBase):
|
|
44
44
|
self.url = url
|
45
45
|
|
46
46
|
|
47
|
+
def create_session(
|
48
|
+
self,
|
49
|
+
account: str,
|
50
|
+
password: str,
|
51
|
+
account_type: Literal['name', 'email', 'phone'] = 'name'
|
52
|
+
) -> str:
|
53
|
+
"""
|
54
|
+
Create session.
|
55
|
+
|
56
|
+
Parameters
|
57
|
+
----------
|
58
|
+
account : User account, name or email or phone.
|
59
|
+
password : User password.
|
60
|
+
account_type : User account type.
|
61
|
+
|
62
|
+
Returns
|
63
|
+
-------
|
64
|
+
Token.
|
65
|
+
"""
|
66
|
+
|
67
|
+
# Parameter.
|
68
|
+
url = join_url(self.url, 'sessions')
|
69
|
+
json = {
|
70
|
+
'account': account,
|
71
|
+
'password': password,
|
72
|
+
'account_type': account_type
|
73
|
+
}
|
74
|
+
|
75
|
+
# Request.
|
76
|
+
response = request(url, json=json, check=True)
|
77
|
+
response_dict = response.json()
|
78
|
+
print(response_dict)
|
79
|
+
token = response_dict['token']
|
80
|
+
|
81
|
+
return token
|
82
|
+
|
83
|
+
|
47
84
|
def upload_file(
|
48
85
|
self,
|
49
86
|
source: str | bytes,
|
reyserver/rfile.py
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
|
12
12
|
from fastapi import APIRouter
|
13
13
|
from fastapi.responses import FileResponse
|
14
|
-
from reydb import rorm
|
14
|
+
from reydb import rorm, DatabaseEngine, DatabaseEngineAsync
|
15
15
|
from reykit.ros import FileStore, get_md5
|
16
16
|
|
17
17
|
from .rbase import ServerConfig, Bind, exit_api
|
@@ -51,13 +51,16 @@ class DatabaseORMTableData(rorm.Model, table=True):
|
|
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() -> None:
|
54
|
+
def build_file_db(engine: DatabaseEngine | DatabaseEngineAsync) -> None:
|
55
55
|
"""
|
56
56
|
Check and build `file` database tables.
|
57
|
+
|
58
|
+
Parameters
|
59
|
+
----------
|
60
|
+
db : Database engine instance.
|
57
61
|
"""
|
58
62
|
|
59
63
|
# Set parameter.
|
60
|
-
engine = ServerConfig.server.db.file
|
61
64
|
database = engine.database
|
62
65
|
|
63
66
|
## Table.
|
@@ -179,11 +182,38 @@ depend_file_sess = Bind.create_depend_db('file', 'sess')
|
|
179
182
|
depend_file_conn = Bind.create_depend_db('file', 'conn')
|
180
183
|
|
181
184
|
|
182
|
-
@file_router.
|
185
|
+
@file_router.get('/files/{file_id}')
|
186
|
+
async def get_file_info(
|
187
|
+
file_id: int = Bind.i.path,
|
188
|
+
sess: Bind.Sess = depend_file_sess
|
189
|
+
) -> DatabaseORMTableInfo:
|
190
|
+
"""
|
191
|
+
Get file information.
|
192
|
+
|
193
|
+
Parameters
|
194
|
+
----------
|
195
|
+
file_id : File ID.
|
196
|
+
|
197
|
+
Returns
|
198
|
+
-------
|
199
|
+
File information.
|
200
|
+
"""
|
201
|
+
|
202
|
+
# Get.
|
203
|
+
table_info = await sess.get(DatabaseORMTableInfo, file_id)
|
204
|
+
|
205
|
+
# Check.
|
206
|
+
if table_info is None:
|
207
|
+
exit_api(404)
|
208
|
+
|
209
|
+
return table_info
|
210
|
+
|
211
|
+
|
212
|
+
@file_router.post('/files')
|
183
213
|
async def upload_file(
|
184
|
-
file: Bind.File = Bind.forms,
|
185
|
-
name: str = Bind.forms_n,
|
186
|
-
note: str = Bind.forms_n,
|
214
|
+
file: Bind.File = Bind.i.forms,
|
215
|
+
name: str = Bind.i.forms_n,
|
216
|
+
note: str = Bind.i.forms_n,
|
187
217
|
sess: Bind.Sess = depend_file_sess
|
188
218
|
) -> DatabaseORMTableInfo:
|
189
219
|
"""
|
@@ -233,9 +263,9 @@ async def upload_file(
|
|
233
263
|
return table_info
|
234
264
|
|
235
265
|
|
236
|
-
@file_router.get('/{file_id}/download')
|
266
|
+
@file_router.get('/files/{file_id}/download')
|
237
267
|
async def download_file(
|
238
|
-
file_id: int = Bind.path,
|
268
|
+
file_id: int = Bind.i.path,
|
239
269
|
conn: Bind.Conn = depend_file_conn
|
240
270
|
) -> FileResponse:
|
241
271
|
"""
|
@@ -273,30 +303,3 @@ async def download_file(
|
|
273
303
|
response = FileResponse(file_path, filename=file_name)
|
274
304
|
|
275
305
|
return response
|
276
|
-
|
277
|
-
|
278
|
-
@file_router.get('/{file_id}')
|
279
|
-
async def get_file_info(
|
280
|
-
file_id: int = Bind.path,
|
281
|
-
sess: Bind.Sess = depend_file_sess
|
282
|
-
) -> DatabaseORMTableInfo:
|
283
|
-
"""
|
284
|
-
Get file information.
|
285
|
-
|
286
|
-
Parameters
|
287
|
-
----------
|
288
|
-
file_id : File ID.
|
289
|
-
|
290
|
-
Returns
|
291
|
-
-------
|
292
|
-
File information.
|
293
|
-
"""
|
294
|
-
|
295
|
-
# Get.
|
296
|
-
table_info = await sess.get(DatabaseORMTableInfo, file_id)
|
297
|
-
|
298
|
-
# Check.
|
299
|
-
if table_info is None:
|
300
|
-
exit_api(404)
|
301
|
-
|
302
|
-
return table_info
|
reyserver/rserver.py
CHANGED
@@ -19,7 +19,8 @@ from fastapi.staticfiles import StaticFiles
|
|
19
19
|
from fastapi.middleware.gzip import GZipMiddleware
|
20
20
|
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
|
21
21
|
from reydb import DatabaseAsync
|
22
|
-
from reykit.rbase import
|
22
|
+
from reykit.rbase import CoroutineFunctionSimple, Singleton, throw
|
23
|
+
from reykit.rrand import randchar
|
23
24
|
|
24
25
|
from .rbase import ServerBase, ServerConfig, Bind
|
25
26
|
|
@@ -102,6 +103,10 @@ class Server(ServerBase, Singleton):
|
|
102
103
|
self.__add_default_middleware()
|
103
104
|
|
104
105
|
# API.
|
106
|
+
self.api_auth_key: str
|
107
|
+
'Authentication API JWT encryption key.'
|
108
|
+
self.api_auth_sess_seconds: int
|
109
|
+
'Authentication API session valid seconds.'
|
105
110
|
self.api_file_dir: str
|
106
111
|
'File API store directory path.'
|
107
112
|
|
@@ -187,13 +192,32 @@ class Server(ServerBase, Singleton):
|
|
187
192
|
setattr(self.app, key, value)
|
188
193
|
|
189
194
|
|
190
|
-
def add_api_auth(self):
|
195
|
+
def add_api_auth(self, key: str | None = None, sess_seconds: int = 28800) -> None:
|
191
196
|
"""
|
192
|
-
Add
|
197
|
+
Add authentication API.
|
193
198
|
Note: must include database engine of `auth` name.
|
199
|
+
|
200
|
+
Parameters
|
201
|
+
----------
|
202
|
+
key : JWT encryption key.
|
203
|
+
- `None`: Random 32 length string.
|
204
|
+
sess_seconds : Session valid seconds.
|
194
205
|
"""
|
195
206
|
|
196
|
-
|
207
|
+
from .rauth import build_auth_db, auth_router
|
208
|
+
|
209
|
+
# Parameter.
|
210
|
+
if key is None:
|
211
|
+
key = randchar(32)
|
212
|
+
|
213
|
+
# Build database.
|
214
|
+
engine = self.db.auth
|
215
|
+
build_auth_db(engine)
|
216
|
+
|
217
|
+
# Add.
|
218
|
+
self.api_auth_key = key
|
219
|
+
self.api_auth_sess_seconds = sess_seconds
|
220
|
+
self.app.include_router(auth_router, tags=['auth'])
|
197
221
|
|
198
222
|
|
199
223
|
def add_api_file(self, file_dir: str = 'file') -> None:
|
@@ -207,11 +231,12 @@ class Server(ServerBase, Singleton):
|
|
207
231
|
prefix : File API path prefix.
|
208
232
|
"""
|
209
233
|
|
210
|
-
from .rfile import
|
234
|
+
from .rfile import build_file_db, file_router
|
211
235
|
|
212
236
|
# Build database.
|
213
|
-
|
237
|
+
engine = self.db.file
|
238
|
+
build_file_db(engine)
|
214
239
|
|
215
240
|
# Add.
|
216
241
|
self.api_file_dir = file_dir
|
217
|
-
self.app.include_router(file_router,
|
242
|
+
self.app.include_router(file_router, 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=T2oafUAmXr4WfVYmEHO5v0j9K703KUYLGNVEom0J76Q,11716
|
4
|
+
reyserver/rbase.py,sha256=xgdLP_O77e-pSrRWm9GVSziPSqEOh2w20cWkF4HBeWo,7042
|
5
|
+
reyserver/rclient.py,sha256=IWZ3smyIP0_YJrfSrM8JFCr0FCtN02AyT3hp8YuSsDQ,5103
|
6
|
+
reyserver/rfile.py,sha256=bvuXOYO3UDM1jMiyNzQDz56_0ekZUEIRcfNFAhGgdUY,9010
|
7
|
+
reyserver/rserver.py,sha256=gOvLfaLqiDgHcZbzd3h2iIaDtraCuBcmsy1d61TaJ2c,6717
|
8
|
+
reyserver-1.1.51.dist-info/METADATA,sha256=F4eENaUB_2lE1aEeV4ZZ_W7AHW7iB6NfPuTsR1fy-8U,1689
|
9
|
+
reyserver-1.1.51.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
10
|
+
reyserver-1.1.51.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
|
11
|
+
reyserver-1.1.51.dist-info/RECORD,,
|
@@ -1,11 +0,0 @@
|
|
1
|
-
reyserver/__init__.py,sha256=7GX64p7uI2eetJH9NJ-DTg-8iyQwOsGcviADFJCPxVA,373
|
2
|
-
reyserver/rall.py,sha256=riyDRTUsigco_Bee1H4aZFb8IgvjnxdX9qcnVb9i9mE,270
|
3
|
-
reyserver/rauth.py,sha256=VC6Gq2uoiQuON4pmSueZojucU4m2FTdPxLPhGgM4G0A,8390
|
4
|
-
reyserver/rbase.py,sha256=IUVkkNsLmQh-QRLX6qtbCjPZAbQAsxoe0goPLCxG9KA,5283
|
5
|
-
reyserver/rclient.py,sha256=pTJtn78jPKgFo5EoQwZRdM0cYHdCs7QUKqfl-jUBRgk,4220
|
6
|
-
reyserver/rfile.py,sha256=C_kuH9KQS6E5VFDmg_dvbEYfyWxa1hl64fjoh8BFiXQ,8874
|
7
|
-
reyserver/rserver.py,sha256=hqpemzJHO6xHy_7pO3cvvjnfy8Yfqy8HfyIq4sjk4Dc,5889
|
8
|
-
reyserver-1.1.49.dist-info/METADATA,sha256=LnFaa55uE9AkN95GWcvdVCPyIjQjw9S-xh3OE7QOLlo,1689
|
9
|
-
reyserver-1.1.49.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
10
|
-
reyserver-1.1.49.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
|
11
|
-
reyserver-1.1.49.dist-info/RECORD,,
|
File without changes
|
File without changes
|