From ed40267d71477f01a016ae2fbc84f2dce0bfab02 Mon Sep 17 00:00:00 2001 From: Liad Noam Date: Sat, 20 Feb 2021 17:28:43 +0200 Subject: [PATCH 01/14] Added game releases --- app/database/models.py | 13 +++++++++++++ app/main.py | 2 ++ app/templates/partials/calendar/calendar_base.html | 1 + app/templates/partials/calendar/navigation.html | 3 +++ 4 files changed, 19 insertions(+) diff --git a/app/database/models.py b/app/database/models.py index 0e4f4aea..0964ca71 100644 --- a/app/database/models.py +++ b/app/database/models.py @@ -382,6 +382,19 @@ def __repr__(self): ) +class UserSettings(Base): + __tablename__ = "user_settings" + + id = Column(Integer, primary_key=True, index=True) + user_id = Column(Integer, ForeignKey("users.id"), unique=True) + music_on = Column(Boolean, default=False, nullable=False) + music_vol = Column(Integer, default=None) + sfx_on = Column(Boolean, default=False, nullable=False) + sfx_vol = Column(Integer, default=None) + primary_cursor = Column(String, default="default", nullable=False) + secondary_cursor = Column(String, default="default", nullable=False) + video_game_releases = Column(Boolean, default=False) + # insert language data # Credit to adrihanu https://stackoverflow.com/users/9127249/adrihanu diff --git a/app/main.py b/app/main.py index 39e24cdc..da518cbd 100644 --- a/app/main.py +++ b/app/main.py @@ -44,6 +44,7 @@ def create_tables(engine, psql_environment): currency, dayview, email, event, export, four_o_four, friendview, google_connect, invitation, login, logout, profile, register, search, telegram, user, weekview, whatsapp, + game_release_dates_service, ) json_data_loader.load_to_database(next(get_db())) @@ -91,6 +92,7 @@ async def swagger_ui_redirect(): telegram.router, user.router, whatsapp.router, + game_release_dates_service.router, ] for router in routers_to_include: diff --git a/app/templates/partials/calendar/calendar_base.html b/app/templates/partials/calendar/calendar_base.html index 740add68..d09dcf5b 100644 --- a/app/templates/partials/calendar/calendar_base.html +++ b/app/templates/partials/calendar/calendar_base.html @@ -19,6 +19,7 @@ + {% include 'partials/calendar/feature_settings/game_release_modal.html' %} diff --git a/app/templates/partials/calendar/navigation.html b/app/templates/partials/calendar/navigation.html index 84a1303b..0ebbe721 100644 --- a/app/templates/partials/calendar/navigation.html +++ b/app/templates/partials/calendar/navigation.html @@ -18,6 +18,9 @@
+
+ +
From 1714078afa315bb984fe5103d0f1759f24f7b97c Mon Sep 17 00:00:00 2001 From: Liad Noam Date: Sun, 21 Feb 2021 21:53:55 +0200 Subject: [PATCH 02/14] Partial game release form --- app/main.py | 1 + app/routers/game_release_dates_service.py | 24 +++- .../feature_settings/game_release_modal.html | 127 +++++++++++------- .../calendar/feature_settings/games_list.html | 50 +++++++ 4 files changed, 153 insertions(+), 49 deletions(-) create mode 100644 app/templates/partials/calendar/feature_settings/games_list.html diff --git a/app/main.py b/app/main.py index 5b1e5c65..45e2a10a 100644 --- a/app/main.py +++ b/app/main.py @@ -44,6 +44,7 @@ def create_tables(engine, psql_environment): currency, dayview, email, event, export, four_o_four, friendview, google_connect, invitation, joke, login, logout, profile, register, search, telegram, user, weekview, weight, whatsapp, + game_release_dates_service, ) json_data_loader.load_to_database(next(get_db())) diff --git a/app/routers/game_release_dates_service.py b/app/routers/game_release_dates_service.py index c3d4cf66..f9ee16c3 100644 --- a/app/routers/game_release_dates_service.py +++ b/app/routers/game_release_dates_service.py @@ -17,6 +17,7 @@ from app.database.models import Event, User, UserEvent, UserSettings from app.dependencies import get_db, templates from app.internal.utils import get_current_user, create_model +from app.routers.event import create_event router = APIRouter( @@ -37,17 +38,33 @@ def is_user_signed_up_for_game_releases( return False +@router.post("/add-games-to-calendar") +async def add_games_to_calendar( + request: Request, session=Depends(get_db)): + current_user = get_current_user(session) + data = await request.form() + + print(data) + for game in data: + print(game) + game_data = requests.get( + f"https://api.rawg.io/api/games/{game[0]}").json() + + create_event(session, title=game['name'], start=game['release_date'], end=game['release_date'], owner_id=current_user.id) + print(game_data) + + @router.post("/get_releases_by_dates") async def fetch_released_games( request: Request, session=Depends(get_db)): current_user = get_current_user(session) data = await request.form() - + from_date = data['from_date'] to_date = data['to_date'] template = templates.get_template( - 'partials/calendar/feature_settings/game_release_modal.html' + 'partials/calendar/feature_settings/games_list.html' ) games = get_games_data(from_date, to_date) content = template.render(games=games) @@ -84,6 +101,9 @@ def get_games_data(start_date, end_date): for result in current_day_games: current = {} current["name"] = result["name"] + current["slug"] = result["slug"] + # current["id"] = result["id"] + # print(current["id"]) current["platforms"] = [] for platform in result["platforms"]: current["platforms"].append(platform["platform"]["name"]) diff --git a/app/templates/partials/calendar/feature_settings/game_release_modal.html b/app/templates/partials/calendar/feature_settings/game_release_modal.html index aa9d80c8..9e9b6f1b 100644 --- a/app/templates/partials/calendar/feature_settings/game_release_modal.html +++ b/app/templates/partials/calendar/feature_settings/game_release_modal.html @@ -1,52 +1,85 @@ - - diff --git a/tests/test_game_releases.py b/tests/test_game_releases.py index 61f48139..85358ed9 100644 --- a/tests/test_game_releases.py +++ b/tests/test_game_releases.py @@ -32,7 +32,7 @@ def test_get_game_releases_month(client): def test_get_game_releases(client): day_1 = "2020-12-10" day_2 = "2020-12-20" - dates = {"from_date": day_1, "to_date": day_2} + dates = {"from-date": day_1, "to-date": day_2} response = client.post( "/game-releases/get_releases_by_dates", data=dates, @@ -46,7 +46,7 @@ def test_get_games_data_separated_by_days(): day_2 = "2020-12-20" formatted = get_games_data_separated_by_days(day_1, day_2) assert isinstance(formatted, dict) - assert "Cyberpunk 2077" in formatted["10-December-2020"] + assert "platforms" in formatted["10-December-2020"][0].keys() @staticmethod def test_ymd_to_dby(): From 70f63a3bcc7e3e2fe4512c8bc20a46fa38d7173b Mon Sep 17 00:00:00 2001 From: Liad Noam Date: Thu, 25 Feb 2021 21:31:35 +0200 Subject: [PATCH 07/14] Removed is_active=True in game releases, to be added only for users signed up for the service. --- app/routers/calendar_grid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/routers/calendar_grid.py b/app/routers/calendar_grid.py index 7b9bce32..9d65af6f 100644 --- a/app/routers/calendar_grid.py +++ b/app/routers/calendar_grid.py @@ -181,7 +181,7 @@ def create_weeks( num_days: int = len(ndays) weeks = [Week(ndays[i : i + length]) for i in range(0, num_days, length)] - weeks = add_game_events_to_weeks(weeks, is_active=True) + weeks = add_game_events_to_weeks(weeks, is_active=False) return weeks From 6bc12514cf1786d5ef07064cf30f23c4ff34948f Mon Sep 17 00:00:00 2001 From: Liad Noam Date: Thu, 25 Feb 2021 22:39:54 +0200 Subject: [PATCH 08/14] changed request type in one test --- tests/test_game_releases.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/test_game_releases.py b/tests/test_game_releases.py index 85358ed9..11705d76 100644 --- a/tests/test_game_releases.py +++ b/tests/test_game_releases.py @@ -1,24 +1,22 @@ from app.internal.game_releases_utils import ( get_games_data_separated_by_days, - translate_ymd_date_to_dby, translate_dby_date_to_ymd, + translate_ymd_date_to_dby, ) class TestGameReleases: @staticmethod - def test_get_subscribe(client): - response = client.get("/game-releases/subscribe") + def test_subscribe(client): + response = client.post("/game-releases/subscribe") assert response.ok - assert b"Profile" in response.content @staticmethod - def test_get_unsubscribe(client): - response = client.get("/game-releases/subscribe") + def test_unsubscribe(client): + response = client.post("/game-releases/subscribe") assert response.ok - response = client.get("/game-releases/unsubscribe") + response = client.post("/game-releases/unsubscribe") assert response.ok - assert b"Profile" in response.content @staticmethod def test_get_game_releases_month(client): From 0c27fe5e55e4a95fcc2228588da134b6ecf67939 Mon Sep 17 00:00:00 2001 From: Liad Noam Date: Fri, 26 Feb 2021 00:30:29 +0200 Subject: [PATCH 09/14] fixed isort confusing import condition --- app/internal/game_releases_utils.py | 33 ++++++++++++++--------------- app/routers/calendar_grid.py | 4 ++-- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/app/internal/game_releases_utils.py b/app/internal/game_releases_utils.py index ba9d6567..479cdc81 100644 --- a/app/internal/game_releases_utils.py +++ b/app/internal/game_releases_utils.py @@ -1,16 +1,14 @@ from __future__ import annotations -from typing import List, TYPE_CHECKING - -if TYPE_CHECKING: - from app.routers.calendar_grid import Week, Day - -from datetime import datetime - from collections import defaultdict +from datetime import datetime +from typing import TYPE_CHECKING, List import requests +if TYPE_CHECKING: + from app.routers.calendar_grid import Day, Week + def add_game_events_to_weeks( weeks: List["Week"], @@ -32,12 +30,13 @@ def add_game_events_to_weeks( for week in weeks: for day in week.days: if day.set_id() in formatted_games.keys(): - day.dailyevents.append( - ( - f"GR!- {(formatted_games[day.set_id()][0])[:10]}", - (formatted_games[day.set_id()][0]), - ), - ) + for game in formatted_games[day.set_id()]: + day.dailyevents.append( + ( + f"GR!- {(game)[:10]}", + (game), + ), + ) return weeks @@ -51,15 +50,15 @@ def get_games_data_separated_by_days( current_day_games = requests.get( f"{API}?dates={start_date},{end_date}", ) - current_day_games = current_day_games.json()["results"] games_data = defaultdict(list) for result in current_day_games: current = {} current["name"] = result["name"] - current["platforms"] = [] - for platform in result["platforms"]: - current["platforms"].append(platform["platform"]["name"]) + if result["platforms"]: + current["platforms"] = [] + for platform in result["platforms"]: + current["platforms"].append(platform["platform"]["name"]) ybd_release_date = translate_ymd_date_to_dby(result["released"]) games_data[ybd_release_date].append(current) return games_data diff --git a/app/routers/calendar_grid.py b/app/routers/calendar_grid.py index 9d65af6f..159c8e6f 100644 --- a/app/routers/calendar_grid.py +++ b/app/routers/calendar_grid.py @@ -179,9 +179,9 @@ def create_weeks( """Return lists of Weeks objects.""" ndays: List[Day] = list(days) num_days: int = len(ndays) - weeks = [Week(ndays[i : i + length]) for i in range(0, num_days, length)] + _weeks = [Week(ndays[i : i + length]) for i in range(0, num_days, length)] - weeks = add_game_events_to_weeks(weeks, is_active=False) + weeks = add_game_events_to_weeks(_weeks, is_active=False) return weeks From 66f8282503b5b899ce7d19a3cc4501912ec13305 Mon Sep 17 00:00:00 2001 From: Liad Noam Date: Fri, 26 Feb 2021 05:32:32 +0200 Subject: [PATCH 10/14] fixed more CR change requests by Yam --- app/internal/game_releases_utils.py | 19 ++++ app/routers/calendar_grid.py | 3 +- app/routers/game_release_dates_service.py | 99 ++++++------------- app/static/game_releases.css | 7 ++ .../feature_settings/game_release_modal.html | 4 + .../calendar/feature_settings/games_list.html | 6 +- tests/test_game_releases.py | 19 ++-- 7 files changed, 76 insertions(+), 81 deletions(-) create mode 100644 app/static/game_releases.css diff --git a/app/internal/game_releases_utils.py b/app/internal/game_releases_utils.py index 479cdc81..104e7343 100644 --- a/app/internal/game_releases_utils.py +++ b/app/internal/game_releases_utils.py @@ -5,11 +5,30 @@ from typing import TYPE_CHECKING, List import requests +from sqlalchemy.orm import Session + +from app.database.models import UserSettings if TYPE_CHECKING: from app.routers.calendar_grid import Day, Week +def is_user_signed_up_for_game_releases( + session: Session, + current_user_id: int, +) -> bool: + is_signed_up = ( + session.query(UserSettings) + .filter(UserSettings.user_id == current_user_id) + .filter(UserSettings.video_game_releases.is_(True)) + .first() + ) + + if is_signed_up: + return True + return False + + def add_game_events_to_weeks( weeks: List["Week"], is_active: bool = True, diff --git a/app/routers/calendar_grid.py b/app/routers/calendar_grid.py index 159c8e6f..bf5c2bef 100644 --- a/app/routers/calendar_grid.py +++ b/app/routers/calendar_grid.py @@ -181,8 +181,7 @@ def create_weeks( num_days: int = len(ndays) _weeks = [Week(ndays[i : i + length]) for i in range(0, num_days, length)] - weeks = add_game_events_to_weeks(_weeks, is_active=False) - return weeks + return add_game_events_to_weeks(_weeks, is_active=False) def get_month_block(day: Day, n: int = MONTH_BLOCK) -> List[Week]: diff --git a/app/routers/game_release_dates_service.py b/app/routers/game_release_dates_service.py index fef96c7a..374a02db 100644 --- a/app/routers/game_release_dates_service.py +++ b/app/routers/game_release_dates_service.py @@ -1,20 +1,21 @@ import datetime +from typing import Dict, List +import requests from fastapi import APIRouter, Depends, Request from fastapi.responses import RedirectResponse, Response from sqlalchemy.orm import Session from starlette.status import HTTP_302_FOUND -import requests from app.database.models import UserSettings from app.dependencies import get_db, templates +from app.internal.game_releases_utils import ( + is_user_signed_up_for_game_releases, +) from app.internal.security.dependencies import current_user from app.internal.security.schema import CurrentUser from app.internal.utils import create_model -from typing import Dict, List - - router = APIRouter( prefix="/game-releases", tags=["game-releases"], @@ -22,36 +23,6 @@ ) -def is_user_signed_up_for_game_releases( - session: Session, - current_user_id: int, -) -> bool: - is_signed_up = ( - session.query(UserSettings) - .filter(UserSettings.user_id == current_user_id) - .filter(UserSettings.video_game_releases.is_(True)) - .first() - ) - - if is_signed_up: - return True - return False - - -# @router.post("/add-games-to-calendar") -# async def add_games_to_calendar(request: Request, session=Depends(get_db)): -# current_user = get_current_user(session) -# data = await request.form() -# create_event( -# session, -# title=game["name"], -# start=game["release_date"], -# end=game["release_date"], -# owner_id=current_user.id, -# ) -# print(game_data) - - @router.post("/get_releases_by_dates") async def fetch_released_games( request: Request, @@ -70,23 +41,14 @@ async def fetch_released_games( ) -@router.get("/get_game_releases_next_month") +@router.get("/next-month") def get_game_releases_month(request: Request) -> List: today = datetime.datetime.today() delta = datetime.timedelta(days=30) today_str = today.strftime("%Y-%m-%d") in_month_str = (today + delta).strftime("%Y-%m-%d") - games = get_games_data(today_str, in_month_str) - - return games - - -# @router.post -# TODO -# add game to calendar -# @router.post -# remove game from calendar + return get_games_data(today_str, in_month_str) def get_games_data(start_date: datetime, end_date: datetime) -> List[Dict]: @@ -98,10 +60,12 @@ def get_games_data(start_date: datetime, end_date: datetime) -> List[Dict]: current_day_games = current_day_games.json()["results"] games_data = [] for result in current_day_games: - current = {} - current["name"] = result["name"] - current["slug"] = result["slug"] - current["platforms"] = [] + current = { + "name": result["name"], + "slug": result["slug"], + "platforms": [], + } + for platform in result["platforms"]: current["platforms"].append(platform["platform"]["name"]) current["release_date"] = result["released"] @@ -118,24 +82,22 @@ async def subscribe_game_release_service( ) -> Response: if is_user_signed_up_for_game_releases(session, user.user_id): return RedirectResponse("/profile", status_code=HTTP_302_FOUND) + games_setting_true_for_model = { + "user_id": user.user_id, + "video_game_releases": True, + } + current_user_settings = session.query(UserSettings).filter( + UserSettings.user_id == user.user_id, + ) + if current_user_settings: + # TODO: + # If all users are created with a UserSettings entry - + # unnecessary check + current_user_settings.update(games_setting_true_for_model) + session.commit() else: - games_setting_true = {UserSettings.video_game_releases: True} - games_setting_true_for_model = { - "user_id": user.user_id, - "video_game_releases": True, - } - current_user_settings = session.query(UserSettings).filter( - UserSettings.user_id == user.user_id, - ) - if current_user_settings: - # TODO: - # If all users are created with a UserSettings entry - - # unnecessary check - current_user_settings.update(games_setting_true) - session.commit() - else: - create_model(session, UserSettings, **games_setting_true_for_model) - return RedirectResponse("/profile", status_code=HTTP_302_FOUND) + create_model(session, UserSettings, **games_setting_true_for_model) + return RedirectResponse("/profile", status_code=HTTP_302_FOUND) @router.post("/unsubscribe") @@ -149,9 +111,8 @@ async def unsubscribe_game_release_service( if not is_user_signed_up_for_game_releases(session, current_user_id): return RedirectResponse("/profile", status_code=HTTP_302_FOUND) else: - games_setting_false = {UserSettings.video_game_releases: False} games_setting_false_for_model = { - "user_id": current_user_id, + "user_id": str(current_user_id), "video_game_releases": False, } current_user_settings = session.query(UserSettings).filter( @@ -161,7 +122,7 @@ async def unsubscribe_game_release_service( # TODO: # If all users are created with a UserSettings entry - # unnecessary check - current_user_settings.update(games_setting_false) + current_user_settings.update(games_setting_false_for_model) session.commit() else: create_model( diff --git a/app/static/game_releases.css b/app/static/game_releases.css new file mode 100644 index 00000000..ee6bc0e9 --- /dev/null +++ b/app/static/game_releases.css @@ -0,0 +1,7 @@ +.game-title { + font-size: 1.1em; + font-weight: bolder; +} +.secondary-title { + font-weight: bold; +} diff --git a/app/templates/partials/calendar/feature_settings/game_release_modal.html b/app/templates/partials/calendar/feature_settings/game_release_modal.html index 849d9c73..9a9b7083 100644 --- a/app/templates/partials/calendar/feature_settings/game_release_modal.html +++ b/app/templates/partials/calendar/feature_settings/game_release_modal.html @@ -1,4 +1,6 @@ + + -
Platforms
+
"{{ game['name'] }}"
+
Platforms
{% for platform in game['platforms']%}
{{ platform }}
{% endfor %} -
Release date
+
Release date
{{ game['release_date'] }}

{% endfor %} diff --git a/tests/test_game_releases.py b/tests/test_game_releases.py index 11705d76..83d69ddf 100644 --- a/tests/test_game_releases.py +++ b/tests/test_game_releases.py @@ -3,26 +3,31 @@ translate_dby_date_to_ymd, translate_ymd_date_to_dby, ) +from app.routers.game_release_dates_service import router class TestGameReleases: @staticmethod def test_subscribe(client): - response = client.post("/game-releases/subscribe") + response = client.post( + router.url_path_for("subscribe_game_release_service"), + ) assert response.ok @staticmethod def test_unsubscribe(client): - response = client.post("/game-releases/subscribe") + response = client.post( + router.url_path_for("subscribe_game_release_service"), + ) assert response.ok - response = client.post("/game-releases/unsubscribe") + response = client.post( + router.url_path_for("unsubscribe_game_release_service"), + ) assert response.ok @staticmethod def test_get_game_releases_month(client): - response = client.get( - "/game-releases/get_game_releases_next_month", - ) + response = client.get(router.url_path_for("get_game_releases_month")) assert response.ok assert b"Prince" in response.content @@ -32,7 +37,7 @@ def test_get_game_releases(client): day_2 = "2020-12-20" dates = {"from-date": day_1, "to-date": day_2} response = client.post( - "/game-releases/get_releases_by_dates", + router.url_path_for("fetch_released_games"), data=dates, ) assert response.ok From 28b61ba94da54d4f4489c2a8a8a9f0cc7527fc92 Mon Sep 17 00:00:00 2001 From: Liad Noam Date: Fri, 26 Feb 2021 19:01:53 +0200 Subject: [PATCH 11/14] fixed CR change requests --- app/internal/game_releases_utils.py | 41 ++++++++++++++--------- app/routers/game_release_dates_service.py | 21 +++++++++--- app/static/js/game_releases.js | 32 +++++++++--------- tests/test_game_releases.py | 16 +++++---- 4 files changed, 70 insertions(+), 40 deletions(-) diff --git a/app/internal/game_releases_utils.py b/app/internal/game_releases_utils.py index 104e7343..59abc755 100644 --- a/app/internal/game_releases_utils.py +++ b/app/internal/game_releases_utils.py @@ -2,7 +2,7 @@ from collections import defaultdict from datetime import datetime -from typing import TYPE_CHECKING, List +from typing import TYPE_CHECKING, DefaultDict, Dict, List import requests from sqlalchemy.orm import Session @@ -46,6 +46,14 @@ def add_game_events_to_weeks( end_date=last_day_str.strftime("%Y-%m-%d"), ) formatted_games = get_formatted_games_in_days(games_by_dates) + + return insert_formatted_games_to_weeks(weeks, formatted_games) + + +def insert_formatted_games_to_weeks( + weeks: List["Week"], + formatted_games: DefaultDict[List[str]], +) -> List["Week"]: for week in weeks: for day in week.days: if day.set_id() in formatted_games.keys(): @@ -56,14 +64,13 @@ def add_game_events_to_weeks( (game), ), ) - return weeks def get_games_data_separated_by_days( start_date: datetime, end_date: datetime, -) -> defaultdict[List]: +) -> DefaultDict[List[Dict]]: API = "https://api.rawg.io/api/games" current_day_games = requests.get( @@ -72,10 +79,11 @@ def get_games_data_separated_by_days( current_day_games = current_day_games.json()["results"] games_data = defaultdict(list) for result in current_day_games: - current = {} - current["name"] = result["name"] + current = { + "name": result["name"], + "platforms": [], + } if result["platforms"]: - current["platforms"] = [] for platform in result["platforms"]: current["platforms"].append(platform["platform"]["name"]) ybd_release_date = translate_ymd_date_to_dby(result["released"]) @@ -86,21 +94,24 @@ def get_games_data_separated_by_days( def get_formatted_games_in_days( separated_games_dict: defaultdict[List], with_platforms: bool = False, -) -> defaultdict[List]: +) -> DefaultDict[List[str]]: formatted_games = defaultdict(list) for date, game_data in separated_games_dict.items(): - for game in game_data: - formatted_game_str = "" - formatted_game_str += game["name"] - if with_platforms: - formatted_game_str += "-Platforms-
" - for platform in game["platforms"]: - formatted_game_str += f"{platform}," - formatted_games[date].append(formatted_game_str) + formatted_game_str = format_single_game(game_data, with_platforms) + formatted_games[date].append(formatted_game_str) return formatted_games +def format_single_game(raw_game, with_platforms=False): + formatted_game_str = "" + formatted_game_str += raw_game["name"] + if with_platforms: + formatted_game_str += "-Platforms-
" + for platform in raw_game["platforms"]: + formatted_game_str += f"{platform}," + + def translate_ymd_date_to_dby(ymd_str: str) -> str: ymd_time = datetime.strptime(ymd_str, "%Y-%m-%d") return ymd_time.strftime("%d-%B-%Y") diff --git a/app/routers/game_release_dates_service.py b/app/routers/game_release_dates_service.py index 374a02db..1db2c942 100644 --- a/app/routers/game_release_dates_service.py +++ b/app/routers/game_release_dates_service.py @@ -15,6 +15,7 @@ from app.internal.security.dependencies import current_user from app.internal.security.schema import CurrentUser from app.internal.utils import create_model +from app.routers.profile import router as profile_router router = APIRouter( prefix="/game-releases", @@ -81,7 +82,10 @@ async def subscribe_game_release_service( user: CurrentUser = Depends(current_user), ) -> Response: if is_user_signed_up_for_game_releases(session, user.user_id): - return RedirectResponse("/profile", status_code=HTTP_302_FOUND) + return RedirectResponse( + profile_router.url_path_for("profile"), + status_code=HTTP_302_FOUND, + ) games_setting_true_for_model = { "user_id": user.user_id, "video_game_releases": True, @@ -97,7 +101,10 @@ async def subscribe_game_release_service( session.commit() else: create_model(session, UserSettings, **games_setting_true_for_model) - return RedirectResponse("/profile", status_code=HTTP_302_FOUND) + return RedirectResponse( + profile_router.url_path_for("profile"), + status_code=HTTP_302_FOUND, + ) @router.post("/unsubscribe") @@ -109,7 +116,10 @@ async def unsubscribe_game_release_service( current_user_id = user.user_id if not is_user_signed_up_for_game_releases(session, current_user_id): - return RedirectResponse("/profile", status_code=HTTP_302_FOUND) + return RedirectResponse( + profile_router.url_path_for("profile"), + status_code=HTTP_302_FOUND, + ) else: games_setting_false_for_model = { "user_id": str(current_user_id), @@ -128,4 +138,7 @@ async def unsubscribe_game_release_service( create_model( session, UserSettings, **games_setting_false_for_model ) - return RedirectResponse("/profile", status_code=HTTP_302_FOUND) + return RedirectResponse( + profile_router.url_path_for("profile"), + status_code=HTTP_302_FOUND, + ) diff --git a/app/static/js/game_releases.js b/app/static/js/game_releases.js index 3845de2e..a1130ac0 100644 --- a/app/static/js/game_releases.js +++ b/app/static/js/game_releases.js @@ -1,17 +1,19 @@ -get_games_btn = document.getElementById("get-games"); -get_games_btn.addEventListener("click", function (e) { - let formData = new FormData(); - formData.append("from-date", document.getElementById("from-date").value); - formData.append("to-date", document.getElementById("to-date").value); - let clickedElem = e.target.id; - fetch("/game-releases/get_releases_by_dates", { - method: "post", - body: formData, - }) - .then(function (response) { - return response.text(); +document.addEventListener("DOMContentLoaded", () => { + get_games_btn = document.getElementById("get-games"); + get_games_btn.addEventListener("click", function (e) { + const formData = new FormData(); + formData.append("from-date", document.getElementById("from-date").value); + formData.append("to-date", document.getElementById("to-date").value); + + fetch("/game-releases/get_releases_by_dates", { + method: "post", + body: formData, }) - .then(function (body) { - document.querySelector("#content-div").innerHTML = body; - }); + .then(function (response) { + return response.text(); + }) + .then(function (body) { + document.querySelector("#content-div").innerHTML = body; + }); + }); }); diff --git a/tests/test_game_releases.py b/tests/test_game_releases.py index 83d69ddf..160e0540 100644 --- a/tests/test_game_releases.py +++ b/tests/test_game_releases.py @@ -3,31 +3,35 @@ translate_dby_date_to_ymd, translate_ymd_date_to_dby, ) -from app.routers.game_release_dates_service import router +from app.routers.game_release_dates_service import game_release_router class TestGameReleases: @staticmethod def test_subscribe(client): response = client.post( - router.url_path_for("subscribe_game_release_service"), + game_release_router.url_path_for("subscribe_game_release_service"), ) assert response.ok @staticmethod def test_unsubscribe(client): response = client.post( - router.url_path_for("subscribe_game_release_service"), + game_release_router.url_path_for("subscribe_game_release_service"), ) assert response.ok response = client.post( - router.url_path_for("unsubscribe_game_release_service"), + game_release_router.url_path_for( + "unsubscribe_game_release_service", + ), ) assert response.ok @staticmethod def test_get_game_releases_month(client): - response = client.get(router.url_path_for("get_game_releases_month")) + response = client.get( + game_release_router.url_path_for("get_game_releases_month"), + ) assert response.ok assert b"Prince" in response.content @@ -37,7 +41,7 @@ def test_get_game_releases(client): day_2 = "2020-12-20" dates = {"from-date": day_1, "to-date": day_2} response = client.post( - router.url_path_for("fetch_released_games"), + game_release_router.url_path_for("fetch_released_games"), data=dates, ) assert response.ok From 7144971d05e6b6c9ae2f95a1635f105ffab0133c Mon Sep 17 00:00:00 2001 From: Liad Noam Date: Fri, 26 Feb 2021 23:02:40 +0200 Subject: [PATCH 12/14] fixed CR change requests --- tests/test_game_releases.py | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/tests/test_game_releases.py b/tests/test_game_releases.py index fbf11201..70b43523 100644 --- a/tests/test_game_releases.py +++ b/tests/test_game_releases.py @@ -6,18 +6,36 @@ from app.routers.game_release_dates_service import ( router as game_release_router, ) +from tests.test_login import test_login_successfull + +REGISTER_DETAIL = { + "username": "correct_user", + "full_name": "full_name", + "password": "correct_password", + "confirm_password": "correct_password", + "email": "example@email.com", + "description": "", +} class TestGameReleases: @staticmethod - def test_subscribe(client): + def test_subscribe_not_logged(client): response = client.post( game_release_router.url_path_for("subscribe_game_release_service"), ) assert response.ok @staticmethod - def test_unsubscribe(client): + def test_subscribe_logged(session, security_test_client): + test_login_successfull(session, security_test_client) + response = security_test_client.post( + game_release_router.url_path_for("subscribe_game_release_service"), + ) + assert response.ok + + @staticmethod + def test_unsubscribe_not_logged(client): response = client.post( game_release_router.url_path_for("subscribe_game_release_service"), ) @@ -29,6 +47,21 @@ def test_unsubscribe(client): ) assert response.ok + @staticmethod + def test_unsubscribe_logged(session, security_test_client): + test_login_successfull(session, security_test_client) + + response = security_test_client.post( + game_release_router.url_path_for("subscribe_game_release_service"), + ) + assert response.ok + response = security_test_client.post( + game_release_router.url_path_for( + "unsubscribe_game_release_service", + ), + ) + assert response.ok + @staticmethod def test_get_game_releases_month(client): response = client.get( From 7a0af20993272091ea830ecaa2970628a3e63961 Mon Sep 17 00:00:00 2001 From: Liad Noam Date: Tue, 30 Mar 2021 03:06:56 +0300 Subject: [PATCH 13/14] Fixed calendar grid test with game releases, added cached API call and changed requests to httpx --- app/config.py.example | 1 + app/internal/game_releases_utils.py | 83 +++++++++++++++++++++-------- app/routers/calendar_grid.py | 2 +- tests/test_calendar_grid.py | 8 ++- tests/test_game_releases.py | 41 ++++++++++++-- 5 files changed, 106 insertions(+), 29 deletions(-) diff --git a/app/config.py.example b/app/config.py.example index d296d02e..628c1c23 100644 --- a/app/config.py.example +++ b/app/config.py.example @@ -40,6 +40,7 @@ WEBSITE_LANGUAGE = "en" # Get a free API KEY for Astronomy feature @ www.weatherapi.com/signup.aspx ASTRONOMY_API_KEY = os.getenv('ASTRONOMY_API_KEY') WEATHER_API_KEY = os.getenv('WEATHER_API_KEY') +RAWG_API_KEY = os.getenv("RAWG_API_KEY") # https://developers.google.com/calendar/quickstart/python - # follow instracions and make an env variable with the path to the file. diff --git a/app/internal/game_releases_utils.py b/app/internal/game_releases_utils.py index 59abc755..93ea7da8 100644 --- a/app/internal/game_releases_utils.py +++ b/app/internal/game_releases_utils.py @@ -2,11 +2,14 @@ from collections import defaultdict from datetime import datetime -from typing import TYPE_CHECKING, DefaultDict, Dict, List +from functools import lru_cache +from typing import TYPE_CHECKING, Any, DefaultDict, Dict, List -import requests +import httpx +from loguru import logger from sqlalchemy.orm import Session +from app import config from app.database.models import UserSettings if TYPE_CHECKING: @@ -17,16 +20,14 @@ def is_user_signed_up_for_game_releases( session: Session, current_user_id: int, ) -> bool: - is_signed_up = ( + is_signed_up = bool( session.query(UserSettings) .filter(UserSettings.user_id == current_user_id) .filter(UserSettings.video_game_releases.is_(True)) - .first() + .first(), ) - if is_signed_up: - return True - return False + return is_signed_up def add_game_events_to_weeks( @@ -41,11 +42,20 @@ def add_game_events_to_weeks( last_day: Day = last_week.days[-1] first_day_str = datetime.strptime(first_day.set_id(), "%d-%B-%Y") last_day_str = datetime.strptime(last_day.set_id(), "%d-%B-%Y") - games_by_dates = get_games_data_separated_by_days( + + output = get_games_data_by_dates_from_api( start_date=first_day_str.strftime("%Y-%m-%d"), end_date=last_day_str.strftime("%Y-%m-%d"), ) - formatted_games = get_formatted_games_in_days(games_by_dates) + if not output["success"]: + logger.exception("Unsuccessful RAWG API call") + return weeks + games_by_dates = output["results"] + + unformatted_games_by_dates = get_games_data_separated_by_dates( + games_by_dates, + ) + formatted_games = get_formatted_games_in_days(unformatted_games_by_dates) return insert_formatted_games_to_weeks(weeks, formatted_games) @@ -67,18 +77,47 @@ def insert_formatted_games_to_weeks( return weeks -def get_games_data_separated_by_days( - start_date: datetime, - end_date: datetime, -) -> DefaultDict[List[Dict]]: +@lru_cache(maxsize=128) +def get_games_data_by_dates_from_api( + start_date: str, + end_date: str, +) -> Dict[str, Any]: API = "https://api.rawg.io/api/games" - - current_day_games = requests.get( - f"{API}?dates={start_date},{end_date}", - ) - current_day_games = current_day_games.json()["results"] + NO_API_RESPONSE = "The RAWG server did not response" + input_query_string = { + "dates": f"{start_date},{end_date}", + "key": config.RAWG_API_KEY, + } + + output: Dict[str, Any] = {} + try: + response = httpx.get( + API, + params=input_query_string, + ) + except httpx.HTTPError: + output["success"] = False + output["error"] = NO_API_RESPONSE + return output + + if response.status_code != httpx.codes.OK: + output["success"] = False + output["error"] = NO_API_RESPONSE + return output + + output["success"] = True + try: + output.update(response.json()) + return output + except KeyError: + output["success"] = False + output["error"] = response.json()["error"]["message"] + return output + + +def get_games_data_separated_by_dates(api_data): games_data = defaultdict(list) - for result in current_day_games: + for result in api_data: current = { "name": result["name"], "platforms": [], @@ -98,8 +137,9 @@ def get_formatted_games_in_days( formatted_games = defaultdict(list) for date, game_data in separated_games_dict.items(): - formatted_game_str = format_single_game(game_data, with_platforms) - formatted_games[date].append(formatted_game_str) + for game in game_data: + formatted_game_str = format_single_game(game, with_platforms) + formatted_games[date].append(formatted_game_str) return formatted_games @@ -110,6 +150,7 @@ def format_single_game(raw_game, with_platforms=False): formatted_game_str += "-Platforms-
" for platform in raw_game["platforms"]: formatted_game_str += f"{platform}," + return formatted_game_str def translate_ymd_date_to_dby(ymd_str: str) -> str: diff --git a/app/routers/calendar_grid.py b/app/routers/calendar_grid.py index b7d50df1..e43ad04b 100644 --- a/app/routers/calendar_grid.py +++ b/app/routers/calendar_grid.py @@ -194,7 +194,7 @@ def create_weeks( num_days: int = len(ndays) _weeks = [Week(ndays[i : i + length]) for i in range(0, num_days, length)] - return add_game_events_to_weeks(_weeks, is_active=False) + return add_game_events_to_weeks(_weeks, is_active=True) def get_month_block(day: Day, n: int = MONTH_BLOCK) -> List[Week]: diff --git a/tests/test_calendar_grid.py b/tests/test_calendar_grid.py index e5442b02..cf1353a3 100644 --- a/tests/test_calendar_grid.py +++ b/tests/test_calendar_grid.py @@ -80,15 +80,19 @@ def test_create_weeks(): @staticmethod def test_get_month_block(Calendar): + dates_iterator = Calendar.itermonthdates(1988, 5) month_weeks = cg.create_weeks( - Calendar.itermonthdates(1988, 5), + (cg.Day(date) for date in dates_iterator), WEEK_DAYS, ) get_block = cg.get_month_block(cg.Day(DATE), n=len(month_weeks)) for i in range(len(month_weeks)): for j in range(cg.Week.WEEK_DAYS): - assert get_block[i].days[j].date == month_weeks[i].days[j] + assert ( + get_block[i].days[j].set_id() + == month_weeks[i].days[j].set_id() + ) @staticmethod def test_get_user_local_time(): diff --git a/tests/test_game_releases.py b/tests/test_game_releases.py index 70b43523..b2ddf8e2 100644 --- a/tests/test_game_releases.py +++ b/tests/test_game_releases.py @@ -1,5 +1,9 @@ +from collections import defaultdict + from app.internal.game_releases_utils import ( - get_games_data_separated_by_days, + get_formatted_games_in_days, + get_games_data_by_dates_from_api, + get_games_data_separated_by_dates, translate_dby_date_to_ymd, translate_ymd_date_to_dby, ) @@ -68,7 +72,7 @@ def test_get_game_releases_month(client): game_release_router.url_path_for("get_game_releases_month"), ) assert response.ok - assert b"Prince" in response.content + assert b"name" in response.content @staticmethod def test_get_game_releases(client): @@ -86,9 +90,24 @@ def test_get_game_releases(client): def test_get_games_data_separated_by_days(): day_1 = "2020-12-10" day_2 = "2020-12-20" - formatted = get_games_data_separated_by_days(day_1, day_2) - assert isinstance(formatted, dict) - assert "platforms" in formatted["10-December-2020"][0].keys() + output = get_games_data_by_dates_from_api( + start_date=day_1, + end_date=day_2, + ) + games_by_dates = output["results"] + unformatted_games_by_dates = get_games_data_separated_by_dates( + games_by_dates, + ) + formatted_games = get_formatted_games_in_days( + unformatted_games_by_dates, + ) + + assert isinstance(unformatted_games_by_dates, defaultdict) + assert isinstance(formatted_games, defaultdict) + assert ( + "platforms" + in unformatted_games_by_dates["10-December-2020"][0].keys() + ) @staticmethod def test_ymd_to_dby(): @@ -99,3 +118,15 @@ def test_ymd_to_dby(): def test_dby_to_ymd(): dby_date = "12-December-2020" assert translate_dby_date_to_ymd(dby_date) == "2020-12-12" + + @staticmethod + def test_get_game_releases_async(client): + day_1 = "2020-12-10" + day_2 = "2020-12-20" + dates = {"from-date": day_1, "to-date": day_2} + response = client.post( + game_release_router.url_path_for("fetch_released_games"), + data=dates, + ) + assert response.ok + assert b"Xbox" in response.content From 0351e3554111219eebe1e63bfa84731122d7a79a Mon Sep 17 00:00:00 2001 From: Liad Noam Date: Tue, 30 Mar 2021 03:06:56 +0300 Subject: [PATCH 14/14] Fixed calendar grid test with game releases, added cached API call and changed requests to httpx --- app/config.py.example | 1 + app/internal/game_releases_utils.py | 89 +++++++++++++++++++++-------- app/routers/calendar_grid.py | 2 +- tests/test_calendar_grid.py | 8 ++- tests/test_game_releases.py | 41 +++++++++++-- 5 files changed, 110 insertions(+), 31 deletions(-) diff --git a/app/config.py.example b/app/config.py.example index d296d02e..628c1c23 100644 --- a/app/config.py.example +++ b/app/config.py.example @@ -40,6 +40,7 @@ WEBSITE_LANGUAGE = "en" # Get a free API KEY for Astronomy feature @ www.weatherapi.com/signup.aspx ASTRONOMY_API_KEY = os.getenv('ASTRONOMY_API_KEY') WEATHER_API_KEY = os.getenv('WEATHER_API_KEY') +RAWG_API_KEY = os.getenv("RAWG_API_KEY") # https://developers.google.com/calendar/quickstart/python - # follow instracions and make an env variable with the path to the file. diff --git a/app/internal/game_releases_utils.py b/app/internal/game_releases_utils.py index 59abc755..c06b645b 100644 --- a/app/internal/game_releases_utils.py +++ b/app/internal/game_releases_utils.py @@ -2,11 +2,14 @@ from collections import defaultdict from datetime import datetime -from typing import TYPE_CHECKING, DefaultDict, Dict, List +from functools import lru_cache +from typing import TYPE_CHECKING, Any, DefaultDict, Dict, List -import requests +import httpx +from loguru import logger from sqlalchemy.orm import Session +from app import config from app.database.models import UserSettings if TYPE_CHECKING: @@ -17,16 +20,14 @@ def is_user_signed_up_for_game_releases( session: Session, current_user_id: int, ) -> bool: - is_signed_up = ( + is_signed_up = bool( session.query(UserSettings) .filter(UserSettings.user_id == current_user_id) .filter(UserSettings.video_game_releases.is_(True)) - .first() + .first(), ) - if is_signed_up: - return True - return False + return is_signed_up def add_game_events_to_weeks( @@ -41,11 +42,20 @@ def add_game_events_to_weeks( last_day: Day = last_week.days[-1] first_day_str = datetime.strptime(first_day.set_id(), "%d-%B-%Y") last_day_str = datetime.strptime(last_day.set_id(), "%d-%B-%Y") - games_by_dates = get_games_data_separated_by_days( + + output = get_games_data_by_dates_from_api( start_date=first_day_str.strftime("%Y-%m-%d"), end_date=last_day_str.strftime("%Y-%m-%d"), ) - formatted_games = get_formatted_games_in_days(games_by_dates) + if not output["success"]: + logger.exception("Unsuccessful RAWG API call") + return weeks + games_by_dates = output["results"] + + unformatted_games_by_dates = get_games_data_separated_by_dates( + games_by_dates, + ) + formatted_games = get_formatted_games_in_days(unformatted_games_by_dates) return insert_formatted_games_to_weeks(weeks, formatted_games) @@ -67,18 +77,49 @@ def insert_formatted_games_to_weeks( return weeks -def get_games_data_separated_by_days( - start_date: datetime, - end_date: datetime, -) -> DefaultDict[List[Dict]]: +@lru_cache(maxsize=128) +def get_games_data_by_dates_from_api( + start_date: str, + end_date: str, +) -> Dict[str, Any]: API = "https://api.rawg.io/api/games" - - current_day_games = requests.get( - f"{API}?dates={start_date},{end_date}", - ) - current_day_games = current_day_games.json()["results"] + NO_API_RESPONSE = "The RAWG server did not response" + input_query_string = { + "dates": f"{start_date},{end_date}", + "key": config.RAWG_API_KEY, + } + + output: Dict[str, Any] = {} + try: + response = httpx.get( + API, + params=input_query_string, + ) + except httpx.HTTPError: + output["success"] = False + output["error"] = NO_API_RESPONSE + return output + + if response.status_code != httpx.codes.OK: + output["success"] = False + output["error"] = NO_API_RESPONSE + return output + + output["success"] = True + try: + output.update(response.json()) + return output + except KeyError: + output["success"] = False + output["error"] = response.json()["error"]["message"] + return output + + +def get_games_data_separated_by_dates( + api_data: Dict[str, Any], +) -> DefaultDict[List]: games_data = defaultdict(list) - for result in current_day_games: + for result in api_data: current = { "name": result["name"], "platforms": [], @@ -92,24 +133,26 @@ def get_games_data_separated_by_days( def get_formatted_games_in_days( - separated_games_dict: defaultdict[List], + separated_games_dict: DefaultDict[List], with_platforms: bool = False, ) -> DefaultDict[List[str]]: formatted_games = defaultdict(list) for date, game_data in separated_games_dict.items(): - formatted_game_str = format_single_game(game_data, with_platforms) - formatted_games[date].append(formatted_game_str) + for game in game_data: + formatted_game_str = format_single_game(game, with_platforms) + formatted_games[date].append(formatted_game_str) return formatted_games -def format_single_game(raw_game, with_platforms=False): +def format_single_game(raw_game: Dict, with_platforms: bool = False) -> str: formatted_game_str = "" formatted_game_str += raw_game["name"] if with_platforms: formatted_game_str += "-Platforms-
" for platform in raw_game["platforms"]: formatted_game_str += f"{platform}," + return formatted_game_str def translate_ymd_date_to_dby(ymd_str: str) -> str: diff --git a/app/routers/calendar_grid.py b/app/routers/calendar_grid.py index b7d50df1..e43ad04b 100644 --- a/app/routers/calendar_grid.py +++ b/app/routers/calendar_grid.py @@ -194,7 +194,7 @@ def create_weeks( num_days: int = len(ndays) _weeks = [Week(ndays[i : i + length]) for i in range(0, num_days, length)] - return add_game_events_to_weeks(_weeks, is_active=False) + return add_game_events_to_weeks(_weeks, is_active=True) def get_month_block(day: Day, n: int = MONTH_BLOCK) -> List[Week]: diff --git a/tests/test_calendar_grid.py b/tests/test_calendar_grid.py index e5442b02..cf1353a3 100644 --- a/tests/test_calendar_grid.py +++ b/tests/test_calendar_grid.py @@ -80,15 +80,19 @@ def test_create_weeks(): @staticmethod def test_get_month_block(Calendar): + dates_iterator = Calendar.itermonthdates(1988, 5) month_weeks = cg.create_weeks( - Calendar.itermonthdates(1988, 5), + (cg.Day(date) for date in dates_iterator), WEEK_DAYS, ) get_block = cg.get_month_block(cg.Day(DATE), n=len(month_weeks)) for i in range(len(month_weeks)): for j in range(cg.Week.WEEK_DAYS): - assert get_block[i].days[j].date == month_weeks[i].days[j] + assert ( + get_block[i].days[j].set_id() + == month_weeks[i].days[j].set_id() + ) @staticmethod def test_get_user_local_time(): diff --git a/tests/test_game_releases.py b/tests/test_game_releases.py index 70b43523..b2ddf8e2 100644 --- a/tests/test_game_releases.py +++ b/tests/test_game_releases.py @@ -1,5 +1,9 @@ +from collections import defaultdict + from app.internal.game_releases_utils import ( - get_games_data_separated_by_days, + get_formatted_games_in_days, + get_games_data_by_dates_from_api, + get_games_data_separated_by_dates, translate_dby_date_to_ymd, translate_ymd_date_to_dby, ) @@ -68,7 +72,7 @@ def test_get_game_releases_month(client): game_release_router.url_path_for("get_game_releases_month"), ) assert response.ok - assert b"Prince" in response.content + assert b"name" in response.content @staticmethod def test_get_game_releases(client): @@ -86,9 +90,24 @@ def test_get_game_releases(client): def test_get_games_data_separated_by_days(): day_1 = "2020-12-10" day_2 = "2020-12-20" - formatted = get_games_data_separated_by_days(day_1, day_2) - assert isinstance(formatted, dict) - assert "platforms" in formatted["10-December-2020"][0].keys() + output = get_games_data_by_dates_from_api( + start_date=day_1, + end_date=day_2, + ) + games_by_dates = output["results"] + unformatted_games_by_dates = get_games_data_separated_by_dates( + games_by_dates, + ) + formatted_games = get_formatted_games_in_days( + unformatted_games_by_dates, + ) + + assert isinstance(unformatted_games_by_dates, defaultdict) + assert isinstance(formatted_games, defaultdict) + assert ( + "platforms" + in unformatted_games_by_dates["10-December-2020"][0].keys() + ) @staticmethod def test_ymd_to_dby(): @@ -99,3 +118,15 @@ def test_ymd_to_dby(): def test_dby_to_ymd(): dby_date = "12-December-2020" assert translate_dby_date_to_ymd(dby_date) == "2020-12-12" + + @staticmethod + def test_get_game_releases_async(client): + day_1 = "2020-12-10" + day_2 = "2020-12-20" + dates = {"from-date": day_1, "to-date": day_2} + response = client.post( + game_release_router.url_path_for("fetch_released_games"), + data=dates, + ) + assert response.ok + assert b"Xbox" in response.content