From 88b3cfc750e023e7a56f5d6121b58de2ee649f2f Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Tue, 12 Mar 2024 17:48:12 +0100 Subject: [PATCH] idac: fixed frontend --- titles/idac/frontend.py | 123 ++++++++++++---------- titles/idac/index.py | 9 +- titles/idac/schema/item.py | 18 ++-- titles/idac/templates/idac_index.jinja | 4 +- titles/idac/templates/profile/index.jinja | 8 +- titles/idac/templates/ranking/index.jinja | 4 +- 6 files changed, 87 insertions(+), 79 deletions(-) diff --git a/titles/idac/frontend.py b/titles/idac/frontend.py index 91f2e3a..9eb0639 100644 --- a/titles/idac/frontend.py +++ b/titles/idac/frontend.py @@ -1,11 +1,11 @@ import json -from typing import List -from starlette.routing import Route -from starlette.responses import Response, RedirectResponse import yaml import jinja2 from os import path +from typing import List, Any, Type +from starlette.routing import Route, Mount +from starlette.responses import Response, RedirectResponse, JSONResponse from starlette.requests import Request from core.frontend import FE_Base, UserSession @@ -54,7 +54,7 @@ class RequestValidator: required: bool = True, ) -> None: # Check if the parameter is missing - if param_name.encode() not in request_args: + if param_name not in request_args: if required: self.success = False self.error += f"Missing parameter: '{param_name}'. " @@ -64,7 +64,7 @@ class RequestValidator: return default return None - param_value = request_args[param_name.encode()][0].decode() + param_value = request_args[param_name] # Check if the parameter type is not empty if param_type: @@ -108,10 +108,6 @@ class RankingResponse: return ret - def to_json(self): - return json.dumps(self.make(), default=str, ensure_ascii=False).encode("utf-8") - - class IDACFrontend(FE_Base): isLeaf = False children: Dict[str, Any] = {} @@ -127,36 +123,52 @@ class IDACFrontend(FE_Base): self.game_cfg.update( yaml.safe_load(open(f"{cfg_dir}/{IDACConstants.CONFIG_NAME}")) ) - #self.nav_name = "頭文字D THE ARCADE" - self.nav_name = "IDAC" + self.nav_name = "頭文字D THE ARCADE" + # self.nav_name = "IDAC" # TODO: Add version list self.version = IDACConstants.VER_IDAC_SEASON_2 - self.putChild(b"profile", IDACProfileFrontend(cfg, self.environment)) - self.putChild(b"ranking", IDACRankingFrontend(cfg, self.environment)) + self.profile = IDACProfileFrontend(cfg, self.environment) + self.ranking = IDACRankingFrontend(cfg, self.environment) + + def get_routes(self) -> List[Route]: + return [ + Route("/", self.render_GET), + Mount("/profile", routes=[ + Route("/", self.profile.render_GET), + # dirty hack + Route("/export.get", self.profile.render_GET), + ]), + Mount("/ranking", routes=[ + Route("/", self.ranking.render_GET), + # dirty hack + Route("/const.get", self.ranking.render_GET), + Route("/ranking.get", self.ranking.render_GET), + ]), + ] - - def render_GET(self, request: Request) -> bytes: - uri: str = request.uri.decode() + async def render_GET(self, request: Request) -> bytes: + uri: str = request.url.path template = self.environment.get_template( - "titles/idac/frontend/idac_index.jinja" + "titles/idac/templates/idac_index.jinja" ) - sesh: Session = request.getSession() - usr_sesh = IUserSession(sesh) + usr_sesh = self.validate_session(request) + if not usr_sesh: + usr_sesh = UserSession() # redirect to the ranking page if uri.startswith("/game/idac"): - return redirectTo(b"/game/idac/ranking", request) + return RedirectResponse("/game/idac/ranking", 303) - return template.render( + return Response(template.render( title=f"{self.core_config.server.name} | {self.nav_name}", game_list=self.environment.globals["game_list"], sesh=vars(usr_sesh), active_page="idac", - ).encode("utf-16") + ), media_type="text/html; charset=utf-8") - def render_POST(self, request: Request) -> bytes: + async def render_POST(self, request: Request) -> bytes: pass @@ -170,48 +182,42 @@ class IDACRankingFrontend(FE_Base): # TODO: Add version list self.version = IDACConstants.VER_IDAC_SEASON_2 - def render_GET(self, request: Request) -> bytes: - uri: str = request.uri.decode() + async def render_GET(self, request: Request) -> bytes: + uri: str = request.url.path template = self.environment.get_template( - "titles/idac/frontend/ranking/index.jinja" + "titles/idac/templates/ranking/index.jinja" ) - sesh: Session = request.getSession() - usr_sesh = IUserSession(sesh) - user_id = usr_sesh.userId - # user_id = usr_sesh.user_id + usr_sesh = self.validate_session(request) + if not usr_sesh: + usr_sesh = UserSession() + user_id = usr_sesh.user_id # IDAC constants if uri.startswith("/game/idac/ranking/const.get"): - # set the content type to json - request.responseHeaders.addRawHeader(b"content-type", b"application/json") - # get the constants - with open("titles/idac/frontend/const.json", "r", encoding="utf-8") as f: + with open("titles/idac/templates/const.json", "r", encoding="utf-8") as f: constants = json.load(f) - return json.dumps(constants, ensure_ascii=False).encode("utf-8") + return JSONResponse(constants) # leaderboard ranking elif uri.startswith("/game/idac/ranking/ranking.get"): - # set the content type to json - request.responseHeaders.addRawHeader(b"content-type", b"application/json") - - req = RankingRequest(request.args) + req = RankingRequest(request.query_params._dict) resp = RankingResponse() if not req.success: resp.error = req.error - return resp.to_json() + return JSONResponse(resp.make()) # get the total number of records - total_records = self.data.item.get_time_trial_ranking_by_course_total( + total_records = await self.data.item.get_time_trial_ranking_by_course_total( self.version, req.course_id ) # return an error if there are no records if total_records is None or total_records == 0: resp.error = "No records found." - return resp.to_json() + return JSONResponse(resp.make()) # get the total number of records total = total_records["count"] @@ -219,7 +225,7 @@ class IDACRankingFrontend(FE_Base): limit = 50 offset = (req.page_number - 1) * limit - ranking = self.data.item.get_time_trial_ranking_by_course( + ranking = await self.data.item.get_time_trial_ranking_by_course( self.version, req.course_id, limit=limit, @@ -230,8 +236,8 @@ class IDACRankingFrontend(FE_Base): user_id = rank["user"] # get the username, country and store from the profile - profile = self.data.profile.get_profile(user_id, self.version) - arcade = self.data.arcade.get_arcade(profile["store"]) + profile = await self.data.profile.get_profile(user_id, self.version) + arcade = await self.data.arcade.get_arcade(profile["store"]) if arcade is None: arcade = {} @@ -258,15 +264,15 @@ class IDACRankingFrontend(FE_Base): resp.success = True resp.total_pages = (total // limit) + 1 resp.total_records = total - return resp.to_json() + return JSONResponse(resp.make()) - return template.render( + return Response(template.render( title=f"{self.core_config.server.name} | {self.nav_name}", game_list=self.environment.globals["game_list"], sesh=vars(usr_sesh), active_page="idac", active_tab="ranking", - ).encode("utf-16") + ), media_type="text/html; charset=utf-8") class IDACProfileFrontend(FE_Base): @@ -285,11 +291,6 @@ class IDACProfileFrontend(FE_Base): 25: "full_tune_tickets", 34: "full_tune_fragments", } - - def get_routes(self) -> List[Route]: - return [ - Route("/", self.render_GET) - ] async def generate_all_tables_json(self, user_id: int): json_export = {} @@ -344,25 +345,29 @@ class IDACProfileFrontend(FE_Base): uri: str = request.url.path template = self.environment.get_template( - "titles/idac/templates/idac_index.jinja" + "titles/idac/templates/profile/index.jinja" ) usr_sesh = self.validate_session(request) if not usr_sesh: usr_sesh = UserSession() user_id = usr_sesh.user_id - # user_id = usr_sesh.user_id + + user = await self.data.user.get_user(user_id) + if user is None: + self.logger.debug(f"User {user_id} not found") + return RedirectResponse("/user/", 303) # profile export if uri.startswith("/game/idac/profile/export.get"): if user_id == 0: - return RedirectResponse(b"/game/idac", request) + return RedirectResponse("/game/idac", 303) # set the file name, content type and size to download the json - content = await self.generate_all_tables_json(user_id).encode("utf-8") + content = await self.generate_all_tables_json(user_id) self.logger.info(f"User {user_id} exported their IDAC data") return Response( - content, + content.encode("utf-8"), 200, {'content-disposition': 'attachment; filename=idac_profile.json'}, "application/octet-stream" @@ -387,5 +392,7 @@ class IDACProfileFrontend(FE_Base): tickets=tickets, rank=rank, sesh=vars(usr_sesh), + username=user["username"], active_page="idac", + active_tab="profile", ), media_type="text/html; charset=utf-8") diff --git a/titles/idac/index.py b/titles/idac/index.py index 4e24491..03d4a5c 100644 --- a/titles/idac/index.py +++ b/titles/idac/index.py @@ -1,15 +1,16 @@ import json import traceback -from starlette.routing import Route -from starlette.requests import Request -from starlette.responses import JSONResponse import yaml import logging import coloredlogs +import asyncio + from os import path from typing import Dict, List, Tuple from logging.handlers import TimedRotatingFileHandler -import asyncio +from starlette.routing import Route +from starlette.requests import Request +from starlette.responses import JSONResponse from core.config import CoreConfig from core.title import BaseServlet, JSONResponseNoASCII diff --git a/titles/idac/schema/item.py b/titles/idac/schema/item.py index 8ba7d59..93b0e7f 100644 --- a/titles/idac/schema/item.py +++ b/titles/idac/schema/item.py @@ -555,7 +555,7 @@ class IDACItemData(BaseData): return None return result.fetchall() - def get_time_trial_ranking_by_course_total( + async def get_time_trial_ranking_by_course_total( self, version: int, course_id: int, @@ -582,7 +582,7 @@ class IDACItemData(BaseData): ) ) - result = self.execute(sql) + result = await self.execute(sql) if result is None: return None return result.fetchone() @@ -798,23 +798,23 @@ class IDACItemData(BaseData): return None return result.fetchall() - def get_vs_info_by_mode(self, aime_id: int, battle_mode: int) -> Optional[List[Row]]: + async def get_vs_info_by_mode(self, aime_id: int, battle_mode: int) -> Optional[List[Row]]: sql = select(vs_info).where( and_(vs_info.c.user == aime_id, vs_info.c.battle_mode == battle_mode) ) - result = self.execute(sql) + result = await self.execute(sql) if result is None: return None return result.fetchone() # This method returns a list of course_info - def get_vs_course_infos_by_mode(self, aime_id: int, battle_mode: int) -> Optional[List[Row]]: + async def get_vs_course_infos_by_mode(self, aime_id: int, battle_mode: int) -> Optional[List[Row]]: sql = select(vs_course_info).where( and_(vs_course_info.c.user == aime_id, vs_course_info.c.battle_mode == battle_mode) ) - result = self.execute(sql) + result = await self.execute(sql) if result is None: return None return result.fetchall() @@ -1015,7 +1015,7 @@ class IDACItemData(BaseData): return None return result.lastrowid - def put_vs_info(self, aime_id: int, battle_mode: int, vs_info_data: Dict) -> Optional[int]: + async def put_vs_info(self, aime_id: int, battle_mode: int, vs_info_data: Dict) -> Optional[int]: vs_info_data["user"] = aime_id vs_info_data["battle_mode"] = battle_mode @@ -1028,13 +1028,13 @@ class IDACItemData(BaseData): return None return result.lastrowid - def put_vs_course_info(self, aime_id: int, battle_mode: int, course_info_data: Dict) -> Optional[int]: + async def put_vs_course_info(self, aime_id: int, battle_mode: int, course_info_data: Dict) -> Optional[int]: course_info_data["user"] = aime_id course_info_data["battle_mode"] = battle_mode sql = insert(vs_course_info).values(**course_info_data) conflict = sql.on_duplicate_key_update(**course_info_data) - result = self.execute(conflict) + result = await self.execute(conflict) if result is None: self.logger.warn(f"put_vs_course_info: Failed to update! aime_id: {aime_id}") diff --git a/titles/idac/templates/idac_index.jinja b/titles/idac/templates/idac_index.jinja index 1e7e1c3..ecd60dd 100644 --- a/titles/idac/templates/idac_index.jinja +++ b/titles/idac/templates/idac_index.jinja @@ -5,10 +5,10 @@ diff --git a/titles/idac/templates/profile/index.jinja b/titles/idac/templates/profile/index.jinja index 31ca14c..e96b455 100644 --- a/titles/idac/templates/profile/index.jinja +++ b/titles/idac/templates/profile/index.jinja @@ -1,12 +1,12 @@ -{% extends "titles/idac/frontend/idac_index.jinja" %} +{% extends "titles/idac/templates/idac_index.jinja" %} {% block tab %} -{% if sesh is defined and sesh["userId"] > 0 %} +{% if sesh is defined and sesh["user_id"] > 0 %}
-

{{ sesh["username"] }}'s Profile

+

{{ username }}'s Profile

@@ -123,7 +123,7 @@
{% endblock tab %} \ No newline at end of file diff --git a/titles/idac/templates/ranking/index.jinja b/titles/idac/templates/ranking/index.jinja index a5bbc7a..fa1e8c3 100644 --- a/titles/idac/templates/ranking/index.jinja +++ b/titles/idac/templates/ranking/index.jinja @@ -1,4 +1,4 @@ -{% extends "titles/idac/frontend/idac_index.jinja" %} +{% extends "titles/idac/templates/idac_index.jinja" %} {% block tab %} {% endblock tab %}