Merge branch 'develop' into idac

This commit is contained in:
Dniel97
2024-03-12 14:33:25 +01:00
203 changed files with 9242 additions and 5355 deletions

View File

@@ -9,4 +9,3 @@ database = IDACData
reader = IDACReader
frontend = IDACFrontend
game_codes = [IDACConstants.GAME_CODE]
current_schema_version = 2

View File

@@ -1,7 +1,6 @@
import logging
import socket
from twisted.internet.protocol import DatagramProtocol
from socketserver import BaseRequestHandler, TCPServer
from typing import Tuple
@@ -10,19 +9,14 @@ from titles.idac.config import IDACConfig
from titles.idac.database import IDACData
class IDACEchoUDP(DatagramProtocol):
def __init__(self, cfg: CoreConfig, game_cfg: IDACConfig, port: int) -> None:
super().__init__()
self.port = port
self.core_config = cfg
self.game_config = game_cfg
self.logger = logging.getLogger("idac")
class IDACEchoUDP:
def connection_made(self, transport):
self.transport = transport
def datagram_received(self, data, addr):
logging.getLogger('idz').debug(f'Received echo from {addr}')
self.transport.sendto(data, addr)
def datagramReceived(self, data, addr):
self.logger.info(
f"UDP Ping from from {addr[0]}:{addr[1]} -> {self.port} - {data.hex()}"
)
self.transport.write(data, addr)
class IDACEchoTCP(BaseRequestHandler):

View File

@@ -1,15 +1,14 @@
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 Any, Type
from twisted.web import resource
from twisted.web.util import redirectTo
from twisted.web.http import Request
from twisted.web.server import Session
from starlette.requests import Request
from core.frontend import FE_Base, IUserSession
from core.frontend import FE_Base, UserSession
from core.config import CoreConfig
from titles.idac.database import IDACData
from titles.idac.schema.profile import *
@@ -128,7 +127,8 @@ 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 = "頭文字D THE ARCADE"
self.nav_name = "IDAC"
# TODO: Add version list
self.version = IDACConstants.VER_IDAC_SEASON_2
@@ -286,7 +286,12 @@ class IDACProfileFrontend(FE_Base):
34: "full_tune_fragments",
}
def generate_all_tables_json(self, user_id: int):
def get_routes(self) -> List[Route]:
return [
Route("/", self.render_GET)
]
async def generate_all_tables_json(self, user_id: int):
json_export = {}
idac_tables = {
@@ -322,7 +327,7 @@ class IDACProfileFrontend(FE_Base):
sql = sql.where(table.c.version == self.version)
# lol use the profile connection for items, dirty hack
result = self.data.profile.execute(sql)
result = await self.data.profile.execute(sql)
data_list = result.fetchall()
# add the list to the json export with the correct table name
@@ -335,50 +340,47 @@ class IDACProfileFrontend(FE_Base):
return json.dumps(json_export, indent=4, default=str, ensure_ascii=False)
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/profile/index.jinja"
"titles/idac/templates/idac_index.jinja"
)
sesh: Session = request.getSession()
usr_sesh = IUserSession(sesh)
user_id = usr_sesh.userId
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
# profile export
if uri.startswith("/game/idac/profile/export.get"):
if user_id == 0:
return redirectTo(b"/game/idac", request)
return RedirectResponse(b"/game/idac", request)
# set the file name, content type and size to download the json
content = self.generate_all_tables_json(user_id).encode("utf-8")
request.responseHeaders.addRawHeader(
b"content-type", b"application/octet-stream"
)
request.responseHeaders.addRawHeader(
b"content-disposition", b"attachment; filename=idac_profile.json"
)
request.responseHeaders.addRawHeader(
b"content-length", str(len(content)).encode("utf-8")
)
content = await self.generate_all_tables_json(user_id).encode("utf-8")
self.logger.info(f"User {user_id} exported their IDAC data")
return content
return Response(
content,
200,
{'content-disposition': 'attachment; filename=idac_profile.json'},
"application/octet-stream"
)
profile_data, tickets, rank = None, None, None
if user_id > 0:
profile_data = self.data.profile.get_profile(user_id, self.version)
ticket_data = self.data.item.get_tickets(user_id)
rank = self.data.profile.get_profile_rank(user_id, self.version)
profile_data = await self.data.profile.get_profile(user_id, self.version)
ticket_data = await self.data.item.get_tickets(user_id)
rank = await self.data.profile.get_profile_rank(user_id, self.version)
tickets = {
self.ticket_names[ticket["ticket_id"]]: ticket["ticket_cnt"]
for ticket in ticket_data
}
if ticket_data:
tickets = {
self.ticket_names[ticket["ticket_id"]]: ticket["ticket_cnt"]
for ticket in ticket_data
}
return template.render(
return Response(template.render(
title=f"{self.core_config.server.name} | {self.nav_name}",
game_list=self.environment.globals["game_list"],
profile=profile_data,
@@ -386,5 +388,4 @@ class IDACProfileFrontend(FE_Base):
rank=rank,
sesh=vars(usr_sesh),
active_page="idac",
active_tab="profile",
).encode("utf-16")
), media_type="text/html; charset=utf-8")

View File

@@ -1,28 +1,26 @@
import json
import traceback
import inflection
from starlette.routing import Route
from starlette.requests import Request
from starlette.responses import JSONResponse
import yaml
import logging
import coloredlogs
from os import path
from typing import Dict, List, Tuple
from logging.handlers import TimedRotatingFileHandler
from twisted.web import server
from twisted.web.http import Request
from twisted.internet import reactor, endpoints
import asyncio
from core.config import CoreConfig
from core.title import BaseServlet, JSONResponseNoASCII
from core.utils import Utils
from titles.idac.base import IDACBase
from titles.idac.season2 import IDACSeason2
from titles.idac.config import IDACConfig
from titles.idac.const import IDACConstants
from titles.idac.echo import IDACEchoUDP
from titles.idac.matching import IDACMatching
class IDACServlet:
class IDACServlet(BaseServlet):
def __init__(self, core_cfg: CoreConfig, cfg_dir: str) -> None:
self.core_cfg = core_cfg
self.game_cfg = IDACConfig()
@@ -72,12 +70,12 @@ class IDACServlet:
return False
return True
def get_endpoint_matchers(self) -> Tuple[List[Tuple[str, str, Dict]], List[Tuple[str, str, Dict]]]:
return (
[],
[("render_POST", "/SDGT/{version}/initiald/{category}/{endpoint}", {})]
)
def get_routes(self) -> List[Route]:
return [
Route("/{version:int}/initiald/{category:str}/{endpoint:str}", self.render_POST, methods=["POST"]),
Route("/{version:int}/initiald-matching/{endpoint:str}", self.render_matching, methods=["POST"]),
]
def get_allnet_info(
self, game_code: str, game_ver: int, keychip: str
@@ -88,15 +86,15 @@ class IDACServlet:
return (
f"",
# requires http or else it defaults to https
f"http://{self.core_cfg.title.hostname}{t_port}/{game_code}/{game_ver}/",
f"http://{self.core_cfg.server.hostname}{t_port}/{game_ver}/",
)
def render_POST(self, request: Request, game_code: int, matchers: Dict) -> bytes:
req_raw = request.content.getvalue()
async def render_POST(self, request: Request) -> bytes:
req_raw = await request.body()
internal_ver = 0
version = int(matchers['version'])
category = matchers['category']
endpoint = matchers['endpoint']
version: int = request.path_params.get('version')
category: str = request.path_params.get('category')
endpoint: str = request.path_params.get('endpoint')
client_ip = Utils.get_ip_addr(request)
if version >= 100 and version < 140: # IDAC Season 1
@@ -104,7 +102,7 @@ class IDACServlet:
elif version >= 140 and version < 171: # IDAC Season 2
internal_ver = IDACConstants.VER_IDAC_SEASON_2
header_application = self.decode_header(request.getAllHeaders())
header_application = self.decode_header(request.headers.get("application", ""))
req_data = json.loads(req_raw)
@@ -119,27 +117,61 @@ class IDACServlet:
if not hasattr(self.versions[internal_ver], func_to_find):
self.logger.warning(f"Unhandled v{version} request {endpoint}")
return '{"status_code": "0"}'.encode("utf-8")
return JSONResponse('{"status_code": "0"}')
resp = None
try:
handler = getattr(self.versions[internal_ver], func_to_find)
resp = handler(req_data, header_application)
resp = await handler(req_data, header_application)
except Exception as e:
traceback.print_exc()
self.logger.error(f"Error handling v{version} method {endpoint} - {e}")
return '{"status_code": "0"}'.encode("utf-8")
return JSONResponse('{"status_code": "0"}')
if resp is None:
resp = {"status_code": "0"}
self.logger.debug(f"Response {resp}")
return json.dumps(resp, ensure_ascii=False).encode("utf-8")
return JSONResponseNoASCII(resp)
async def render_matching(self, request: Request):
url: str = request.path_params.get("endpoint")
ver: int = request.path_params.get("version")
client_ip = Utils.get_ip_addr(request)
req_data = await request.json()
header_application = self.decode_header(request.headers.get('application', ''))
user_id = int(header_application["session"])
def decode_header(self, data: Dict) -> Dict:
app: str = data[b"application"].decode()
# self.getMatchingStatus(user_id)
self.logger.info(
f"IDAC Matching request from {client_ip}: {url} - {req_data}"
)
resp = {"status_code": "0"}
if url == "/regist":
self.queue = self.queue + 1
elif url == "/status":
if req_data.get("cancel_flag"):
self.queue = self.queue - 1
self.logger.info(
f"IDAC Matching endpoint {client_ip} had quited"
)
resp = {
"status_code": "0",
# Only IPv4 is supported
"host": self.game_config.server.matching_host,
"port": self.game_config.server.matching_p2p,
"room_name": "INDTA",
"state": 1,
}
self.logger.debug(f"Response {resp}")
return JSONResponseNoASCII(resp)
def decode_header(self, app: str) -> Dict:
ret = {}
for x in app.split(", "):
@@ -150,18 +182,13 @@ class IDACServlet:
def setup(self):
if self.game_cfg.server.enable:
endpoints.serverFromString(
reactor,
f"tcp:{self.game_cfg.server.matching}:interface={self.core_cfg.server.listen_address}",
).listen(server.Site(IDACMatching(self.core_cfg, self.game_cfg)))
reactor.listenUDP(
self.game_cfg.server.echo1,
IDACEchoUDP(self.core_cfg, self.game_cfg, self.game_cfg.server.echo1),
)
reactor.listenUDP(
self.game_cfg.server.echo2,
IDACEchoUDP(self.core_cfg, self.game_cfg, self.game_cfg.server.echo2),
loop = asyncio.get_running_loop()
asyncio.create_task(
loop.create_datagram_endpoint(
lambda: IDACEchoUDP(),
local_addr=(self.core_cfg.server.listen_address, self.game_cfg.server.echo1)
)
)
self.logger.info(f"Matching listening on {self.game_cfg.server.matching} with echos on {self.game_cfg.server.echo1} and {self.game_cfg.server.echo2}")
self.logger.info(f"Matching listening on {self.game_cfg.server.matching} with echo on {self.game_cfg.server.echo1}")

View File

@@ -33,7 +33,7 @@ class IDACReader(BaseReader):
self.logger.error(f"Invalid Initial D THE ARCADE version {version}")
exit(1)
def read(self) -> None:
async def read(self) -> None:
if self.bin_dir is None and self.opt_dir is None:
self.logger.error(
(
@@ -59,9 +59,9 @@ class IDACReader(BaseReader):
)
exit(1)
self.read_idac_profile(self.opt_dir)
await self.read_idac_profile(self.opt_dir)
def read_idac_profile(self, file_path: str) -> None:
async def read_idac_profile(self, file_path: str) -> None:
self.logger.info(f"Reading profile from {file_path}...")
# read it as binary to avoid encoding issues
@@ -88,14 +88,14 @@ class IDACReader(BaseReader):
self.logger.info("Exiting...")
exit(0)
user_id = self.data.user.create_user()
user_id = await self.data.user.create_user()
if user_id is None:
self.logger.error("Failed to register user!")
user_id = -1
else:
card_id = self.data.card.create_card(user_id, access_code)
card_id = await self.data.card.create_card(user_id, access_code)
if card_id is None:
self.logger.error("Failed to register card!")
@@ -150,7 +150,7 @@ class IDACReader(BaseReader):
# lol use the profile connection for items, dirty hack
conflict = sql.on_duplicate_key_update(**data)
result = self.data.profile.execute(conflict)
result = await self.data.profile.execute(conflict)
if result is None:
self.logger.error(f"Failed to insert data into table {name}")

View File

@@ -323,7 +323,7 @@ timetrial_event = Table(
class IDACItemData(BaseData):
def get_random_user_car(self, aime_id: int, version: int) -> Optional[List[Row]]:
async def get_random_user_car(self, aime_id: int, version: int) -> Optional[List[Row]]:
sql = (
select(car)
.where(and_(car.c.user == aime_id, car.c.version == version))
@@ -331,20 +331,20 @@ class IDACItemData(BaseData):
.limit(1)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_random_car(self, version: int) -> Optional[List[Row]]:
async def get_random_car(self, version: int) -> Optional[List[Row]]:
sql = select(car).where(car.c.version == version).order_by(func.rand()).limit(1)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_car(
async def get_car(
self, aime_id: int, version: int, style_car_id: int
) -> Optional[List[Row]]:
sql = select(car).where(
@@ -355,12 +355,12 @@ class IDACItemData(BaseData):
)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_cars(
async def get_cars(
self, version: int, aime_id: int, only_pickup: bool = False
) -> Optional[List[Row]]:
if only_pickup:
@@ -376,106 +376,106 @@ class IDACItemData(BaseData):
and_(car.c.user == aime_id, car.c.version == version)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_ticket(self, aime_id: int, ticket_id: int) -> Optional[Row]:
async def get_ticket(self, aime_id: int, ticket_id: int) -> Optional[Row]:
sql = select(ticket).where(
ticket.c.user == aime_id, ticket.c.ticket_id == ticket_id
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_tickets(self, aime_id: int) -> Optional[List[Row]]:
async def get_tickets(self, aime_id: int) -> Optional[List[Row]]:
sql = select(ticket).where(ticket.c.user == aime_id)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_story(self, aime_id: int, chapter_id: int) -> Optional[Row]:
async def get_story(self, aime_id: int, chapter_id: int) -> Optional[Row]:
sql = select(story).where(
and_(story.c.user == aime_id, story.c.chapter == chapter_id)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_stories(self, aime_id: int) -> Optional[List[Row]]:
async def get_stories(self, aime_id: int) -> Optional[List[Row]]:
sql = select(story).where(story.c.user == aime_id)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_story_episodes(self, aime_id: int, chapter_id: int) -> Optional[List[Row]]:
async def get_story_episodes(self, aime_id: int, chapter_id: int) -> Optional[List[Row]]:
sql = select(episode).where(
and_(episode.c.user == aime_id, episode.c.chapter == chapter_id)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_story_episode(self, aime_id: int, episode_id: int) -> Optional[Row]:
async def get_story_episode(self, aime_id: int, episode_id: int) -> Optional[Row]:
sql = select(episode).where(
and_(episode.c.user == aime_id, episode.c.episode == episode_id)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_story_episode_difficulties(
async def get_story_episode_difficulties(
self, aime_id: int, episode_id: int
) -> Optional[List[Row]]:
sql = select(difficulty).where(
and_(difficulty.c.user == aime_id, difficulty.c.episode == episode_id)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_courses(self, aime_id: int) -> Optional[List[Row]]:
async def get_courses(self, aime_id: int) -> Optional[List[Row]]:
sql = select(course).where(course.c.user == aime_id)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_course(self, aime_id: int, course_id: int) -> Optional[Row]:
async def get_course(self, aime_id: int, course_id: int) -> Optional[Row]:
sql = select(course).where(
and_(course.c.user == aime_id, course.c.course_id == course_id)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_time_trial_courses(self, version: int) -> Optional[List[Row]]:
async def get_time_trial_courses(self, version: int) -> Optional[List[Row]]:
sql = select(trial.c.course_id).where(trial.c.version == version).distinct()
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_time_trial_user_best_time_by_course_car(
async def get_time_trial_user_best_time_by_course_car(
self, version: int, aime_id: int, course_id: int, style_car_id: int
) -> Optional[Row]:
sql = select(trial).where(
@@ -487,12 +487,12 @@ class IDACItemData(BaseData):
)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_time_trial_user_best_courses(
async def get_time_trial_user_best_courses(
self, version: int, aime_id: int
) -> Optional[List[Row]]:
# get for a given aime_id the best time for each course
@@ -517,12 +517,12 @@ class IDACItemData(BaseData):
)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_time_trial_best_cars_by_course(
async def get_time_trial_best_cars_by_course(
self, version: int, course_id: int, aime_id: Optional[int] = None
) -> Optional[List[Row]]:
subquery = select(
@@ -550,7 +550,7 @@ class IDACItemData(BaseData):
)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
@@ -587,7 +587,7 @@ class IDACItemData(BaseData):
return None
return result.fetchone()
def get_time_trial_ranking_by_course(
async def get_time_trial_ranking_by_course(
self,
version: int,
course_id: int,
@@ -628,12 +628,12 @@ class IDACItemData(BaseData):
if offset is not None:
sql = sql.offset(offset)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_time_trial_best_ranking_by_course(
async def get_time_trial_best_ranking_by_course(
self, version: int, aime_id: int, course_id: int
) -> Optional[Row]:
sql = (
@@ -649,12 +649,12 @@ class IDACItemData(BaseData):
.limit(1)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_challenge(
async def get_challenge(
self, aime_id: int, vs_type: int, play_difficulty: int
) -> Optional[Row]:
sql = select(challenge).where(
@@ -665,20 +665,20 @@ class IDACItemData(BaseData):
)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_challenges(self, aime_id: int) -> Optional[List[Row]]:
async def get_challenges(self, aime_id: int) -> Optional[List[Row]]:
sql = select(challenge).where(challenge.c.user == aime_id)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_best_challenges_by_vs_type(
async def get_best_challenges_by_vs_type(
self, aime_id: int, story_type: int = 4
) -> Optional[List[Row]]:
subquery = (
@@ -713,20 +713,20 @@ class IDACItemData(BaseData):
.order_by(challenge.c.vs_type)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_theory_courses(self, aime_id: int) -> Optional[List[Row]]:
async def get_theory_courses(self, aime_id: int) -> Optional[List[Row]]:
sql = select(theory_course).where(theory_course.c.user == aime_id)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_theory_course_by_powerhouse_lv(
async def get_theory_course_by_powerhouse_lv(
self, aime_id: int, course_id: int, powerhouse_lv: int, count: int = 3
) -> Optional[List[Row]]:
sql = (
@@ -742,40 +742,40 @@ class IDACItemData(BaseData):
.limit(count)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_theory_course(self, aime_id: int, course_id: int) -> Optional[List[Row]]:
async def get_theory_course(self, aime_id: int, course_id: int) -> Optional[List[Row]]:
sql = select(theory_course).where(
and_(
theory_course.c.user == aime_id, theory_course.c.course_id == course_id
)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_theory_partners(self, aime_id: int) -> Optional[List[Row]]:
async def get_theory_partners(self, aime_id: int) -> Optional[List[Row]]:
sql = select(theory_partner).where(theory_partner.c.user == aime_id)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_theory_running(self, aime_id: int) -> Optional[List[Row]]:
async def get_theory_running(self, aime_id: int) -> Optional[List[Row]]:
sql = select(theory_running).where(theory_running.c.user == aime_id)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_theory_running_by_course(
async def get_theory_running_by_course(
self, aime_id: int, course_id: int
) -> Optional[Row]:
sql = select(theory_running).where(
@@ -785,15 +785,15 @@ class IDACItemData(BaseData):
)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_vs_infos(self, aime_id: int) -> Optional[List[Row]]:
async def get_vs_infos(self, aime_id: int) -> Optional[List[Row]]:
sql = select(vs_info).where(vs_info.c.user == aime_id)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
@@ -819,21 +819,19 @@ class IDACItemData(BaseData):
return None
return result.fetchall()
def get_stamps(self, aime_id: int) -> Optional[List[Row]]:
async def get_stamps(self, aime_id: int) -> Optional[List[Row]]:
sql = select(stamp).where(
and_(
stamp.c.user == aime_id,
)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_timetrial_event(
self, aime_id: int, timetrial_event_id: int
) -> Optional[Row]:
async def get_timetrial_event(self, aime_id: int, timetrial_event_id: int) -> Optional[Row]:
sql = select(timetrial_event).where(
and_(
timetrial_event.c.user == aime_id,
@@ -841,49 +839,49 @@ class IDACItemData(BaseData):
)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def put_car(self, aime_id: int, version: int, car_data: Dict) -> Optional[int]:
async def put_car(self, aime_id: int, version: int, car_data: Dict) -> Optional[int]:
car_data["user"] = aime_id
car_data["version"] = version
sql = insert(car).values(**car_data)
conflict = sql.on_duplicate_key_update(**car_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(f"put_car: Failed to update! aime_id: {aime_id}")
return None
return result.lastrowid
def put_ticket(self, aime_id: int, ticket_data: Dict) -> Optional[int]:
async def put_ticket(self, aime_id: int, ticket_data: Dict) -> Optional[int]:
ticket_data["user"] = aime_id
sql = insert(ticket).values(**ticket_data)
conflict = sql.on_duplicate_key_update(**ticket_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(f"put_ticket: Failed to update! aime_id: {aime_id}")
return None
return result.lastrowid
def put_story(self, aime_id: int, story_data: Dict) -> Optional[int]:
async def put_story(self, aime_id: int, story_data: Dict) -> Optional[int]:
story_data["user"] = aime_id
sql = insert(story).values(**story_data)
conflict = sql.on_duplicate_key_update(**story_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(f"put_story: Failed to update! aime_id: {aime_id}")
return None
return result.lastrowid
def put_story_episode_play_status(
async def put_story_episode_play_status(
self, aime_id: int, chapter_id: int, play_status: int = 1
) -> Optional[int]:
sql = (
@@ -892,7 +890,7 @@ class IDACItemData(BaseData):
.values(play_status=play_status)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
self.logger.warn(
f"put_story_episode_play_status: Failed to update! aime_id: {aime_id}"
@@ -900,7 +898,7 @@ class IDACItemData(BaseData):
return None
return result.lastrowid
def put_story_episode(
async def put_story_episode(
self, aime_id: int, chapter_id: int, episode_data: Dict
) -> Optional[int]:
episode_data["user"] = aime_id
@@ -908,14 +906,14 @@ class IDACItemData(BaseData):
sql = insert(episode).values(**episode_data)
conflict = sql.on_duplicate_key_update(**episode_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(f"put_story_episode: Failed to update! aime_id: {aime_id}")
return None
return result.lastrowid
def put_story_episode_difficulty(
async def put_story_episode_difficulty(
self, aime_id: int, episode_id: int, difficulty_data: Dict
) -> Optional[int]:
difficulty_data["user"] = aime_id
@@ -923,7 +921,7 @@ class IDACItemData(BaseData):
sql = insert(difficulty).values(**difficulty_data)
conflict = sql.on_duplicate_key_update(**difficulty_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(
@@ -932,19 +930,19 @@ class IDACItemData(BaseData):
return None
return result.lastrowid
def put_course(self, aime_id: int, course_data: Dict) -> Optional[int]:
async def put_course(self, aime_id: int, course_data: Dict) -> Optional[int]:
course_data["user"] = aime_id
sql = insert(course).values(**course_data)
conflict = sql.on_duplicate_key_update(**course_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(f"put_course: Failed to update! aime_id: {aime_id}")
return None
return result.lastrowid
def put_time_trial(
async def put_time_trial(
self, version: int, aime_id: int, time_trial_data: Dict
) -> Optional[int]:
time_trial_data["user"] = aime_id
@@ -952,47 +950,47 @@ class IDACItemData(BaseData):
sql = insert(trial).values(**time_trial_data)
conflict = sql.on_duplicate_key_update(**time_trial_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(f"put_time_trial: Failed to update! aime_id: {aime_id}")
return None
return result.lastrowid
def put_challenge(self, aime_id: int, challenge_data: Dict) -> Optional[int]:
async def put_challenge(self, aime_id: int, challenge_data: Dict) -> Optional[int]:
challenge_data["user"] = aime_id
sql = insert(challenge).values(**challenge_data)
conflict = sql.on_duplicate_key_update(**challenge_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(f"put_challenge: Failed to update! aime_id: {aime_id}")
return None
return result.lastrowid
def put_theory_course(
async def put_theory_course(
self, aime_id: int, theory_course_data: Dict
) -> Optional[int]:
theory_course_data["user"] = aime_id
sql = insert(theory_course).values(**theory_course_data)
conflict = sql.on_duplicate_key_update(**theory_course_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(f"put_theory_course: Failed to update! aime_id: {aime_id}")
return None
return result.lastrowid
def put_theory_partner(
async def put_theory_partner(
self, aime_id: int, theory_partner_data: Dict
) -> Optional[int]:
theory_partner_data["user"] = aime_id
sql = insert(theory_partner).values(**theory_partner_data)
conflict = sql.on_duplicate_key_update(**theory_partner_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(
@@ -1001,14 +999,14 @@ class IDACItemData(BaseData):
return None
return result.lastrowid
def put_theory_running(
async def put_theory_running(
self, aime_id: int, theory_running_data: Dict
) -> Optional[int]:
theory_running_data["user"] = aime_id
sql = insert(theory_running).values(**theory_running_data)
conflict = sql.on_duplicate_key_update(**theory_running_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(
@@ -1023,7 +1021,7 @@ class IDACItemData(BaseData):
sql = insert(vs_info).values(**vs_info_data)
conflict = sql.on_duplicate_key_update(**vs_info_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(f"put_vs_info: Failed to update! aime_id: {aime_id}")
@@ -1043,21 +1041,21 @@ class IDACItemData(BaseData):
return None
return result.lastrowid
def put_stamp(
async def put_stamp(
self, aime_id: int, stamp_data: Dict
) -> Optional[int]:
stamp_data["user"] = aime_id
sql = insert(stamp).values(**stamp_data)
conflict = sql.on_duplicate_key_update(**stamp_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(f"putstamp: Failed to update! aime_id: {aime_id}")
return None
return result.lastrowid
def put_timetrial_event(
async def put_timetrial_event(
self, aime_id: int, time_trial_event_id: int, point: int
) -> Optional[int]:
timetrial_event_data = {
@@ -1068,7 +1066,7 @@ class IDACItemData(BaseData):
sql = insert(timetrial_event).values(**timetrial_event_data)
conflict = sql.on_duplicate_key_update(**timetrial_event_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(

View File

@@ -253,7 +253,7 @@ class IDACProfileData(BaseData):
)
self.date_time_format_short = "%Y-%m-%d"
def get_profile(self, aime_id: int, version: int) -> Optional[Row]:
async def get_profile(self, aime_id: int, version: int) -> Optional[Row]:
sql = select(profile).where(
and_(
profile.c.user == aime_id,
@@ -261,12 +261,12 @@ class IDACProfileData(BaseData):
)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_different_random_profiles(
async def get_different_random_profiles(
self, aime_id: int, version: int, count: int = 9
) -> Optional[Row]:
sql = (
@@ -281,36 +281,36 @@ class IDACProfileData(BaseData):
.limit(count)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_profile_config(self, aime_id: int) -> Optional[Row]:
async def get_profile_config(self, aime_id: int) -> Optional[Row]:
sql = select(config).where(
and_(
config.c.user == aime_id,
)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_profile_avatar(self, aime_id: int) -> Optional[Row]:
async def get_profile_avatar(self, aime_id: int) -> Optional[Row]:
sql = select(avatar).where(
and_(
avatar.c.user == aime_id,
)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_profile_rank(self, aime_id: int, version: int) -> Optional[Row]:
async def get_profile_rank(self, aime_id: int, version: int) -> Optional[Row]:
sql = select(rank).where(
and_(
rank.c.user == aime_id,
@@ -318,12 +318,12 @@ class IDACProfileData(BaseData):
)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_profile_stock(self, aime_id: int, version: int) -> Optional[Row]:
async def get_profile_stock(self, aime_id: int, version: int) -> Optional[Row]:
sql = select(stock).where(
and_(
stock.c.user == aime_id,
@@ -331,12 +331,12 @@ class IDACProfileData(BaseData):
)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_profile_theory(self, aime_id: int, version: int) -> Optional[Row]:
async def get_profile_theory(self, aime_id: int, version: int) -> Optional[Row]:
sql = select(theory).where(
and_(
theory.c.user == aime_id,
@@ -344,12 +344,12 @@ class IDACProfileData(BaseData):
)
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def put_profile(
async def put_profile(
self, aime_id: int, version: int, profile_data: Dict
) -> Optional[int]:
profile_data["user"] = aime_id
@@ -357,19 +357,19 @@ class IDACProfileData(BaseData):
sql = insert(profile).values(**profile_data)
conflict = sql.on_duplicate_key_update(**profile_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(f"put_profile: Failed to update! aime_id: {aime_id}")
return None
return result.lastrowid
def put_profile_config(self, aime_id: int, config_data: Dict) -> Optional[int]:
async def put_profile_config(self, aime_id: int, config_data: Dict) -> Optional[int]:
config_data["user"] = aime_id
sql = insert(config).values(**config_data)
conflict = sql.on_duplicate_key_update(**config_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(
@@ -378,12 +378,12 @@ class IDACProfileData(BaseData):
return None
return result.lastrowid
def put_profile_avatar(self, aime_id: int, avatar_data: Dict) -> Optional[int]:
async def put_profile_avatar(self, aime_id: int, avatar_data: Dict) -> Optional[int]:
avatar_data["user"] = aime_id
sql = insert(avatar).values(**avatar_data)
conflict = sql.on_duplicate_key_update(**avatar_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(
@@ -392,7 +392,7 @@ class IDACProfileData(BaseData):
return None
return result.lastrowid
def put_profile_rank(
async def put_profile_rank(
self, aime_id: int, version: int, rank_data: Dict
) -> Optional[int]:
rank_data["user"] = aime_id
@@ -400,14 +400,14 @@ class IDACProfileData(BaseData):
sql = insert(rank).values(**rank_data)
conflict = sql.on_duplicate_key_update(**rank_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(f"put_profile_rank: Failed to update! aime_id: {aime_id}")
return None
return result.lastrowid
def put_profile_stock(
async def put_profile_stock(
self, aime_id: int, version: int, stock_data: Dict
) -> Optional[int]:
stock_data["user"] = aime_id
@@ -415,14 +415,14 @@ class IDACProfileData(BaseData):
sql = insert(stock).values(**stock_data)
conflict = sql.on_duplicate_key_update(**stock_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(f"put_profile_stock: Failed to update! aime_id: {aime_id}")
return None
return result.lastrowid
def put_profile_theory(
async def put_profile_theory(
self, aime_id: int, version: int, theory_data: Dict
) -> Optional[int]:
theory_data["user"] = aime_id
@@ -430,7 +430,7 @@ class IDACProfileData(BaseData):
sql = insert(theory).values(**theory_data)
conflict = sql.on_duplicate_key_update(**theory_data)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
self.logger.warn(

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
{% extends "core/frontend/index.jinja" %}
{% extends "core/templates/index.jinja" %}
{% block content %}
<h1 class="mb-3">頭文字D THE ARCADE</h1>
@@ -18,7 +18,7 @@
{% endblock tab %}
<script type="text/javascript">
{% include "titles/idac/frontend/js/idac_scripts.js" %}
{% include "titles/idac/templates/js/idac_scripts.js" %}
</script>
{% endblock content %}