mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-24 12:06:54 -05:00
Sync can edit tournament perms UI/action perm check
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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 (
|
||||
<div className={clsx("stack lg", containerClassName("wide"))}>
|
||||
{tournament.isAdmin(user) && !tournament.hasStarted ? (
|
||||
{tournament.canEditEventInfo(user, { isTournamentAdder }) &&
|
||||
!tournament.hasStarted ? (
|
||||
<div className="stack horizontal items-end">
|
||||
<LinkButton
|
||||
to={tournamentEditPage(tournament.ctx.eventId)}
|
||||
|
||||
@@ -1382,6 +1382,31 @@ export class Tournament {
|
||||
return this.ctx.author.id === user.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given user can edit the tournament's calendar event info.
|
||||
*
|
||||
* Mirrors the authorization enforced when the edit is submitted: organization
|
||||
* admins can only edit when the organization is established, unless they have
|
||||
* the TOURNAMENT_ADDER role.
|
||||
*/
|
||||
canEditEventInfo(
|
||||
user: OptionalIdObject,
|
||||
{ isTournamentAdder }: { isTournamentAdder: boolean },
|
||||
) {
|
||||
if (!user) return false;
|
||||
if (isAdmin(user)) return true;
|
||||
if (this.ctx.author.id === user.id) return true;
|
||||
|
||||
const isOrganizationAdmin = this.ctx.organization?.members.some(
|
||||
(member) => 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;
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -782,6 +782,7 @@ describe("tournamentNameParts", () => {
|
||||
id: 1,
|
||||
name: "Sendou's Tournaments",
|
||||
slug: "sendou",
|
||||
isEstablished: 1,
|
||||
logoUrl: null,
|
||||
members: [],
|
||||
series: [{ name: "In The Zone" }],
|
||||
|
||||
Reference in New Issue
Block a user