From 7b6e611dd811e8d12c90675206f4c5d85cd9daaa Mon Sep 17 00:00:00 2001 From: JackAttack-365 <142643773+jackattack-4@users.noreply.github.com> Date: Thu, 9 Apr 2026 17:54:26 -0700 Subject: [PATCH 01/13] make shift generator unauthenticated --- .../manager/scoutershifts/generateSchedule.ts | 14 ++++++++------ src/routes/manager/scoutershifts.routes.ts | 3 +-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/handler/manager/scoutershifts/generateSchedule.ts b/src/handler/manager/scoutershifts/generateSchedule.ts index 785b6a71..6fb2b1c9 100644 --- a/src/handler/manager/scoutershifts/generateSchedule.ts +++ b/src/handler/manager/scoutershifts/generateSchedule.ts @@ -4,8 +4,7 @@ import prismaClient from "../../../prismaClient.js"; // import { writeFileSync } from "fs"; // import { join } from "path"; // import { homedir } from "os"; -import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; -import { Response } from "express"; +import { Request, Response } from "express"; const shiftScouterEx = [ ["Christian", "Oren", "Ben"], @@ -80,6 +79,10 @@ const generateSchedule = async ( }, }); + if (!matchesResponse || !teamsResponse) { + throw "NO_SCHEDULE"; + } + matchesResponse.data = matchesResponse.data.filter( (match: any) => match.comp_level === "qm", ); @@ -171,10 +174,7 @@ const generateSchedule = async ( return csvRows.join("\n"); }; -export const superScoutingSchedule = async ( - req: AuthenticatedRequest, - res: Response, -) => { +export const superScoutingSchedule = async (req: Request, res: Response) => { try { const params = z.object({ tournamentKey: z.string() }).parse(req.query); @@ -184,6 +184,8 @@ export const superScoutingSchedule = async ( } catch (error) { if (error instanceof ZodError) { res.status(400).send("Bad input"); + } else if (error === "NO_SCHEDULE") { + res.status(404).send("No schedule available"); } else { res.status(500).send("Internal server error"); } diff --git a/src/routes/manager/scoutershifts.routes.ts b/src/routes/manager/scoutershifts.routes.ts index d5147207..cca6dc0b 100644 --- a/src/routes/manager/scoutershifts.routes.ts +++ b/src/routes/manager/scoutershifts.routes.ts @@ -59,11 +59,10 @@ registry.registerPath({ }, security: [{ bearerAuth: [] }], }); +router.get("/generate", superScoutingSchedule); router.use(requireAuth, requireVerifiedTeam); -router.get("/generate", superScoutingSchedule); - router.post("/:uuid", updateScouterShift); router.delete("/:uuid", deleteScouterShift); From fab02ac73fab9f7e2e70ef08b0096b0dd893d1ee Mon Sep 17 00:00:00 2001 From: JackAttack-365 <142643773+jackattack-4@users.noreply.github.com> Date: Thu, 9 Apr 2026 18:18:22 -0700 Subject: [PATCH 02/13] remove logging --- .../coreAnalysis/arrayAndAverageTeams.ts | 39 ------------------- src/handler/manager/getTeams.ts | 1 - 2 files changed, 40 deletions(-) diff --git a/src/handler/analysis/coreAnalysis/arrayAndAverageTeams.ts b/src/handler/analysis/coreAnalysis/arrayAndAverageTeams.ts index f69ad63f..aaf83869 100644 --- a/src/handler/analysis/coreAnalysis/arrayAndAverageTeams.ts +++ b/src/handler/analysis/coreAnalysis/arrayAndAverageTeams.ts @@ -387,15 +387,6 @@ const config: AnalysisFunctionConfig = { .filter((t) => t <= autoEnd) .sort((a, b) => a - b); const first = filteredAutoTimes[0]; - try { - console.debug("autoClimbStartTime", { - reportIndex: idx, - autoClimb: ac, - rawClimbTimes, - filteredAutoTimes, - first, - }); - } catch {} if (ac === "SUCCEEDED" && first !== undefined) { const remaining = autoEnd - first; const clamped = remaining >= 0 ? remaining : 0; @@ -437,19 +428,6 @@ const config: AnalysisFunctionConfig = { .filter((t) => t > autoEnd && t <= 158) .sort((a, b) => a - b); const firstTeleop = filteredTeleopTimes[0]; - console.debug("lXStartTime", { - reportIndex: idx, - endgameClimb: eg, - required, - scoutReportUuid: (r as any).uuid, - events: (r.events ?? []).map((e) => ({ - action: e.action, - time: e.time, - })), - rawClimbTimes, - filteredTeleopTimes, - firstTeleop, - }); if (eg === required && firstTeleop !== undefined) { const remaining = 158 - firstTeleop; const clamped = remaining >= 0 ? remaining : 0; @@ -585,23 +563,6 @@ const config: AnalysisFunctionConfig = { dataPoint: matchValue, tournamentName: row.tournament.name, }); - // Debug logging for climb start metrics - if ( - metric === Metric.autoClimbStartTime || - metric === Metric.l1StartTime || - metric === Metric.l2StartTime || - metric === Metric.l3StartTime - ) { - try { - console.debug("timeline", { - team, - match: row.key, - tnmt, - reports: row.scoutReports.length, - matchValue, - }); - } catch {} - } // Accumulate per tournament perTeamTournamentValues[team][tnmt].push(matchValue); } diff --git a/src/handler/manager/getTeams.ts b/src/handler/manager/getTeams.ts index a1c589ba..dd1afc6b 100644 --- a/src/handler/manager/getTeams.ts +++ b/src/handler/manager/getTeams.ts @@ -155,7 +155,6 @@ export const getTeams = async ( ); rows.unshift(rows[indexOfTeamNumber]); rows.splice(indexOfTeamNumber + 1, 1); - console.log(rows); } } res.status(200).send({ teams: rows, count: count }); From de67cd3b4a28871f59a7401e80902449c7e26187 Mon Sep 17 00:00:00 2001 From: JackAttack-365 <142643773+jackattack-4@users.noreply.github.com> Date: Thu, 9 Apr 2026 18:54:54 -0700 Subject: [PATCH 03/13] add scouter shift param --- .../manager/scoutershifts/generateSchedule.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/handler/manager/scoutershifts/generateSchedule.ts b/src/handler/manager/scoutershifts/generateSchedule.ts index 6fb2b1c9..754b8e3f 100644 --- a/src/handler/manager/scoutershifts/generateSchedule.ts +++ b/src/handler/manager/scoutershifts/generateSchedule.ts @@ -176,9 +176,17 @@ const generateSchedule = async ( export const superScoutingSchedule = async (req: Request, res: Response) => { try { - const params = z.object({ tournamentKey: z.string() }).parse(req.query); - - const schedule = await generateSchedule(params.tournamentKey); + const params = z + .object({ + tournamentKey: z.string(), + shiftScouters: z.array(z.array(z.string())), + }) + .parse(req.query); + + const schedule = await generateSchedule( + params.tournamentKey, + params.shiftScouters, + ); res.status(200).send(schedule); } catch (error) { @@ -187,6 +195,7 @@ export const superScoutingSchedule = async (req: Request, res: Response) => { } else if (error === "NO_SCHEDULE") { res.status(404).send("No schedule available"); } else { + console.error(error); res.status(500).send("Internal server error"); } } From 68a47118b8882f78b878eb048018b6f2775aad07 Mon Sep 17 00:00:00 2001 From: JackAttack-365 <142643773+jackattack-4@users.noreply.github.com> Date: Thu, 9 Apr 2026 21:28:58 -0700 Subject: [PATCH 04/13] Revert "add scouter shift param" This reverts commit de67cd3b4a28871f59a7401e80902449c7e26187. --- .../manager/scoutershifts/generateSchedule.ts | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/handler/manager/scoutershifts/generateSchedule.ts b/src/handler/manager/scoutershifts/generateSchedule.ts index 754b8e3f..6fb2b1c9 100644 --- a/src/handler/manager/scoutershifts/generateSchedule.ts +++ b/src/handler/manager/scoutershifts/generateSchedule.ts @@ -176,17 +176,9 @@ const generateSchedule = async ( export const superScoutingSchedule = async (req: Request, res: Response) => { try { - const params = z - .object({ - tournamentKey: z.string(), - shiftScouters: z.array(z.array(z.string())), - }) - .parse(req.query); - - const schedule = await generateSchedule( - params.tournamentKey, - params.shiftScouters, - ); + const params = z.object({ tournamentKey: z.string() }).parse(req.query); + + const schedule = await generateSchedule(params.tournamentKey); res.status(200).send(schedule); } catch (error) { @@ -195,7 +187,6 @@ export const superScoutingSchedule = async (req: Request, res: Response) => { } else if (error === "NO_SCHEDULE") { res.status(404).send("No schedule available"); } else { - console.error(error); res.status(500).send("Internal server error"); } } From 5585ff8fa51a5b121e4ddbe976f1a5fe91413151 Mon Sep 17 00:00:00 2001 From: JackAttack-365 <142643773+jackattack-4@users.noreply.github.com> Date: Sat, 11 Apr 2026 11:12:05 -0700 Subject: [PATCH 05/13] add practice match fetching, settings, and exclusion --- prisma/schema.prisma | 2 + .../analysis/autoPaths/autoPathsTeam.ts | 5 ++ src/handler/analysis/csv/getReportCSV.ts | 5 ++ src/handler/analysis/csv/getTeamCSV.ts | 5 ++ .../picklist/endgamePicklistTeamFast.ts | 6 ++ .../analysis/teamLookUp/breakdownMetrics.ts | 5 ++ .../analysis/teamLookUp/categoryMetrics.ts | 5 ++ src/handler/analysis/teamLookUp/getNotes.ts | 10 +++ src/handler/manager/addTournamentMatches.ts | 80 +++++++++++++++++++ .../manager/settings/addPracticeSource.ts | 31 +++++++ .../manager/settings/getPracticeSource.ts | 14 ++++ .../manager/settings/updateSettings.ts | 2 + src/routes/manager/settings.routes.ts | 47 +++++++++++ 13 files changed, 217 insertions(+) create mode 100644 src/handler/manager/settings/addPracticeSource.ts create mode 100644 src/handler/manager/settings/getPracticeSource.ts diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 4f2e1a8d..7a641d8c 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -210,6 +210,7 @@ model User { role UserRole @default(ANALYST) teamSourceRule Json @default("{\"mode\": \"EXCLUDE\", \"items\": []}") tournamentSourceRule Json @default("{\"mode\": \"EXCLUDE\", \"items\": []}") + includePracticeMatches Boolean @default(false) ApiKeys ApiKey[] mutablePicklists MutablePicklist[] sharedPicklists SharedPicklist[] @@ -331,6 +332,7 @@ enum UserRole { } enum MatchType { + PRACTICE QUALIFICATION ELIMINATION } diff --git a/src/handler/analysis/autoPaths/autoPathsTeam.ts b/src/handler/analysis/autoPaths/autoPathsTeam.ts index fedec324..5f84ba17 100644 --- a/src/handler/analysis/autoPaths/autoPathsTeam.ts +++ b/src/handler/analysis/autoPaths/autoPathsTeam.ts @@ -86,6 +86,11 @@ const config = { teamMatchData: { teamNumber: teamNumber, tournamentKey: sourceTnmtFilter, + matchType: ctx.user.includePracticeMatches + ? undefined + : { + not: "PRACTICE", + }, }, scouter: { sourceTeamNumber: sourceTeamFilter, diff --git a/src/handler/analysis/csv/getReportCSV.ts b/src/handler/analysis/csv/getReportCSV.ts index fbdc6933..44bffbdf 100644 --- a/src/handler/analysis/csv/getReportCSV.ts +++ b/src/handler/analysis/csv/getReportCSV.ts @@ -139,6 +139,11 @@ export const getReportCSV = async ( const where: any = { teamMatchData: { tournamentKey: params.data.tournamentKey, + matchType: req.user.includePracticeMatches + ? undefined + : { + not: "PRACTICE", + }, }, }; const parsedRule = dataSourceRuleSchema(z.number()).safeParse( diff --git a/src/handler/analysis/csv/getTeamCSV.ts b/src/handler/analysis/csv/getTeamCSV.ts index 7092934c..502b94cc 100644 --- a/src/handler/analysis/csv/getTeamCSV.ts +++ b/src/handler/analysis/csv/getTeamCSV.ts @@ -222,6 +222,11 @@ export const getTeamCSV = async ( ...(tournamentFilter ? { tournamentKey: tournamentFilter } : {}), + matchType: req.user.includePracticeMatches + ? undefined + : { + not: "PRACTICE", + }, }, ...(teamFilter ? { scouter: { sourceTeamNumber: teamFilter } } diff --git a/src/handler/analysis/picklist/endgamePicklistTeamFast.ts b/src/handler/analysis/picklist/endgamePicklistTeamFast.ts index ad041218..c92c1476 100644 --- a/src/handler/analysis/picklist/endgamePicklistTeamFast.ts +++ b/src/handler/analysis/picklist/endgamePicklistTeamFast.ts @@ -23,6 +23,7 @@ export const endgamePicklistTeamFast = async ( team: number, sourceTeamFilter: { in?: number[]; notIn?: number[] } | undefined, sourceTnmtFilter: { in?: string[]; notIn?: string[] } | undefined, + sourcePracticeMatchFilter: boolean | undefined, ): Promise => { try { // Get data @@ -35,6 +36,11 @@ export const endgamePicklistTeamFast = async ( teamMatchData: { teamNumber: team, ...(sourceTnmtFilter && { tournamentKey: sourceTnmtFilter }), + matchType: sourcePracticeMatchFilter + ? undefined + : { + not: "PRACTICE", + }, }, ...(sourceTeamFilter && { scouter: { sourceTeamNumber: sourceTeamFilter }, diff --git a/src/handler/analysis/teamLookUp/breakdownMetrics.ts b/src/handler/analysis/teamLookUp/breakdownMetrics.ts index 145ab272..511a00be 100644 --- a/src/handler/analysis/teamLookUp/breakdownMetrics.ts +++ b/src/handler/analysis/teamLookUp/breakdownMetrics.ts @@ -33,6 +33,11 @@ export const breakdownMetrics = createAnalysisHandler({ where: { teamMatchData: { teamNumber: params.team, + matchType: ctx.user.includePracticeMatches + ? undefined + : { + not: "PRACTICE", + }, }, }, }); diff --git a/src/handler/analysis/teamLookUp/categoryMetrics.ts b/src/handler/analysis/teamLookUp/categoryMetrics.ts index 97e165ef..41c430e5 100644 --- a/src/handler/analysis/teamLookUp/categoryMetrics.ts +++ b/src/handler/analysis/teamLookUp/categoryMetrics.ts @@ -34,6 +34,11 @@ export const categoryMetrics = createAnalysisHandler({ where: { teamMatchData: { teamNumber: params.team, + matchType: ctx.user.includePracticeMatches + ? undefined + : { + not: "PRACTICE", + }, }, }, }); diff --git a/src/handler/analysis/teamLookUp/getNotes.ts b/src/handler/analysis/teamLookUp/getNotes.ts index d7ca9b56..bd69f779 100644 --- a/src/handler/analysis/teamLookUp/getNotes.ts +++ b/src/handler/analysis/teamLookUp/getNotes.ts @@ -35,6 +35,11 @@ export const getNotes = createAnalysisHandler({ where: { teamMatchData: { teamNumber: params.team, + matchType: ctx.user.includePracticeMatches + ? undefined + : { + not: "PRACTICE", + }, }, }, }); @@ -63,6 +68,11 @@ export const getNotes = createAnalysisHandler({ teamMatchData: { teamNumber: params.team, tournamentKey: sourceTnmtFilter, + matchType: ctx.user.includePracticeMatches + ? undefined + : { + not: "PRACTICE", + }, }, scouter: { sourceTeamNumber: sourceTeamFilter, diff --git a/src/handler/manager/addTournamentMatches.ts b/src/handler/manager/addTournamentMatches.ts index 96fd6404..9d055ca0 100644 --- a/src/handler/manager/addTournamentMatches.ts +++ b/src/handler/manager/addTournamentMatches.ts @@ -29,6 +29,84 @@ export const addTournamentMatches = async ( headers: { "X-TBA-Auth-Key": process.env.TBA_KEY }, }); + const nexusResponse = await fetch( + `https://frc.nexus/api/v1/event/${tournamentKey}`, + { + method: "GET", + headers: { + "Nexus-Api-Key": process.env.NEXUS_KEY ?? "", + }, + }, + ); + + console.log(nexusResponse); + + if (!nexusResponse.ok) { + const errorMessage = await nexusResponse.text(); + console.error("Error getting live event status:", errorMessage); + return; + } + + const data = await nexusResponse.json(); + + console.log(data); + + for (const match of data.matches) { + if (match.label.startsWith("Practice")) { + const practiceMatchNumber = parseInt(match.label.split(" ")[1]); + if (isNaN(practiceMatchNumber)) { + continue; + } + + const matchKey = `${tournamentKey}_pr${practiceMatchNumber}`; + for (let i = 0; i < match.redTeams.length; i++) { + const teamNumber = Number(match.redTeams[i]); + const currMatchKey = `${matchKey}_${i}`; + await prismaClient.teamMatchData.upsert({ + where: { + key: currMatchKey, + }, + update: { + tournamentKey: tournamentKey, + matchNumber: practiceMatchNumber, + teamNumber: teamNumber, + matchType: "PRACTICE", + }, + create: { + key: currMatchKey, + tournamentKey: tournamentKey, + matchNumber: practiceMatchNumber, + teamNumber: teamNumber, + matchType: "PRACTICE", + }, + }); + } + for (let i = 0; i < match.blueTeams.length; i++) { + const teamNumber = Number(match.blueTeams[i]); + const currMatchKey = `${matchKey}_${i + 3}`; + + await prismaClient.teamMatchData.upsert({ + where: { + key: currMatchKey, + }, + update: { + tournamentKey: tournamentKey, + matchNumber: practiceMatchNumber, + teamNumber: teamNumber, + matchType: "PRACTICE", + }, + create: { + key: currMatchKey, + tournamentKey: tournamentKey, + matchNumber: practiceMatchNumber, + teamNumber: teamNumber, + matchType: "PRACTICE", + }, + }); + } + } + } + const json = await eventResponse.json(); const { remap_teams } = z @@ -235,3 +313,5 @@ export const addTournamentMatches = async ( console.log(error); } }; + +addTournamentMatches("2026cancmp"); diff --git a/src/handler/manager/settings/addPracticeSource.ts b/src/handler/manager/settings/addPracticeSource.ts new file mode 100644 index 00000000..86a642d8 --- /dev/null +++ b/src/handler/manager/settings/addPracticeSource.ts @@ -0,0 +1,31 @@ +import { Response } from "express"; +import prismaClient from "../../../prismaClient.js"; +import z from "zod"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; + +export const addPracticeSource = async ( + req: AuthenticatedRequest, + res: Response, +): Promise => { + try { + const user = req.user; + + const params = z + .object({ + includePracticeMatches: z.boolean(), + }) + .parse(req.body); + await prismaClient.user.update({ + where: { + id: user.id, + }, + data: { + includePracticeMatches: params.includePracticeMatches, + }, + }); + res.status(200).send("Settings successfully updated"); + } catch (error) { + console.error(error); + res.status(500).send(error); + } +}; diff --git a/src/handler/manager/settings/getPracticeSource.ts b/src/handler/manager/settings/getPracticeSource.ts new file mode 100644 index 00000000..f679ba09 --- /dev/null +++ b/src/handler/manager/settings/getPracticeSource.ts @@ -0,0 +1,14 @@ +import { Response } from "express"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; + +export const getPracticeSource = async ( + req: AuthenticatedRequest, + res: Response, +): Promise => { + try { + res.status(200).send(req.user.includePracticeMatches); + } catch (error) { + console.error(error); + res.status(500).send(error); + } +}; diff --git a/src/handler/manager/settings/updateSettings.ts b/src/handler/manager/settings/updateSettings.ts index a9a7fa85..52a362a5 100644 --- a/src/handler/manager/settings/updateSettings.ts +++ b/src/handler/manager/settings/updateSettings.ts @@ -25,6 +25,7 @@ export const updateSettings = async ( .object({ teamSource: z.array(z.number()), tournamentSource: z.array(z.string()), + includePracticeMatches: z.boolean(), }) .parse(req.body); @@ -38,6 +39,7 @@ export const updateSettings = async ( params.tournamentSource, await allTournaments, ), + includePracticeMatches: params.includePracticeMatches, }, }); res.status(200).send("Settings successfully updated"); diff --git a/src/routes/manager/settings.routes.ts b/src/routes/manager/settings.routes.ts index 3fe56968..9541c1e4 100644 --- a/src/routes/manager/settings.routes.ts +++ b/src/routes/manager/settings.routes.ts @@ -11,6 +11,8 @@ import { registry } from "../../lib/openapi.js"; import { z } from "zod"; import { getTeamEmail } from "../../handler/manager/settings/getTeamEmail.js"; import { requireVerifiedTeam } from "../../lib/middleware/requireVerifiedTeam.js"; +import { addPracticeSource } from "../../handler/manager/settings/addPracticeSource.js"; +import { getPracticeSource } from "../../handler/manager/settings/getPracticeSource.js"; const updateTeamEmails = rateLimit({ windowMs: 2 * 60 * 1000, @@ -107,6 +109,48 @@ registry.registerPath({ security: [{ bearerAuth: [] }], }); +registry.registerPath({ + method: "get", + path: "/v1/manager/settings/practicesource", + tags: ["Manager - Settings"], + summary: "Get practice source", + responses: { + 200: { + description: "Practice source", + content: { "application/json": { schema: z.boolean() } }, + }, + 401: { description: "Unauthorized" }, + 500: { description: "Server error" }, + }, + security: [{ bearerAuth: [] }], +}); + +registry.registerPath({ + method: "post", + path: "/v1/manager/settings/practicesource", + tags: ["Manager - Settings"], + summary: "Add practice source", + request: { + body: { + content: { + "application/json": { + schema: z.object({ includePracticeMatches: z.boolean() }), + }, + }, + }, + }, + responses: { + 200: { + description: "Added", + content: { "text/plain": { schema: z.string() } }, + }, + 400: { description: "Invalid request" }, + 401: { description: "Unauthorized" }, + 500: { description: "Server error" }, + }, + security: [{ bearerAuth: [] }], +}); + registry.registerPath({ method: "get", path: "/v1/manager/settings/tournamentsource", @@ -196,6 +240,9 @@ router.put("/", updateSettings); router.get("/teamsource", getTeamSource); router.post("/teamsource", addTeamSource); +router.get("/practicesource", getPracticeSource); +router.post("/practicesource", addPracticeSource); + router.get("/tournamentsource", getTournamentSource); router.post("/tournamentsource", addTournamentSource); From 601a48b764e856d8588b54290b1bf879e181cd85 Mon Sep 17 00:00:00 2001 From: JackAttack-365 <142643773+jackattack-4@users.noreply.github.com> Date: Sat, 11 Apr 2026 11:15:47 -0700 Subject: [PATCH 06/13] update analysis files --- src/handler/analysis/coreAnalysis/arrayAndAverageTeams.ts | 8 +++++++- src/handler/analysis/coreAnalysis/averageManyFast.ts | 5 +++++ src/handler/analysis/coreAnalysis/nonEventMetric.ts | 5 +++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/handler/analysis/coreAnalysis/arrayAndAverageTeams.ts b/src/handler/analysis/coreAnalysis/arrayAndAverageTeams.ts index aaf83869..b1939d5a 100644 --- a/src/handler/analysis/coreAnalysis/arrayAndAverageTeams.ts +++ b/src/handler/analysis/coreAnalysis/arrayAndAverageTeams.ts @@ -462,7 +462,13 @@ const config: AnalysisFunctionConfig = { } // Finish setting up filters to decrease server load - const tmdFilter: Prisma.TeamMatchDataWhereInput = {}; + const tmdFilter: Prisma.TeamMatchDataWhereInput = { + matchType: ctx.user.includePracticeMatches + ? undefined + : { + not: "PRACTICE", + }, + }; // Team filter tmdFilter.teamNumber = { in: teams }; diff --git a/src/handler/analysis/coreAnalysis/averageManyFast.ts b/src/handler/analysis/coreAnalysis/averageManyFast.ts index 73e6c769..087df315 100644 --- a/src/handler/analysis/coreAnalysis/averageManyFast.ts +++ b/src/handler/analysis/coreAnalysis/averageManyFast.ts @@ -77,6 +77,11 @@ const config: AnalysisFunctionConfig = { const tmdWhere: Prisma.TeamMatchDataWhereInput = { teamNumber: { in: args.teams }, ...(tnmtFilter && { tournamentKey: tnmtFilter }), + matchType: ctx.user.includePracticeMatches + ? undefined + : { + not: "PRACTICE", + }, }; const srWhere: Prisma.ScoutReportWhereInput = teamFilter diff --git a/src/handler/analysis/coreAnalysis/nonEventMetric.ts b/src/handler/analysis/coreAnalysis/nonEventMetric.ts index 8bf8ffd6..92f482a1 100644 --- a/src/handler/analysis/coreAnalysis/nonEventMetric.ts +++ b/src/handler/analysis/coreAnalysis/nonEventMetric.ts @@ -52,6 +52,9 @@ const config = { teamRule.mode === "INCLUDE" ? `sc."sourceTeamNumber" = ANY($2)` : `sc."sourceTeamNumber" != ALL($2)`; + const practiceCondition = ctx.user.includePracticeMatches + ? "TRUE" + : `tmd."matchType" != 'PRACTICE'`; const ARRAY_METRICS = new Set([ MetricsBreakdown.robotRole, @@ -71,6 +74,7 @@ const config = { WHERE tmd."teamNumber" = $3 AND ${tournamentCondition} AND ${teamCondition} + AND ${practiceCondition} GROUP BY value ` : ` @@ -82,6 +86,7 @@ const config = { WHERE tmd."teamNumber" = $3 AND ${tournamentCondition} AND ${teamCondition} + AND ${practiceCondition} GROUP BY s."${args.metric}" `; From 5d62c436f5ba7c9d0de170bb6a65367b8f5d5df3 Mon Sep 17 00:00:00 2001 From: JackAttack-365 <142643773+jackattack-4@users.noreply.github.com> Date: Sat, 11 Apr 2026 11:24:44 -0700 Subject: [PATCH 07/13] pass build and remove test --- src/handler/manager/addTournamentMatches.ts | 2 -- src/handler/manager/managerConstants.ts | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/handler/manager/addTournamentMatches.ts b/src/handler/manager/addTournamentMatches.ts index 9d055ca0..297809f6 100644 --- a/src/handler/manager/addTournamentMatches.ts +++ b/src/handler/manager/addTournamentMatches.ts @@ -313,5 +313,3 @@ export const addTournamentMatches = async ( console.log(error); } }; - -addTournamentMatches("2026cancmp"); diff --git a/src/handler/manager/managerConstants.ts b/src/handler/manager/managerConstants.ts index c4b06dbd..f041c9c0 100644 --- a/src/handler/manager/managerConstants.ts +++ b/src/handler/manager/managerConstants.ts @@ -78,6 +78,7 @@ const MatchTypeMap: Record = { const ReverseMatchTypeMap: Record = { [MatchType.QUALIFICATION]: 0, [MatchType.ELIMINATION]: 1, + [MatchType.PRACTICE]: 2, }; const ScouterScheduleMap = { 0: "team1", From 45eb3d5cb7949b697b8964dbd3ff5f1281719703 Mon Sep 17 00:00:00 2001 From: JackAttack-365 <142643773+jackattack-4@users.noreply.github.com> Date: Sat, 11 Apr 2026 11:26:24 -0700 Subject: [PATCH 08/13] pass build 2 --- src/handler/manager/managerConstants.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/handler/manager/managerConstants.ts b/src/handler/manager/managerConstants.ts index f041c9c0..820bca5f 100644 --- a/src/handler/manager/managerConstants.ts +++ b/src/handler/manager/managerConstants.ts @@ -103,6 +103,7 @@ const MatchTypeToAbrivation = { const MatchEnumToAbrivation: Record = { [MatchType.QUALIFICATION]: "qm", [MatchType.ELIMINATION]: "em", + [MatchType.PRACTICE]: "pr", }; export { From ca67b02105930dd3e5c9ffe6e22c15c233a42031 Mon Sep 17 00:00:00 2001 From: jackattack-4 <142643773+jackattack-4@users.noreply.github.com> Date: Sat, 11 Apr 2026 11:27:28 -0700 Subject: [PATCH 09/13] Update src/handler/manager/settings/getPracticeSource.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/handler/manager/settings/getPracticeSource.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/handler/manager/settings/getPracticeSource.ts b/src/handler/manager/settings/getPracticeSource.ts index f679ba09..40473bf0 100644 --- a/src/handler/manager/settings/getPracticeSource.ts +++ b/src/handler/manager/settings/getPracticeSource.ts @@ -6,7 +6,7 @@ export const getPracticeSource = async ( res: Response, ): Promise => { try { - res.status(200).send(req.user.includePracticeMatches); + res.status(200).json(req.user.includePracticeMatches); } catch (error) { console.error(error); res.status(500).send(error); From 6a1c4b84ac4bcc160a8480cd3593a86367c46eab Mon Sep 17 00:00:00 2001 From: jackattack-4 <142643773+jackattack-4@users.noreply.github.com> Date: Sat, 11 Apr 2026 11:27:56 -0700 Subject: [PATCH 10/13] Update src/handler/manager/settings/addPracticeSource.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/handler/manager/settings/addPracticeSource.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/handler/manager/settings/addPracticeSource.ts b/src/handler/manager/settings/addPracticeSource.ts index 86a642d8..853660ed 100644 --- a/src/handler/manager/settings/addPracticeSource.ts +++ b/src/handler/manager/settings/addPracticeSource.ts @@ -26,6 +26,6 @@ export const addPracticeSource = async ( res.status(200).send("Settings successfully updated"); } catch (error) { console.error(error); - res.status(500).send(error); + res.status(500).send({ error: "Internal server error" }); } }; From fdbca6f0b39728dd72b327779ba52cf54707fa8c Mon Sep 17 00:00:00 2001 From: jackattack-4 <142643773+jackattack-4@users.noreply.github.com> Date: Sat, 11 Apr 2026 11:28:32 -0700 Subject: [PATCH 11/13] Update src/handler/manager/addTournamentMatches.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/handler/manager/addTournamentMatches.ts | 111 ++++++++++---------- 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/src/handler/manager/addTournamentMatches.ts b/src/handler/manager/addTournamentMatches.ts index 297809f6..497f10cf 100644 --- a/src/handler/manager/addTournamentMatches.ts +++ b/src/handler/manager/addTournamentMatches.ts @@ -44,65 +44,64 @@ export const addTournamentMatches = async ( if (!nexusResponse.ok) { const errorMessage = await nexusResponse.text(); console.error("Error getting live event status:", errorMessage); - return; - } - - const data = await nexusResponse.json(); + } else { + const data = await nexusResponse.json(); - console.log(data); + console.log(data); - for (const match of data.matches) { - if (match.label.startsWith("Practice")) { - const practiceMatchNumber = parseInt(match.label.split(" ")[1]); - if (isNaN(practiceMatchNumber)) { - continue; - } - - const matchKey = `${tournamentKey}_pr${practiceMatchNumber}`; - for (let i = 0; i < match.redTeams.length; i++) { - const teamNumber = Number(match.redTeams[i]); - const currMatchKey = `${matchKey}_${i}`; - await prismaClient.teamMatchData.upsert({ - where: { - key: currMatchKey, - }, - update: { - tournamentKey: tournamentKey, - matchNumber: practiceMatchNumber, - teamNumber: teamNumber, - matchType: "PRACTICE", - }, - create: { - key: currMatchKey, - tournamentKey: tournamentKey, - matchNumber: practiceMatchNumber, - teamNumber: teamNumber, - matchType: "PRACTICE", - }, - }); - } - for (let i = 0; i < match.blueTeams.length; i++) { - const teamNumber = Number(match.blueTeams[i]); - const currMatchKey = `${matchKey}_${i + 3}`; + for (const match of data.matches) { + if (match.label.startsWith("Practice")) { + const practiceMatchNumber = parseInt(match.label.split(" ")[1]); + if (isNaN(practiceMatchNumber)) { + continue; + } - await prismaClient.teamMatchData.upsert({ - where: { - key: currMatchKey, - }, - update: { - tournamentKey: tournamentKey, - matchNumber: practiceMatchNumber, - teamNumber: teamNumber, - matchType: "PRACTICE", - }, - create: { - key: currMatchKey, - tournamentKey: tournamentKey, - matchNumber: practiceMatchNumber, - teamNumber: teamNumber, - matchType: "PRACTICE", - }, - }); + const matchKey = `${tournamentKey}_pr${practiceMatchNumber}`; + for (let i = 0; i < match.redTeams.length; i++) { + const teamNumber = Number(match.redTeams[i]); + const currMatchKey = `${matchKey}_${i}`; + await prismaClient.teamMatchData.upsert({ + where: { + key: currMatchKey, + }, + update: { + tournamentKey: tournamentKey, + matchNumber: practiceMatchNumber, + teamNumber: teamNumber, + matchType: "PRACTICE", + }, + create: { + key: currMatchKey, + tournamentKey: tournamentKey, + matchNumber: practiceMatchNumber, + teamNumber: teamNumber, + matchType: "PRACTICE", + }, + }); + } + for (let i = 0; i < match.blueTeams.length; i++) { + const teamNumber = Number(match.blueTeams[i]); + const currMatchKey = `${matchKey}_${i + 3}`; + + await prismaClient.teamMatchData.upsert({ + where: { + key: currMatchKey, + }, + update: { + tournamentKey: tournamentKey, + matchNumber: practiceMatchNumber, + teamNumber: teamNumber, + matchType: "PRACTICE", + }, + create: { + key: currMatchKey, + tournamentKey: tournamentKey, + matchNumber: practiceMatchNumber, + teamNumber: teamNumber, + matchType: "PRACTICE", + }, + }); + } } } } From 4c20d4ae7af3590a21e673294bcfbe8100a61406 Mon Sep 17 00:00:00 2001 From: jackattack-4 <142643773+jackattack-4@users.noreply.github.com> Date: Sat, 11 Apr 2026 11:29:03 -0700 Subject: [PATCH 12/13] Update src/handler/manager/settings/updateSettings.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/handler/manager/settings/updateSettings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/handler/manager/settings/updateSettings.ts b/src/handler/manager/settings/updateSettings.ts index 52a362a5..eb7b57bc 100644 --- a/src/handler/manager/settings/updateSettings.ts +++ b/src/handler/manager/settings/updateSettings.ts @@ -25,7 +25,7 @@ export const updateSettings = async ( .object({ teamSource: z.array(z.number()), tournamentSource: z.array(z.string()), - includePracticeMatches: z.boolean(), + includePracticeMatches: z.boolean().optional().default(false), }) .parse(req.body); From cfba0e0e9abf856ba76f29d1f63752ef559a3a97 Mon Sep 17 00:00:00 2001 From: JackAttack-365 <142643773+jackattack-4@users.noreply.github.com> Date: Sat, 11 Apr 2026 11:32:53 -0700 Subject: [PATCH 13/13] fix docs, remove logs, update error handling --- src/handler/manager/addTournamentMatches.ts | 4 ---- src/handler/manager/settings/getPracticeSource.ts | 2 +- src/routes/manager/settings.routes.ts | 1 + 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/handler/manager/addTournamentMatches.ts b/src/handler/manager/addTournamentMatches.ts index 497f10cf..4485f26d 100644 --- a/src/handler/manager/addTournamentMatches.ts +++ b/src/handler/manager/addTournamentMatches.ts @@ -39,16 +39,12 @@ export const addTournamentMatches = async ( }, ); - console.log(nexusResponse); - if (!nexusResponse.ok) { const errorMessage = await nexusResponse.text(); console.error("Error getting live event status:", errorMessage); } else { const data = await nexusResponse.json(); - console.log(data); - for (const match of data.matches) { if (match.label.startsWith("Practice")) { const practiceMatchNumber = parseInt(match.label.split(" ")[1]); diff --git a/src/handler/manager/settings/getPracticeSource.ts b/src/handler/manager/settings/getPracticeSource.ts index 40473bf0..c71ec8bc 100644 --- a/src/handler/manager/settings/getPracticeSource.ts +++ b/src/handler/manager/settings/getPracticeSource.ts @@ -9,6 +9,6 @@ export const getPracticeSource = async ( res.status(200).json(req.user.includePracticeMatches); } catch (error) { console.error(error); - res.status(500).send(error); + res.status(500).send("Error getting practice source"); } }; diff --git a/src/routes/manager/settings.routes.ts b/src/routes/manager/settings.routes.ts index 9541c1e4..510654a1 100644 --- a/src/routes/manager/settings.routes.ts +++ b/src/routes/manager/settings.routes.ts @@ -36,6 +36,7 @@ registry.registerPath({ schema: z.object({ teamSource: z.array(z.number().int()), tournamentSource: z.array(z.string()), + includePracticeMatches: z.boolean().optional(), }), }, },