mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-09 04:36:02 -05:00
Move calendar new action to different file
This commit is contained in:
256
app/features/calendar/actions/calendar.new.server.ts
Normal file
256
app/features/calendar/actions/calendar.new.server.ts
Normal file
@@ -0,0 +1,256 @@
|
||||
import type { ActionFunction } from "@remix-run/node";
|
||||
import { redirect } from "@remix-run/node";
|
||||
import { z } from "zod";
|
||||
import { CALENDAR_EVENT } from "~/constants";
|
||||
import type { CalendarEventTag } from "~/db/types";
|
||||
import { requireUser } from "~/features/auth/core/user.server";
|
||||
import * as CalendarRepository from "~/features/calendar/CalendarRepository.server";
|
||||
import { MapPool } from "~/features/map-list-generator/core/map-pool";
|
||||
import { tournamentFromDB } from "~/features/tournament-bracket/core/Tournament.server";
|
||||
import {
|
||||
FORMATS_SHORT,
|
||||
TOURNAMENT,
|
||||
} from "~/features/tournament/tournament-constants";
|
||||
import { rankedModesShort } from "~/modules/in-game-lists/modes";
|
||||
import { canEditCalendarEvent } from "~/permissions";
|
||||
import {
|
||||
databaseTimestampToDate,
|
||||
dateToDatabaseTimestamp,
|
||||
} from "~/utils/dates";
|
||||
import {
|
||||
badRequestIfFalsy,
|
||||
parseRequestFormData,
|
||||
validate,
|
||||
} from "~/utils/remix";
|
||||
import { calendarEventPage } from "~/utils/urls";
|
||||
import {
|
||||
actualNumber,
|
||||
checkboxValueToBoolean,
|
||||
date,
|
||||
falsyToNull,
|
||||
id,
|
||||
processMany,
|
||||
removeDuplicates,
|
||||
safeJSONParse,
|
||||
toArray,
|
||||
} from "~/utils/zod";
|
||||
import { canAddNewEvent, regClosesAtDate } from "../calendar-utils";
|
||||
import {
|
||||
canCreateTournament,
|
||||
formValuesToBracketProgression,
|
||||
} from "../calendar-utils.server";
|
||||
import { REG_CLOSES_AT_OPTIONS } from "../calendar-constants";
|
||||
import { calendarEventMaxDate, calendarEventMinDate } from "../calendar-utils";
|
||||
|
||||
export const action: ActionFunction = async ({ request }) => {
|
||||
const user = await requireUser(request);
|
||||
const data = await parseRequestFormData({
|
||||
request,
|
||||
schema: newCalendarEventActionSchema,
|
||||
parseAsync: true,
|
||||
});
|
||||
|
||||
validate(canAddNewEvent(user), "Not authorized", 401);
|
||||
|
||||
const startTimes = data.date.map((date) => dateToDatabaseTimestamp(date));
|
||||
const commonArgs = {
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
rules: data.rules,
|
||||
startTimes,
|
||||
bracketUrl: data.bracketUrl,
|
||||
discordInviteCode: data.discordInviteCode,
|
||||
tags: data.tags
|
||||
? data.tags
|
||||
.sort(
|
||||
(a, b) =>
|
||||
CALENDAR_EVENT.TAGS.indexOf(a as CalendarEventTag) -
|
||||
CALENDAR_EVENT.TAGS.indexOf(b as CalendarEventTag),
|
||||
)
|
||||
.join(",")
|
||||
: data.tags,
|
||||
badges: data.badges ?? [],
|
||||
toToolsEnabled: canCreateTournament(user) ? Number(data.toToolsEnabled) : 0,
|
||||
toToolsMode:
|
||||
rankedModesShort.find((mode) => mode === data.toToolsMode) ?? null,
|
||||
bracketProgression: formValuesToBracketProgression(data),
|
||||
teamsPerGroup: data.teamsPerGroup ?? undefined,
|
||||
thirdPlaceMatch: data.thirdPlaceMatch ?? undefined,
|
||||
isRanked: data.isRanked ?? undefined,
|
||||
enableNoScreenToggle: data.enableNoScreenToggle ?? undefined,
|
||||
autoCheckInAll: data.autoCheckInAll ?? undefined,
|
||||
autonomousSubs: data.autonomousSubs ?? undefined,
|
||||
swissGroupCount: data.swissGroupCount ?? undefined,
|
||||
swissRoundCount: data.swissRoundCount ?? undefined,
|
||||
tournamentToCopyId: data.tournamentToCopyId,
|
||||
regClosesAt: data.regClosesAt
|
||||
? dateToDatabaseTimestamp(
|
||||
regClosesAtDate({
|
||||
startTime: databaseTimestampToDate(startTimes[0]),
|
||||
closesAt: data.regClosesAt,
|
||||
}),
|
||||
)
|
||||
: undefined,
|
||||
};
|
||||
validate(
|
||||
!commonArgs.toToolsEnabled || commonArgs.bracketProgression,
|
||||
"Bracket progression must be set for tournaments",
|
||||
);
|
||||
|
||||
const deserializedMaps = (() => {
|
||||
if (!data.pool) return;
|
||||
|
||||
return MapPool.toDbList(data.pool);
|
||||
})();
|
||||
|
||||
if (data.eventToEditId) {
|
||||
const eventToEdit = badRequestIfFalsy(
|
||||
await CalendarRepository.findById({ id: data.eventToEditId }),
|
||||
);
|
||||
if (eventToEdit.tournamentId) {
|
||||
const tournament = await tournamentFromDB({
|
||||
tournamentId: eventToEdit.tournamentId,
|
||||
user,
|
||||
});
|
||||
validate(!tournament.hasStarted, "Tournament has already started", 400);
|
||||
}
|
||||
validate(
|
||||
canEditCalendarEvent({ user, event: eventToEdit }),
|
||||
"Not authorized",
|
||||
401,
|
||||
);
|
||||
|
||||
await CalendarRepository.update({
|
||||
eventId: data.eventToEditId,
|
||||
mapPoolMaps: deserializedMaps,
|
||||
...commonArgs,
|
||||
});
|
||||
|
||||
throw redirect(calendarEventPage(data.eventToEditId));
|
||||
} else {
|
||||
const mapPickingStyle = () => {
|
||||
if (data.toToolsMode === "TO") return "TO" as const;
|
||||
if (data.toToolsMode) return `AUTO_${data.toToolsMode}` as const;
|
||||
|
||||
return "AUTO_ALL" as const;
|
||||
};
|
||||
const createdEventId = await CalendarRepository.create({
|
||||
authorId: user.id,
|
||||
mapPoolMaps: deserializedMaps,
|
||||
isFullTournament: data.toToolsEnabled,
|
||||
mapPickingStyle: mapPickingStyle(),
|
||||
...commonArgs,
|
||||
});
|
||||
|
||||
throw redirect(calendarEventPage(createdEventId));
|
||||
}
|
||||
};
|
||||
|
||||
export const newCalendarEventActionSchema = z
|
||||
.object({
|
||||
eventToEditId: z.preprocess(actualNumber, id.nullish()),
|
||||
tournamentToCopyId: z.preprocess(actualNumber, id.nullish()),
|
||||
name: z
|
||||
.string()
|
||||
.min(CALENDAR_EVENT.NAME_MIN_LENGTH)
|
||||
.max(CALENDAR_EVENT.NAME_MAX_LENGTH),
|
||||
description: z.preprocess(
|
||||
falsyToNull,
|
||||
z.string().max(CALENDAR_EVENT.DESCRIPTION_MAX_LENGTH).nullable(),
|
||||
),
|
||||
rules: z.preprocess(
|
||||
falsyToNull,
|
||||
z.string().max(CALENDAR_EVENT.RULES_MAX_LENGTH).nullable(),
|
||||
),
|
||||
date: z.preprocess(
|
||||
toArray,
|
||||
z
|
||||
.array(
|
||||
z.preprocess(
|
||||
date,
|
||||
z.date().min(calendarEventMinDate()).max(calendarEventMaxDate()),
|
||||
),
|
||||
)
|
||||
.min(1)
|
||||
.max(CALENDAR_EVENT.MAX_AMOUNT_OF_DATES),
|
||||
),
|
||||
bracketUrl: z
|
||||
.string()
|
||||
.url()
|
||||
.max(CALENDAR_EVENT.BRACKET_URL_MAX_LENGTH)
|
||||
.default("https://sendou.ink"),
|
||||
discordInviteCode: z.preprocess(
|
||||
falsyToNull,
|
||||
z.string().max(CALENDAR_EVENT.DISCORD_INVITE_CODE_MAX_LENGTH).nullable(),
|
||||
),
|
||||
tags: z.preprocess(
|
||||
processMany(safeJSONParse, removeDuplicates),
|
||||
z
|
||||
.array(
|
||||
z
|
||||
.string()
|
||||
.refine((val) =>
|
||||
CALENDAR_EVENT.TAGS.includes(val as CalendarEventTag),
|
||||
),
|
||||
)
|
||||
.nullable(),
|
||||
),
|
||||
badges: z.preprocess(
|
||||
processMany(safeJSONParse, removeDuplicates),
|
||||
z.array(id).nullable(),
|
||||
),
|
||||
pool: z.string().optional(),
|
||||
toToolsEnabled: z.preprocess(checkboxValueToBoolean, z.boolean()),
|
||||
toToolsMode: z.enum(["ALL", "TO", "SZ", "TC", "RM", "CB"]).optional(),
|
||||
isRanked: z.preprocess(checkboxValueToBoolean, z.boolean().nullish()),
|
||||
regClosesAt: z.enum(REG_CLOSES_AT_OPTIONS).nullish(),
|
||||
enableNoScreenToggle: z.preprocess(
|
||||
checkboxValueToBoolean,
|
||||
z.boolean().nullish(),
|
||||
),
|
||||
autonomousSubs: z.preprocess(checkboxValueToBoolean, z.boolean().nullish()),
|
||||
//
|
||||
// tournament format related fields
|
||||
//
|
||||
format: z.enum(FORMATS_SHORT).nullish(),
|
||||
withUndergroundBracket: z.preprocess(checkboxValueToBoolean, z.boolean()),
|
||||
thirdPlaceMatch: z.preprocess(
|
||||
checkboxValueToBoolean,
|
||||
z.boolean().nullish(),
|
||||
),
|
||||
autoCheckInAll: z.preprocess(checkboxValueToBoolean, z.boolean().nullish()),
|
||||
teamsPerGroup: z.coerce
|
||||
.number()
|
||||
.min(TOURNAMENT.MIN_GROUP_SIZE)
|
||||
.max(TOURNAMENT.MAX_GROUP_SIZE)
|
||||
.nullish(),
|
||||
swissGroupCount: z.coerce.number().int().positive().nullish(),
|
||||
swissRoundCount: z.coerce.number().int().positive().nullish(),
|
||||
followUpBrackets: z.preprocess(
|
||||
safeJSONParse,
|
||||
z
|
||||
.array(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
placements: z.array(z.number()),
|
||||
}),
|
||||
)
|
||||
.min(1)
|
||||
.nullish(),
|
||||
),
|
||||
})
|
||||
.refine(
|
||||
async (schema) => {
|
||||
if (schema.eventToEditId) {
|
||||
const eventToEdit = await CalendarRepository.findById({
|
||||
id: schema.eventToEditId,
|
||||
});
|
||||
return schema.date.length === 1 || !eventToEdit?.tournamentId;
|
||||
} else {
|
||||
return schema.date.length === 1 || !schema.toToolsEnabled;
|
||||
}
|
||||
},
|
||||
{
|
||||
message: "Tournament must have exactly one date",
|
||||
},
|
||||
);
|
||||
@@ -1,130 +0,0 @@
|
||||
import { z } from "zod";
|
||||
import { CALENDAR_EVENT } from "~/constants";
|
||||
import type { CalendarEventTag } from "~/db/types";
|
||||
import * as CalendarRepository from "~/features/calendar/CalendarRepository.server";
|
||||
import {
|
||||
FORMATS_SHORT,
|
||||
TOURNAMENT,
|
||||
} from "~/features/tournament/tournament-constants";
|
||||
import {
|
||||
actualNumber,
|
||||
checkboxValueToBoolean,
|
||||
date,
|
||||
falsyToNull,
|
||||
id,
|
||||
processMany,
|
||||
removeDuplicates,
|
||||
safeJSONParse,
|
||||
toArray,
|
||||
} from "~/utils/zod";
|
||||
import { calendarEventMaxDate, calendarEventMinDate } from "./calendar-utils";
|
||||
import { REG_CLOSES_AT_OPTIONS } from "./calendar-constants";
|
||||
|
||||
export const newCalendarEventActionSchema = z
|
||||
.object({
|
||||
eventToEditId: z.preprocess(actualNumber, id.nullish()),
|
||||
tournamentToCopyId: z.preprocess(actualNumber, id.nullish()),
|
||||
name: z
|
||||
.string()
|
||||
.min(CALENDAR_EVENT.NAME_MIN_LENGTH)
|
||||
.max(CALENDAR_EVENT.NAME_MAX_LENGTH),
|
||||
description: z.preprocess(
|
||||
falsyToNull,
|
||||
z.string().max(CALENDAR_EVENT.DESCRIPTION_MAX_LENGTH).nullable(),
|
||||
),
|
||||
rules: z.preprocess(
|
||||
falsyToNull,
|
||||
z.string().max(CALENDAR_EVENT.RULES_MAX_LENGTH).nullable(),
|
||||
),
|
||||
date: z.preprocess(
|
||||
toArray,
|
||||
z
|
||||
.array(
|
||||
z.preprocess(
|
||||
date,
|
||||
z.date().min(calendarEventMinDate()).max(calendarEventMaxDate()),
|
||||
),
|
||||
)
|
||||
.min(1)
|
||||
.max(CALENDAR_EVENT.MAX_AMOUNT_OF_DATES),
|
||||
),
|
||||
bracketUrl: z
|
||||
.string()
|
||||
.url()
|
||||
.max(CALENDAR_EVENT.BRACKET_URL_MAX_LENGTH)
|
||||
.default("https://sendou.ink"),
|
||||
discordInviteCode: z.preprocess(
|
||||
falsyToNull,
|
||||
z.string().max(CALENDAR_EVENT.DISCORD_INVITE_CODE_MAX_LENGTH).nullable(),
|
||||
),
|
||||
tags: z.preprocess(
|
||||
processMany(safeJSONParse, removeDuplicates),
|
||||
z
|
||||
.array(
|
||||
z
|
||||
.string()
|
||||
.refine((val) =>
|
||||
CALENDAR_EVENT.TAGS.includes(val as CalendarEventTag),
|
||||
),
|
||||
)
|
||||
.nullable(),
|
||||
),
|
||||
badges: z.preprocess(
|
||||
processMany(safeJSONParse, removeDuplicates),
|
||||
z.array(id).nullable(),
|
||||
),
|
||||
pool: z.string().optional(),
|
||||
toToolsEnabled: z.preprocess(checkboxValueToBoolean, z.boolean()),
|
||||
toToolsMode: z.enum(["ALL", "TO", "SZ", "TC", "RM", "CB"]).optional(),
|
||||
isRanked: z.preprocess(checkboxValueToBoolean, z.boolean().nullish()),
|
||||
regClosesAt: z.enum(REG_CLOSES_AT_OPTIONS).nullish(),
|
||||
enableNoScreenToggle: z.preprocess(
|
||||
checkboxValueToBoolean,
|
||||
z.boolean().nullish(),
|
||||
),
|
||||
autonomousSubs: z.preprocess(checkboxValueToBoolean, z.boolean().nullish()),
|
||||
//
|
||||
// tournament format related fields
|
||||
//
|
||||
format: z.enum(FORMATS_SHORT).nullish(),
|
||||
withUndergroundBracket: z.preprocess(checkboxValueToBoolean, z.boolean()),
|
||||
thirdPlaceMatch: z.preprocess(
|
||||
checkboxValueToBoolean,
|
||||
z.boolean().nullish(),
|
||||
),
|
||||
autoCheckInAll: z.preprocess(checkboxValueToBoolean, z.boolean().nullish()),
|
||||
teamsPerGroup: z.coerce
|
||||
.number()
|
||||
.min(TOURNAMENT.MIN_GROUP_SIZE)
|
||||
.max(TOURNAMENT.MAX_GROUP_SIZE)
|
||||
.nullish(),
|
||||
swissGroupCount: z.coerce.number().int().positive().nullish(),
|
||||
swissRoundCount: z.coerce.number().int().positive().nullish(),
|
||||
followUpBrackets: z.preprocess(
|
||||
safeJSONParse,
|
||||
z
|
||||
.array(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
placements: z.array(z.number()),
|
||||
}),
|
||||
)
|
||||
.min(1)
|
||||
.nullish(),
|
||||
),
|
||||
})
|
||||
.refine(
|
||||
async (schema) => {
|
||||
if (schema.eventToEditId) {
|
||||
const eventToEdit = await CalendarRepository.findById({
|
||||
id: schema.eventToEditId,
|
||||
});
|
||||
return schema.date.length === 1 || !eventToEdit?.tournamentId;
|
||||
} else {
|
||||
return schema.date.length === 1 || !schema.toToolsEnabled;
|
||||
}
|
||||
},
|
||||
{
|
||||
message: "Tournament must have exactly one date",
|
||||
},
|
||||
);
|
||||
@@ -2,8 +2,8 @@ import type { z } from "zod";
|
||||
import { isAdmin } from "~/permissions";
|
||||
import type { TournamentSettings } from "~/db/tables";
|
||||
import { BRACKET_NAMES } from "../tournament/tournament-constants";
|
||||
import type { newCalendarEventActionSchema } from "./calendar-schemas.server";
|
||||
import { validateFollowUpBrackets } from "./calendar-utils";
|
||||
import type { newCalendarEventActionSchema } from "./actions/calendar.new.server";
|
||||
|
||||
const usersWithTournamentPerms =
|
||||
process.env["TOURNAMENT_PERMS"]?.split(",").map(Number) ?? [];
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type {
|
||||
ActionFunction,
|
||||
LoaderFunctionArgs,
|
||||
MetaFunction,
|
||||
SerializeFrom,
|
||||
@@ -20,6 +19,7 @@ import { Input } from "~/components/Input";
|
||||
import { Label } from "~/components/Label";
|
||||
import { Main } from "~/components/Main";
|
||||
import { MapPoolSelector } from "~/components/MapPoolSelector";
|
||||
import { Placement } from "~/components/Placement";
|
||||
import { RequiredHiddenInput } from "~/components/RequiredHiddenInput";
|
||||
import { SubmitButton } from "~/components/SubmitButton";
|
||||
import { Toggle } from "~/components/Toggle";
|
||||
@@ -40,49 +40,39 @@ import {
|
||||
import { useIsMounted } from "~/hooks/useIsMounted";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import type { RankedModeShort } from "~/modules/in-game-lists";
|
||||
import { rankedModesShort } from "~/modules/in-game-lists/modes";
|
||||
import { canEditCalendarEvent } from "~/permissions";
|
||||
import { isDefined, nullFilledArray } from "~/utils/arrays";
|
||||
import {
|
||||
databaseTimestampToDate,
|
||||
dateToDatabaseTimestamp,
|
||||
getDateAtNextFullHour,
|
||||
getDateWithHoursOffset,
|
||||
} from "~/utils/dates";
|
||||
import {
|
||||
badRequestIfFalsy,
|
||||
parseRequestFormData,
|
||||
validate,
|
||||
type SendouRouteHandle,
|
||||
} from "~/utils/remix";
|
||||
import { validate, type SendouRouteHandle } from "~/utils/remix";
|
||||
import { makeTitle, pathnameFromPotentialURL } from "~/utils/strings";
|
||||
import { calendarEventPage, tournamentBracketsPage } from "~/utils/urls";
|
||||
import { newCalendarEventActionSchema } from "../calendar-schemas.server";
|
||||
import { tournamentBracketsPage } from "~/utils/urls";
|
||||
import {
|
||||
REG_CLOSES_AT_OPTIONS,
|
||||
type RegClosesAtOption,
|
||||
} from "../calendar-constants";
|
||||
import type { FollowUpBracket } from "../calendar-types";
|
||||
import {
|
||||
bracketProgressionToShortTournamentFormat,
|
||||
calendarEventMaxDate,
|
||||
calendarEventMinDate,
|
||||
canAddNewEvent,
|
||||
datesToRegClosesAt,
|
||||
regClosesAtDate,
|
||||
regClosesAtToDisplayName,
|
||||
validateFollowUpBrackets,
|
||||
} from "../calendar-utils";
|
||||
import {
|
||||
canCreateTournament,
|
||||
formValuesToBracketProgression,
|
||||
} from "../calendar-utils.server";
|
||||
import { canCreateTournament } from "../calendar-utils.server";
|
||||
import { Tags } from "../components/Tags";
|
||||
import { Placement } from "~/components/Placement";
|
||||
import type { FollowUpBracket } from "../calendar-types";
|
||||
import {
|
||||
REG_CLOSES_AT_OPTIONS,
|
||||
type RegClosesAtOption,
|
||||
} from "../calendar-constants";
|
||||
|
||||
import "~/styles/calendar-new.css";
|
||||
import "~/styles/maps.css";
|
||||
|
||||
import { action } from "../actions/calendar.new.server";
|
||||
export { action };
|
||||
|
||||
export const meta: MetaFunction = (args) => {
|
||||
const data = args.data as SerializeFrom<typeof loader> | null;
|
||||
|
||||
@@ -91,110 +81,6 @@ export const meta: MetaFunction = (args) => {
|
||||
return [{ title: data.title }];
|
||||
};
|
||||
|
||||
export const action: ActionFunction = async ({ request }) => {
|
||||
const user = await requireUser(request);
|
||||
const data = await parseRequestFormData({
|
||||
request,
|
||||
schema: newCalendarEventActionSchema,
|
||||
parseAsync: true,
|
||||
});
|
||||
|
||||
validate(canAddNewEvent(user), "Not authorized", 401);
|
||||
|
||||
const startTimes = data.date.map((date) => dateToDatabaseTimestamp(date));
|
||||
const commonArgs = {
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
rules: data.rules,
|
||||
startTimes,
|
||||
bracketUrl: data.bracketUrl,
|
||||
discordInviteCode: data.discordInviteCode,
|
||||
tags: data.tags
|
||||
? data.tags
|
||||
.sort(
|
||||
(a, b) =>
|
||||
CALENDAR_EVENT.TAGS.indexOf(a as CalendarEventTag) -
|
||||
CALENDAR_EVENT.TAGS.indexOf(b as CalendarEventTag),
|
||||
)
|
||||
.join(",")
|
||||
: data.tags,
|
||||
badges: data.badges ?? [],
|
||||
toToolsEnabled: canCreateTournament(user) ? Number(data.toToolsEnabled) : 0,
|
||||
toToolsMode:
|
||||
rankedModesShort.find((mode) => mode === data.toToolsMode) ?? null,
|
||||
bracketProgression: formValuesToBracketProgression(data),
|
||||
teamsPerGroup: data.teamsPerGroup ?? undefined,
|
||||
thirdPlaceMatch: data.thirdPlaceMatch ?? undefined,
|
||||
isRanked: data.isRanked ?? undefined,
|
||||
enableNoScreenToggle: data.enableNoScreenToggle ?? undefined,
|
||||
autoCheckInAll: data.autoCheckInAll ?? undefined,
|
||||
autonomousSubs: data.autonomousSubs ?? undefined,
|
||||
swissGroupCount: data.swissGroupCount ?? undefined,
|
||||
swissRoundCount: data.swissRoundCount ?? undefined,
|
||||
tournamentToCopyId: data.tournamentToCopyId,
|
||||
regClosesAt: data.regClosesAt
|
||||
? dateToDatabaseTimestamp(
|
||||
regClosesAtDate({
|
||||
startTime: databaseTimestampToDate(startTimes[0]),
|
||||
closesAt: data.regClosesAt,
|
||||
}),
|
||||
)
|
||||
: undefined,
|
||||
};
|
||||
validate(
|
||||
!commonArgs.toToolsEnabled || commonArgs.bracketProgression,
|
||||
"Bracket progression must be set for tournaments",
|
||||
);
|
||||
|
||||
const deserializedMaps = (() => {
|
||||
if (!data.pool) return;
|
||||
|
||||
return MapPool.toDbList(data.pool);
|
||||
})();
|
||||
|
||||
if (data.eventToEditId) {
|
||||
const eventToEdit = badRequestIfFalsy(
|
||||
await CalendarRepository.findById({ id: data.eventToEditId }),
|
||||
);
|
||||
if (eventToEdit.tournamentId) {
|
||||
const tournament = await tournamentFromDB({
|
||||
tournamentId: eventToEdit.tournamentId,
|
||||
user,
|
||||
});
|
||||
validate(!tournament.hasStarted, "Tournament has already started", 400);
|
||||
}
|
||||
validate(
|
||||
canEditCalendarEvent({ user, event: eventToEdit }),
|
||||
"Not authorized",
|
||||
401,
|
||||
);
|
||||
|
||||
await CalendarRepository.update({
|
||||
eventId: data.eventToEditId,
|
||||
mapPoolMaps: deserializedMaps,
|
||||
...commonArgs,
|
||||
});
|
||||
|
||||
throw redirect(calendarEventPage(data.eventToEditId));
|
||||
} else {
|
||||
const mapPickingStyle = () => {
|
||||
if (data.toToolsMode === "TO") return "TO" as const;
|
||||
if (data.toToolsMode) return `AUTO_${data.toToolsMode}` as const;
|
||||
|
||||
return "AUTO_ALL" as const;
|
||||
};
|
||||
const createdEventId = await CalendarRepository.create({
|
||||
authorId: user.id,
|
||||
mapPoolMaps: deserializedMaps,
|
||||
isFullTournament: data.toToolsEnabled,
|
||||
mapPickingStyle: mapPickingStyle(),
|
||||
...commonArgs,
|
||||
});
|
||||
|
||||
throw redirect(calendarEventPage(createdEventId));
|
||||
}
|
||||
};
|
||||
|
||||
export const handle: SendouRouteHandle = {
|
||||
i18n: ["calendar", "game-misc"],
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user