mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-03-21 18:04:39 -05:00
89 lines
2.6 KiB
TypeScript
89 lines
2.6 KiB
TypeScript
import { json, type LoaderFunctionArgs } from "@remix-run/node";
|
|
import { jsonArrayFrom } from "kysely/helpers/sqlite";
|
|
import { cors } from "remix-utils/cors";
|
|
import { z } from "zod/v4";
|
|
import { db } from "~/db/sql";
|
|
import { databaseTimestampToDate } from "~/utils/dates";
|
|
import { notFoundIfFalsy, parseParams } from "~/utils/remix.server";
|
|
import { id } from "~/utils/zod";
|
|
import {
|
|
handleOptionsRequest,
|
|
requireBearerAuth,
|
|
} from "../api-public-utils.server";
|
|
import type { GetTournamentResponse } from "../schema";
|
|
|
|
const paramsSchema = z.object({
|
|
id,
|
|
});
|
|
|
|
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
|
await handleOptionsRequest(request);
|
|
requireBearerAuth(request);
|
|
|
|
const { id } = parseParams({ params, schema: paramsSchema });
|
|
|
|
const tournament = notFoundIfFalsy(
|
|
await db
|
|
.selectFrom("Tournament")
|
|
.innerJoin("CalendarEvent", "CalendarEvent.tournamentId", "Tournament.id")
|
|
.innerJoin(
|
|
"CalendarEventDate",
|
|
"CalendarEventDate.eventId",
|
|
"CalendarEvent.id",
|
|
)
|
|
.select(({ eb, exists, selectFrom }) => [
|
|
"CalendarEvent.name",
|
|
"CalendarEvent.organizationId",
|
|
"CalendarEventDate.startTime",
|
|
"Tournament.settings",
|
|
exists(
|
|
selectFrom("TournamentResult")
|
|
.where("TournamentResult.tournamentId", "=", id)
|
|
.select("TournamentResult.tournamentId"),
|
|
).as("isFinalized"),
|
|
eb
|
|
.selectFrom("UserSubmittedImage")
|
|
.select(["UserSubmittedImage.url"])
|
|
.whereRef("CalendarEvent.avatarImgId", "=", "UserSubmittedImage.id")
|
|
.as("logoUrl"),
|
|
jsonArrayFrom(
|
|
eb
|
|
.selectFrom("TournamentTeam")
|
|
.leftJoin("TournamentTeamCheckIn", (join) =>
|
|
join
|
|
.onRef(
|
|
"TournamentTeam.id",
|
|
"=",
|
|
"TournamentTeamCheckIn.tournamentTeamId",
|
|
)
|
|
.on("TournamentTeamCheckIn.bracketIdx", "is", null),
|
|
)
|
|
.select(["TournamentTeamCheckIn.checkedInAt"])
|
|
.where("TournamentTeam.tournamentId", "=", id),
|
|
).as("teams"),
|
|
])
|
|
.where("Tournament.id", "=", id)
|
|
.executeTakeFirst(),
|
|
);
|
|
|
|
const result: GetTournamentResponse = {
|
|
name: tournament.name,
|
|
startTime: databaseTimestampToDate(tournament.startTime).toISOString(),
|
|
url: `https://sendou.ink/to/${id}/brackets`,
|
|
logoUrl: tournament.logoUrl,
|
|
teams: {
|
|
checkedInCount: tournament.teams.filter((team) => team.checkedInAt)
|
|
.length,
|
|
registeredCount: tournament.teams.length,
|
|
},
|
|
brackets: tournament.settings.bracketProgression.map((bp) => ({
|
|
name: bp.name,
|
|
type: bp.type,
|
|
})),
|
|
organizationId: tournament.organizationId,
|
|
isFinalized: Boolean(tournament.isFinalized),
|
|
};
|
|
|
|
return await cors(request, json(result));
|
|
};
|