Checkpoint: management app redesign, onboarding/signup workflow, and events calendar backend

Large uncommitted body of work accumulated across sessions on this branch --
committing as a checkpoint so it's tracked and future worktree-isolated agents
see the real codebase instead of a stale ancestor commit. Covers the
management app's dedicated Tailwind theme and templates, the club onboarding
requirement/signup workflow (club/services/onboarding.py, requirement/status
models, sign-up dashboard), fee/status auto-activation decoupling, referee
management, and the new events calendar grid service layer.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
This commit is contained in:
2026-08-19 23:34:43 +02:00
parent bff685966d
commit adf1120358
157 changed files with 20342 additions and 4008 deletions

View File

@@ -1,6 +1,8 @@
from io import StringIO
from unittest.mock import patch
from allauth.mfa.models import Authenticator
from celery import shared_task
from django.contrib.auth import get_user_model
from django.core.cache import cache
from django.core.management import call_command
@@ -10,7 +12,8 @@ from waffle import flag_is_active, get_waffle_flag_model
from club.models import Club
from .models import Maintenance
from .jobs import JOB_REGISTRY
from .models import JobRun, Maintenance
Flag = get_waffle_flag_model()
User = get_user_model()
@@ -259,3 +262,63 @@ class MaintenanceCommandTests(TestCase):
Maintenance.start()
self.run_command("migrate", "--check") # raises SystemExit only if migrations are pending
@shared_task(name="features.tests.succeed")
def _succeed_task():
return "did the thing"
@shared_task(name="features.tests.fail")
def _fail_task():
raise RuntimeError("boom")
@shared_task(name="features.tests.untracked")
def _untracked_task():
return "quiet"
class JobRunTests(TestCase):
"""The Celery signal wiring in features/signals.py, exercised against throwaway tasks
(module-level, like any real task -- Celery's registry gets confused if the same task
name is redefined per-test) rather than the real billing/club/events ones: what matters
here is that a JobRun row appears for anything in JOB_REGISTRY and only for that, not the
domain logic of any one scheduled job (each of those has its own tests alongside its
management command)."""
def setUp(self):
self.succeed_task, self.fail_task, self.untracked_task = _succeed_task, _fail_task, _untracked_task
patcher = patch.dict(JOB_REGISTRY, {"features.tests.succeed": {}, "features.tests.fail": {}})
patcher.start()
self.addCleanup(patcher.stop)
def test_a_successful_run_is_recorded(self):
# .apply() runs the task synchronously, in-process, regardless of
# CELERY_TASK_ALWAYS_EAGER -- exactly what the task_prerun/task_postrun signal
# handlers in features/signals.py are wired to react to either way.
self.succeed_task.apply()
run = JobRun.objects.get(name="features.tests.succeed")
self.assertEqual(run.status, JobRun.Status.SUCCESS)
self.assertEqual(run.detail, "did the thing")
self.assertEqual(run.error, "")
self.assertIsNotNone(run.started_at)
self.assertIsNotNone(run.finished_at)
def test_a_failed_run_is_recorded(self):
# A real worker never raises a task's exception back into whoever called .delay() --
# it's async, the caller is long gone by the time the task runs -- so eager mode
# doesn't either (CELERY_TASK_EAGER_PROPAGATES is left at its default False; see
# rosterchief/settings.py). The result carries FAILURE instead, same as production.
result = self.fail_task.apply()
self.assertEqual(result.state, "FAILURE")
run = JobRun.objects.get(name="features.tests.fail")
self.assertEqual(run.status, JobRun.Status.FAILURE)
self.assertIn("boom", run.error)
def test_a_task_outside_the_registry_is_not_tracked(self):
self.untracked_task.apply()
self.assertFalse(JobRun.objects.filter(name="features.tests.untracked").exists())