"""scripts/create_admin.py — create or reset the admin user. Usage: python scripts/create_admin.py # interactive prompts Or supply via env vars (non-interactive, useful for deploy scripts): INITIAL_ADMIN_EMAIL=you@example.com INITIAL_ADMIN_PASSWORD= INITIAL_ADMIN_NAME="Your Name" python scripts/create_admin.py If the user already exists, you'll be prompted before any change is made. """ from __future__ import annotations import os import sys from getpass import getpass from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT)) from web.db import Base, SessionLocal, engine # noqa: E402 from web import models # noqa: E402, F401 ← registers tables def _prompt(prompt: str, *, default: str | None = None) -> str: suffix = f" [{default}]" if default else "" val = input(f"{prompt}{suffix}: ").strip() return val or (default or "") def main() -> int: # Ensure tables exist (idempotent — safe even if init_db.py was run). Base.metadata.create_all(engine) email = os.environ.get("INITIAL_ADMIN_EMAIL") password = os.environ.get("INITIAL_ADMIN_PASSWORD") name = os.environ.get("INITIAL_ADMIN_NAME") if not email: email = _prompt("Admin email") if not email or "@" not in email: print("ERROR: a valid email is required.") return 1 email = email.lower() if not name: name = _prompt("Admin name", default="Administrator") if not password: password = getpass("Admin password: ") confirm = getpass("Confirm password: ") if password != confirm: print("ERROR: passwords do not match.") return 1 if len(password) < 8: print("ERROR: password must be at least 8 characters.") return 1 db = SessionLocal() try: existing = db.query(models.User).filter_by(email=email).first() if existing: print(f"User {email!r} already exists (id={existing.id}, admin={existing.is_admin}).") answer = input("Reset password and grant admin? [y/N] ").strip().lower() if answer != "y": print("Aborted. No changes made.") return 0 existing.set_password(password) existing.name = name or existing.name existing.is_admin = True existing.is_active = True db.commit() print(f"Updated user {email!r} → admin, active, password reset.") return 0 user = models.User( email=email, name=name or "Administrator", is_admin=True, is_active=True, ) user.set_password(password) db.add(user) db.commit() print(f"Created admin user {email!r} (id={user.id}).") print(f"Sign in at the dashboard's /login page.") return 0 finally: db.close() if __name__ == "__main__": sys.exit(main())