from django.conf import settings from django.core.management import call_command from django.core.management.base import BaseCommand from django.db import transaction from apps.accounts.models import ApiKey, User from apps.farms.models import Site from apps.sync.models import CitySite # Every executive role + inactive, for local HQ demos. SEED_USERS = ( { # Break-glass: status=superuser (ops + Manajemen Akun). Hidden from user lists. "user_name": "admin", "password": "admin123", "status": User.STATUS_SUPERUSER, "is_superuser": True, }, { "user_name": "director", "password": "director123", "status": User.STATUS_DIRECTOR, }, { "user_name": "director_admin", "password": "directoradmin123", "status": User.STATUS_DIRECTOR_ADMIN, }, { "user_name": "buh", "password": "buh123", "status": User.STATUS_BUH, }, { "user_name": "bu_admin", "password": "buadmin123", "status": User.STATUS_BU_ADMIN, }, { "user_name": "gm", "password": "gm123", "status": User.STATUS_GM, "managed_by": "buh", }, { "user_name": "gm_admin", "password": "gmadmin123", "status": User.STATUS_GM_ADMIN, "managed_by": None, # not on BUH org chart; only GM requests/confirm }, { "user_name": "account_admin", "password": "accountadmin123", "status": User.STATUS_ACCOUNT_ADMIN, }, ) class Command(BaseCommand): help = ( "Seed all HQ executive role logins + API key, then Sukawarna Kandang 1 " "and Kandang 2 as default closed cycles (local mirror demo data). " "Removes legacy staff login if present." ) def _ensure_user(self, spec: dict, by_name: dict[str, User]) -> User: managed_by_name = spec.get("managed_by") managed_by = by_name.get(managed_by_name) if managed_by_name else None defaults = { "status": spec["status"], "is_superuser": spec.get("is_superuser", False), } if managed_by is not None: defaults["managed_by"] = managed_by user, created = User.objects.get_or_create( user_login=spec["user_name"], defaults={ **defaults, "user_name": spec["user_name"], }, ) user.status = spec["status"] user.is_superuser = spec.get("is_superuser", False) if managed_by is not None: user.managed_by = managed_by elif "managed_by" in spec: user.managed_by = None user.set_password(spec["password"]) user.save() role = spec["status"] if user.is_superuser: role = f"{role}+superuser" link = f", managed_by={managed_by.user_name}" if managed_by else "" action = "Created" if created else "Updated" self.stdout.write( f"{action} user {spec['user_name']} / {spec['password']} ({role}{link})" ) return user def _remove_legacy_staff(self, gm: User) -> None: staff = ( User.objects.filter(user_login="staff").first() or User.objects.filter(user_name="staff").first() ) if not staff: return moved_sites = Site.objects.filter(user=staff).update(user=gm) moved_cities = CitySite.objects.filter(registered_by=staff).update(registered_by=gm) ApiKey.objects.filter(user=staff).delete() staff.delete() self.stdout.write( self.style.WARNING( f"Removed legacy staff login " f"(reassigned sites={moved_sites}, city_sites={moved_cities} to gm)" ) ) @transaction.atomic def handle(self, *args, **options): by_name: dict[str, User] = {} for spec in SEED_USERS: user = self._ensure_user(spec, by_name) by_name[user.user_name] = user admin = by_name["admin"] gm = by_name["gm"] self._remove_legacy_staff(gm) bootstrap = settings.BOOTSTRAP_API_KEY if bootstrap: api_key, _raw_key = ApiKey.generate(admin, "bootstrap") api_key.prefix = bootstrap[:8] api_key.key_hash = ApiKey.hash_key(bootstrap) api_key.save(update_fields=["prefix", "key_hash", "updated_at"]) self.stdout.write(f"Bootstrap API key installed (prefix={api_key.prefix})") elif not ApiKey.objects.filter(user=admin).exists(): _api_key, raw_key = ApiKey.generate(admin, "seed") self.stdout.write(self.style.WARNING(f"Demo API key (save now): {raw_key}")) call_command("seed_sukawarna_kandang4") call_command("seed_sukawarna_kandang5") call_command("seed_iot_10min") self.stdout.write( self.style.SUCCESS( "Seed OK: all executive roles + Sukawarna cycles + IoT panels " "(Sukawarna owned by gm)" ) )