diff --git a/api/v1/node.py b/api/v1/node.py index 64786f6..f37515f 100644 --- a/api/v1/node.py +++ b/api/v1/node.py @@ -72,11 +72,11 @@ async def _get_image_data(tags: dict[str, str], photo_state: PhotoStateDep) -> d @router.get('/node/{node_id}') @configure_cache(timedelta(minutes=1), stale=timedelta(minutes=5)) -async def get_node(node_id: str, aed_state: AEDStateDep, photo_state: PhotoStateDep): +async def get_node(node_id: int, aed_state: AEDStateDep, photo_state: PhotoStateDep): aed = await aed_state.get_aed_by_id(node_id) if aed is None: - raise HTTPException(404, f'Node {node_id!r} not found') + raise HTTPException(404, f'Node {node_id} not found') photo_dict = await _get_image_data(aed.tags, photo_state) diff --git a/api/v1/photos.py b/api/v1/photos.py index 8f0885e..f46f9c6 100644 --- a/api/v1/photos.py +++ b/api/v1/photos.py @@ -90,7 +90,7 @@ async def proxy_wikimedia_commons(path_encoded: str) -> FileResponse: @router.post('/upload') async def upload( request: Request, - node_id: Annotated[str, Form()], + node_id: Annotated[int, Form()], file_license: Annotated[str, Form()], file: Annotated[UploadFile, File()], oauth2_credentials: Annotated[str, Form()], @@ -119,7 +119,7 @@ async def upload( aed = await aed_state.get_aed_by_id(node_id) if aed is None: - raise HTTPException(404, f'Node {node_id!r} not found, perhaps it is not an AED?') + raise HTTPException(404, f'Node {node_id} not found, perhaps it is not an AED?') osm = OpenStreetMap(oauth2_credentials_) osm_user = await osm.get_authorized_user() @@ -129,7 +129,7 @@ async def upload( if osm_user_has_active_block(osm_user): raise HTTPException(403, 'User has an active block on OpenStreetMap') - photo_info = await photo_state.set_photo(node_id, str(osm_user['id']), file) + photo_info = await photo_state.set_photo(node_id, osm_user['id'], file) photo_url = f'{request.base_url}api/v1/photos/view/{photo_info.id}.webp' node_xml = await osm.get_node_xml(node_id) diff --git a/openstreetmap.py b/openstreetmap.py index 75c90da..4416c9f 100644 --- a/openstreetmap.py +++ b/openstreetmap.py @@ -28,7 +28,7 @@ async def get_authorized_user(self) -> dict | None: return r.json()['user'] @retry_exponential(timedelta(seconds=10)) - async def get_node_xml(self, node_id: str) -> dict | None: + async def get_node_xml(self, node_id: int) -> dict | None: r = await self._http.get(f'/node/{node_id}') if r.status_code in (404, 410): diff --git a/states/aed_state.py b/states/aed_state.py index 18fde38..d44ae64 100644 --- a/states/aed_state.py +++ b/states/aed_state.py @@ -138,7 +138,7 @@ def _process_create_or_modify(node: dict) -> AED | str: return node_id def _process_delete(node: dict) -> str: - node_id = str(node['@id']) + node_id = int(node['@id']) return node_id if action['@type'] in ('create', 'modify'): @@ -270,7 +270,7 @@ async def get_aeds_within_geom(self, geometry, group_eps: float | None) -> Seque return tuple(result) - async def get_aed_by_id(self, aed_id: str) -> AED | None: + async def get_aed_by_id(self, aed_id: int) -> AED | None: doc = await AED_COLLECTION.find_one({'id': aed_id}, projection={'_id': False}) return from_dict(AED, doc) if doc else None diff --git a/states/photo_state.py b/states/photo_state.py index 5f21a3f..5f45c1b 100644 --- a/states/photo_state.py +++ b/states/photo_state.py @@ -4,7 +4,6 @@ from typing import Annotated import anyio -import pymongo from dacite import from_dict from fastapi import Depends, UploadFile from PIL import Image, ImageOps @@ -90,36 +89,20 @@ async def get_photo_by_id(self, id: str, *, check_file: bool = True) -> PhotoInf return info - async def get_photo_by_node_id(self, node_id: str) -> PhotoInfo | None: - cursor = PHOTO_COLLECTION.find( - {'node_id': node_id}, - projection={'_id': False}, - ).sort('timestamp', pymongo.DESCENDING) - - async for c in cursor: - info = from_dict(PhotoInfo, c) - - # find newest, non-deleted photo - # NOTE: maybe delete missing photos from database? if at least one successful - if await info.path.is_file(): - return info - - return None - - async def set_photo(self, node_id: str, user_id: str, file: UploadFile) -> PhotoInfo: + async def set_photo(self, node_id: int, user_id: int, file: UploadFile) -> PhotoInfo: info = PhotoInfo( id=secrets.token_urlsafe(16), - node_id=node_id, - user_id=user_id, + node_id=str(node_id), + user_id=str(user_id), timestamp=time(), ) img = Image.open(file.file) - img = await anyio.to_thread.run_sync(ImageOps.exif_transpose, img) - img = await anyio.to_thread.run_sync(_resize_image, img) - img_b = await anyio.to_thread.run_sync(_optimize_image, img) + img = ImageOps.exif_transpose(img) + img = _resize_image(img) + img_bytes = await anyio.to_thread.run_sync(_optimize_image, img) - await info.path.write_bytes(img_b) + await info.path.write_bytes(img_bytes) await PHOTO_COLLECTION.insert_one(as_dict(info)) return info