fashionistar-celery-queues / scripts /create_superuser.py
FASHIONISTAR CI/CD
🔄 Celery Queues Deploy: 4aae6106b1530c3cc7d7d64f5e3c3e1d5015691d [GitHub Actions]
27c799c
Raw
History Blame
4.35 kB
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
scripts/create_superuser.py
Non-interactive UnifiedUser superuser creation helper.
Usage (via Makefile):
make su EMAIL=admin@example.com PASS=MySecret2026!
make su # uses defaults
Usage (direct):
DJANGO_SETTINGS_MODULE=backend.config.development
venv/Scripts/python scripts/create_superuser.py [email] [password]
Logic:
1. If a UnifiedUser exists for that email (even soft-deleted) ->
RESTORE it, reset to superuser, update password.
2. If no user exists -> CREATE a fresh superuser.
Exit codes: 0 = success, 1 = error
"""
from __future__ import annotations
import io
import os
import sys
# -----------------------------------------------------------
# Windows UTF-8 fix: cp1252 terminals reject non-ASCII chars
# This is a no-op on Linux/Mac (already UTF-8).
# -----------------------------------------------------------
if getattr(sys.stdout, 'encoding', 'utf-8').lower() != 'utf-8':
try:
sys.stdout = io.TextIOWrapper(
sys.stdout.buffer, encoding='utf-8', errors='replace'
)
except Exception:
pass
if getattr(sys.stderr, 'encoding', 'utf-8').lower() != 'utf-8':
try:
sys.stderr = io.TextIOWrapper(
sys.stderr.buffer, encoding='utf-8', errors='replace'
)
except Exception:
pass
# -----------------------------------------------------------
# Bootstrap Django
# -----------------------------------------------------------
def _bootstrap() -> None:
if not os.environ.get('DJANGO_SETTINGS_MODULE'):
os.environ['DJANGO_SETTINGS_MODULE'] = 'backend.config.development'
root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if root not in sys.path:
sys.path.insert(0, root)
import django
django.setup()
_bootstrap()
# -----------------------------------------------------------
# Models (safe to import after django.setup())
# -----------------------------------------------------------
from apps.authentication.models import UnifiedUser # noqa: E402
def ok(msg: str) -> None:
print(f"[OK] {msg}")
def warn(msg: str) -> None:
print(f"[WARN] {msg}")
def err(msg: str) -> None:
print(f"[ERROR] {msg}", file=sys.stderr)
def create_or_restore_superuser(
email: str = 'admin@fashionistar.io',
password: str = 'FashionAdmin2026!',
) -> int:
"""Create or restore a UnifiedUser superuser. Returns 0/1."""
try:
qs = UnifiedUser.objects.all_with_deleted().filter(email=email)
if qs.exists():
user = qs.first()
was_deleted = user.is_deleted
user.is_deleted = False
user.deleted_at = None
user.is_superuser = True
user.is_staff = True
user.is_verified = True
user.is_active = True
user.role = 'admin'
# Clear any stale/invalid avatar URLs so full_clean() doesn't reject
if user.avatar and not user.avatar.startswith(('http://', 'https://')):
user.avatar = ''
user.set_password(password)
user.save(using='default')
action = 'Restored soft-deleted' if was_deleted else 'Updated existing'
ok(f"{action} superuser: {user.email} | {user.member_id}")
else:
user = UnifiedUser.objects.create_superuser(
email=email,
password=password,
role='admin',
)
ok(f"Created new superuser: {user.email} | {user.member_id}")
# Verify login works
from django.contrib.auth import authenticate
auth_user = authenticate(None, username=email, password=password)
if auth_user:
ok(f"Login verified: {auth_user.email}")
else:
warn("User saved but authenticate() returned None. Check AUTHENTICATION_BACKENDS.")
return 0
except Exception as exc:
err(f"Failed: {exc}")
import traceback
traceback.print_exc()
return 1
if __name__ == '__main__':
_email = sys.argv[1] if len(sys.argv) > 1 and sys.argv[1] else 'admin@fashionistar.io'
_password = sys.argv[2] if len(sys.argv) > 2 and sys.argv[2] else 'FashionAdmin2026!'
sys.exit(create_or_restore_superuser(_email, _password))