idac: fixed frontend

This commit is contained in:
Dniel97
2024-03-12 17:48:12 +01:00
parent a0fba8c3a4
commit 88b3cfc750
6 changed files with 87 additions and 79 deletions

View File

@@ -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")