From f4c1124a82380ec11f734120800668f7be72c3c4 Mon Sep 17 00:00:00 2001 From: patrick Date: Fri, 4 Sep 2026 00:26:19 +0200 Subject: [PATCH] =?UTF-8?q?Sprint=208:=20Admin-Seed-Skript=20f=C3=BCr=20Er?= =?UTF-8?q?stinbetriebnahme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt --- backend/scripts/create_admin.py | 49 +++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 backend/scripts/create_admin.py diff --git a/backend/scripts/create_admin.py b/backend/scripts/create_admin.py new file mode 100644 index 0000000..7ae0aa0 --- /dev/null +++ b/backend/scripts/create_admin.py @@ -0,0 +1,49 @@ +"""Einmaliges Anlegen des ersten Administration-Benutzers (idempotent). + +Deployment-Regel (Prompt 19): nur Skript-Datei hier, Ausführung auf Zielsystem. + +Aufruf (im aktivierten venv auf dem Server): + + python -m scripts.create_admin --login admin --name "Administrator" --password "..." +""" + +from __future__ import annotations + +import argparse +import asyncio + +from sqlalchemy import select + +from app.core.security import hash_password +from app.db.session import SessionLocal +from app.models.auth import Benutzer, BenutzerRolle, RolleTyp + + +async def erstelle_admin(login: str, name: str, password: str, email: str | None) -> None: + async with SessionLocal() as db: + bestehender = (await db.execute(select(Benutzer).where(Benutzer.login == login))).scalar_one_or_none() + if bestehender is not None: + print(f"Übersprungen (Login existiert bereits): {login}") + return + + benutzer = Benutzer(name=name, login=login, passwort_hash=hash_password(password), email=email) + db.add(benutzer) + await db.flush() + db.add(BenutzerRolle(benutzer_id=benutzer.id, rolle=RolleTyp.administration)) + await db.commit() + print(f"Angelegt: {login} (id={benutzer.id}, Rolle administration)") + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument("--login", required=True) + parser.add_argument("--name", required=True) + parser.add_argument("--password", required=True) + parser.add_argument("--email", default=None) + argumente = parser.parse_args() + + asyncio.run(erstelle_admin(argumente.login, argumente.name, argumente.password, argumente.email)) + + +if __name__ == "__main__": + main()