Fix tournament delete permission check

This commit is contained in:
Kalle
2026-08-24 19:19:43 +03:00
parent 8b9d7bf750
commit de6e8a4ffa
2 changed files with 61 additions and 11 deletions

View File

@@ -1,12 +1,19 @@
import type { ActionFunction } from "react-router";
import { redirect } from "react-router";
import * as v from "valibot";
import { requireUser } from "~/features/auth/core/user.server";
import * as CalendarRepository from "~/features/calendar/CalendarRepository.server";
import * as ShowcaseTournaments from "~/features/front-page/core/ShowcaseTournaments.server";
import * as BracketRepository from "~/features/tournament-bracket/BracketRepository.server";
import { clearTournamentDataCache } from "~/features/tournament-bracket/core/Tournament.server";
import {
clearTournamentDataCache,
tournamentFromDB,
} from "~/features/tournament-bracket/core/Tournament.server";
import { requirePermission } from "~/modules/permissions/guards.server";
import { errorToastIfFalsy, notFoundIfNullish } from "~/utils/remix.server";
import {
errorToastIfFalsy,
forbidden,
notFoundIfNullish,
} from "~/utils/remix.server";
import { actualNumber, id, preprocess } from "~/utils/schema";
import { CALENDAR_PAGE } from "~/utils/urls";
@@ -19,14 +26,17 @@ export const action: ActionFunction = async ({ params }) => {
await CalendarRepository.findById(parsedParams.id),
);
requirePermission(event, "DELETE");
if (event.tournamentId) {
errorToastIfFalsy(
(await BracketRepository.findByTournamentId(event.tournamentId)).stage
.length === 0,
"Tournament has already started",
);
const user = requireUser();
const tournament = await tournamentFromDB(event.tournamentId);
if (!tournament.canEditEventInfo(user)) {
throw forbidden();
}
errorToastIfFalsy(!tournament.hasStarted, "Tournament has already started");
} else {
requirePermission(event, "DELETE");
}
await CalendarRepository.deleteById({

View File

@@ -1,7 +1,8 @@
import { addDays } from "date-fns";
import { addDays, subDays } from "date-fns";
import type * as v from "valibot";
import { describe, expect, test } from "vitest";
import * as TournamentFactory from "~/db/seed/factories/TournamentFactory";
import * as TournamentOrganizationFactory from "~/db/seed/factories/TournamentOrganizationFactory";
import * as UserFactory from "~/db/seed/factories/UserFactory";
import * as CalendarRepository from "~/features/calendar/CalendarRepository.server";
import { dateToDatabaseTimestamp } from "~/utils/dates";
@@ -47,4 +48,43 @@ describe("calendar event deletion", () => {
const eventAfter = await CalendarRepository.findById(tournament.eventId);
expect(eventAfter).toBeNull();
});
test("lets the author delete a tournament whose start time passed without it ever starting", async () => {
await UserFactory.createAdmin();
const regular = await UserFactory.createRegular();
const tournament = await TournamentFactory.create({
authorId: regular.id,
startTimes: [dateToDatabaseTimestamp(subDays(new Date(), 2))],
});
await deleteAction(
{},
{ user: "regular", params: { id: String(tournament.eventId) } },
);
const eventAfter = await CalendarRepository.findById(tournament.eventId);
expect(eventAfter).toBeNull();
});
test("lets an admin of an established organization delete its tournament", async () => {
const admin = await UserFactory.createAdmin();
await UserFactory.createRegular();
const orgAdmin = await UserFactory.create();
const organization = await TournamentOrganizationFactory.create(
{ ownerId: orgAdmin.id },
{ isEstablished: true },
);
const tournament = await TournamentFactory.create({
authorId: admin.id,
organizationId: organization.id,
});
await deleteAction(
{},
{ user: orgAdmin.id, params: { id: String(tournament.eventId) } },
);
const eventAfter = await CalendarRepository.findById(tournament.eventId);
expect(eventAfter).toBeNull();
});
});