feat(main): main

This commit is contained in:
2026-03-20 15:00:24 -04:00
parent af3076342a
commit c9718c5483
30 changed files with 2513 additions and 559 deletions

View File

@@ -0,0 +1,92 @@
"""
Bootstrap service — idempotent startup initialisation.
Ensures a default media library exists as soon as the first user is available.
Called from three places:
1. AppConfig.ready() every server start (DB already populated)
2. post_migrate signal after `manage.py migrate` runs
3. auth.setup_admin endpoint immediately after the first user is created
"""
import logging
logger = logging.getLogger(__name__)
DEFAULT_LIBRARY_NAME = "Default Library"
# One-shot flag: after the first request triggers the bootstrap, disconnect
# the signal so we don't repeat the DB check on every subsequent request.
_startup_bootstrap_done = False
def ensure_default_library():
"""
Create a default media library if none exists yet.
Idempotent — safe to call multiple times; does nothing when a library
already exists. Returns the newly-created Library, or None if no action
was taken (either a library already exists, or no users exist yet to be
the owner).
"""
from core.models import Library, AppUser
if Library.objects.exists():
return None # Already bootstrapped
# Need an owner — prefer the first superuser, fall back to any user.
owner = (
AppUser.objects.filter(is_superuser=True).order_by("date_joined").first()
or AppUser.objects.order_by("date_joined").first()
)
if owner is None:
# No users yet — setup_admin will call us again once the first user exists.
logger.debug("ensure_default_library: no users yet, skipping.")
return None
library = Library.objects.create(
owner_user=owner,
name=DEFAULT_LIBRARY_NAME,
visibility="public",
description=(
"Default media library. "
"Add media sources here to start building your channels."
),
)
logger.info(
"Bootstrap: created default library '%s' (id=%d) owned by '%s'.",
library.name,
library.id,
owner.username,
)
return library
# ---------------------------------------------------------------------------
# Signal handlers — wired up in CoreConfig.ready()
# ---------------------------------------------------------------------------
def _on_post_migrate(sender, **kwargs):
"""Run bootstrap after every successful migration."""
try:
ensure_default_library()
except Exception as exc: # pragma: no cover
logger.warning("ensure_default_library failed in post_migrate: %s", exc)
def _on_first_request(sender, **kwargs):
"""
One-shot: run bootstrap on the very first HTTP request after server start.
Disconnects itself immediately so subsequent requests pay zero overhead.
"""
global _startup_bootstrap_done
if _startup_bootstrap_done:
return
_startup_bootstrap_done = True
from django.core.signals import request_started
request_started.disconnect(_on_first_request)
try:
ensure_default_library()
except Exception as exc: # pragma: no cover
logger.warning("ensure_default_library failed on first request: %s", exc)