Tournament select field

This commit is contained in:
Timothy Armes
2023-10-16 18:07:38 +02:00
committed by Owen Rees
parent a0f9d4dd4e
commit db369a3979
15 changed files with 518 additions and 88 deletions
+4
View File
@@ -1,11 +1,15 @@
import { addTournament } from "./procedures/addTournament";
import { contactUs } from "./procedures/contactUs";
import { fetchTournamentResults } from "./procedures/fetchTournamentResults";
import { getTournamentDetails } from "./procedures/getTournamentDetails";
import { searchTournaments } from "./procedures/searchTournaments";
import { router } from "./trpc";
export const appRouter = router({
contactUs,
addTournament,
searchTournaments,
getTournamentDetails,
fetchTournamentResults,
});
+1 -1
View File
@@ -24,7 +24,7 @@ export const addTournament = publicProcedure
const { name, email, message, tournament } = input;
const tournamentData: Omit<TournamentData, "_id"> = {
const tournamentData: Omit<TournamentData, "_id" | "tournament_id"> = {
...tournament,
date: format(tournament.date, "dd/MM/yyyy"),
time_control: tcMap[tournament.time_control],
@@ -5,7 +5,7 @@ import { errorLog } from "@/utils/logger";
import { publicProcedure } from "../trpc";
const scrapedSchema = z.array(
const dbSchema = z.array(
z.object({
id: z.string(),
name: z.string(),
@@ -55,7 +55,7 @@ const getEloDetails = (elo: string | null) => {
};
const getResultDetails = (
results: z.infer<typeof scrapedSchema>[number]["results"][number],
results: z.infer<typeof dbSchema>[number]["results"][number],
) => {
if (results.opponent_name === null) {
return { result: 0, lostByForfeit: true, wonByForfeit: false };
@@ -107,17 +107,6 @@ export const fetchTournamentResults = publicProcedure
.output(outputSchema)
.query(async ({ input }) => {
try {
// Depending on which page the user copied the URL from, we need to extract the tournament ID
// http://echecs.asso.fr/FicheTournoi.aspx?Ref=59975
// http://echecs.asso.fr/Resultats.aspx?URL=Tournois/Id/59975/59975&Action=Ls
const tournamentId =
input.url.match(/Ref=(\d+)/)?.[1] ?? input.url.match(/Id\/(\d+)/)?.[1];
if (!tournamentId) {
throw new Error("ERR_NO_TOURNAMENT_ID");
}
const headers = new Headers();
const apiKey = process.env.RESULTS_API_KEY;
@@ -125,8 +114,10 @@ export const fetchTournamentResults = publicProcedure
headers.append("api-key", apiKey);
}
console.log(input.id);
const rawResults = await fetch(
`${process.env.RESULTS_SCRAPER_URL}${tournamentId}`,
`${process.env.RESULTS_SCRAPER_URL}${input.id}`,
{
headers: headers,
},
@@ -138,7 +129,7 @@ export const fetchTournamentResults = publicProcedure
throw new Error("ERR_TOURNAMENT_NOT_FOUND");
}
const parsedResults = scrapedSchema.parse(results);
const parsedResults = dbSchema.parse(results);
return parsedResults.map<z.infer<typeof outputSchema>[number]>(
(player) => ({
id: player.id,
@@ -158,7 +149,7 @@ export const fetchTournamentResults = publicProcedure
}),
);
} catch (error) {
reportFetchError(input.url, error);
reportFetchError(input.id, error);
errorLog(JSON.stringify(error, null, 2));
throw error;
}
@@ -0,0 +1,45 @@
import { z } from "zod";
import clientPromise from "@/lib/mongodb";
import { TournamentData } from "@/types";
import { TimeControl, tcMap } from "@/types";
import { errorLog } from "@/utils/logger";
import { publicProcedure } from "../trpc";
const inputSchema = z.object({
ffeId: z.string(),
});
export const getTournamentDetails = publicProcedure
.input(inputSchema)
.query(async ({ input }) => {
try {
const client = await clientPromise;
const db = client.db("tournamentsFranceDB");
const t = await db
.collection("tournaments")
.findOne<TournamentData>({ tournament_id: input.ffeId });
if (t === null) {
return null;
}
const timeControl = tcMap[t.time_control] ?? TimeControl.Other;
return {
id: t._id.toString(),
ffeId: t.tournament_id,
tournament: t.tournament,
town: t.town,
department: t.department,
date: t.date,
url: t.url,
timeControl,
status: t.status,
};
} catch (error) {
errorLog(JSON.stringify(error, null, 2));
throw error;
}
});
@@ -0,0 +1,96 @@
import { endOfDay } from "date-fns";
import { z } from "zod";
import clientPromise from "@/lib/mongodb";
import { TournamentData } from "@/types";
import { TimeControl, Tournament, tcMap } from "@/types";
import { errorLog } from "@/utils/logger";
import { removeDiacritics } from "@/utils/string";
import { publicProcedure } from "../trpc";
const inputSchema = z.object({
searchValue: z.string(),
limit: z.number().optional(),
});
type SearchedTournament = Pick<
Tournament,
| "id"
| "ffeId"
| "date"
| "department"
| "status"
| "timeControl"
| "tournament"
| "town"
| "url"
>;
export const searchTournaments = publicProcedure
.input(inputSchema)
.query(async ({ input }) => {
try {
const client = await clientPromise;
const db = client.db("tournamentsFranceDB");
const searchTerms = input.searchValue
.split(" ")
.map((s) => removeDiacritics(s.trim()))
.filter((s) => s !== "")
.map((s) => ({ tournament_index: { $regex: s, $options: "i" } }));
const data = await db
.collection("tournaments")
.aggregate<TournamentData>([
{
$addFields: {
dateParts: {
$dateFromString: {
dateString: "$end_date",
format: "%d/%m/%Y",
},
},
},
},
{
$match: {
$and: [
{ federation: { $eq: "FFE" } },
{ dateParts: { $lte: endOfDay(new Date()) } },
...searchTerms,
],
},
},
{
$sort: {
dateParts: -1,
},
},
{ $limit: input.limit ?? 20 },
{
$unset: "dateParts",
},
])
.toArray();
return data.map<SearchedTournament>((t) => {
const timeControl = tcMap[t.time_control] ?? TimeControl.Other;
return {
id: t._id.toString(),
ffeId: t.tournament_id,
tournament: t.tournament,
town: t.town,
department: t.department,
date: t.date,
url: t.url,
timeControl,
status: t.status,
};
});
} catch (error) {
errorLog(JSON.stringify(error, null, 2));
throw error;
}
});