Complete backend verification: fix syntax errors, create __init__.py files, add setup_db.py, update docker-compose for two PostgreSQL containers

This commit is contained in:
2026-07-18 23:02:44 +00:00
parent 3a70feaba5
commit 02ef8e36bc
27 changed files with 687 additions and 121 deletions
+223
View File
@@ -0,0 +1,223 @@
"""
Database initialization script for MTG Online backend.
Creates all necessary tables matching the SQLAlchemy ORM models
for both databases.
"""
import asyncio
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
from sqlalchemy import text
from app.core.settings import get_settings
async def setup_mtg_online_database():
"""Create tables for the mtgonline database."""
settings = get_settings()
engine = create_async_engine(settings.MTGO_DATABASE_URL)
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
async with async_session() as session:
# Create tables
tables = [
"""
CREATE TABLE IF NOT EXISTS mtgonline_users (
id SERIAL PRIMARY KEY,
username VARCHAR(64) UNIQUE NOT NULL,
password_hash VARCHAR(128) NOT NULL,
salt VARCHAR(128) NOT NULL,
email VARCHAR(255),
country VARCHAR(2),
real_name VARCHAR(128),
avatar_bmp TEXT,
privlevel VARCHAR(50) DEFAULT 'User',
is_active BOOLEAN DEFAULT TRUE,
is_banned BOOLEAN DEFAULT FALSE,
ban_reason TEXT,
ban_ends TIMESTAMP,
vip_status INTEGER DEFAULT 0,
vip_expiry TIMESTAMP,
creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP
)
""",
"""
CREATE TABLE IF NOT EXISTS mtgonline_decklist_folders (
id SERIAL PRIMARY KEY,
owner_id INTEGER REFERENCES mtgonline_users(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
parent_id INTEGER REFERENCES mtgonline_decklist_folders(id) ON DELETE CASCADE,
creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""",
"""
CREATE TABLE IF NOT EXISTS mtgonline_decklist_files (
id SERIAL PRIMARY KEY,
folder_id INTEGER REFERENCES mtgonline_decklist_folders(id) ON DELETE CASCADE,
owner_id INTEGER REFERENCES mtgonline_users(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
format VARCHAR(50) DEFAULT 'native',
creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""",
"""
CREATE TABLE IF NOT EXISTS mtgonline_rooms (
id SERIAL PRIMARY KEY,
name VARCHAR(100) UNIQUE NOT NULL,
description TEXT,
is_password_protected BOOLEAN DEFAULT FALSE,
password_hash VARCHAR(128),
creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""",
"""
CREATE TABLE IF NOT EXISTS mtgonline_rooms_gametypes (
id SERIAL PRIMARY KEY,
room_id INTEGER REFERENCES mtgonline_rooms(id) ON DELETE CASCADE,
name VARCHAR(100) NOT NULL,
description TEXT
)
""",
"""
CREATE TABLE IF NOT EXISTS mtgonline_bans (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES mtgonline_users(id) ON DELETE CASCADE,
server_id INTEGER,
reason TEXT NOT NULL,
moderators VARCHAR(255),
ip_address VARCHAR(45),
expiration_time TIMESTAMP,
active BOOLEAN DEFAULT TRUE,
creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""",
"""
CREATE TABLE IF NOT EXISTS mtgonline_log (
id SERIAL PRIMARY KEY,
room_id INTEGER REFERENCES mtgonline_rooms(id) ON DELETE CASCADE,
player_id INTEGER REFERENCES mtgonline_users(id) ON DELETE CASCADE,
message TEXT NOT NULL,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""",
"""
CREATE TABLE IF NOT EXISTS mtgonline_audit (
id SERIAL PRIMARY KEY,
admin_id INTEGER REFERENCES mtgonline_users(id) ON DELETE SET NULL,
action_type VARCHAR(50) NOT NULL,
target_user_id INTEGER REFERENCES mtgonline_users(id) ON DELETE SET NULL,
details TEXT,
ip_address VARCHAR(45),
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""",
]
for table_sql in tables:
await session.execute(text(table_sql))
# Create indexes
indexes = [
"CREATE INDEX IF NOT EXISTS idx_decks_owner ON mtgonline_decklist_files(owner_id);",
"CREATE INDEX IF NOT EXISTS idx_decks_folder ON mtgonline_decklist_files(folder_id);",
"CREATE INDEX IF NOT EXISTS idx_bans_active ON mtgonline_bans(active);",
"CREATE INDEX IF NOT EXISTS idx_log_timestamp ON mtgonline_log(timestamp);",
]
for idx_sql in indexes:
await session.execute(text(idx_sql))
print("✓ All mtgonline tables created")
await engine.dispose()
async def setup_mtg_data_database():
"""Create tables for the mtgdata database."""
settings = get_settings()
engine = create_async_engine(settings.MTG_DATABASE_URL)
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
async with async_session() as session:
# Create tables
tables = [
"""
CREATE TABLE IF NOT EXISTS mtg_sets (
id SERIAL PRIMARY KEY,
code VARCHAR(10) UNIQUE NOT NULL,
name VARCHAR(255),
type VARCHAR(100),
release_date DATE,
base_set_size INTEGER,
total_size INTEGER,
is_foil_only BOOLEAN,
is_non_foil_only BOOLEAN,
digital BOOLEAN,
icon_svg_url TEXT,
parent_code VARCHAR(10),
mtgo_code VARCHAR(10),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""",
"""
CREATE TABLE IF NOT EXISTS mtg_cards (
id SERIAL PRIMARY KEY,
set_id INTEGER REFERENCES mtg_sets(id) ON DELETE CASCADE,
name VARCHAR(255),
mana_cost VARCHAR(255),
type_line VARCHAR(255),
oracle_text TEXT,
power VARCHAR(50),
toughness VARCHAR(50),
rarity VARCHAR(50),
layout VARCHAR(50),
artist VARCHAR(255),
flavor_text TEXT,
numbers VARCHAR(100),
identifiers TEXT,
images TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""",
]
for table_sql in tables:
await session.execute(text(table_sql))
# Create indexes
indexes = [
"CREATE INDEX IF NOT EXISTS idx_mtg_cards_name ON mtg_cards(name);",
"CREATE INDEX IF NOT EXISTS idx_mtg_cards_type ON mtg_cards(type_line);",
"CREATE INDEX IF NOT EXISTS idx_mtg_cards_rarity ON mtg_cards(rarity);",
"CREATE INDEX IF NOT EXISTS idx_mtg_cards_set_id ON mtg_cards(set_id);",
]
for idx_sql in indexes:
await session.execute(text(idx_sql))
print("✓ All mtgdata tables created")
await engine.dispose()
async def main():
"""Main initialization function."""
print("MTG Online Database Initialization")
print("=" * 50)
# Setup mtgonline database
print("\nSetting up mtgonline database...")
await setup_mtg_online_database()
# Setup mtgdata database
print("\nSetting up mtgdata database...")
await setup_mtg_data_database()
print("\n✓ Database initialization complete!")
if __name__ == "__main__":
asyncio.run(main())