Files
mcma-backend/app/cli.py
T
2026-06-03 10:40:00 +03:00

78 lines
2.6 KiB
Python

"""Management CLI (``mcma``).
Commands:
* ``mcma version`` — print the backend version.
* ``mcma create-admin`` — create the first (or another) superuser. Private
instance, so there is no public sign-up — bootstrap
admins here (plan §11 step 3).
"""
import argparse
import asyncio
import getpass
from app import __version__
async def _create_admin(username: str, password: str) -> None:
from app.application.user_service import UserService
from app.core.security import Argon2PasswordHasher
from app.infrastructure.db import session_scope
from app.infrastructure.db.repositories import (
SqlAlchemyRefreshTokenRepository,
SqlAlchemyUserRepository,
)
async with session_scope() as session:
service = UserService(
users=SqlAlchemyUserRepository(session),
refresh_tokens=SqlAlchemyRefreshTokenRepository(session),
hasher=Argon2PasswordHasher(),
)
user = await service.create_user(username=username, password=password, is_superuser=True)
print(f"Created admin {user.username!r} ({user.id}).")
def _cmd_create_admin(args: argparse.Namespace) -> None:
username: str = args.username or input("Username: ").strip()
if not username:
raise SystemExit("Username is required.")
password: str = args.password or getpass.getpass("Password: ")
if len(password) < 8:
raise SystemExit("Password must be at least 8 characters.")
if args.password is None and getpass.getpass("Confirm password: ") != password:
raise SystemExit("Passwords do not match.")
from app.domain.errors import AlreadyExistsError
try:
asyncio.run(_create_admin(username, password))
except AlreadyExistsError as exc:
raise SystemExit(str(exc)) from exc
def main() -> None:
parser = argparse.ArgumentParser(prog="mcma", description="mcma-backend management CLI")
sub = parser.add_subparsers(dest="command")
sub.add_parser("version", help="Print the backend version")
admin = sub.add_parser("create-admin", help="Create a superuser")
admin.add_argument("username", nargs="?", help="Username (prompted if omitted)")
admin.add_argument(
"--password",
help="Password (prompted securely if omitted; avoid on shared shells)",
)
args = parser.parse_args()
if args.command == "version":
print(__version__)
elif args.command == "create-admin":
_cmd_create_admin(args)
else:
parser.print_help()
if __name__ == "__main__":
main()