Update to v2.1.1 - Clean Design
This commit is contained in:
parent
de25b3e19c
commit
709f362194
20 changed files with 8127 additions and 191 deletions
315
migrate.py
Normal file
315
migrate.py
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Database Migration Script for UrNetwork Stats Dashboard v2.0
|
||||
Migrates from single-account to multi-account structure
|
||||
"""
|
||||
|
||||
import sqlite3
|
||||
import os
|
||||
import sys
|
||||
from getpass import getpass
|
||||
|
||||
def print_header(text):
|
||||
print("\n" + "=" * 60)
|
||||
print(f" {text}")
|
||||
print("=" * 60)
|
||||
|
||||
def print_success(text):
|
||||
print(f"✓ {text}")
|
||||
|
||||
def print_warning(text):
|
||||
print(f"⚠ {text}")
|
||||
|
||||
def print_error(text):
|
||||
print(f"✗ {text}")
|
||||
|
||||
def backup_files():
|
||||
"""Create backups of existing files"""
|
||||
print_header("Vytváření záloh")
|
||||
|
||||
if os.path.exists('.env'):
|
||||
os.system('cp .env .env.backup')
|
||||
print_success("Zazálohován .env → .env.backup")
|
||||
|
||||
# Check for database in multiple locations
|
||||
db_locations = ['transfer_stats.db', 'instance/transfer_stats.db']
|
||||
for db_path in db_locations:
|
||||
if os.path.exists(db_path):
|
||||
backup_path = db_path + '.backup'
|
||||
os.system(f'cp {db_path} {backup_path}')
|
||||
print_success(f"Zazálohována databáze → {backup_path}")
|
||||
break
|
||||
|
||||
def migrate_database():
|
||||
"""Migrate database to new structure"""
|
||||
print_header("Migrace databáze")
|
||||
|
||||
# Check for database in multiple locations
|
||||
db_path = None
|
||||
possible_paths = [
|
||||
'transfer_stats.db',
|
||||
'instance/transfer_stats.db',
|
||||
'../transfer_stats.db'
|
||||
]
|
||||
|
||||
for path in possible_paths:
|
||||
if os.path.exists(path):
|
||||
db_path = path
|
||||
print_success(f"Nalezena databáze: {db_path}")
|
||||
break
|
||||
|
||||
if not db_path:
|
||||
print_error("Databáze transfer_stats.db nenalezena!")
|
||||
print_warning("Hledáno v: " + ", ".join(possible_paths))
|
||||
return False
|
||||
|
||||
try:
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 1. Create accounts table
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS accounts (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
username TEXT UNIQUE NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
nickname TEXT,
|
||||
is_active BOOLEAN DEFAULT 1,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
''')
|
||||
print_success("Vytvořena tabulka accounts")
|
||||
|
||||
# 2. Add account_id column to stats
|
||||
try:
|
||||
cursor.execute('ALTER TABLE stats ADD COLUMN account_id INTEGER')
|
||||
print_success("Přidán sloupec account_id do tabulky stats")
|
||||
except sqlite3.OperationalError as e:
|
||||
if "duplicate column" in str(e).lower():
|
||||
print_warning("Sloupec account_id již existuje")
|
||||
else:
|
||||
raise
|
||||
|
||||
# 3. Migrate existing account from .env
|
||||
if os.path.exists('.env'):
|
||||
username = None
|
||||
password = None
|
||||
|
||||
with open('.env', 'r') as f:
|
||||
for line in f:
|
||||
if line.startswith('UR_USER='):
|
||||
username = line.split('=', 1)[1].strip()
|
||||
elif line.startswith('UR_PASS='):
|
||||
password = line.split('=', 1)[1].strip()
|
||||
|
||||
if username and password:
|
||||
cursor.execute('SELECT COUNT(*) FROM accounts WHERE username = ?', (username,))
|
||||
|
||||
if cursor.fetchone()[0] == 0:
|
||||
print(f"\nNalezen existující účet: {username}")
|
||||
nickname = input("Zadejte přezdívku pro tento účet (nebo stiskněte Enter pro přeskočení): ").strip()
|
||||
|
||||
cursor.execute(
|
||||
'INSERT INTO accounts (username, password, nickname, is_active) VALUES (?, ?, ?, 1)',
|
||||
(username, password, nickname if nickname else None)
|
||||
)
|
||||
account_id = cursor.lastrowid
|
||||
|
||||
# Update existing stats
|
||||
cursor.execute('UPDATE stats SET account_id = ? WHERE account_id IS NULL', (account_id,))
|
||||
updated_count = cursor.rowcount
|
||||
|
||||
print_success(f"Migrován účet: {username}")
|
||||
if nickname:
|
||||
print_success(f" Přezdívka: {nickname}")
|
||||
print_success(f" Aktualizováno {updated_count} statistických záznamů")
|
||||
else:
|
||||
print_warning(f"Účet {username} již existuje v databázi")
|
||||
else:
|
||||
print_warning("Nenalezeny credentials v .env souboru")
|
||||
else:
|
||||
print_warning(".env soubor nenalezen")
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
print_success("Migrace databáze dokončena!")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print_error(f"Chyba při migraci databáze: {e}")
|
||||
return False
|
||||
|
||||
def update_env_file():
|
||||
"""Update .env file with admin password"""
|
||||
print_header("Aktualizace .env souboru")
|
||||
|
||||
if not os.path.exists('.env'):
|
||||
print_warning(".env soubor nenalezen, bude vytvořen nový")
|
||||
env_lines = []
|
||||
else:
|
||||
with open('.env', 'r') as f:
|
||||
env_lines = f.readlines()
|
||||
|
||||
# Check if ADMIN_PASSWORD exists
|
||||
has_admin_pass = any(line.startswith('ADMIN_PASSWORD=') for line in env_lines)
|
||||
|
||||
if has_admin_pass:
|
||||
print_warning("ADMIN_PASSWORD již existuje v .env")
|
||||
response = input("Chcete nastavit nové heslo? (y/n): ").lower()
|
||||
if response != 'y':
|
||||
return True
|
||||
|
||||
# Remove old password
|
||||
env_lines = [line for line in env_lines if not line.startswith('ADMIN_PASSWORD=')]
|
||||
|
||||
print("\nNastavte administrátorské heslo pro přístup do dashboardu.")
|
||||
print("(Toto je oddělené od vašich UrNetwork credentials)")
|
||||
|
||||
while True:
|
||||
admin_pass = getpass("\nAdministrátorské heslo: ")
|
||||
admin_pass_confirm = getpass("Potvrďte heslo: ")
|
||||
|
||||
if admin_pass == admin_pass_confirm:
|
||||
if len(admin_pass) < 6:
|
||||
print_error("Heslo musí mít alespoň 6 znaků!")
|
||||
continue
|
||||
break
|
||||
else:
|
||||
print_error("Hesla se neshodují!")
|
||||
|
||||
# Add admin password
|
||||
if not any(line.strip() == "# Admin Access" for line in env_lines):
|
||||
env_lines.insert(0, "# Admin Access\n")
|
||||
env_lines.insert(1, f"ADMIN_PASSWORD={admin_pass}\n")
|
||||
env_lines.insert(2, "\n")
|
||||
|
||||
# Write updated .env
|
||||
with open('.env', 'w') as f:
|
||||
f.writelines(env_lines)
|
||||
|
||||
print_success("Administrátorské heslo nastaveno")
|
||||
return True
|
||||
|
||||
def verify_migration():
|
||||
"""Verify that migration was successful"""
|
||||
print_header("Ověření migrace")
|
||||
|
||||
# Find database
|
||||
db_path = None
|
||||
for path in ['transfer_stats.db', 'instance/transfer_stats.db']:
|
||||
if os.path.exists(path):
|
||||
db_path = path
|
||||
break
|
||||
|
||||
if not db_path:
|
||||
print_error("Databáze nenalezena pro ověření")
|
||||
return False
|
||||
|
||||
try:
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Check accounts table
|
||||
cursor.execute("SELECT COUNT(*) FROM accounts")
|
||||
account_count = cursor.fetchone()[0]
|
||||
print_success(f"Nalezeno {account_count} účtů v databázi")
|
||||
|
||||
# Check stats with account_id
|
||||
cursor.execute("SELECT COUNT(*) FROM stats WHERE account_id IS NOT NULL")
|
||||
stats_count = cursor.fetchone()[0]
|
||||
print_success(f"Nalezeno {stats_count} statistických záznamů s account_id")
|
||||
|
||||
# Check orphaned stats
|
||||
cursor.execute("SELECT COUNT(*) FROM stats WHERE account_id IS NULL")
|
||||
orphaned_count = cursor.fetchone()[0]
|
||||
if orphaned_count > 0:
|
||||
print_warning(f"Nalezeno {orphaned_count} statistik bez přiřazeného účtu")
|
||||
|
||||
conn.close()
|
||||
|
||||
# Check .env
|
||||
if os.path.exists('.env'):
|
||||
with open('.env', 'r') as f:
|
||||
env_content = f.read()
|
||||
if 'ADMIN_PASSWORD=' in env_content:
|
||||
print_success("ADMIN_PASSWORD nalezeno v .env")
|
||||
else:
|
||||
print_warning("ADMIN_PASSWORD chybí v .env")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print_error(f"Chyba při ověření: {e}")
|
||||
return False
|
||||
|
||||
def print_next_steps():
|
||||
"""Print next steps after migration"""
|
||||
print_header("Další kroky")
|
||||
print("""
|
||||
1. Restartujte aplikaci:
|
||||
pkill -f main.py
|
||||
python3 main.py
|
||||
|
||||
2. Přihlaste se pomocí nového admin hesla
|
||||
|
||||
3. Přejděte do "Správa účtů" pro přidání dalších UrNetwork účtů
|
||||
|
||||
4. Pokud něco nefunguje, obnovte zálohy:
|
||||
cp .env.backup .env
|
||||
cp transfer_stats.db.backup transfer_stats.db
|
||||
|
||||
Dokumentace: README_CZ.md
|
||||
""")
|
||||
|
||||
def main():
|
||||
print("""
|
||||
╔════════════════════════════════════════════════════════════╗
|
||||
║ UrNetwork Stats Dashboard - Migration Script v2.0 ║
|
||||
║ Migrace z single-account na multi-account strukturu ║
|
||||
╚════════════════════════════════════════════════════════════╝
|
||||
""")
|
||||
|
||||
print("\nTento skript provede následující:")
|
||||
print(" • Vytvoří zálohy .env a databáze")
|
||||
print(" • Přidá podporu pro více účtů")
|
||||
print(" • Nastaví administrátorské heslo")
|
||||
print(" • Migruje existující data")
|
||||
|
||||
response = input("\nPokračovat? (y/n): ").lower()
|
||||
if response != 'y':
|
||||
print("Migrace zrušena.")
|
||||
sys.exit(0)
|
||||
|
||||
# Run migration steps
|
||||
backup_files()
|
||||
|
||||
if not migrate_database():
|
||||
print_error("\nMigrace selhala při aktualizaci databáze!")
|
||||
print("Obnovte zálohy a zkuste to znovu.")
|
||||
sys.exit(1)
|
||||
|
||||
if not update_env_file():
|
||||
print_error("\nMigrace selhala při aktualizaci .env!")
|
||||
print("Obnovte zálohy a zkuste to znovu.")
|
||||
sys.exit(1)
|
||||
|
||||
if not verify_migration():
|
||||
print_warning("\nOvěření migrace selhalo, ale data by měla být OK")
|
||||
|
||||
print_next_steps()
|
||||
|
||||
print_header("Migrace úspěšně dokončena! 🎉")
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nMigrace přerušena uživatelem.")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print_error(f"\nNeočekávaná chyba: {e}")
|
||||
print("Obnovte zálohy pomocí:")
|
||||
print(" cp .env.backup .env")
|
||||
print(" cp transfer_stats.db.backup transfer_stats.db")
|
||||
sys.exit(1)
|
||||
Loading…
Add table
Add a link
Reference in a new issue