diff --git a/src/api.py b/src/api.py index 5ff8109..dad5342 100644 --- a/src/api.py +++ b/src/api.py @@ -11,6 +11,7 @@ from datamodels import DataModel from constants import DATA_VERSION from routes.stamps import routes as stamp_routes +from routes.documents import routes as doc_routes from routes.lib import dbvar, datamodelsv sys.path.insert(0, os.path.join(os.getcwd())) @@ -74,6 +75,7 @@ async def app_factory(): app.cleanup_ctx.append(attach_db) app.router.add_get('/', test) app.router.add_routes(stamp_routes) + app.router.add_routes(doc_routes) return app diff --git a/src/routes/documents.py b/src/routes/documents.py index f539aea..01bc660 100644 --- a/src/routes/documents.py +++ b/src/routes/documents.py @@ -83,9 +83,9 @@ class Document: conds = [] if document_id is not None: - conds.append(Doc.document_id == document_id) + conds.append(Doc.document_id == int(document_id)) if seal is not None: - conds.append(Doc.seal == seal) + conds.append(Doc.seal == int(seal)) if created_before is not None: cbefore = datetime.fromisoformat(created_before) conds.append(Doc.created_at <= cbefore) @@ -96,9 +96,9 @@ class Document: conds.append(Doc.metadata == metadata) query = data.Document.table.fetch_rows_where(*conds) - results = await query + # results = await query - query = data.Document.table.select_where(*conds) + # query = data.Document.table.select_where(*conds) if stamp_type is not None: query.join('document_stamps', using=('document_id',), join_type=JOINTYPE.LEFT) query.join( @@ -119,7 +119,7 @@ class Document: else: rows = await query - return [cls(app, row) for row in rows] + return [cls(app, row) for row in sorted(rows, key=lambda row:row.created_at)] @classmethod async def create(cls, app: web.Application, **kwargs: Unpack[DocCreateParams]) -> Self: @@ -147,7 +147,7 @@ class Document: return cls(app, row) async def get_stamps(self) -> List[Stamp]: - stamprows = await self.data.DocumentStamp.table.fetch_rows_where(document_id=self.row.document_id) + stamprows = await self.data.DocumentStamp.table.fetch_rows_where(document_id=self.row.document_id).order_by('stamp_id') return [Stamp(self.app, row) for row in stamprows] async def prepare(self) -> DocPayload: @@ -191,6 +191,7 @@ class Document: @routes.view('/documents') +@routes.view('/documents/') class DocumentsView(web.View): async def get(self): request = self.request @@ -229,3 +230,64 @@ class DocumentsView(web.View): document = await Document.create(self.request.app, **params) payload = await document.prepare() return web.json_response(payload) + +@routes.view('/documents/{document_id}') +@routes.view('/documents/{document_id}/') +class DocumentView(web.View): + + async def resolve_document(self): + request = self.request + document_id = request.match_info['document_id'] + document = await Document.fetch_from_id(request.app, int(document_id)) + if document is None: + raise web.HTTPNotFound(text="No document exists with the given ID.") + return document + + async def get(self): + doc = await self.resolve_document() + payload = await doc.prepare() + return web.json_response(payload) + + async def patch(self): + doc = await self.resolve_document() + params = await self.request.json() + + edit_data = {} + for key, value in params.items(): + if key not in edit_fields: + raise web.HTTPBadRequest(text=f"You cannot update field '{key}' of Document!") + edit_data[key] = value + + for key in edit_fields: + if key in self.request: + edit_data.setdefault(key, self.request[key]) + + await doc.edit(**edit_data) + payload = await doc.prepare() + return web.json_response(payload) + + async def delete(self): + doc = await self.resolve_document() + payload = await doc.delete() + return web.json_response(payload) + + +# We have one prefix route, /documents/{document_id}/stamps +@routes.route('*', "/documents/{document_id}{tail:/stamps}") +@routes.route('*', "/documents/{document_id}{tail:/stamps/.*}") +async def document_stamps_route(request: web.Request): + document_id = request.match_info['document_id'] + document = await Document.fetch_from_id(request.app, int(document_id)) + if document is None: + raise web.HTTPNotFound(text="No document exists with the given ID.") + + new_path = request.match_info['tail'] + new_request = request.clone(rel_url=new_path) + new_request['document_id'] = document_id + match_info = await request.app.router.resolve(new_request) + if match_info.handler: + return await match_info.handler(new_request) + else: + raise web.HTTPNotFound() + + diff --git a/src/routes/stamps.py b/src/routes/stamps.py index 84185f0..6f88d7d 100644 --- a/src/routes/stamps.py +++ b/src/routes/stamps.py @@ -76,9 +76,9 @@ class Stamp: query_args = {} if stamp_id is not None: - query_args['stamp_id'] = stamp_id + query_args['stamp_id'] = int(stamp_id) if document_id is not None: - query_args['document_id'] = document_id + query_args['document_id'] = int(document_id) if stamp_type is not None: typerows = await data.StampType.table.fetch_rows_where(stamp_type_name=stamp_type) typeids = [row.stamp_type_id for row in typerows] @@ -86,7 +86,7 @@ class Stamp: return [] query_args['stamp_type'] = typeids results = await data.DocumentStamp.table.fetch_rows_where(**query_args) - return [cls(app, row) for row in results] + return [cls(app, row) for row in sorted(results, key=lambda row:row.stamp_id)] @classmethod async def create( @@ -150,7 +150,7 @@ class Stamp: 'pos_y': 'position_y', 'rotation': 'rotation' } - for editkey, datakey in simple_keys.values(): + for editkey, datakey in simple_keys.items(): if editkey in kwargs: edit_args[datakey] = kwargs[editkey] @@ -165,6 +165,7 @@ class Stamp: @routes.view('/stamps') +@routes.view('/stamps/', name='stamps') class StampsView(web.View): async def get(self): request = self.request @@ -221,6 +222,7 @@ class StampsView(web.View): @routes.view('/stamps/{stamp_id}') +@routes.view('/stamps/{stamp_id}/', name='stamp') class StampView(web.View): async def resolve_stamp(self):