Remove OnboardingRequirement.order; restrict checklist actions to admin/MEMBER_ADMIN

Every active requirement blocks equally and there's no set order to complete
them in, so the configurable "order" field (and its ordering-by-number) is
gone -- requirements list alphabetically now, both in the admin UI and the
Onboarding requirements settings page.

Also closes a real permission gap found while checking this: marking a
checklist item complete, bypassing it, or reopening it (management/views.py's
MemberRequirementCompleteView/BypassView/IncompleteView) was open to *any*
staff member with page access, not just admin/MEMBER_ADMIN, despite the
member detail page's own Documents card implying otherwise. Switched all
three to MemberAdminRequiredMixin and hid the corresponding buttons/dialog
from anyone who can't use them. The Sign-up page's Bypass action was already
admin-only end to end (the whole page is ClubAdminRequiredMixin-gated), so
no change in practice there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
This commit is contained in:
2026-08-20 09:27:05 +02:00
parent 224a3fe4ed
commit 45380dc282
10 changed files with 101 additions and 45 deletions

View File

@@ -3282,11 +3282,13 @@ def _current_membership_or_404(request, member_pk):
return membership
class MemberRequirementCompleteView(ClubStaffRequiredMixin, View):
"""Mark one checklist item done for one membership -- any staff, not just
admins (same visibility as the rest of a member's profile), can record that
a document came in. Reachable from the member detail page's Documents tab
(the default fallback) and from the admin-only Sign-up page (via `next`)."""
class MemberRequirementCompleteView(MemberAdminRequiredMixin, View):
"""Mark one checklist item done for one membership -- admin/MEMBER_ADMIN
only, same gate as the rest of people management (a plain coach can see a
member's checklist on their profile, per ClubStaffRequiredMixin's read
access there, but not touch it). Reachable from the member detail page's
Documents tab (the default fallback) and from the admin-only Sign-up page
(via `next`)."""
def post(self, request, pk, requirement_pk):
membership = _current_membership_or_404(request, pk)
@@ -3302,11 +3304,11 @@ class MemberRequirementCompleteView(ClubStaffRequiredMixin, View):
return _redirect_next_or(request, reverse("management:member_detail", args=[membership.member_id]))
class MemberRequirementBypassView(ClubStaffRequiredMixin, View):
class MemberRequirementBypassView(MemberAdminRequiredMixin, View):
"""Confirm one checklist item isn't needed for this member (e.g. they already
have a recent photo on file) -- see club.services.onboarding.mark_bypassed.
Same visibility as MemberRequirementCompleteView; bypassing isn't a bigger
deal than completing, it's just a different reason the item stops blocking
Same gate as MemberRequirementCompleteView; bypassing isn't a bigger deal
than completing, it's just a different reason the item stops blocking
anything."""
def post(self, request, pk, requirement_pk):
@@ -3323,7 +3325,10 @@ class MemberRequirementBypassView(ClubStaffRequiredMixin, View):
return _redirect_next_or(request, reverse("management:member_detail", args=[membership.member_id]))
class MemberRequirementIncompleteView(ClubStaffRequiredMixin, View):
class MemberRequirementIncompleteView(MemberAdminRequiredMixin, View):
"""Reopen a checklist item -- same admin/MEMBER_ADMIN gate as the other
two mutating requirement views above."""
def post(self, request, pk, requirement_pk):
membership = _current_membership_or_404(request, pk)
requirement = get_object_or_404(OnboardingRequirement.objects.filter(club=request.club), pk=requirement_pk)