From 255cd80e9b2898ad06863aaf6111715c51ddf886 Mon Sep 17 00:00:00 2001 From: Dhruv Ahuja <83733638+dhruv-ahuja@users.noreply.github.com> Date: Sun, 23 Jun 2024 23:54:19 +0530 Subject: [PATCH 1/6] chore: update core libraries --- requirements.txt | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/requirements.txt b/requirements.txt index eb7052b..ed6cd3c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ anyio==3.7.1 APScheduler==3.10.4 argon2-cffi==23.1.0 argon2-cffi-bindings==21.2.0 -beanie==1.24.0 +beanie==1.26.0 billiard==4.2.0 boto3==1.34.131 boto3-stubs==1.28.85 @@ -21,7 +21,8 @@ cryptography==42.0.4 dnspython==2.6.1 ecdsa==0.18.0 email-validator==2.1.0.post1 -fastapi==0.109.2 +fastapi==0.111.0 +fastapi-cli==0.0.4 gunicorn==22.0.0 h11==0.14.0 hiredis==2.3.2 @@ -30,11 +31,15 @@ httptools==0.6.1 httpx==0.26.0 idna==3.7 iniconfig==2.0.0 +Jinja2==3.1.4 jmespath==1.0.1 joblib==1.4.2 kombu==5.3.4 lazy-model==0.2.0 loguru==0.7.2 +markdown-it-py==3.0.0 +MarkupSafe==2.1.5 +mdurl==0.1.2 memory-profiler==0.61.0 motor==3.3.1 mypy-boto3-cloudformation==1.28.83 @@ -55,13 +60,15 @@ passlib==1.7.4 patsy==0.5.6 pluggy==1.3.0 prompt-toolkit==3.0.41 +psutil==6.0.0 pyasn1==0.5.1 pycparser==2.21 pycurl==7.45.2 -pydantic==2.5.0 +pydantic==2.7.4 pydantic-settings==2.1.0 -pydantic_core==2.14.1 +pydantic_core==2.18.4 pyfakefs==5.3.2 +Pygments==2.18.0 pymongo==4.6.3 pytest==7.4.3 pytest-asyncio==0.21.1 @@ -74,22 +81,26 @@ python-multipart==0.0.9 pytz==2023.3.post1 PyYAML==6.0.1 redis==5.0.1 +rich==13.7.1 rsa==4.9 ruff==0.1.5 s3transfer==0.10.1 scikit-learn==1.5.0 scipy==1.13.1 +shellingham==1.5.4 six==1.16.0 sniffio==1.3.0 -starlette==0.36.3 +starlette==0.37.2 statsmodels==0.14.2 threadpoolctl==3.5.0 toml==0.10.2 +typer==0.12.3 types-awscrt==0.19.10 types-s3transfer==0.7.0 typing_extensions==4.8.0 tzdata==2023.3 tzlocal==5.2 +ujson==5.10.0 urllib3==2.2.2 uvicorn==0.24.0.post1 uvloop==0.19.0 From d3a66597c810edb86524aadf6e02c34ac718aa0c Mon Sep 17 00:00:00 2001 From: Dhruv Ahuja <83733638+dhruv-ahuja@users.noreply.github.com> Date: Sun, 23 Jun 2024 23:54:42 +0530 Subject: [PATCH 2/6] chore: add app title to openapi docs --- src/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.py b/src/main.py index a6a5af5..63b8878 100644 --- a/src/main.py +++ b/src/main.py @@ -21,7 +21,9 @@ newrelic.agent.initialize("./newrelic.ini") -app = FastAPI(lifespan=setup_services, redirect_slashes=False, default_response_class=ORJSONResponse) +app = FastAPI( + lifespan=setup_services, redirect_slashes=False, default_response_class=ORJSONResponse, title="Backend Burger" +) app.include_router(users.router) app.include_router(auth.router) From 0f5a9be9358091ce7824a8c5fda013c577d618b5 Mon Sep 17 00:00:00 2001 From: Dhruv Ahuja <83733638+dhruv-ahuja@users.noreply.github.com> Date: Sun, 23 Jun 2024 23:55:21 +0530 Subject: [PATCH 3/6] chore: set updated date in price prediction script --- src/models/poe.py | 1 - src/scripts/price_prediction.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/models/poe.py b/src/models/poe.py index 486ae3c..0a21eac 100644 --- a/src/models/poe.py +++ b/src/models/poe.py @@ -30,7 +30,6 @@ class Item(DateMetadataDocument): """Item represents a Path of Exile in-game item. Each item belongs to a category. It contains information such as item type and the current, past and predicted pricing, encapsulated in the `ItemPrice` schema.""" - # TODO: ensure type_ field is serialized as 'type' poe_ninja_id: int id_type: ItemIdType | None = None name: str diff --git a/src/scripts/price_prediction.py b/src/scripts/price_prediction.py index 700098b..fa6de7e 100644 --- a/src/scripts/price_prediction.py +++ b/src/scripts/price_prediction.py @@ -83,7 +83,7 @@ async def update_items_data(items: list[Item], iteration_count: int) -> None: pymongo.UpdateOne( {"_id": item.id}, { - "$set": {"price": item_price_json}, + "$set": {"price": item_price_json, "updated_date": dt.datetime.now(dt.UTC)}, }, ) ) From 90e61d01033cd9a3d87d4dea24838f845357c213 Mon Sep 17 00:00:00 2001 From: Dhruv Ahuja <83733638+dhruv-ahuja@users.noreply.github.com> Date: Sun, 23 Jun 2024 23:58:43 +0530 Subject: [PATCH 4/6] chore: replace deprecated datetime.utcnow method where applicable --- src/config/services.py | 2 +- src/services/auth.py | 4 ++-- src/services/users.py | 2 +- src/tests/config/test_utils.py | 2 +- src/utils/auth_utils.py | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/config/services.py b/src/config/services.py index c38fed1..8fb15b1 100644 --- a/src/config/services.py +++ b/src/config/services.py @@ -267,7 +267,7 @@ async def setup_services(app_: FastAPI) -> t.AsyncGenerator[None, t.Any]: scheduler.start() async_scheduler.start() - delete_older_than = dt.datetime.utcnow() - dt.timedelta(days=1) + delete_older_than = dt.datetime.now(dt.UTC) - dt.timedelta(days=1) jobs.schedule_tokens_deletion(delete_older_than, async_scheduler) jobs.schedule_price_prediction_run(async_scheduler) diff --git a/src/services/auth.py b/src/services/auth.py index dde70d3..a7703b3 100644 --- a/src/services/auth.py +++ b/src/services/auth.py @@ -50,7 +50,7 @@ async def save_session_details( """Saves users session details, storing the issued refresh token and its expiration time in the database. Re-uses an existing session record or creates a new one.""" - now = dt.datetime.utcnow() + now = dt.datetime.now(dt.UTC) try: user_record = await users_service.get_user_from_database(user.id) @@ -104,7 +104,7 @@ async def invalidate_refresh_token(user: User, db_session: AgnosticClientSession if user.session is not None: user.session.refresh_token = None user.session.expiration_time = None - user.session.updated_time = dt.datetime.utcnow() + user.session.updated_time = dt.datetime.now(dt.UTC) await user.replace(session=db_session) # type: ignore except Exception as exc: logger.error(f"error invalidating refresh token: {exc}") diff --git a/src/services/users.py b/src/services/users.py index 83553d5..d1f46b2 100644 --- a/src/services/users.py +++ b/src/services/users.py @@ -119,7 +119,7 @@ async def update_user(user_id: PydanticObjectId, user_input: UserUpdateInput) -> user.name = user_input.name user.email = user_input.email - user.updated_time = dt.datetime.utcnow() + user.updated_time = dt.datetime.now(dt.UTC) try: await user.replace() # type: ignore diff --git a/src/tests/config/test_utils.py b/src/tests/config/test_utils.py index adc8f57..7a3f6a7 100644 --- a/src/tests/config/test_utils.py +++ b/src/tests/config/test_utils.py @@ -233,7 +233,7 @@ def sample_job(): scheduler = get_scheduler job_id = "sample_job" - trigger = DateTrigger(run_date=dt.datetime.utcnow()) + trigger = DateTrigger(run_date=dt.datetime.now(dt.UTC)) misfire_grace_time = None job = setup_job(scheduler, sample_job, job_id, trigger, misfire_grace_time) diff --git a/src/utils/auth_utils.py b/src/utils/auth_utils.py index 2f8bbbf..825979d 100644 --- a/src/utils/auth_utils.py +++ b/src/utils/auth_utils.py @@ -22,7 +22,7 @@ def compare_values(value: str, hashed_value: str) -> bool: def create_bearer_token(expiry_time: dt.timedelta, sub: str | None = None) -> Tuple[str, dt.datetime]: """Creates an encoded access or refresh token with the given sub and expiry time.""" - token_expires_in = dt.datetime.utcnow() + expiry_time + token_expires_in = dt.datetime.now(dt.UTC) + expiry_time token_data: dict[str, Any] = {"exp": token_expires_in} if sub is not None: From 6529bbe43f1da3f76fec9d5392a823c0404b1042 Mon Sep 17 00:00:00 2001 From: Dhruv Ahuja <83733638+dhruv-ahuja@users.noreply.github.com> Date: Mon, 24 Jun 2024 00:00:15 +0530 Subject: [PATCH 5/6] chore: use UTC-time when updating time field for documents --- src/models/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/common.py b/src/models/common.py index 7b7d746..d752013 100644 --- a/src/models/common.py +++ b/src/models/common.py @@ -13,4 +13,4 @@ class DateMetadataDocument(Document): @after_event(Update, Replace, SaveChanges, ValidateOnSave) def update_document_time(self) -> None: - self.updated_time = dt.datetime.now() + self.updated_time = dt.datetime.now(dt.UTC) From 4398812ee4fb747ffdc95fd981b577d72277c623 Mon Sep 17 00:00:00 2001 From: Dhruv Ahuja <83733638+dhruv-ahuja@users.noreply.github.com> Date: Mon, 24 Jun 2024 00:17:28 +0530 Subject: [PATCH 6/6] chore: read db data in consistent timezone - set tz aware mode when connecting to db - remove timezone conversion for refresh token expiry date during token refresh flow --- src/config/services.py | 2 +- src/dependencies.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/config/services.py b/src/config/services.py index 8fb15b1..0fcb9e3 100644 --- a/src/config/services.py +++ b/src/config/services.py @@ -289,4 +289,4 @@ async def setup_services(app_: FastAPI) -> t.AsyncGenerator[None, t.Any]: settings = generate_settings_config() # initialize global client object for use across app -db_client = AsyncIOMotorClient(settings.db_url.get_secret_value()) +db_client = AsyncIOMotorClient(settings.db_url.get_secret_value(), tz_aware=True) diff --git a/src/dependencies.py b/src/dependencies.py index 7818dfa..ee0c6c1 100644 --- a/src/dependencies.py +++ b/src/dependencies.py @@ -1,6 +1,5 @@ import datetime as dt import orjson -import pytz from typing import Any, cast from beanie import PydanticObjectId @@ -80,6 +79,7 @@ async def check_refresh_token(refresh_token: str) -> dict[str, Any]: forbidden_error = HTTPException(status.HTTP_401_UNAUTHORIZED) + breakpoint() token_data = check_bearer_token(refresh_token, forbidden_error) user_id = token_data["sub"] token_expiration_time = dt.datetime.fromtimestamp(token_data["exp"], dt.UTC) @@ -97,9 +97,8 @@ async def check_refresh_token(refresh_token: str) -> dict[str, Any]: session_refresh_token = user_session.refresh_token session_expiration_time = cast(dt.datetime, user_session.expiration_time) - session_token_expiration_time = pytz.utc.localize(session_expiration_time) - if session_token_expiration_time < token_expiration_time or session_refresh_token != refresh_token: + if session_expiration_time < token_expiration_time or session_refresh_token != refresh_token: raise forbidden_error return token_data