Files
dashboard-cpsp-executive/backend/apps/jobs/management/commands/bootstrap_admin.py
T
2026-09-08 16:17:29 +07:00

119 lines
4.1 KiB
Python

from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from apps.accounts.models import ApiKey, User
def ensure_bootstrap_user(
*,
user_login: str,
password: str,
status: str,
is_superuser: bool,
force_password: bool,
stdout,
) -> User:
user, created = User.objects.get_or_create(
user_login=user_login,
defaults={
"user_name": user_login,
"status": status,
"is_superuser": is_superuser,
},
)
if not created and user.status != status:
stdout.write(
f"Updating {user_login!r} status {user.status!r} → {status!r}"
)
should_set_password = created or not user.has_usable_password() or force_password
if should_set_password:
user.set_password(password)
user.status = status
user.is_superuser = is_superuser
user.save()
action = "Created" if created else "Updated password for"
stdout.write(f"{action} {status} user {user_login}")
else:
user.status = status
user.is_superuser = is_superuser
user.save(update_fields=["status", "is_superuser", "updated_at"])
stdout.write(f"User {user_login} already exists (password unchanged)")
return user
class Command(BaseCommand):
help = (
"Create production login accounts only (no demo sites/cycles/data). "
"BOOTSTRAP_ADMIN_* creates the break-glass superuser (ops dashboards + "
"user management; hidden from user lists). Optional BOOTSTRAP_STAFF_* creates a GM."
)
def add_arguments(self, parser):
parser.add_argument(
"--force-password",
action="store_true",
help="Reset password even when the user already has one",
)
@transaction.atomic
def handle(self, *args, **options):
force_password = options["force_password"]
admin_user_name = (settings.BOOTSTRAP_ADMIN_USER or "admin").strip()
admin_password = settings.BOOTSTRAP_ADMIN_PASSWORD or ""
if not admin_password:
raise CommandError(
"BOOTSTRAP_ADMIN_PASSWORD is required. Set it in .env before running bootstrap_admin."
)
admin = ensure_bootstrap_user(
user_login=admin_user_name,
password=admin_password,
status=User.STATUS_SUPERUSER,
is_superuser=True,
force_password=force_password,
stdout=self.stdout,
)
staff_user_name = (settings.BOOTSTRAP_STAFF_USER or "").strip()
staff_password = settings.BOOTSTRAP_STAFF_PASSWORD or ""
if staff_user_name:
if staff_user_name == admin_user_name:
raise CommandError(
"BOOTSTRAP_STAFF_USER must differ from BOOTSTRAP_ADMIN_USER."
)
if not staff_password:
raise CommandError(
"BOOTSTRAP_STAFF_PASSWORD is required when BOOTSTRAP_STAFF_USER is set."
)
ensure_bootstrap_user(
user_login=staff_user_name,
password=staff_password,
status=User.STATUS_GM,
is_superuser=False,
force_password=force_password,
stdout=self.stdout,
)
bootstrap_key = settings.BOOTSTRAP_API_KEY
if bootstrap_key:
api_key, _ = ApiKey.generate(admin, "bootstrap")
api_key.prefix = bootstrap_key[:8]
api_key.key_hash = ApiKey.hash_key(bootstrap_key)
api_key.save(update_fields=["prefix", "key_hash", "updated_at"])
self.stdout.write(f"Bootstrap API key installed (prefix={api_key.prefix})")
accounts = admin_user_name
if staff_user_name:
accounts = f"{admin_user_name}, {staff_user_name}"
self.stdout.write(
self.style.SUCCESS(
f"Bootstrap OK: login={accounts} "
"(no demo farm data — use Pengaturan to add sites/kandang/cycles)"
)
)