sendou.ink/app/features/api-public/routes/tournament.$id.teams.ts
Kalle 2c5004f623
Logos for tournament pickups (#1768)
* Progress

* Adjust when elements show up etc.

* Reorganize

* Can upload

* Delete logo admin action

* Filter out avas pre-start

* Util func

* Remove old code

* Fixes
2024-06-22 14:35:04 +03:00

144 lines
4.4 KiB
TypeScript

import { json, type LoaderFunctionArgs } from "@remix-run/node";
import { z } from "zod";
import { db } from "~/db/sql";
import { parseParams } from "~/utils/remix";
import { id } from "~/utils/zod";
import type { GetTournamentTeamsResponse } from "../schema";
import { databaseTimestampToDate } from "~/utils/dates";
import { jsonArrayFrom, jsonObjectFrom } from "kysely/helpers/sqlite";
import {
handleOptionsRequest,
requireBearerAuth,
} from "../api-public-utils.server";
import i18next from "~/modules/i18n/i18next.server";
import { cors } from "remix-utils/cors";
import { userSubmittedImage } from "~/utils/urls";
const paramsSchema = z.object({
id,
});
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
await handleOptionsRequest(request);
requireBearerAuth(request);
const t = await i18next.getFixedT("en", ["game-misc"]);
const { id } = parseParams({
params,
schema: paramsSchema,
});
const teams = await db
.selectFrom("TournamentTeam")
.leftJoin("UserSubmittedImage", "avatarImgId", "UserSubmittedImage.id")
.leftJoin("TournamentTeamCheckIn", (join) =>
join
.onRef(
"TournamentTeam.id",
"=",
"TournamentTeamCheckIn.tournamentTeamId",
)
.on("TournamentTeamCheckIn.bracketIdx", "is", null),
)
.select(({ eb }) => [
"TournamentTeam.id",
"TournamentTeam.name",
"TournamentTeam.seed",
"TournamentTeam.createdAt",
"TournamentTeamCheckIn.checkedInAt",
"UserSubmittedImage.url as avatarUrl",
jsonObjectFrom(
eb
.selectFrom("AllTeam")
.leftJoin(
"UserSubmittedImage",
"AllTeam.avatarImgId",
"UserSubmittedImage.id",
)
.whereRef("AllTeam.id", "=", "TournamentTeam.teamId")
.select([
"AllTeam.customUrl",
"UserSubmittedImage.url as logoUrl",
"AllTeam.deletedAt",
]),
).as("team"),
jsonArrayFrom(
eb
.selectFrom("TournamentTeamMember")
.innerJoin("User", "User.id", "TournamentTeamMember.userId")
.select([
"User.id as userId",
"User.username",
"User.discordId",
"User.discordAvatar",
"TournamentTeamMember.isOwner",
"TournamentTeamMember.createdAt",
])
.whereRef(
"TournamentTeamMember.tournamentTeamId",
"=",
"TournamentTeam.id",
)
.orderBy("TournamentTeamMember.createdAt asc"),
).as("members"),
jsonArrayFrom(
eb
.selectFrom("MapPoolMap")
.select(["MapPoolMap.stageId", "MapPoolMap.mode"])
.whereRef("MapPoolMap.tournamentTeamId", "=", "TournamentTeam.id"),
).as("mapPool"),
])
.where("TournamentTeam.tournamentId", "=", id)
.orderBy("TournamentTeam.createdAt asc")
.execute();
const logoUrl = (team: (typeof teams)[number]) => {
const url = team.team?.logoUrl ?? team.avatarUrl;
if (!url) return null;
return userSubmittedImage(url);
};
const result: GetTournamentTeamsResponse = teams.map((team) => {
return {
id: team.id,
name: team.name,
url: `https://sendou.ink/to/${id}/teams/${team.id}`,
teamPageUrl:
team.team?.customUrl && !team.team.deletedAt
? `https://sendou.ink/t/${team.team.customUrl}`
: null,
seed: team.seed,
registeredAt: databaseTimestampToDate(team.createdAt).toISOString(),
checkedIn: Boolean(team.checkedInAt),
members: team.members.map((member) => {
return {
userId: member.userId,
name: member.username,
discordId: member.discordId,
avatarUrl: member.discordAvatar
? `https://cdn.discordapp.com/avatars/${member.discordId}/${member.discordAvatar}.png`
: null,
captain: Boolean(member.isOwner),
joinedAt: databaseTimestampToDate(member.createdAt).toISOString(),
};
}),
logoUrl: logoUrl(team),
mapPool:
team.mapPool.length > 0
? team.mapPool.map((map) => {
return {
mode: map.mode,
stage: {
id: map.stageId,
name: t(`game-misc:STAGE_${map.stageId}`),
},
};
})
: null,
};
});
return await cors(request, json(result));
};