feat: tournament setup, roles, and permissions - #59
Merged
Conversation
…bles for relational role/permission system
…ssion expansion with explicit per-role lists
…MembershipRole tables, add owner short-circuit
…k rank-bound checks for role CRUD
…packages, extract role schemas and membership-role assignment routes
…elds and TournamentJoinCode model
…apters and tournaments, add TournamentJoinCode routes and admin verify endpoint
…, drop admin special-case from tournaments/me, use require_membership() dependency on GET /tournaments/{id}
…ubpackage (core, admin, memberships, join_codes), mirroring the tournament structure
…ion PATCH and dedicated deactivate DELETE route
…ed, add mark_confirmed() helper
…/tournament/ subpackage
…erify routes, add paginated audit-log GET
…h PATCH, one audit entry per call
…chema/blocks/positions JSON columns, DEFAULT_POSITIONS→DEFAULT_ROLES with rank
…ip/event/sync bugs surfaced along the way
…t, and tournament join codes
…ournament memberships
…th slim/full user-nested responses
…e/tournament schema changes
…ershipsApi list methods
…it log, archive, transfer
…coming preview endpoint
… (stubbed) chapter codes
…sign-in exemptions already covered by proxy.ts
…n proxy.ts's already-authenticated bounce
…low can bounce back
…ollable ancestors
…ate+time in tooltip
…ds on tournaments
…es instead of resetting on every keystroke
…umers, not just roles editor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
🚅 Deployed to the nexus-pr-59 environment in nexus
|
… university_id over location
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces
Tournament.blocks/Tournament.volunteer_schema/TournamentMembership.positions(opaque JSON blobs) with a relational role/permission system —TournamentRole+TournamentMembershipRole, tournament ownership, rank-gated staff management, visibility/verification fields, join codes, and a per-tournament audit log. This is foundational cleanup several planned features (staff management, public directory, Forms) depend on directly.Also folded in, along the way: the tournament date timezone-offset bug fix (
start_date/end_datedatetime → date). #28What changed
Backend — relational roles & permissions
TournamentRole(key,label,permissions[],rank) andTournamentMembershipRole(junction), replacingvolunteer_schema["positions"]andTournamentMembership.positions.Tournament.owner_id— direct FK to creator, not a role, not ranked, sits structurally above rank 1. Transferable only by current owner viaPOST /tournaments/{id}/transfer-ownership/; outgoing owner keeps their existing role assignments.get_user_permissions()cut over to the relational tables, with an owner short-circuit that grants full permissions independent of role assignments.MANAGE_STAFForiginally proposed:MANAGE_ROLES— create/edit/delete/reorder role definitionsMANAGE_MEMBERS— assign/remove roles on a membershipMANAGE_TOURNAMENTdoes not bypass it, intentionally stricter than a flat reading of the original design.owner_id, so role setup is a deliberatePOST /roles/apply-template/action (default template, or custom) rather than implicit on create.is_public(TD-controlled) /is_verified(admin-only, viaPATCH /admin/tournaments/{id}/verify/) added for the future public directory.TournamentJoinCode— same shape as the existing chapter join-code pattern. Redemption creates a bareTournamentMembership(status="interested")with no roles; staff assign roles afterward.TournamentMembership.status:interested(default) /confirmed. Doesn't gate role/event assignment.AuditLogEntry— records role create/update/delete/reorder, membership-role assignment, join-code lifecycle, staff invites, verification, archive/unarchive, and ownership transfer, each tied totournament_id+actor_id. New paginatedGETaudit-log endpoint with action/actor filters.tournament.py/chapters.pysplit intotournament/andchapter/subpackages (core, admin, memberships, roles, join_codes, audit, setup_checklist) mirroring each other;permissions.pymoved undercore/tournament/.POST /join/redemption endpoint (tournament + chapter codes) replacing separate per-type routes; join codes for chapters and tournaments merged into one table.end_date; archived tournaments lock general/role settings and deactivate all join codes.Backend — date timezone fix
start_date/end_datechanged fromdatetimetodateon the model and schemas — a date-only field needs no timezone handling at all.tournaments.start_date/end_datefrom timestamp toDATE.end_date < start_datevalidator continues to work unchanged againstdateobjects; still returns 422.Frontend
/join?code=public redemption page;?redirect=threaded through sign-in/sign-up/onboarding so a join link survives the auth detour.TournamentCard'sfmt()now parsesYYYY-MM-DDlocally (lib/date.ts) instead ofnew Date(d), fixing the UTC-offset display shift; single vs. range date display uses an explicit equality check.NewTournamentModalvalidates end-date-before-start-date (and past start dates) inline before submit, no round trip.Select→Dropdown,RadioGroup/RadioOption→ButtonGroup, canonicalizedvariant/lockedprops, newToggle,Checkbox,ChipInput,Popover,HoverCard,SidePanel,Cardcomponents; toast system.Deviations from the original issue
TournamentDeadlinewas never built. No model, migration, route, or audit action exists for it — the "TD-defined arbitrary deadlines" pillar of the design doc is entirely out of this PR.interest_due_at/registration_due_at/confirmation_due_atcorrectly never exist as fixed columns, but no relational replacement landed either.registration_opens_atwas scaffolded as a column mid-branch, then dropped before merge — never shipped, no user-facing impact.default_day_start/default_day_endwere not implemented.MANAGE_STAFFwas split intoMANAGE_ROLES+MANAGE_MEMBERS(see above) rather than shipped as a single permission.Test plan
backend/tests/api/tournament/— role CRUD incl. rank bounds, rank-gated membership-role assignment (tied ranks, self-modification, owner/admin bypass), ownership transfer (old owner keeps roles), join-code creation/redemption, audit log entries per action, setup checklist, admin verify route.backend/tests/api/chapter/andtest_join.py— unified join-code redemption across chapter/tournament.pytestfull suite green (see CI).