-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathupdate_from_2025.py
More file actions
138 lines (106 loc) · 3.59 KB
/
update_from_2025.py
File metadata and controls
138 lines (106 loc) · 3.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import json
import os
import subprocess
import sys
from pathlib import Path
from dotenv import load_dotenv
from sqlalchemy import create_engine, text
from flask import Flask
from app.models import db, User, Progress
load_dotenv(Path(__file__).resolve().parent / ".env")
POSTGRES_USER = os.getenv("POSTGRES_USER")
POSTGRES_PASSWORD = os.getenv("POSTGRES_PASSWORD")
POSTGRES_SERVER = os.getenv("POSTGRES_SERVER")
POSTGRES_PORT = os.getenv("POSTGRES_PORT")
DATABASE_NAME = os.getenv("DATABASE_NAME")
DATABASE_URL = (
f"postgresql://{POSTGRES_USER}:{POSTGRES_PASSWORD}"
f"@{POSTGRES_SERVER}:{POSTGRES_PORT}/{DATABASE_NAME}"
)
def main():
admin_id = check_args()
engine = create_engine(DATABASE_URL)
old_rows = fetch_old_progress(engine)
drop_tables(engine)
run_setup(admin_id)
migrate_user_data(old_rows)
def check_args():
if len(sys.argv) != 2:
sys.exit(
"\nPlease include your administrator Discord ID.\n"
"Usage: python update.py <admin_discord_user_id>"
)
return sys.argv[1].strip()
def fetch_old_progress(engine):
with engine.begin() as conn:
result = conn.execute(text("SELECT * FROM progress"))
rows = [dict(row._mapping) for row in result]
print(f"Fetched {len(rows)} old progress rows.")
return rows
def drop_tables(engine):
with engine.begin() as conn:
result = conn.execute(
text(
"""
SELECT tablename
FROM pg_tables
WHERE schemaname = 'public'
"""
)
)
tables = [row[0] for row in result]
if not tables:
print("No tables to drop.")
return
print(f"Dropping {len(tables)} table(s): {', '.join(tables)}")
for table in tables:
conn.execute(text(f'DROP TABLE "{table}" CASCADE'))
def run_setup(admin_id: str):
print("Running setup.py...\n")
subprocess.run(
[sys.executable, "setup.py", admin_id],
check=True,
)
def migrate_user_data(old_rows):
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = DATABASE_URL
db.init_app(app)
def parse(val):
if val is None:
return [False, False]
if isinstance(val, str):
return json.loads(val)
return val
skipped = 0
migrated = 0
with app.app_context():
for row in old_rows:
if all(parse(row.get(f"c{i}")) == [False, False] for i in range(1, 11)):
skipped += 1
continue
discord_id = row["user_id"]
user = User.query.filter_by(user_id=discord_id).one_or_none()
if not user:
user = User(
user_id=discord_id, # type: ignore
name=row.get("name", ""), # type: ignore
github=row.get("github", ""), # type: ignore
)
db.session.add(user)
db.session.flush()
progress = Progress(
user_id=user.id, # type: ignore
year="2025", # type: ignore
**{f"c{i}": parse(row.get(f"c{i}")) for i in range(1, 11)},
)
db.session.add(progress)
migrated += 1
db.session.commit()
print(f"Migrated: {migrated}")
print(f"Skipped (no progress): {skipped}")
if __name__ == "__main__":
main()
print(
"Database update and setup complete.\nAfter logging in with your administrator account, "
"go to the Admin dashboard (/admin) to customize this app for your server."
)