From 2c80c3120c1c54413e2b12fb15b50c8d4f3541d1 Mon Sep 17 00:00:00 2001 From: dilaraCerenMoral Date: Thu, 28 Dec 2023 19:06:39 +0300 Subject: [PATCH 1/2] Closes #4 --- .gitignore | 1 + endpoints/stories.py | 101 ++++++++++++++++++++++++++++++++++++++++++- requirements.txt | Bin 3444 -> 3488 bytes 3 files changed, 100 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index df4483f..7aef0f7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ __pycache__/ # C extensions *.so +cached_*.json # Distribution / packaging .Python build/ diff --git a/endpoints/stories.py b/endpoints/stories.py index e08c58a..171fb8e 100644 --- a/endpoints/stories.py +++ b/endpoints/stories.py @@ -1,11 +1,15 @@ +import json +import math from typing import List, Optional from fastapi import APIRouter, HTTPException, Query +from fastapi_utils.tasks import repeat_every import settings +import pytz from database import models import logging -from datetime import datetime +from datetime import datetime, timedelta from tortoise.functions import Count, Sum # import Q from tortoise orm: from tortoise.expressions import Q, Subquery @@ -14,7 +18,8 @@ router = APIRouter() - +cached_weekly_program_path = "./cached_program_weekly.json" +logging.getLogger().setLevel(logging.INFO if settings.DEBUG else logging.WARNING) @router.get("/story") async def get_story(storyGlobalId: str): try: @@ -236,3 +241,95 @@ async def get_series( except Exception as e: logging.error(e) return {"isFound": False, "next": None, "page": page, "series": []} + + +@router.get("/program") +async def get_current_week_program(): + # using FileResponse wouldn't help when we switch to a proper cache. So we'll load the json instead: + cached_program = await get_cached_weekly_program() + + if cached_program: + return {"status": "success", "data": cached_program} + else: + return {"status": "error", "message": "Program not available."} + + +async def get_cached_weekly_program(): + try: + with open(cached_weekly_program_path, "r") as file: + cached_program = json.load(file) + logging.info("Received weekly program from cache") + return cached_program + except FileNotFoundError: + logging.info("Received weekly program without cache") + return await build_weekly_program() + except Exception as e: + logging.error(e) + return None + + +async def build_weekly_program(): + try: + # Calculate the start and end date of the current week + today = datetime.now() + start_of_week = today - timedelta(days=today.weekday()) + end_of_week = start_of_week + timedelta(days=6) + + # Query for stories within the current week + current_week_stories = await models.Story.filter( + release_date__gte=start_of_week, + release_date__lte=end_of_week + ).order_by("release_date").prefetch_related('series') + + # Format the response + response_data = { + "week_start_date": start_of_week.strftime("%Y-%m-%d"), + "week_end_date": end_of_week.strftime("%Y-%m-%d"), + "stories": [] + } + for story in current_week_stories: + series_name = story.series.name if story.series else None + series_global_id = story.series.seriesGlobalId if story.series else None + + story_release_date_minute = story.release_date.minute + rounded_release_date = story.release_date + timedelta( + minutes=( + 30 - story_release_date_minute % 30 + ) % 30 + ) if story_release_date_minute != 0 and story_release_date_minute != 30 else story.release_date + + # Check if the story is released + if rounded_release_date <= datetime.now(pytz.utc): + story_global_id = story.storyGlobalId + else: + story_global_id = None + + response_data["stories"].append({ + "idstory": story.idstory, + "title": story.title, + "description": story.description, + "release_date": rounded_release_date.strftime("%Y-%m-%dT%H:%M:00Z"), + # "release_date": story.release_date, + "storyGlobalId": story_global_id, + "series_name": series_name, + "seriesGlobalId": series_global_id + }) + + with open(cached_weekly_program_path, 'w', encoding='utf-8') as f: + json.dump(response_data, f, ensure_ascii=False, default=str) + f.flush() + return response_data + + except Exception as e: + logging.error(e) + return None + # Handle exceptions and log errors + + +@router.on_event("startup") +@repeat_every(seconds=60) # 1 minute +async def task_build_weekly_program() -> None: + now = datetime.now() + if now.minute in [1, 52]: + logging.info("Rebuilding weekly program for minute: {}".format(now.minute)) + await build_weekly_program() diff --git a/requirements.txt b/requirements.txt index 26ec39b8d378ca376c8084adf6862a24535da846..45e87901e8d06fbdfd7d64f2a6249a14ef30d6b0 100644 GIT binary patch delta 52 zcmew&wLp5qC1&+BhD3&9h7urIz>vwH%TNkrXENjf#cYAlfI*MJ2#5_gpJiUo2>@&w B3|IgF delta 12 UcmZ1={Y7fSCFaflm=|#Z04GERt^fc4 From dda5c1025d46c59b37ab6532aa4a0b6cbccc9ac8 Mon Sep 17 00:00:00 2001 From: dilaraCerenMoral Date: Thu, 28 Dec 2023 19:13:49 +0300 Subject: [PATCH 2/2] Fixed wrong minute of hour --- endpoints/stories.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/endpoints/stories.py b/endpoints/stories.py index 171fb8e..b713d95 100644 --- a/endpoints/stories.py +++ b/endpoints/stories.py @@ -330,6 +330,6 @@ async def build_weekly_program(): @repeat_every(seconds=60) # 1 minute async def task_build_weekly_program() -> None: now = datetime.now() - if now.minute in [1, 52]: + if now.minute in [1, 31]: logging.info("Rebuilding weekly program for minute: {}".format(now.minute)) await build_weekly_program()