fix: persist preview admin access

This commit is contained in:
mohamad
2026-10-29 04:00:21 +08:00
parent 641f4e6cee
commit cb54e96db6
5 changed files with 75 additions and 2 deletions
+19
View File
@@ -118,6 +118,25 @@ python manage.py ensure_superuser
python manage.py runserver python manage.py runserver
``` ```
### Persistent local preview without Docker
The local preview uses `instance/preview.sqlite3`, which survives server restarts and is
ignored by Git. Put the preview admin credentials in `instance/preview_admin.env`
(also ignored by Git):
```text
DJANGO_SUPERUSER_USERNAME=admin
DJANGO_SUPERUSER_EMAIL=admin@localhost
DJANGO_SUPERUSER_PASSWORD=your-local-password
DJANGO_SUPERUSER_SYNC_PASSWORD=False
```
Then start the preview with `./run_preview.sh`. It applies migrations and ensures the
admin account exists before starting the server. Existing passwords are preserved;
set `DJANGO_SUPERUSER_SYNC_PASSWORD=True` for one start only if you intentionally
need to reset the account password. This preview database is separate from the
PostgreSQL database used by Docker and production.
## Management commands ## Management commands
```bash ```bash
@@ -31,9 +31,10 @@ class Command(BaseCommand):
user.email = email user.email = email
user.is_staff = True user.is_staff = True
user.is_superuser = True user.is_superuser = True
user.is_active = True
user.set_password(password) user.set_password(password)
user.save( user.save(
update_fields=["email", "is_staff", "is_superuser", "password"] update_fields=["email", "is_staff", "is_superuser", "is_active", "password"]
) )
self.stdout.write( self.stdout.write(
self.style.SUCCESS( self.style.SUCCESS(
@@ -41,9 +42,16 @@ class Command(BaseCommand):
) )
) )
return return
fields_to_update = []
for field in ("is_staff", "is_superuser", "is_active"):
if not getattr(user, field):
setattr(user, field, True)
fields_to_update.append(field)
if fields_to_update:
user.save(update_fields=fields_to_update)
self.stdout.write( self.stdout.write(
self.style.SUCCESS( self.style.SUCCESS(
f"Admin '{username}' already exists; its password was preserved." f"Admin '{username}' is ready; its password was preserved."
) )
) )
return return
@@ -76,6 +76,24 @@ class EnsureSuperuserCommandTests(TestCase):
user.refresh_from_db() user.refresh_from_db()
self.assertTrue(user.check_password("changed-in-admin")) self.assertTrue(user.check_password("changed-in-admin"))
def test_existing_user_regains_admin_access_without_password_reset(self):
user = get_user_model().objects.create_user(
username="admin", email="admin@com2care.com", password="existing-password"
)
user.is_active = False
user.save(update_fields=["is_active"])
environment = {
"DJANGO_SUPERUSER_USERNAME": "admin",
"DJANGO_SUPERUSER_PASSWORD": "different-password",
"DJANGO_SUPERUSER_SYNC_PASSWORD": "False",
}
with patch.dict(os.environ, environment, clear=False):
call_command("ensure_superuser", verbosity=0)
user.refresh_from_db()
self.assertTrue(user.is_active and user.is_staff and user.is_superuser)
self.assertTrue(user.check_password("existing-password"))
def test_server_operator_can_explicitly_rotate_password(self): def test_server_operator_can_explicitly_rotate_password(self):
user = get_user_model().objects.create_superuser( user = get_user_model().objects.create_superuser(
username="admin", username="admin",
+10
View File
@@ -0,0 +1,10 @@
"""Persistent local preview database, separate from the production PostgreSQL database."""
from .development import * # noqa: F401,F403
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "instance" / "preview.sqlite3",
}
}
Executable
+18
View File
@@ -0,0 +1,18 @@
#!/bin/sh
set -eu
cd "$(dirname "$0")"
mkdir -p instance
if [ -f instance/preview_admin.env ]; then
set -a
. ./instance/preview_admin.env
set +a
fi
export DJANGO_SETTINGS_MODULE=config.settings.preview
PYTHON=${PYTHON:-venv/bin/python}
"$PYTHON" manage.py migrate --noinput
"$PYTHON" manage.py ensure_superuser
exec "$PYTHON" manage.py runserver 127.0.0.1:8000