Begin the process of transitioning from megaime

This commit is contained in:
Hay1tsme
2023-02-16 00:06:42 -05:00
commit 32879491f4
31 changed files with 1509 additions and 0 deletions

View File

@ -0,0 +1,6 @@
from core.data.schema.user import UserData
from core.data.schema.card import CardData
from core.data.schema.base import BaseData, metadata
from core.data.schema.arcade import ArcadeData
__all__ = ["UserData", "CardData", "BaseData", "metadata", "ArcadeData"]

113
core/data/schema/arcade.py Normal file
View File

@ -0,0 +1,113 @@
from typing import Optional, Dict
from sqlalchemy import Table, Column
from sqlalchemy.sql.schema import ForeignKey, PrimaryKeyConstraint
from sqlalchemy.types import Integer, String, Boolean
from sqlalchemy.sql import func, select
from sqlalchemy.dialects.mysql import insert
from core.data.schema.base import BaseData, metadata
arcade = Table(
"arcade",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("name", String(255)),
Column("nickname", String(255)),
Column("country", String(3)),
Column("country_id", Integer),
Column("state", String(255)),
Column("city", String(255)),
Column("region_id", Integer),
Column("timezone", String(255)),
mysql_charset='utf8mb4'
)
machine = Table(
"machine",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("arcade", ForeignKey("arcade.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("serial", String(15), nullable=False),
Column("board", String(15)),
Column("game", String(4)),
Column("country", String(3)), # overwrites if not null
Column("timezone", String(255)),
Column("ota_enable", Boolean),
Column("is_cab", Boolean),
mysql_charset='utf8mb4'
)
arcade_owner = Table(
'arcade_owner',
metadata,
Column('user', Integer, ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column('arcade', Integer, ForeignKey("arcade.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column('permissions', Integer, nullable=False),
PrimaryKeyConstraint('user', 'arcade', name='arcade_owner_pk'),
mysql_charset='utf8mb4'
)
class ArcadeData(BaseData):
def get_machine(self, serial: str = None, id: int = None) -> Optional[Dict]:
if serial is not None:
sql = machine.select(machine.c.serial == serial)
elif id is not None:
sql = machine.select(machine.c.id == id)
else:
self.logger.error(f"{__name__ }: Need either serial or ID to look up!")
return None
result = self.execute(sql)
if result is None: return None
return result.fetchone()
def put_machine(self, arcade_id: int, serial: str = None, board: str = None, game: str = None, is_cab: bool = False) -> Optional[int]:
if arcade_id:
self.logger.error(f"{__name__ }: Need arcade id!")
return None
if serial is None:
pass
sql = machine.insert().values(arcade = arcade_id, keychip = serial, board = board, game = game, is_cab = is_cab)
result = self.execute(sql)
if result is None: return None
return result.lastrowid
def get_arcade(self, id: int) -> Optional[Dict]:
sql = arcade.select(arcade.c.id == id)
result = self.execute(sql)
if result is None: return None
return result.fetchone()
def put_arcade(self, name: str, nickname: str = None, country: str = "JPN", country_id: int = 1,
state: str = "", city: str = "", regional_id: int = 1) -> Optional[int]:
if nickname is None: nickname = name
sql = arcade.insert().values(name = name, nickname = nickname, country = country, country_id = country_id,
state = state, city = city, regional_id = regional_id)
result = self.execute(sql)
if result is None: return None
return result.lastrowid
def get_arcade_owners(self, arcade_id: int) -> Optional[Dict]:
sql = select(arcade_owner).where(arcade_owner.c.arcade==arcade_id)
result = self.execute(sql)
if result is None: return None
return result.fetchall()
def add_arcade_owner(self, arcade_id: int, user_id: int) -> None:
sql = insert(arcade_owner).values(
arcade=arcade_id,
user=user_id
)
result = self.execute(sql)
if result is None: return None
return result.lastrowid
def generate_keychip_serial(self, platform_id: int) -> str:
pass

124
core/data/schema/base.py Normal file
View File

@ -0,0 +1,124 @@
import json
import logging
from random import randrange
from typing import Any, Optional, Dict, List
from sqlalchemy.engine.cursor import CursorResult
from sqlalchemy.engine.base import Connection
from sqlalchemy.sql import text, func, select
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy import MetaData, Table, Column
from sqlalchemy.types import Integer, String, TIMESTAMP, JSON
from sqlalchemy.dialects.mysql import insert
from core.config import CoreConfig
metadata = MetaData()
schema_ver = Table(
"schema_versions",
metadata,
Column("game", String(4), primary_key=True, nullable=False),
Column("version", Integer, nullable=False, server_default="1"),
mysql_charset='utf8mb4'
)
event_log = Table(
"event_log",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("system", String(255), nullable=False),
Column("type", String(255), nullable=False),
Column("severity", Integer, nullable=False),
Column("details", JSON, nullable=False),
Column("when_logged", TIMESTAMP, nullable=False, server_default=func.now()),
mysql_charset='utf8mb4'
)
class BaseData():
def __init__(self, cfg: CoreConfig, conn: Connection) -> None:
self.config = cfg
self.conn = conn
self.logger = logging.getLogger("database")
def execute(self, sql: str, opts: Dict[str, Any]={}) -> Optional[CursorResult]:
res = None
try:
self.logger.info(f"SQL Execute: {''.join(str(sql).splitlines())} || {opts}")
res = self.conn.execute(text(sql), opts)
except SQLAlchemyError as e:
self.logger.error(f"SQLAlchemy error {e}")
return None
except UnicodeEncodeError as e:
self.logger.error(f"UnicodeEncodeError error {e}")
return None
except:
try:
res = self.conn.execute(sql, opts)
except SQLAlchemyError as e:
self.logger.error(f"SQLAlchemy error {e}")
return None
except UnicodeEncodeError as e:
self.logger.error(f"UnicodeEncodeError error {e}")
return None
except:
self.logger.error(f"Unknown error")
raise
return res
def generate_id(self) -> int:
"""
Generate a random 5-7 digit id
"""
return randrange(10000, 9999999)
def get_schema_ver(self, game: str) -> Optional[int]:
sql = select(schema_ver).where(schema_ver.c.game == game)
result = self.execute(sql)
if result is None:
return None
return result.fetchone()["version"]
def set_schema_ver(self, ver: int, game: str = "CORE") -> Optional[int]:
sql = insert(schema_ver).values(game = game, version = ver)
conflict = sql.on_duplicate_key_update(version = ver)
result = self.execute(conflict)
if result is None:
self.logger.error(f"Failed to update schema version for game {game} (v{ver})")
return None
return result.lastrowid
def log_event(self, system: str, type: str, severity: int, details: Dict) -> Optional[int]:
sql = event_log.insert().values(system = system, type = type, severity = severity, details = json.dumps(details))
result = self.execute(sql)
if result is None:
self.logger.error(f"{__name__}: Failed to insert event into event log! system = {system}, type = {type}, severity = {severity}, details = {details}")
return None
return result.lastrowid
def get_event_log(self, entries: int = 100) -> Optional[List[Dict]]:
sql = event_log.select().limit(entries).all()
result = self.execute(sql)
if result is None: return None
return result.fetchall()
def fix_bools(self, data: Dict) -> Dict:
for k,v in data.items():
if type(v) == str and v.lower() == "true":
data[k] = True
elif type(v) == str and v.lower() == "false":
data[k] = False
return data

67
core/data/schema/card.py Normal file
View File

@ -0,0 +1,67 @@
from typing import Dict, List, Optional
from sqlalchemy import Table, Column, UniqueConstraint
from sqlalchemy.types import Integer, String, Boolean, TIMESTAMP
from sqlalchemy.sql.schema import ForeignKey
from sqlalchemy.sql import func
from core.data.schema.base import BaseData, metadata
aime_card = Table(
'aime_card',
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("access_code", String(20)),
Column("created_date", TIMESTAMP, server_default=func.now()),
Column("last_login_date", TIMESTAMP, onupdate=func.now()),
Column("is_locked", Boolean, server_default="0"),
Column("is_banned", Boolean, server_default="0"),
UniqueConstraint("user", "access_code", name="aime_card_uk"),
mysql_charset='utf8mb4'
)
class CardData(BaseData):
def get_user_id_from_card(self, access_code: str) -> Optional[int]:
"""
Given a 20 digit access code as a string, get the user id associated with that card
"""
sql = aime_card.select(aime_card.c.access_code == access_code)
result = self.execute(sql)
if result is None: return None
card = result.fetchone()
if card is None: return None
return int(card["user"])
def get_user_cards(self, aime_id: int) -> Optional[List[Dict]]:
"""
Returns all cards owned by a user
"""
sql = aime_card.select(aime_card.c.user == aime_id)
result = self.execute(sql)
if result is None: return None
return result.fetchall()
def create_card(self, user_id: int, access_code: str) -> Optional[int]:
"""
Given a aime_user id and a 20 digit access code as a string, create a card and return the ID if successful
"""
sql = aime_card.insert().values(user=user_id, access_code=access_code)
result = self.execute(sql)
if result is None: return None
return result.lastrowid
def to_access_code(self, luid: str) -> str:
"""
Given a felica cards internal 16 hex character luid, convert it to a 0-padded 20 digit access code as a string
"""
return f"{int(luid, base=16):0{20}}"
def to_idm(self, access_code: str) -> str:
"""
Given a 20 digit access code as a string, return the 16 hex character luid
"""
return f'{int(access_code):0{16}x}'

57
core/data/schema/user.py Normal file
View File

@ -0,0 +1,57 @@
from enum import Enum
from typing import Dict, Optional
from sqlalchemy import Table, Column
from sqlalchemy.types import Integer, String, TIMESTAMP
from sqlalchemy.sql.schema import ForeignKey
from sqlalchemy.sql import func
from core.data.schema.base import BaseData, metadata
aime_user = Table(
"aime_user",
metadata,
Column("id", Integer, nullable=False, primary_key=True, autoincrement=True),
Column("username", String(25), unique=True),
Column("email", String(255), unique=True),
Column("password", String(255)),
Column("permissions", Integer),
Column("created_date", TIMESTAMP, server_default=func.now()),
Column("last_login_date", TIMESTAMP, onupdate=func.now()),
Column("suspend_expire_time", TIMESTAMP),
mysql_charset='utf8mb4'
)
frontend_session = Table(
"frontend_session",
metadata,
Column("id", Integer, primary_key=True, unique=True),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column('session_cookie', String(32), nullable=False, unique=True),
Column("expires", TIMESTAMP, nullable=False),
mysql_charset='utf8mb4'
)
class PermissionBits(Enum):
PermUser = 1
PermMod = 2
PermSysAdmin = 4
class UserData(BaseData):
def create_user(self, username: str = None, email: str = None, password: str = None) -> Optional[int]:
if email is None:
permission = None
else:
permission = 0
sql = aime_user.insert().values(username=username, email=email, password=password, permissions=permission)
result = self.execute(sql)
if result is None: return None
return result.lastrowid
def reset_autoincrement(self, ai_value: int) -> None:
# Didn't feel like learning how to do this the right way
# if somebody wants a free PR go nuts I guess
sql = f"ALTER TABLE aime_user AUTO_INCREMENT={ai_value}"
self.execute(sql)

View File

@ -0,0 +1,14 @@
SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechHighScore int;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechBasicHighScore int;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechAdvancedHighScore int;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechExpertHighScore int;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechMasterHighScore int;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechLunaticHighScore int;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleHighScore int;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleBasicHighScore int;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleAdvancedHighScore int;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleExpertHighScore int;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleMasterHighScore int;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleLunaticHighScore int;
SET FOREIGN_KEY_CHECKS=1;

View File

@ -0,0 +1,14 @@
SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechHighScore bigint;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechBasicHighScore bigint;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechAdvancedHighScore bigint;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechExpertHighScore bigint;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechMasterHighScore bigint;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechLunaticHighScore bigint;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleHighScore bigint;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleBasicHighScore bigint;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleAdvancedHighScore bigint;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleExpertHighScore bigint;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleMasterHighScore bigint;
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleLunaticHighScore bigint;
SET FOREIGN_KEY_CHECKS=1;

View File

@ -0,0 +1,3 @@
UPDATE wacca_score_stageup SET version = 2 WHERE version = 3;
UPDATE wacca_score_stageup SET version = 3 WHERE version = 4;
ALTER TABLE wacca_score_stageup CHANGE version season int(11) DEFAULT NULL NULL;

View File

@ -0,0 +1,16 @@
SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE wacca_profile ADD season int(11) NOT NULL;
ALTER TABLE wacca_profile ADD playcount_stageup_season int(11) NULL;
ALTER TABLE wacca_profile ADD playcount_multi_coop_season int(11) NULL;
ALTER TABLE wacca_profile ADD playcount_multi_vs_season int(11) NULL;
ALTER TABLE wacca_profile ADD playcount_single_season int(11) NULL;
ALTER TABLE wacca_profile ADD xp_season int(11) NULL;
ALTER TABLE wacca_profile ADD wp_season int(11) NULL;
ALTER TABLE wacca_profile ADD wp_spent_season int(11) NULL;
ALTER TABLE wacca_item ADD use_count_season int(11) NULL;
ALTER TABLE wacca_profile DROP COLUMN gate_tutorial_flags;
SET FOREIGN_KEY_CHECKS=1;

View File

@ -0,0 +1,3 @@
ALTER TABLE wacca_score_stageup CHANGE season version int(11) DEFAULT NULL NULL;
UPDATE wacca_score_stageup SET version = 4 WHERE version = 3;
UPDATE wacca_score_stageup SET version = 3 WHERE version = 2;

View File

@ -0,0 +1,15 @@
SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE wacca_profile DROP COLUMN season;
ALTER TABLE wacca_profile DROP COLUMN playcount_stageup_season;
ALTER TABLE wacca_profile DROP COLUMN playcount_multi_coop_season;
ALTER TABLE wacca_profile DROP COLUMN playcount_multi_vs_season;
ALTER TABLE wacca_profile DROP COLUMN playcount_single_season;
ALTER TABLE wacca_profile DROP COLUMN xp_season;
ALTER TABLE wacca_profile DROP COLUMN wp_season;
ALTER TABLE wacca_profile DROP COLUMN wp_spent_season;
ALTER TABLE wacca_item DROP COLUMN use_count_season;
ALTER TABLE wacca_profile ADD gate_tutorial_flags JSON NULL;
SET FOREIGN_KEY_CHECKS=1;