forked from Hay1tsme/artemis
Begin the process of transitioning from megaime
This commit is contained in:
6
core/data/schema/__init__.py
Normal file
6
core/data/schema/__init__.py
Normal 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
113
core/data/schema/arcade.py
Normal 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
124
core/data/schema/base.py
Normal 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
67
core/data/schema/card.py
Normal 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
57
core/data/schema/user.py
Normal 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)
|
14
core/data/schema/versions/SDDT_1_rollback.sql
Normal file
14
core/data/schema/versions/SDDT_1_rollback.sql
Normal 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;
|
14
core/data/schema/versions/SDDT_2_upgrade.sql
Normal file
14
core/data/schema/versions/SDDT_2_upgrade.sql
Normal 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;
|
3
core/data/schema/versions/SDFE_1_rollback.sql
Normal file
3
core/data/schema/versions/SDFE_1_rollback.sql
Normal 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;
|
16
core/data/schema/versions/SDFE_2_rollback.sql
Normal file
16
core/data/schema/versions/SDFE_2_rollback.sql
Normal 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;
|
3
core/data/schema/versions/SDFE_2_upgrade.sql
Normal file
3
core/data/schema/versions/SDFE_2_upgrade.sql
Normal 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;
|
15
core/data/schema/versions/SDFE_3_upgrade.sql
Normal file
15
core/data/schema/versions/SDFE_3_upgrade.sql
Normal 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;
|
Reference in New Issue
Block a user