#!/usr/bin/env python3 import argparse from pathlib import Path import sys ROOT = Path(__file__).resolve().parents[1] sys.path.insert(0, str(ROOT)) from main import engine, hash_password, init_db # noqa: E402 from sqlalchemy import text # noqa: E402 def main() -> int: parser = argparse.ArgumentParser(description="Create or update an intranet app user.") parser.add_argument("username") parser.add_argument("--password", required=True) parser.add_argument("--display-name", default="") parser.add_argument("--role", choices=["admin", "viewer"], default="viewer") parser.add_argument("--inactive", action="store_true") args = parser.parse_args() init_db() with engine.begin() as conn: conn.execute( text( """ INSERT INTO app_users ( username, password_hash, display_name, is_active, is_admin, created_at, updated_at ) VALUES ( :username, :password_hash, :display_name, :is_active, :is_admin, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP ) ON CONFLICT(username) DO UPDATE SET password_hash = excluded.password_hash, display_name = excluded.display_name, is_active = excluded.is_active, is_admin = excluded.is_admin, updated_at = CURRENT_TIMESTAMP """ ), { "username": args.username, "password_hash": hash_password(args.password), "display_name": args.display_name or args.username, "is_active": 0 if args.inactive else 1, "is_admin": 1 if args.role == "admin" else 0, }, ) user_id = conn.execute( text("SELECT id FROM app_users WHERE username = :username"), {"username": args.username}, ).scalar_one() role_id = conn.execute( text("SELECT id FROM app_roles WHERE role_key = :role_key"), {"role_key": args.role}, ).scalar_one() conn.execute(text("DELETE FROM app_user_roles WHERE user_id = :user_id"), {"user_id": user_id}) conn.execute( text( """ INSERT OR IGNORE INTO app_user_roles (user_id, role_id, created_at) VALUES (:user_id, :role_id, CURRENT_TIMESTAMP) """ ), {"user_id": user_id, "role_id": role_id}, ) print(f"ok: {args.username} ({args.role})") return 0 if __name__ == "__main__": raise SystemExit(main())