1
1
import asyncio
2
2
import json
3
+ import sys
3
4
import warnings
4
5
from abc import ABC , abstractmethod
5
6
from datetime import date , datetime , time
6
7
from enum import Enum
7
8
from functools import cached_property , partial
8
9
from types import MappingProxyType
9
- from typing import Any , Literal , Optional , TypedDict , Union
10
+ from typing import Any , Literal , Optional , Union
10
11
11
12
from aiohttp import web
12
13
from aiohttp_security import check_permission , permits
13
- from pydantic import Json , parse_obj_as
14
+ from pydantic import Json
14
15
15
- from ..security import permissions_as_dict
16
- from ..types import FieldState , InputState
16
+ from ..security import check , permissions_as_dict
17
+ from ..types import ComponentState , InputState
18
+
19
+ if sys .version_info >= (3 , 12 ):
20
+ from typing import TypedDict
21
+ else :
22
+ from typing_extensions import TypedDict
17
23
18
24
Record = dict [str , object ]
19
25
@@ -93,7 +99,7 @@ class DeleteManyParams(_Params):
93
99
94
100
class AbstractAdminResource (ABC ):
95
101
name : str
96
- fields : dict [str , FieldState ]
102
+ fields : dict [str , ComponentState ]
97
103
inputs : dict [str , InputState ]
98
104
primary_key : str
99
105
omit_fields : set [str ]
@@ -149,7 +155,7 @@ async def delete_many(self, params: DeleteManyParams) -> list[Union[int, str]]:
149
155
150
156
async def _get_list (self , request : web .Request ) -> web .Response :
151
157
await check_permission (request , f"admin.{ self .name } .view" , context = (request , None ))
152
- query = parse_obj_as (GetListParams , request .query )
158
+ query = check (GetListParams , request .query )
153
159
154
160
# When sort order refers to "id", this should be translated to primary key.
155
161
if query ["sort" ]["field" ] == "id" :
@@ -174,7 +180,7 @@ async def _get_list(self, request: web.Request) -> web.Response:
174
180
175
181
async def _get_one (self , request : web .Request ) -> web .Response :
176
182
await check_permission (request , f"admin.{ self .name } .view" , context = (request , None ))
177
- query = parse_obj_as (GetOneParams , request .query )
183
+ query = check (GetOneParams , request .query )
178
184
179
185
result = await self .get_one (query )
180
186
if not await permits (request , f"admin.{ self .name } .view" , context = (request , result )):
@@ -185,7 +191,7 @@ async def _get_one(self, request: web.Request) -> web.Response:
185
191
186
192
async def _get_many (self , request : web .Request ) -> web .Response :
187
193
await check_permission (request , f"admin.{ self .name } .view" , context = (request , None ))
188
- query = parse_obj_as (GetManyParams , request .query )
194
+ query = check (GetManyParams , request .query )
189
195
190
196
results = await self .get_many (query )
191
197
if not results :
@@ -198,12 +204,12 @@ async def _get_many(self, request: web.Request) -> web.Response:
198
204
return json_response ({"data" : results })
199
205
200
206
async def _create (self , request : web .Request ) -> web .Response :
201
- query = parse_obj_as (CreateParams , request .query )
207
+ query = check (CreateParams , request .query )
202
208
# TODO(Pydantic): Dissallow extra arguments
203
209
for k in query ["data" ]:
204
210
if k not in self .inputs and k != "id" :
205
211
raise web .HTTPBadRequest (reason = f"Invalid field '{ k } '" )
206
- query ["data" ] = parse_obj_as (self ._record_type , query ["data" ])
212
+ query ["data" ] = check (self ._record_type , query ["data" ])
207
213
await check_permission (request , f"admin.{ self .name } .add" , context = (request , query ["data" ]))
208
214
for k , v in query ["data" ].items ():
209
215
if v is not None :
@@ -217,13 +223,13 @@ async def _create(self, request: web.Request) -> web.Response:
217
223
218
224
async def _update (self , request : web .Request ) -> web .Response :
219
225
await check_permission (request , f"admin.{ self .name } .edit" , context = (request , None ))
220
- query = parse_obj_as (UpdateParams , request .query )
226
+ query = check (UpdateParams , request .query )
221
227
# TODO(Pydantic): Dissallow extra arguments
222
228
for k in query ["data" ]:
223
229
if k not in self .inputs and k != "id" :
224
230
raise web .HTTPBadRequest (reason = f"Invalid field '{ k } '" )
225
- query ["data" ] = parse_obj_as (self ._record_type , query ["data" ])
226
- query ["previousData" ] = parse_obj_as (self ._record_type , query ["previousData" ])
231
+ query ["data" ] = check (self ._record_type , query ["data" ])
232
+ query ["previousData" ] = check (self ._record_type , query ["previousData" ])
227
233
228
234
if self .primary_key != "id" :
229
235
query ["data" ].pop ("id" , None )
@@ -251,12 +257,12 @@ async def _update(self, request: web.Request) -> web.Response:
251
257
252
258
async def _update_many (self , request : web .Request ) -> web .Response :
253
259
await check_permission (request , f"admin.{ self .name } .edit" , context = (request , None ))
254
- query = parse_obj_as (UpdateManyParams , request .query )
260
+ query = check (UpdateManyParams , request .query )
255
261
# TODO(Pydantic): Dissallow extra arguments
256
262
for k in query ["data" ]:
257
263
if k not in self .inputs and k != "id" :
258
264
raise web .HTTPBadRequest (reason = f"Invalid field '{ k } '" )
259
- query ["data" ] = parse_obj_as (self ._record_type , query ["data" ])
265
+ query ["data" ] = check (self ._record_type , query ["data" ])
260
266
261
267
# Check original records are allowed by permission filters.
262
268
originals = await self .get_many ({"ids" : query ["ids" ]})
@@ -278,8 +284,8 @@ async def _update_many(self, request: web.Request) -> web.Response:
278
284
279
285
async def _delete (self , request : web .Request ) -> web .Response :
280
286
await check_permission (request , f"admin.{ self .name } .delete" , context = (request , None ))
281
- query = parse_obj_as (DeleteParams , request .query )
282
- query ["previousData" ] = parse_obj_as (self ._record_type , query ["previousData" ])
287
+ query = check (DeleteParams , request .query )
288
+ query ["previousData" ] = check (self ._record_type , query ["previousData" ])
283
289
284
290
original = await self .get_one ({"id" : query ["id" ]})
285
291
if not await permits (request , f"admin.{ self .name } .delete" , context = (request , original )):
@@ -292,7 +298,7 @@ async def _delete(self, request: web.Request) -> web.Response:
292
298
293
299
async def _delete_many (self , request : web .Request ) -> web .Response :
294
300
await check_permission (request , f"admin.{ self .name } .delete" , context = (request , None ))
295
- query = parse_obj_as (DeleteManyParams , request .query )
301
+ query = check (DeleteManyParams , request .query )
296
302
297
303
originals = await self .get_many (query )
298
304
allowed = await asyncio .gather (* (permits (request , f"admin.{ self .name } .delete" ,
0 commit comments