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_name: str, password: str, status: str, is_staff: bool, is_superuser: bool, force_password: bool, stdout, ) -> User: user, created = User.objects.get_or_create( user_name=user_name, defaults={ "display_name": user_name, "status": status, "is_staff": is_staff, "is_superuser": is_superuser, }, ) if not created and user.status != status: raise CommandError( f"User {user_name!r} already exists with status {user.status!r}; " f"cannot bootstrap as {status!r}" ) should_set_password = created or not user.has_usable_password() or force_password if not (user.display_name or "").strip(): user.display_name = user_name if should_set_password: user.set_password(password) user.status = status user.is_staff = is_staff user.is_superuser = is_superuser user.save() action = "Created" if created else "Updated password for" stdout.write(f"{action} {status} user {user_name}") else: user.status = status user.is_staff = is_staff user.is_superuser = is_superuser user.save( update_fields=["display_name", "status", "is_staff", "is_superuser", "updated_at"] ) stdout.write(f"User {user_name} already exists (password unchanged)") return user class Command(BaseCommand): help = ( "Create production login accounts only (no demo sites/cycles/data). " "Uses BOOTSTRAP_ADMIN_* and optional BOOTSTRAP_STAFF_* from settings." ) 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_name=admin_user_name, password=admin_password, status=User.STATUS_SUPERADMIN, is_staff=True, 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_name=staff_user_name, password=staff_password, status=User.STATUS_ACTIVE, is_staff=True, is_superuser=False, force_password=force_password, stdout=self.stdout, ) bootstrap_key = settings.SITE_API_KEY if bootstrap_key: api_key, _ = ApiKey.generate(admin, "site") 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"Site 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)" ) )