From dcbe92d1ddf8928de6491f3ea162938e4b8fe1db Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Mon, 29 Jun 2026 20:44:52 +0300 Subject: [PATCH] Sync can edit tournament perms UI/action perm check --- .../calendar/actions/calendar.new.server.ts | 8 ++++-- .../tournament-admin/routes/to.$id.admin.tsx | 5 +++- .../tournament-bracket/core/Tournament.ts | 25 +++++++++++++++++++ .../tournament-bracket/core/tests/mocks-li.ts | 1 + .../core/tests/mocks-sos.ts | 1 + .../tournament/TournamentRepository.server.ts | 1 + .../tournament/tournament-utils.test.ts | 1 + 7 files changed, 39 insertions(+), 3 deletions(-) diff --git a/app/features/calendar/actions/calendar.new.server.ts b/app/features/calendar/actions/calendar.new.server.ts index dcc32868f..c3f05edf0 100644 --- a/app/features/calendar/actions/calendar.new.server.ts +++ b/app/features/calendar/actions/calendar.new.server.ts @@ -44,6 +44,7 @@ export const action: ActionFunction = async ({ request }) => { const isEditing = Boolean(data.eventToEditId); const isAddingTournament = data.toToolsEnabled; + const isTournamentAdder = user.roles.includes("TOURNAMENT_ADDER"); const organizationId = data.organizationId ? Number(data.organizationId) : null; @@ -52,7 +53,7 @@ export const action: ActionFunction = async ({ request }) => { await validateOrganization({ userId: user.id, organizationId, - isTournamentAdder: user.roles.includes("TOURNAMENT_ADDER"), + isTournamentAdder, }); } else if (!isEditing) { requireRole( @@ -141,7 +142,10 @@ export const action: ActionFunction = async ({ request }) => { "Tournament has already started", ); - errorToastIfFalsy(tournament.isAdmin(user), "Not authorized"); + errorToastIfFalsy( + tournament.canEditEventInfo(user, { isTournamentAdder }), + "Not authorized", + ); // once published, a tournament can't be flipped back to draft if (!tournament.isDraft) { diff --git a/app/features/tournament-admin/routes/to.$id.admin.tsx b/app/features/tournament-admin/routes/to.$id.admin.tsx index 6fc336aeb..11f9934e9 100644 --- a/app/features/tournament-admin/routes/to.$id.admin.tsx +++ b/app/features/tournament-admin/routes/to.$id.admin.tsx @@ -23,6 +23,7 @@ import { Redirect } from "~/components/Redirect"; import { DANGEROUS_CAN_ACCESS_DEV_CONTROLS } from "~/features/admin/core/dev-controls"; import { useUser } from "~/features/auth/core/user"; import { useTournament } from "~/features/tournament/routes/to.$id"; +import { useHasRole } from "~/modules/permissions/hooks"; import { calendarEventPage, tournamentAdminPage, @@ -42,6 +43,7 @@ export default function TournamentAdminLayout() { const tournament = useTournament(); const outletContext = useOutletContext(); const user = useUser(); + const isTournamentAdder = useHasRole("TOURNAMENT_ADDER"); const location = useLocation(); const showReopen = Boolean( @@ -73,7 +75,8 @@ export default function TournamentAdminLayout() { return (
- {tournament.isAdmin(user) && !tournament.hasStarted ? ( + {tournament.canEditEventInfo(user, { isTournamentAdder }) && + !tournament.hasStarted ? (
member.userId === user.id && member.role === "ADMIN", + ); + + return Boolean( + isOrganizationAdmin && + (isTournamentAdder || this.ctx.organization?.isEstablished), + ); + } + /** Checks if the given user is an organizer of the tournament. */ isOrganizer(user: OptionalIdObject) { if (!user) return false; diff --git a/app/features/tournament-bracket/core/tests/mocks-li.ts b/app/features/tournament-bracket/core/tests/mocks-li.ts index 5c2f5dc27..9d25cc332 100644 --- a/app/features/tournament-bracket/core/tests/mocks-li.ts +++ b/app/features/tournament-bracket/core/tests/mocks-li.ts @@ -6923,6 +6923,7 @@ export const LOW_INK_DECEMBER_2024 = (): TournamentData => ({ id: 3, name: "Inkling Performance Labs", slug: "inkling-performance-labs", + isEstablished: 1, logoUrl: "fZrToLQrkqV3UZkdgwp0Q-1722263644749.webp", series: [], members: [ diff --git a/app/features/tournament-bracket/core/tests/mocks-sos.ts b/app/features/tournament-bracket/core/tests/mocks-sos.ts index d638f3c0f..794d8b3f8 100644 --- a/app/features/tournament-bracket/core/tests/mocks-sos.ts +++ b/app/features/tournament-bracket/core/tests/mocks-sos.ts @@ -2026,6 +2026,7 @@ export const SWIM_OR_SINK_167 = ( id: 3, name: "Inkling Performance Labs", slug: "inkling-performance-labs", + isEstablished: 1, logoUrl: "fZrToLQrkqV3UZkdgwp0Q-1722263644749.webp", series: [], members: [ diff --git a/app/features/tournament/TournamentRepository.server.ts b/app/features/tournament/TournamentRepository.server.ts index e05e664e1..de27605bf 100644 --- a/app/features/tournament/TournamentRepository.server.ts +++ b/app/features/tournament/TournamentRepository.server.ts @@ -85,6 +85,7 @@ export async function findById(id: number) { "TournamentOrganization.id", "TournamentOrganization.name", "TournamentOrganization.slug", + "TournamentOrganization.isEstablished", concatUserSubmittedImagePrefix( innerEb.ref("UserSubmittedImage.url"), ).as("logoUrl"), diff --git a/app/features/tournament/tournament-utils.test.ts b/app/features/tournament/tournament-utils.test.ts index bd3a83c88..0a9f2da7d 100644 --- a/app/features/tournament/tournament-utils.test.ts +++ b/app/features/tournament/tournament-utils.test.ts @@ -782,6 +782,7 @@ describe("tournamentNameParts", () => { id: 1, name: "Sendou's Tournaments", slug: "sendou", + isEstablished: 1, logoUrl: null, members: [], series: [{ name: "In The Zone" }],