Skip to content

Bug: Fix and Align Permission System Across Tickets and Talk Components #1031

@mariobehling

Description

@mariobehling

Permission handling is inconsistent between the Tickets and Talk components.

In the Tickets component, users with Site Admin rights can activate Admin Mode as expected.
However, when moving to the Talk component, an info message appears claiming that the user has superuser rights, even though they are not Django superusers.

This indicates that the permission system is not aligned between components.
Site Admins should have the same level of access in both components, and standard users should remain standard users.
Superuser status should only apply to actual Django superusers (is_superuser=True).

Goal

Unify the role model, checks, and UI indicators so that permissions behave identically across all Eventyay components.

  • Site Admins (platform admins) in Tickets must be recognized as Site Admins in Talk.
  • Standard users remain standard users in both components.
  • The system should not conflate Site Admins with Django superusers.
  • Permission checks, role handling, and admin mode toggling must use the same logic and helpers across components.

Expected Behavior

  1. Establish a single shared source of truth for roles in eventyay-common:

    • UserRole.SITE_ADMIN
    • UserRole.ORGANIZER
    • UserRole.STANDARD_USER
  2. Both Tickets and Talk must use the same helper functions to determine:

    • Whether a user is a site admin
    • Whether a user is a superuser
    • Whether a user is an organizer admin
  3. The UI should show:

    • “Admin Mode” toggle only for site admins (and organizer admins where appropriate)
    • “Superuser” banner only for true Django superusers

Steps to Reproduce (Current)

  1. Log in as a Site Admin (not a Django superuser).
  2. Go to Tickets → Admin Mode toggle appears correctly.
  3. Go to Talk → An info message appears stating the user has superuser rights.

The behavior differs, and permission messages are inconsistent.

Technical Details and Implementation Plan

Relevant File Locations

Talk:

  • app/eventyay/orga/views/*.py (view-level permission checks)
  • app/eventyay/orga/templates/orga/** (banner and admin messages)
  • app/eventyay/common/context_processors.py (permission context)
  • app/eventyay/orga/templatetags/** (template permission helpers if any)

Tickets (reference for correct behavior):

  • app/eventyay/base/views/**
  • app/eventyay/**/templates/** where “Admin Mode” toggle logic exists

To identify all locations:

rg -n "(is_superuser|is_staff|Admin Mode|superuser)" app/eventyay -S
rg -n "(site_admin|siteadmin|role.*admin)" app/eventyay -S

Shared Helper Module

Create a shared module in app/eventyay/common/auth/permissions.py:

from django.contrib.auth.models import Group

SITE_ADMIN_GROUP = "site_admin"

def is_superuser(user):
    return bool(user and user.is_authenticated and user.is_superuser)

def is_site_admin(user):
    if not (user and user.is_authenticated):
        return False
    try:
        return user.groups.filter(name=SITE_ADMIN_GROUP).exists()
    except Exception:
        return False

def is_organizer_admin(user, organizer=None):
    if not (user and user.is_authenticated and organizer):
        return False
    return organizer.admins.filter(pk=user.pk).exists()

If the project already uses User.is_site_admin, use that field in is_site_admin(user) instead of group logic.

Shared Context Processor

Add a context processor to inject permission flags into templates:

app/eventyay/common/context_processors.py

from .auth.permissions import is_site_admin, is_superuser

def permission_flags(request):
    u = getattr(request, "user", None)
    return {
        "is_site_admin": is_site_admin(u),
        "is_superuser": is_superuser(u),
    }

In settings.py for both components:

TEMPLATES[0]["OPTIONS"]["context_processors"] += [
    "eventyay.common.context_processors.permission_flags",
]

Template Updates

Before (Talk):

{% if request.user.is_superuser %}
  <div class="alert alert-info">You have superuser rights</div>
{% endif %}

After (Unified):

{% if is_site_admin %}
  <div class="alert alert-info">You have site admin rights</div>
{% endif %}
{% if is_superuser %}
  <div class="alert alert-warning">You are a Django superuser</div>
{% endif %}

View Updates

Replace direct permission checks:

if request.user.is_superuser:
    # old logic

With:

from eventyay.common.auth.permissions import is_site_admin, is_superuser

if is_site_admin(request.user) or is_superuser(request.user):
    # new logic

Admin Mode Toggle

Extract and centralize:

def can_toggle_admin_mode(user):
    from eventyay.common.auth.permissions import is_site_admin, is_superuser
    return is_site_admin(user) or is_superuser(user)

Use this in both Tickets and Talk headers or navigation bars.

Data Migration

Ensure all current site admins are recognized:

from django.contrib.auth.models import Group, User
g, _ = Group.objects.get_or_create(name="site_admin")
for u in User.objects.filter(is_staff=True):
    u.groups.add(g)

If using User.is_site_admin, verify it’s correctly set.

Testing Plan

Unit Tests

  • Test is_site_admin, is_superuser, and is_organizer_admin helpers.
  • Test anonymous, standard, site admin, and superuser cases.

Template Tests

  • Verify site admins see “Admin Mode” but not superuser banners.
  • Verify superusers see both banners.
  • Verify standard users see neither.

View Tests

  • Test that endpoints restricted to admins are accessible only by site admins and superusers.
  • Test that standard users receive 403 responses.

Integration and E2E Tests

  • Log in as site admin → Tickets shows Admin Mode, Talk shows Admin Mode, no superuser banner.
  • Log in as superuser → Both Admin Mode and superuser banner visible.
  • Log in as standard user → No admin controls in either component.

Acceptance Criteria

Permission Model:

  • Shared helper functions used consistently across components.
  • is_site_admin returns true only for platform admins.
  • is_superuser used exclusively for Django superusers.
  • Organizer-scoped checks aligned.

Tickets Component:

  • Admin Mode toggle appears correctly.
  • No behavioral regressions.

Talk Component:

  • Misleading superuser banner removed.
  • Admin Mode and rights consistent with Tickets.

Cross-Component:

  • UI and permission messages aligned.
  • No regressions for standard users.
  • Documentation updated.
Image Image

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions