Source code for django_program.conference.management.commands.setup_groups

"""Management command to create default permission groups for conference staff."""

from typing import Any

from django.contrib.auth.models import Group, Permission
from django.core.management.base import BaseCommand

# All custom Conference permissions for granting to the organizer group.
_ALL_CONFERENCE_PERMS = [
    "view_dashboard",
    "manage_conference_settings",
    "view_program",
    "change_program",
    "view_registration",
    "change_registration",
    "view_commerce",
    "change_commerce",
    "view_badges",
    "change_badges",
    "view_sponsors",
    "change_sponsors",
    "view_bulk_purchases",
    "change_bulk_purchases",
    "view_finance",
    "change_finance",
    "view_reports",
    "export_reports",
    "view_checkin",
    "use_terminal",
    "view_overrides",
    "change_overrides",
]

_ALL_VIEW_CONFERENCE_PERMS = [
    p for p in _ALL_CONFERENCE_PERMS if (p.startswith("view_") or p == "export_reports") and p != "view_checkin"
]

# Mapping of group name -> list of (app_label, codename) permissions.
_GROUP_PERMISSIONS: dict[str, list[tuple[str, str]]] = {
    "Conference Organizer": [
        # Django CRUD on Conference model
        ("program_conference", "add_conference"),
        ("program_conference", "change_conference"),
        ("program_conference", "delete_conference"),
        ("program_conference", "view_conference"),
        # All custom Conference permissions
        *[("program_conference", p) for p in _ALL_CONFERENCE_PERMS],
        # Programs app
        ("program_programs", "view_activity"),
        ("program_programs", "manage_activity"),
        ("program_programs", "view_travel_grant"),
        ("program_programs", "review_travel_grant"),
        ("program_programs", "disburse_travel_grant"),
        ("program_programs", "review_receipt"),
    ],
    "Program Committee": [
        ("program_conference", "view_conference"),
        ("program_conference", "view_dashboard"),
        ("program_conference", "view_program"),
        ("program_conference", "change_program"),
        ("program_conference", "view_overrides"),
        ("program_conference", "change_overrides"),
    ],
    "Registration Manager": [
        ("program_conference", "view_conference"),
        ("program_conference", "view_dashboard"),
        ("program_conference", "view_registration"),
        ("program_conference", "change_registration"),
        ("program_conference", "view_commerce"),
        ("program_conference", "change_commerce"),
        ("program_conference", "view_badges"),
        ("program_conference", "change_badges"),
        ("program_conference", "view_checkin"),
        ("program_conference", "use_terminal"),
        ("program_conference", "view_bulk_purchases"),
        ("program_conference", "change_bulk_purchases"),
    ],
    "Finance Team": [
        ("program_conference", "view_conference"),
        ("program_conference", "view_dashboard"),
        ("program_conference", "view_finance"),
        ("program_conference", "change_finance"),
        ("program_conference", "view_reports"),
        ("program_conference", "export_reports"),
        ("program_conference", "view_registration"),
        ("program_conference", "view_commerce"),
    ],
    "Travel Grant Reviewer": [
        ("program_conference", "view_conference"),
        ("program_conference", "view_dashboard"),
        ("program_programs", "view_travel_grant"),
        ("program_programs", "review_travel_grant"),
        ("program_programs", "review_receipt"),
    ],
    "Sponsor Manager": [
        ("program_conference", "view_conference"),
        ("program_conference", "view_dashboard"),
        ("program_conference", "view_sponsors"),
        ("program_conference", "change_sponsors"),
        ("program_conference", "view_bulk_purchases"),
        ("program_conference", "change_bulk_purchases"),
    ],
    "Check-in Staff": [
        ("program_conference", "view_conference"),
        ("program_conference", "view_dashboard"),
        ("program_conference", "view_checkin"),
    ],
    "Activity Organizer": [
        ("program_conference", "view_conference"),
        ("program_conference", "view_dashboard"),
        ("program_programs", "view_activity"),
        ("program_programs", "manage_activity"),
    ],
    "Reports Viewer": [
        ("program_conference", "view_conference"),
        ("program_conference", "view_dashboard"),
        ("program_conference", "view_reports"),
    ],
    "Read-Only Staff": [
        ("program_conference", "view_conference"),
        *[("program_conference", p) for p in _ALL_VIEW_CONFERENCE_PERMS],
        ("program_programs", "view_activity"),
        ("program_programs", "view_travel_grant"),
    ],
}


[docs] class Command(BaseCommand): """Create default permission groups for conference staff roles. Creates ten groups with granular permissions: * **Conference Organizer** -- full access to all conference management * **Program Committee** -- program content and Pretalx overrides * **Registration Manager** -- attendees, orders, commerce, badges, check-in * **Finance Team** -- financial dashboard, expenses, reports, read-only commerce * **Travel Grant Reviewer** -- travel grant review and receipt approval * **Sponsor Manager** -- sponsor and bulk purchase management * **Check-in Staff** -- check-in dashboard access only * **Activity Organizer** -- activity and signup management * **Reports Viewer** -- read-only access to reports dashboard * **Read-Only Staff** -- view-only access to all sections Safe to run multiple times; existing groups are updated with the defined permission set. """ help = "Create default permission groups for conference staff roles."
[docs] def handle(self, *args: Any, **options: Any) -> None: """Execute the setup_groups command. Args: *args: Positional arguments (unused). **options: Parsed command-line options. """ verbosity = options.get("verbosity", 1) for group_name, perm_specs in _GROUP_PERMISSIONS.items(): group, created = Group.objects.get_or_create(name=group_name) verb = "Created" if created else "Updated" perm_set = set(perm_specs) app_labels = {app for app, _ in perm_set} permissions = Permission.objects.filter( content_type__app_label__in=app_labels, ) matched = [p for p in permissions if (p.content_type.app_label, p.codename) in perm_set] missing = perm_set - {(p.content_type.app_label, p.codename) for p in matched} group.permissions.set(matched) if missing and verbosity > 0: labels = ", ".join(f"{app}.{code}" for app, code in sorted(missing)) self.stdout.write(self.style.WARNING(f" Warning: {group_name} missing permissions: {labels}")) if verbosity > 0: self.stdout.write(self.style.SUCCESS(f" {verb} group '{group_name}' with {len(matched)} permissions")) if verbosity > 0: self.stdout.write(self.style.SUCCESS("\nDone."))