From 8a24a5e97939d9d43de6e532e7b2cf054ced0242 Mon Sep 17 00:00:00 2001 From: Lucas Jensen Date: Wed, 1 May 2024 10:37:41 -0700 Subject: [PATCH] added logging and reworked Series query --- server/.gitignore | 4 +- server/app/controllers/__init__.py | 2 +- server/app/controllers/base_controller.py | 18 +++++++ server/app/controllers/controller.py | 2 +- server/app/controllers/events.py | 32 +++++------ server/app/controllers/group.py | 2 +- server/app/controllers/logs/.gitkeep | 0 server/app/controllers/musicians.py | 4 +- server/app/controllers/users.py | 4 +- server/app/db/base_queries.py | 4 +- server/app/db/events.py | 65 ++++++++++++++--------- server/app/db/group.py | 4 +- server/pyproject.toml | 2 +- 13 files changed, 89 insertions(+), 54 deletions(-) create mode 100644 server/app/controllers/logs/.gitkeep diff --git a/server/.gitignore b/server/.gitignore index 90f8fbb..f0476d7 100644 --- a/server/.gitignore +++ b/server/.gitignore @@ -173,4 +173,6 @@ poetry.toml # LSP config files pyrightconfig.json -# End of https://www.toptal.com/developers/gitignore/api/python \ No newline at end of file +# End of https://www.toptal.com/developers/gitignore/api/python + +*.log \ No newline at end of file diff --git a/server/app/controllers/__init__.py b/server/app/controllers/__init__.py index 98becfe..e719f08 100644 --- a/server/app/controllers/__init__.py +++ b/server/app/controllers/__init__.py @@ -1,3 +1,3 @@ -from app.controllers.controller import Controller +from .controller import Controller controller = Controller() diff --git a/server/app/controllers/base_controller.py b/server/app/controllers/base_controller.py index 10203ae..81c67f5 100644 --- a/server/app/controllers/base_controller.py +++ b/server/app/controllers/base_controller.py @@ -1,4 +1,10 @@ +import logging +import traceback +from datetime import datetime +from pathlib import Path + from fastapi import HTTPException, UploadFile, status +from icecream import ic from app.db.base_queries import BaseQueries @@ -26,3 +32,15 @@ class BaseController: detail=f"File size {len(image_file)} bytes exceeds maximum of {self.MAX_FILE_SIZE} bytes", ) return image_file + + def log_error(self, e: Exception) -> None: + curr_dir = Path(__file__).parent + log_dir = curr_dir / "logs" + log_dir.mkdir(exist_ok=True) + log_file = f"{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.log" + with open(log_dir / log_file, "w") as f: + f.write(f"{type(e)}") + f.write("\n\n") + f.write(str(e)) + f.write("\n\n") + f.write(traceback.format_exc()) diff --git a/server/app/controllers/controller.py b/server/app/controllers/controller.py index 84c8ca3..6b25c48 100644 --- a/server/app/controllers/controller.py +++ b/server/app/controllers/controller.py @@ -51,7 +51,7 @@ class Controller: return await self.event_controller.get_all_series() async def get_event(self, id: int) -> EventSeries: - return await self.event_controller.get_one_series(id) + return await self.event_controller.get_one_series_by_id(id) async def create_event( self, series: NewEventSeries, token: HTTPAuthorizationCredentials diff --git a/server/app/controllers/events.py b/server/app/controllers/events.py index 28e0854..3548a7c 100644 --- a/server/app/controllers/events.py +++ b/server/app/controllers/events.py @@ -19,34 +19,34 @@ class EventController(BaseController): for event_series_row in data: series_name: str = event_series_row["name"] - event = Event(**event_series_row) if series_name not in all_series: all_series[series_name] = EventSeries(**event_series_row, events=[]) - all_series[series_name].events.append(event) + if event_series_row.get("event_id"): + all_series[series_name].events.append(Event(**event_series_row)) return [series for series in all_series.values()] async def get_all_series(self) -> list[EventSeries]: - data = await self.db.get_all() + series_data = await self.db.select_all_series() + try: - return self._all_series(data) + return self._all_series(series_data) except Exception as e: - ic(e) + self.log_error(e) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Error retrieving event objects: {e}", ) - async def get_one_series(self, id: int) -> EventSeries: - if not (data := await self.db.get_one(id)): + async def get_one_series_by_id(self, series_id: int) -> EventSeries: + if not (data := await self.db.select_one_series_by_id(series_id)): raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Event not found" ) try: - event = EventSeries( - **data[0], events=[Event(**e) for e in data if e.get("event_id")] + return EventSeries( + **data[0], events=[Event(**e) for e in data if e["event_id"]] ) - return event except Exception as e: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, @@ -58,7 +58,7 @@ class EventController(BaseController): inserted_id = await self.db.insert_one_series(series) for new_event in series.events: await self.db.insert_one_event(new_event, inserted_id) - return await self.get_one_series(inserted_id) + return await self.get_one_series_by_id(inserted_id) except IntegrityError as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -66,10 +66,10 @@ class EventController(BaseController): ) async def add_series_poster(self, series_id, poster: UploadFile) -> EventSeries: - series = await self.get_one_series(series_id) + series = await self.get_one_series_by_id(series_id) series.poster_id = await self._upload_poster(poster) await self.db.update_series_poster(series) - return await self.get_one_series(series.series_id) + return await self.get_one_series_by_id(series.series_id) async def _upload_poster(self, poster: UploadFile) -> str: image_file = await self.verify_image(poster) @@ -83,7 +83,7 @@ class EventController(BaseController): ) async def delete_series(self, id: int) -> None: - series = await self.get_one_series(id) + series = await self.get_one_series_by_id(id) await self.db.delete_one_series(series) async def update_series(self, route_id: int, series: EventSeries) -> EventSeries: @@ -93,7 +93,7 @@ class EventController(BaseController): status_code=status.HTTP_400_BAD_REQUEST, detail="ID in URL does not match ID in request body", ) - prev_series = await self.get_one_series(series.series_id) + prev_series = await self.get_one_series_by_id(series.series_id) if series.poster_id != prev_series.poster_id: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -103,4 +103,4 @@ class EventController(BaseController): await self.db.replace_series(series) for event in series.events: await self.db.insert_one_event(event, series.series_id) - return await self.get_one_series(series.series_id) + return await self.get_one_series_by_id(series.series_id) diff --git a/server/app/controllers/group.py b/server/app/controllers/group.py index 73ee9df..264bd24 100644 --- a/server/app/controllers/group.py +++ b/server/app/controllers/group.py @@ -12,7 +12,7 @@ class GroupController(BaseController): self.db: GroupQueries = group_queries async def get_group(self) -> Group: - if (data := await self.db.get_one()) is None: + if (data := await self.db.select_one_series_by_id()) is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Group not found" ) diff --git a/server/app/controllers/logs/.gitkeep b/server/app/controllers/logs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/server/app/controllers/musicians.py b/server/app/controllers/musicians.py index 78f01c0..d8ccd73 100644 --- a/server/app/controllers/musicians.py +++ b/server/app/controllers/musicians.py @@ -14,7 +14,7 @@ class MusicianController(BaseController): self.db: MusicianQueries = musician_queries async def get_musicians(self) -> list[Musician]: - data = await self.db.get_all() + data = await self.db.select_all_series() try: return [Musician(**m) for m in data] except Exception as e: @@ -24,7 +24,7 @@ class MusicianController(BaseController): ) async def get_musician(self, id: int) -> Musician: - if (data := await self.db.get_one(id)) is None: + if (data := await self.db.select_one_series_by_id(id)) is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Musician not found" ) diff --git a/server/app/controllers/users.py b/server/app/controllers/users.py index cea8a8b..ca05e0a 100644 --- a/server/app/controllers/users.py +++ b/server/app/controllers/users.py @@ -14,7 +14,7 @@ class UserController(BaseController): self.db: UserQueries = user_queries async def get_users(self) -> list[User]: - data = await self.db.get_all() + data = await self.db.select_all_series() try: return [User(**e) for e in data] except Exception as e: @@ -24,7 +24,7 @@ class UserController(BaseController): ) async def get_user_by_id(self, id: int) -> User: - if (data := await self.db.get_one(id)) is None: + if (data := await self.db.select_one_series_by_id(id)) is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="User not found" ) diff --git a/server/app/db/base_queries.py b/server/app/db/base_queries.py index 6b44080..971097e 100644 --- a/server/app/db/base_queries.py +++ b/server/app/db/base_queries.py @@ -10,7 +10,7 @@ class BaseQueries: self.table: str = None # type: ignore self.connect_db: Callable = connect_db - async def get_all(self) -> list[dict]: + async def select_all_series(self) -> list[dict]: query = f"SELECT * FROM {self.table}" db = connect_db() cursor = db.cursor(dictionary=True) @@ -20,7 +20,7 @@ class BaseQueries: db.close() return data # type: ignore - async def get_one(self, id: int) -> dict | None: + async def select_one_series_by_id(self, id: int) -> dict | None: query = f"SELECT * FROM {self.table} WHERE id = %s" db = self.connect_db() cursor = db.cursor(dictionary=True) diff --git a/server/app/db/events.py b/server/app/db/events.py index 1c057cf..211a375 100644 --- a/server/app/db/events.py +++ b/server/app/db/events.py @@ -18,15 +18,14 @@ class EventQueries(BaseQueries): super().__init__() self.table = SERIES_TABLE - async def get_one(self, series_id: int) -> list[dict] | None: + async def select_one_series_by_id(self, series_id: int) -> list[dict] | None: query = f""" - SELECT * - FROM {SERIES_TABLE} - INNER JOIN {EVENT_TABLE} - ON {SERIES_TABLE}.series_id = {EVENT_TABLE}.series_id - WHERE {SERIES_TABLE}.series_id = %s + SELECT s.series_id , s.name , s.description , s.poster_id , e.event_id , e.location , e.`time` , e.ticket_url , e.map_url + FROM {SERIES_TABLE} s + LEFT JOIN {EVENT_TABLE} e + ON s.series_id = e.series_id + WHERE s.series_id = %s """ - db = self.connect_db() cursor = db.cursor(dictionary=True) cursor.execute(query, (series_id,)) @@ -35,12 +34,12 @@ class EventQueries(BaseQueries): db.close() return data - async def get_all(self) -> list[dict]: + async def select_all_series(self) -> list[dict]: query = f""" - SELECT * - FROM {SERIES_TABLE} - INNER JOIN {EVENT_TABLE} - ON {SERIES_TABLE}.series_id = {EVENT_TABLE}.series_id + SELECT s.series_id , s.name , s.description , s.poster_id , e.event_id , e.location , e.`time` , e.ticket_url , e.map_url + FROM {SERIES_TABLE} s + LEFT JOIN {EVENT_TABLE} e + ON s.series_id = e.series_id """ db = self.connect_db() @@ -52,7 +51,10 @@ class EventQueries(BaseQueries): return data async def insert_one_series(self, series: NewEventSeries) -> int: - query = f"INSERT INTO {self.table} (name, description) VALUES (%s, %s)" + query = f""" + INSERT INTO {self.table} (name, description) + VALUES (%s, %s) + """ db = self.connect_db() cursor = db.cursor() cursor.execute( @@ -69,7 +71,10 @@ class EventQueries(BaseQueries): return inserted_id async def insert_one_event(self, event: NewEvent, series_id: int) -> int: - query = f"INSERT INTO {EVENT_TABLE} (series_id, location, time, ticket_url, map_url) VALUES (%s, %s, %s, %s, %s)" + query = f""" + INSERT INTO {EVENT_TABLE} (series_id, location, time, ticket_url, map_url) + VALUES (%s, %s, %s, %s, %s) + """ db = self.connect_db() cursor = db.cursor() ticket_url = str(event.ticket_url) if event.ticket_url else None @@ -84,7 +89,10 @@ class EventQueries(BaseQueries): return iserted_id async def delete_events_by_series(self, series: EventSeries) -> None: - query = f"DELETE FROM {EVENT_TABLE} WHERE series_id = %s" + query = f""" + DELETE FROM {EVENT_TABLE} + WHERE series_id = %s + """ db = self.connect_db() cursor = db.cursor() cursor.execute(query, (series.series_id,)) @@ -92,7 +100,10 @@ class EventQueries(BaseQueries): cursor.close() async def delete_one_series(self, series: EventSeries) -> None: - query = f"DELETE FROM {self.table} WHERE series_id = %s" + query = f""" + DELETE FROM {self.table} + WHERE series_id = %s + """ db = self.connect_db() cursor = db.cursor() cursor.execute(query, (series.series_id,)) @@ -100,7 +111,11 @@ class EventQueries(BaseQueries): cursor.close() async def update_series_poster(self, series: EventSeries) -> None: - query = f"UPDATE {self.table} SET poster_id = %s WHERE series_id = %s" + query = f""" + UPDATE {self.table} + SET poster_id = %s + WHERE series_id = %s + """ db = self.connect_db() cursor = db.cursor() cursor.execute(query, (series.poster_id, series.series_id)) @@ -109,10 +124,10 @@ class EventQueries(BaseQueries): async def replace_event(self, event: Event) -> None: query = f""" - UPDATE {EVENT_TABLE} - SET location = %s, time = %s, ticket_url = %s, map_url = %s - WHERE event_id = %s - """ + UPDATE {EVENT_TABLE} + SET location = %s, time = %s, ticket_url = %s, map_url = %s + WHERE event_id = %s + """ db = self.connect_db() cursor = db.cursor() ticket_url = str(event.ticket_url) if event.ticket_url else None @@ -126,10 +141,10 @@ class EventQueries(BaseQueries): async def replace_series(self, series: EventSeries) -> None: query = f""" - UPDATE {self.table} - SET name = %s, description = %s, poster_id = %s - WHERE series_id = %s - """ + UPDATE {self.table} + SET name = %s, description = %s, poster_id = %s + WHERE series_id = %s + """ db = self.connect_db() cursor = db.cursor() cursor.execute( diff --git a/server/app/db/group.py b/server/app/db/group.py index b000e44..f2a43a4 100644 --- a/server/app/db/group.py +++ b/server/app/db/group.py @@ -7,7 +7,7 @@ class GroupQueries(BaseQueries): super().__init__() self.table = GROUP_TABLE - async def get_one(self) -> dict: + async def select_one_series_by_id(self) -> dict: query = f"SELECT * FROM {self.table}" db = self.connect_db() cursor = db.cursor(dictionary=True) @@ -21,7 +21,7 @@ class GroupQueries(BaseQueries): return data - async def get_all(self) -> None: + async def select_all_series(self) -> None: raise NotImplementedError( "get_all method not implemented for GroupQueries. There's only one row in the table." ) diff --git a/server/pyproject.toml b/server/pyproject.toml index 18c4ccd..eadef62 100644 --- a/server/pyproject.toml +++ b/server/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "thegrapefruitsduo" -version = "0.3.1" +version = "0.4.0" package-mode = false description = "FastAPI backend for thegrapefruitsduo.com" authors = ["Lucas Jensen "]