import sqlite3 import os import secrets DB_PATH = os.path.join(os.path.dirname(__file__), 'grepo.db') def get_db(): conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row return conn def init_db(): conn = get_db() c = conn.cursor() # Commands queue — sent from dashboard, consumed by Tampermonkey c.execute(''' CREATE TABLE IF NOT EXISTS commands ( id INTEGER PRIMARY KEY AUTOINCREMENT, town_id TEXT NOT NULL, town_name TEXT, type TEXT NOT NULL, -- 'build' | 'recruit' payload TEXT NOT NULL, -- JSON string status TEXT NOT NULL DEFAULT 'pending', -- pending | executing | done | failed result_msg TEXT, position INTEGER, -- manual sort order for build queue (lower = first) created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT NOT NULL DEFAULT (datetime('now')) ) ''') # Town state — pushed by Tampermonkey every poll cycle c.execute(''' CREATE TABLE IF NOT EXISTS town_state ( town_id TEXT PRIMARY KEY, town_name TEXT, player TEXT, player_id TEXT, alliance_id TEXT, world_id TEXT, x REAL, y REAL, sea INTEGER, data TEXT NOT NULL, -- full JSON snapshot updated_at TEXT NOT NULL DEFAULT (datetime('now')) ) ''') # Key-value store — generic flags (e.g. captcha_active) c.execute(''' CREATE TABLE IF NOT EXISTS kv_store ( key TEXT PRIMARY KEY, value TEXT, updated_at TEXT NOT NULL DEFAULT (datetime('now')) ) ''') # Farm settings — per-player auto-farm configuration c.execute(''' CREATE TABLE IF NOT EXISTS farm_settings ( player_id TEXT PRIMARY KEY, enabled INTEGER NOT NULL DEFAULT 0, bandit_camp_enabled INTEGER NOT NULL DEFAULT 0, loot_option INTEGER NOT NULL DEFAULT 1, -- 1=5min, 2=20min, 3=90min, 4=4h updated_at TEXT NOT NULL DEFAULT (datetime('now')) ) ''') # Bot settings — per-player config for bootcamp & rural-trade auto-loops c.execute(''' CREATE TABLE IF NOT EXISTS bot_settings ( player_id TEXT PRIMARY KEY, bootcamp_enabled INTEGER NOT NULL DEFAULT 0, bootcamp_use_def INTEGER NOT NULL DEFAULT 0, rural_trade_enabled INTEGER NOT NULL DEFAULT 0, rural_trade_ratio INTEGER NOT NULL DEFAULT 3, -- 1=0.25 2=0.5 3=0.75 4=1.0 5=1.25 updated_at TEXT NOT NULL DEFAULT (datetime('now')) ) ''') # Bot logs — ring buffer of last 50 entries per player per feature c.execute(''' CREATE TABLE IF NOT EXISTS bot_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, player_id TEXT NOT NULL, feature TEXT NOT NULL, -- 'bootcamp' | 'rural_trade' message TEXT NOT NULL, created_at TEXT NOT NULL DEFAULT (datetime('now')) ) ''') c.execute('CREATE INDEX IF NOT EXISTS idx_bot_logs_player_feature ON bot_logs(player_id, feature)') # Blueprints - assigns a blueprint to a specific town c.execute(''' CREATE TABLE IF NOT EXISTS town_blueprints ( town_id TEXT PRIMARY KEY, blueprint_name TEXT NOT NULL, is_active INTEGER NOT NULL DEFAULT 1, updated_at TEXT NOT NULL DEFAULT (datetime('now')) ) ''') # Migration: add new columns if upgrading an existing database for _col in [ 'ALTER TABLE town_state ADD COLUMN player_id TEXT', 'ALTER TABLE town_state ADD COLUMN alliance_id TEXT', 'ALTER TABLE town_state ADD COLUMN x REAL', 'ALTER TABLE town_state ADD COLUMN y REAL', 'ALTER TABLE town_state ADD COLUMN sea INTEGER', 'ALTER TABLE commands ADD COLUMN player_id TEXT', 'ALTER TABLE commands ADD COLUMN position INTEGER', 'ALTER TABLE farm_settings ADD COLUMN bandit_camp_enabled INTEGER NOT NULL DEFAULT 0', "ALTER TABLE clan_members ADD COLUMN features TEXT NOT NULL DEFAULT 'farm,admin'", 'ALTER TABLE users ADD COLUMN clan_id INTEGER REFERENCES clans(id)', ]: try: c.execute(_col) except Exception: pass # column already exists # Back-fill position for existing rows that have NULL position try: c.execute('UPDATE commands SET position = id WHERE position IS NULL') except Exception: pass # Users — website admin accounts c.execute(''' CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL UNIQUE, password_hash TEXT NOT NULL, clan_id INTEGER REFERENCES clans(id), created_at TEXT NOT NULL DEFAULT (datetime('now')) ) ''') # Clans — groups owned by a user, identified by a unique clan_key c.execute(''' CREATE TABLE IF NOT EXISTS clans ( id INTEGER PRIMARY KEY AUTOINCREMENT, owner_id INTEGER NOT NULL REFERENCES users(id), name TEXT NOT NULL, clan_key TEXT NOT NULL UNIQUE, created_at TEXT NOT NULL DEFAULT (datetime('now')) ) ''') # Clan members — links Grepolis player_ids to a clan c.execute(''' CREATE TABLE IF NOT EXISTS clan_members ( id INTEGER PRIMARY KEY AUTOINCREMENT, clan_id INTEGER NOT NULL REFERENCES clans(id), player_id TEXT NOT NULL, player_name TEXT, features TEXT NOT NULL DEFAULT 'farm,admin', joined_at TEXT NOT NULL DEFAULT (datetime('now')), UNIQUE(clan_id, player_id) ) ''') # Migration: Auto-assign existing users to their clan_id if they are the owner try: c.execute(''' UPDATE users SET clan_id = (SELECT id FROM clans WHERE owner_id = users.id) WHERE clan_id IS NULL AND EXISTS (SELECT 1 FROM clans WHERE owner_id = users.id) ''') except Exception: pass conn.commit() conn.close() def generate_clan_key(): """Generate a short, unique, human-readable clan key.""" return secrets.token_urlsafe(8).upper()[:10]