Skip to content

Conversation

@Saksham-Sirohi
Copy link
Contributor

@Saksham-Sirohi Saksham-Sirohi commented Nov 25, 2025

Fixes #921,#919

Summary by Sourcery

Unify organizer administration by moving all team and permission management into the organizer settings page and deprecating legacy team-specific views and URLs.

New Features:

  • Introduce a tabbed organizer management page that combines general settings with team creation and permission management in a single interface.
  • Expose inline management of team members, invites, and API tokens directly from the organizer settings view.

Bug Fixes:

  • Ensure team-related operations respect scoping and transaction boundaries while logging detailed change data for auditing.

Enhancements:

  • Refine organizer update permissions so general settings and team management are controlled independently.
  • Add reusable permission fieldset partials for team forms to keep organizer and team UIs consistent.
  • Improve navigation links and redirects so all team-related entry points lead to the unified organizer page and highlight its permissions section.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Nov 25, 2025

Reviewer's Guide

Unifies organizer team management into the common organizer edit page by embedding full team CRUD, member/invite/token handling, and redirects from legacy team URLs, while updating navigation and templates to point to the new unified interface.

Sequence diagram for unified team creation on organizer page

sequenceDiagram
    actor Admin
    participant Browser
    participant OrganizerUpdateView as OrganizerUpdate
    participant TeamForm
    participant DB as Database
    participant Messages

    Admin->>Browser: Click Create team (on Teams tab)
    Browser->>OrganizerUpdateView: POST /organizer/<slug>/edit, team_action=create, form data (TeamForm)

    OrganizerUpdateView->>OrganizerUpdateView: post()
    OrganizerUpdateView->>OrganizerUpdateView: can_manage_teams check
    alt has team permissions
        OrganizerUpdateView->>OrganizerUpdateView: _handle_team_create()
        OrganizerUpdateView->>TeamForm: __init__(data, organizer, prefix=team-create)
        OrganizerUpdateView->>TeamForm: is_valid()
        alt form valid
            OrganizerUpdateView->>DB: transaction.atomic begin
            OrganizerUpdateView->>TeamForm: save(commit=False)
            TeamForm-->>OrganizerUpdateView: team (unsaved)
            OrganizerUpdateView->>DB: save team
            OrganizerUpdateView->>TeamForm: save_m2m()
            OrganizerUpdateView->>DB: add current user to team.members
            OrganizerUpdateView->>DB: team.log_action(eventyay.team.created, data)
            OrganizerUpdateView->>DB: transaction.atomic commit
            OrganizerUpdateView->>Messages: success("The team has been created…")
            OrganizerUpdateView->>OrganizerUpdateView: _teams_tab_url(team.pk)
            OrganizerUpdateView-->>Browser: HTTP 302 redirect to ?section=teams&team=<id>
        else form invalid
            OrganizerUpdateView->>Messages: error("Something went wrong…")
            OrganizerUpdateView->>OrganizerUpdateView: _team_create_form_override = form
            OrganizerUpdateView->>OrganizerUpdateView: _render_with_team_errors(section=teams)
            OrganizerUpdateView->>OrganizerUpdateView: _build_unbound_organizer_form()
            OrganizerUpdateView->>OrganizerUpdateView: get_context_data(form)
            OrganizerUpdateView-->>Browser: Render organizer page with errors
        end
    else no team permissions
        OrganizerUpdateView-->>Browser: PermissionDenied (403)
    end
Loading

Class diagram for updated organizer and team management views

classDiagram
    class OrganizerUpdate {
        +object Organizer
        +can_edit_general_info bool
        +can_manage_teams bool
        -_team_form_overrides dict
        -_team_create_form_override TeamForm
        -_forced_section str
        -_selected_team_override str
        -_team_queryset QuerySet
        +dispatch(request, *args, **kwargs)
        +post(request, *args, **kwargs)
        +get_context_data(**kwargs)
        +get_form(form_class)
        +form_valid(form)
        +get_success_url() str
        -_get_team_queryset() QuerySet
        -_get_team_create_form() TeamForm
        -_build_team_panel(team, selected_team_id) dict
        -_team_form_prefix(team) str
        -_invite_form_prefix(team) str
        -_token_form_prefix(team) str
        -_set_team_override(team_id, form, invite_form, token_form)
        -_teams_tab_url(team_id, section) str
        -_build_unbound_organizer_form() OrganizerForm
        -_render_with_team_errors(section)
        -_get_team_from_post() Team
        -_handle_team_create()
        -_handle_team_update()
        -_handle_team_members()
        -_handle_team_tokens()
        -_handle_team_delete()
        -_send_invite(instance)
        -_can_delete_team(team) bool
        -_build_changed_data_dict(form, obj) dict
        -_collect_team_change_data(team, form) dict
    }

    class UnifiedTeamManagementRedirectMixin {
        +dispatch(request, *args, **kwargs)
    }

    class TeamListView {
        +get_queryset() QuerySet
    }

    class TeamMemberView {
    }

    class TeamCreateView {
    }

    class TeamUpdateView {
    }

    class TeamDeleteView {
    }

    class Team {
        +name str
        +members ManyToMany(User)
        +invites RelatedManager(TeamInvite)
        +tokens RelatedManager(TeamAPIToken)
        +active_tokens QuerySet
        +memcount int
        +eventcount int
        +invcount int
        +all_events bool
        +log_action(action, user, data)
    }

    class Organizer {
        +name str
        +slug str
        +teams RelatedManager(Team)
    }

    class TeamForm {
        +name
        +can_create_events
        +can_manage_gift_cards
        +can_change_teams
        +can_change_organizer_settings
        +all_events
        +limit_events
        +can_change_event_settings
        +can_change_items
        +can_view_orders
        +can_change_orders
        +can_checkin_orders
        +can_view_vouchers
        +can_change_vouchers
        +can_change_submissions
        +is_reviewer
        +force_hide_speaker_names
        +limit_tracks
    }

    class InviteForm {
        +user
    }

    class TokenForm {
        +name
    }

    class TeamInvite {
        +email str
        +team Team
        +token str
    }

    class TeamAPIToken {
        +name str
        +token str
        +active bool
        +team Team
    }

    class User {
        +email str
        +fullname str
        +require_2fa bool
        +has_organizer_permission(organizer, permission, request) bool
    }

    OrganizerUpdate --> Organizer : edits
    OrganizerUpdate --> Team : manages teams
    OrganizerUpdate --> TeamForm : uses
    OrganizerUpdate --> InviteForm : uses
    OrganizerUpdate --> TokenForm : uses
    OrganizerUpdate --> TeamInvite : creates
    OrganizerUpdate --> TeamAPIToken : creates
    OrganizerUpdate --> User : adds or removes members

    UnifiedTeamManagementRedirectMixin <|-- TeamListView
    UnifiedTeamManagementRedirectMixin <|-- TeamMemberView
    UnifiedTeamManagementRedirectMixin <|-- TeamCreateView
    UnifiedTeamManagementRedirectMixin <|-- TeamUpdateView
    UnifiedTeamManagementRedirectMixin <|-- TeamDeleteView

    Organizer o-- Team : has many
    Team o-- User : members
    Team o-- TeamInvite : invites
    Team o-- TeamAPIToken : tokens
Loading

File-Level Changes

Change Details Files
Extend OrganizerUpdate view to handle all team management actions inline (create, update permissions, manage members/invites, manage API tokens, delete) and provide rich context for the new tabbed UI.
  • Add permission helpers and dispatch initialization for team-related state in OrganizerUpdate
  • Handle POSTed team_action values to route to specific team management handlers with permission checks
  • Introduce helpers to load and cache team querysets, construct team panels, and handle form overrides for error re-rendering
  • Implement handler methods for creating, updating, deleting teams, and managing team members, invites, and API tokens, including logging and transactional safety
  • Add utility methods for building success/error redirects, building change-data payloads (including ManyToMany fields), and sending invite emails
app/eventyay/eventyay_common/views/organizer.py
Replace the simple organizer edit template with a tabbed unified admin page that combines organizer general settings with team creation and team permission management, using shared permission fieldset partials.
  • Introduce nav tabs for General, Create Team, and Manage Team Permissions, with active tab driven by context
  • Wire the General tab to the existing organizer form, preserving general info and link to full settings
  • Add a Teams tab with an inline create-team form using the shared permissions partial
  • Add a Permissions tab that renders expandable panels per team with embedded forms for permissions, members/invites, and API tokens, plus inline delete
  • Render stateful selection/expansion of a specific team panel and handle empty-team state messaging
app/eventyay/eventyay_common/templates/eventyay_common/organizers/edit.html
Introduce a shared permissions fieldset partial for team forms and reuse it in both unified organizer page and legacy team-edit template.
  • Create a new _permissions_fieldsets.html partial that renders all team permission-related fields in logical grouped fieldsets
  • Replace inline fieldsets in the legacy team_edit template with an include of the new partial
  • Include review-settings section with dynamic toggle wiring for reviewer-specific fields
app/eventyay/eventyay_common/templates/eventyay_common/organizers/teams/_permissions_fieldsets.html
app/eventyay/eventyay_common/templates/eventyay_common/organizers/teams/team_edit.html
Deprecate legacy team management views in orga and control apps in favor of the unified organizer update page, replacing them with redirects and removing unused templates and URL patterns.
  • Remove TeamView, Invite/Member management views, and related mixins from orga.views.organizer, replacing them with a simple redirect_team_management helper
  • Add a UnifiedTeamManagementRedirectMixin in eventyay_common.views.team and make all team-related views subclass it to redirect to the unified organizer.update with appropriate section and team query params
  • Delete legacy organizer team templates and view module from control and orga apps
  • Remove team-related URL patterns from control and pretix control URLconfs and replace organizer team URLs in orga urls.py with redirect routes that forward to the unified page
app/eventyay/orga/views/organizer.py
app/eventyay/eventyay_common/views/team.py
app/eventyay/control/urls.py
src/pretix/control/urls.py
app/eventyay/control/templates/pretixcontrol/organizers/team_delete.html
app/eventyay/control/templates/pretixcontrol/organizers/team_edit.html
app/eventyay/control/templates/pretixcontrol/organizers/team_members.html
app/eventyay/control/templates/pretixcontrol/organizers/teams.html
app/eventyay/control/views/organizer_views/team_view.py
app/eventyay/orga/templates/orga/organizer/team/_form.html
app/eventyay/orga/templates/orga/organizer/team/create.html
app/eventyay/orga/templates/orga/organizer/team/list.html
app/eventyay/orga/templates/orga/organizer/team/update.html
Update navigation, index, and user-facing links to point to the unified organizer page for team and permission management instead of legacy team URLs.
  • Change organizer index action buttons to link to organizer.update with section=permissions instead of separate Ticket Teams / Talk Teams links
  • Update control navigation to make the Teams entry open the unified organizer.update permissions tab and mark it as non-active based on old URL names
  • Update admin user team listing and event info box partials to link into the unified organizer.update permissions tab with the appropriate team pre-selected
  • Adjust orga base navigation to drop the explicit teams URL and instead link to the unified organizer.update permissions section
app/eventyay/eventyay_common/templates/eventyay_common/organizers/index.html
app/eventyay/control/navigation.py
app/eventyay/control/templates/pretixcontrol/admin/users/form.html
app/eventyay/control/templates/pretixcontrol/event/fragment_info_box.html
app/eventyay/orga/templates/orga/base.html

Assessment against linked issues

Issue Objective Addressed Explanation
#921 Provide a single unified organiser management page under the common organiser URL that lists all teams and allows creating teams and editing team permissions (merging the old team overview and edit pages into this one interface).
#921 Deprecate or redirect the old team management routes (including /teams, /team/... and /edit-style team URLs in both control and orga areas) so that team management is accessed consistently via the unified organiser page with a simplified URL structure.
#921 Ensure that talk and video permissions for teams are visible and manageable on the unified organiser permissions interface. The unified interface renders talk-related permissions (e.g. can_change_submissions, is_reviewer, force_hide_speaker_names, limit_tracks) via the shared _permissions_fieldsets partial, but there are no visible fields or code changes for any video-related permissions. Therefore talk permissions are integrated but video permissions are not yet exposed on the unified page.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

Unify team creation and management pages under a single organiser permissions interface

1 participant