diff --git a/.gitignore b/.gitignore index f19688c9..14b910b4 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ node_modules dist .DS_Store .rdb -.vscode/ \ No newline at end of file +.vscode/ +scripts/ \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b16c3d40..19d74bce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1714,23 +1714,23 @@ } }, "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", + "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", "type-is": "~1.6.18", - "unpipe": "1.0.0" + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8", @@ -1746,12 +1746,41 @@ "ms": "2.0.0" } }, + "node_modules/body-parser/node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, + "node_modules/body-parser/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/brace-expansion": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", @@ -2719,39 +2748,39 @@ "license": "MIT" }, "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", + "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.13.0", + "qs": "~6.14.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", + "send": "~0.19.0", + "serve-static": "~1.16.2", "setprototypeof": "1.2.0", - "statuses": "2.0.1", + "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -4358,12 +4387,12 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -4403,20 +4432,49 @@ } }, "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" } }, + "node_modules/raw-body/node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/rc9": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", diff --git a/package.json b/package.json index ffc2e7ab..4d2e08ff 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,9 @@ "description": "", "type": "module", "scripts": { - "dev": "NODE_ENV=development tsx watch src/index.ts", + "dev": "NODE_ENV=development tsx watch src/server.ts", "build": "tsc", - "start": "node dist/index.js", + "start": "node dist/server.js", "test": "tsc", "lint": "eslint .", "format": "prettier --write ." diff --git a/src/app.ts b/src/app.ts new file mode 100644 index 00000000..4d94fa51 --- /dev/null +++ b/src/app.ts @@ -0,0 +1,24 @@ +import express from "express"; +import bodyParser from "body-parser"; +import cookieParser from "cookie-parser"; +import "dotenv/config"; + +import { setupExpressErrorHandler } from "posthog-node"; +import { posthog } from "./posthogClient.js"; +import posthogReporter from "./lib/middleware/posthogMiddleware.js"; + +import routes from "./routes/index.js"; + +export const app = express(); + +setupExpressErrorHandler(posthog, app); +app.set("trust proxy", true); + +app.use(bodyParser.json()); +app.use(cookieParser()); + +// Logs requests using posthog +app.use(posthogReporter); + +// API entry point +app.use("/v1", routes); diff --git a/src/handler/analysis/alliancePredictions/alliancePage.ts b/src/handler/analysis/alliancePredictions/alliancePage.ts index 60c6ca46..24dc0692 100644 --- a/src/handler/analysis/alliancePredictions/alliancePage.ts +++ b/src/handler/analysis/alliancePredictions/alliancePage.ts @@ -1,6 +1,9 @@ import z from "zod"; import { runAnalysis } from "../analysisFunction.js"; -import { FlippedRoleMap, Metric } from "../analysisConstants.js"; +import { + FlippedRoleMap, + Metric, +} from "../analysisConstants.js"; import { arrayAndAverageTeams } from "../coreAnalysis/arrayAndAverageTeams.js"; import { autoPathsTeam } from "../autoPaths/autoPathsTeam.js"; import { robotRole } from "../coreAnalysis/robotRole.js"; diff --git a/src/handler/analysis/analysisHandler.ts b/src/handler/analysis/analysisHandler.ts index 6772dc17..44f63999 100644 --- a/src/handler/analysis/analysisHandler.ts +++ b/src/handler/analysis/analysisHandler.ts @@ -120,7 +120,7 @@ export const createAnalysisHandler: < context, ); - res.set('X-Lovat-Cache','miss'); + res.set("X-Lovat-Cache", "miss"); res.status(200).send(calculatedAnalysis.error ?? calculatedAnalysis); try { @@ -143,7 +143,7 @@ export const createAnalysisHandler: < return; } } else { - res.set('X-Lovat-Cache','hit'); + res.set("X-Lovat-Cache", "hit"); res.status(200).send(JSON.parse(cacheRow.toString())); } } catch (error) { diff --git a/src/handler/analysis/coreAnalysis/arrayAndAverageTeams.ts b/src/handler/analysis/coreAnalysis/arrayAndAverageTeams.ts index f4a943e5..9e49f337 100644 --- a/src/handler/analysis/coreAnalysis/arrayAndAverageTeams.ts +++ b/src/handler/analysis/coreAnalysis/arrayAndAverageTeams.ts @@ -14,7 +14,10 @@ import { dataSourceRuleToPrismaFilter, } from "../dataSourceRule.js"; import z from "zod"; -import { runAnalysis, AnalysisFunctionConfig } from "../analysisFunction.js"; +import { + runAnalysis, + AnalysisFunctionConfig, +} from "../analysisFunction.js"; // Accurately aggregate an analog metric on multiple teams at once (weighs matches equally regardless of extra scout reports). // Provides a timeline of metric value per match. diff --git a/src/handler/analysis/coreAnalysis/averageManyFast.ts b/src/handler/analysis/coreAnalysis/averageManyFast.ts index ef03d129..9b90834c 100644 --- a/src/handler/analysis/coreAnalysis/averageManyFast.ts +++ b/src/handler/analysis/coreAnalysis/averageManyFast.ts @@ -17,7 +17,10 @@ import { dataSourceRuleToPrismaFilter, dataSourceRuleSchema, } from "../dataSourceRule.js"; -import { runAnalysis, AnalysisFunctionConfig } from "../analysisFunction.js"; +import { + runAnalysis, + AnalysisFunctionConfig, +} from "../analysisFunction.js"; import { User } from "@prisma/client"; export interface ArrayFilter { diff --git a/src/handler/analysis/coreAnalysis/averageScoutReport.ts b/src/handler/analysis/coreAnalysis/averageScoutReport.ts index 04a589ba..c4c41fff 100644 --- a/src/handler/analysis/coreAnalysis/averageScoutReport.ts +++ b/src/handler/analysis/coreAnalysis/averageScoutReport.ts @@ -7,7 +7,10 @@ import { } from "../analysisConstants.js"; import { EventAction, Position, User } from "@prisma/client"; import z from "zod"; -import { runAnalysis, AnalysisFunctionConfig } from "../analysisFunction.js"; +import { + runAnalysis, + AnalysisFunctionConfig, +} from "../analysisFunction.js"; export async function computeAverageScoutReport( scoutReportUuid: string, diff --git a/src/handler/analysis/coreAnalysis/robotRole.ts b/src/handler/analysis/coreAnalysis/robotRole.ts index 5983af80..af66485f 100644 --- a/src/handler/analysis/coreAnalysis/robotRole.ts +++ b/src/handler/analysis/coreAnalysis/robotRole.ts @@ -1,7 +1,13 @@ import z from "zod"; import { MetricsBreakdown } from "../analysisConstants.js"; -import { nonEventMetric, NonEventMetricResult } from "./nonEventMetric.js"; -import { runAnalysis, AnalysisFunctionConfig } from "../analysisFunction.js"; +import { + nonEventMetric, + NonEventMetricResult, +} from "./nonEventMetric.js"; +import { + runAnalysis, + AnalysisFunctionConfig, +} from "../analysisFunction.js"; import { User } from "@prisma/client"; const argsSchema = z.object({ team: z.number() }); diff --git a/src/handler/manager/getReportCSV.ts b/src/handler/analysis/csv/getReportCSV.ts similarity index 97% rename from src/handler/manager/getReportCSV.ts rename to src/handler/analysis/csv/getReportCSV.ts index 2af0c9f3..262a37e1 100644 --- a/src/handler/manager/getReportCSV.ts +++ b/src/handler/analysis/csv/getReportCSV.ts @@ -1,6 +1,6 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import prismaClient from "../../../prismaClient.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; import { stringify } from "csv-stringify/sync"; import { UserRole, @@ -16,12 +16,15 @@ import { TeamMatchData, Event, } from "@prisma/client"; -import { autoEnd, endgameToPoints } from "../analysis/analysisConstants.js"; +import { + autoEnd, + endgameToPoints, +} from "../analysisConstants.js"; import { z } from "zod"; import { dataSourceRuleToPrismaFilter, dataSourceRuleSchema, -} from "../analysis/dataSourceRule.js"; +} from "../dataSourceRule.js"; // Scouting report condensed into a single dimension that can be pushed to a row in the csv export interface CondensedReport { diff --git a/src/handler/manager/getTeamCSV.ts b/src/handler/analysis/csv/getTeamCSV.ts similarity index 98% rename from src/handler/manager/getTeamCSV.ts rename to src/handler/analysis/csv/getTeamCSV.ts index 973402a1..091be5c1 100644 --- a/src/handler/manager/getTeamCSV.ts +++ b/src/handler/analysis/csv/getTeamCSV.ts @@ -1,6 +1,6 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import prismaClient from "../../../prismaClient.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; import { stringify } from "csv-stringify/sync"; import { UserRole, @@ -14,12 +14,15 @@ import { UnderShallowCage, Event, } from "@prisma/client"; -import { autoEnd, endgameToPoints } from "../analysis/analysisConstants.js"; +import { + autoEnd, + endgameToPoints, +} from "../analysisConstants.js"; import { z } from "zod"; import { dataSourceRuleToPrismaFilter, dataSourceRuleSchema, -} from "../analysis/dataSourceRule.js"; +} from "../dataSourceRule.js"; interface AggregatedTeamData { teamNumber: number; diff --git a/src/handler/manager/getTeamMatchCSV.ts b/src/handler/analysis/csv/getTeamMatchCSV.ts similarity index 98% rename from src/handler/manager/getTeamMatchCSV.ts rename to src/handler/analysis/csv/getTeamMatchCSV.ts index e66c2bda..035d8d36 100644 --- a/src/handler/manager/getTeamMatchCSV.ts +++ b/src/handler/analysis/csv/getTeamMatchCSV.ts @@ -1,6 +1,6 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import prismaClient from "../../../prismaClient.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; import { stringify } from "csv-stringify/sync"; import { UserRole, @@ -15,13 +15,16 @@ import { Scouter, Event, } from "@prisma/client"; -import { autoEnd, endgameToPoints } from "../analysis/analysisConstants.js"; +import { + autoEnd, + endgameToPoints, +} from "../analysisConstants.js"; import { z } from "zod"; import { CondensedReport } from "./getReportCSV.js"; import { dataSourceRuleToPrismaFilter, dataSourceRuleSchema, -} from "../analysis/dataSourceRule.js"; +} from "../dataSourceRule.js"; // Simplified scouting report with properties required for aggregation interface PointsReport { diff --git a/src/handler/analysis/picklist/endgamePicklistTeamFast.ts b/src/handler/analysis/picklist/endgamePicklistTeamFast.ts index b658cc4e..6e744213 100644 --- a/src/handler/analysis/picklist/endgamePicklistTeamFast.ts +++ b/src/handler/analysis/picklist/endgamePicklistTeamFast.ts @@ -1,6 +1,9 @@ import prismaClient from "../../../prismaClient.js"; import { BargeResult } from "@prisma/client"; -import { defaultEndgamePoints, endgameToPoints } from "../analysisConstants.js"; +import { + defaultEndgamePoints, + endgameToPoints, +} from "../analysisConstants.js"; import { ArrayFilter } from "../coreAnalysis/averageManyFast.js"; // Number of endgame possibilities that result in points earned (essentially, successes) diff --git a/src/handler/analysis/rankFlag.ts b/src/handler/analysis/rankFlag.ts index c046c61f..a02fd7af 100644 --- a/src/handler/analysis/rankFlag.ts +++ b/src/handler/analysis/rankFlag.ts @@ -1,6 +1,9 @@ import axios from "axios"; import z from "zod"; -import { runAnalysis, AnalysisFunctionConfig } from "./analysisFunction.js"; +import { + runAnalysis, + AnalysisFunctionConfig, +} from "./analysisFunction.js"; import { User } from "@prisma/client"; export async function computeRankFlag( diff --git a/src/handler/analysis/scoutingLead.ts b/src/handler/analysis/scoutingLead.ts index 25942736..cefe7671 100644 --- a/src/handler/analysis/scoutingLead.ts +++ b/src/handler/analysis/scoutingLead.ts @@ -1,5 +1,5 @@ // import { Request, Response } from "express"; -// import prismaClient from '../../prismaClient' +// import prismaClient from '../../prismaClient.js' // import z from 'zod' // import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; diff --git a/src/handler/analysis/scoutingLead/scouterScoutReports.ts b/src/handler/analysis/scoutingLead/scouterScoutReports.ts index 5323da1c..ae3bf82f 100644 --- a/src/handler/analysis/scoutingLead/scouterScoutReports.ts +++ b/src/handler/analysis/scoutingLead/scouterScoutReports.ts @@ -1,6 +1,6 @@ import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { createAnalysisHandler } from "../../analysis/analysisHandler.js"; +import { createAnalysisHandler } from "../analysisHandler.js"; export const scouterScoutReports = createAnalysisHandler({ params: { diff --git a/src/handler/analysis/scoutingLead/scoutingLeadPage.ts b/src/handler/analysis/scoutingLead/scoutingLeadPage.ts index 69ba0c08..b27eed10 100644 --- a/src/handler/analysis/scoutingLead/scoutingLeadPage.ts +++ b/src/handler/analysis/scoutingLead/scoutingLeadPage.ts @@ -1,11 +1,11 @@ // import { Request, Response } from "express"; -// import prismaClient from '../../../prismaClient' +// import prismaClient from '../../../prismaClient.js' // import z from 'zod' -// import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth"; +// import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; // import { driverAbility, highNoteMap, matchTimeEnd, metricToEvent, stageMap } from "../analysisConstants.js"; -// import { autoPathSingleMatchSingleScoutReport } from "../autoPaths/autoPathSingleMatchSingleScoutReport"; -// import { singleMatchSingleScoutReport } from "../coreAnalysis/singleMatchSingleScoutReport"; -// import { cooperationSingleMatch } from "../coreAnalysis/cooperationSingleMatch"; +// import { autoPathSingleMatchSingleScoutReport } from "../autoPaths/autoPathSingleMatchSingleScoutReport.js"; +// import { singleMatchSingleScoutReport } from "../coreAnalysis/singleMatchSingleScoutReport.js"; +// import { cooperationSingleMatch } from "../coreAnalysis/cooperationSingleMatch.js"; // // import { cooperationSingleMatch } from "./cooperationSingleMatch.js"; // export const scoutingLeadPage = async (req : AuthenticatedRequest, res : Response) => { diff --git a/src/handler/analysis/specificMatchPage/matchPageAllScouters.ts b/src/handler/analysis/specificMatchPage/matchPageAllScouters.ts index a4650646..abbf8f70 100644 --- a/src/handler/analysis/specificMatchPage/matchPageAllScouters.ts +++ b/src/handler/analysis/specificMatchPage/matchPageAllScouters.ts @@ -1,13 +1,13 @@ // import { Request, Response } from "express"; -// import prismaClient from '../../../prismaClient' +// import prismaClient from '../../../prismaClient.js' // import z from 'zod' -// import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth"; -// import { singleMatchEventsAverage } from "../coreAnalysis/singleMatchEventsAverage"; -// import { arrayAndAverageTeam } from "../coreAnalysis/arrayAndAverageTeam"; +// import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; +// import { singleMatchEventsAverage } from "../coreAnalysis/singleMatchEventsAverage.js"; +// import { arrayAndAverageTeam } from "../coreAnalysis/arrayAndAverageTeam.js"; // import { specificMatchPageMetrics } from "../analysisConstants.js"; -// import { singleMatchSingleScouter } from "../coreAnalysis/singleMatchSingleScouter"; +// import { singleMatchSingleScouter } from "../coreAnalysis/singleMatchSingleScouter.js"; // import { match } from "assert"; -// import { autoPathSingleMatchSingleScouter } from "../autoPaths/autoPathSingleMatchSingleScouter"; +// import { autoPathSingleMatchSingleScouter } from "../autoPaths/autoPathSingleMatchSingleScouter.js"; // export const matchPageAllScouters = async (req: AuthenticatedRequest, res: Response) => { // try { diff --git a/src/handler/analysis/specificMatchPage/timelineForScoutReport.ts b/src/handler/analysis/specificMatchPage/timelineForScoutReport.ts index 4cb7b98f..5a4ce7d6 100644 --- a/src/handler/analysis/specificMatchPage/timelineForScoutReport.ts +++ b/src/handler/analysis/specificMatchPage/timelineForScoutReport.ts @@ -1,6 +1,9 @@ import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { FlippedActionMap, FlippedPositionMap } from "../analysisConstants.js"; +import { + FlippedActionMap, + FlippedPositionMap, +} from "../analysisConstants.js"; import { createAnalysisHandler } from "../analysisHandler.js"; export const timelineForScoutReport = createAnalysisHandler({ diff --git a/src/handler/analysis/teamLookUp/categoryMetrics.ts b/src/handler/analysis/teamLookUp/categoryMetrics.ts index 802f9c3b..ebe50219 100644 --- a/src/handler/analysis/teamLookUp/categoryMetrics.ts +++ b/src/handler/analysis/teamLookUp/categoryMetrics.ts @@ -1,5 +1,8 @@ import z from "zod"; -import { metricsCategory, metricToName } from "../analysisConstants.js"; +import { + metricsCategory, + metricToName, +} from "../analysisConstants.js"; import { averageManyFast } from "../coreAnalysis/averageManyFast.js"; import { createAnalysisHandler } from "../analysisHandler.js"; diff --git a/src/handler/analysis/teamLookUp/detailsPage.ts b/src/handler/analysis/teamLookUp/detailsPage.ts index d816df35..dc9e3b8a 100644 --- a/src/handler/analysis/teamLookUp/detailsPage.ts +++ b/src/handler/analysis/teamLookUp/detailsPage.ts @@ -1,7 +1,10 @@ import z from "zod"; import { autoPathsTeam } from "../autoPaths/autoPathsTeam.js"; import { averageAllTeamFast } from "../coreAnalysis/averageAllTeamFast.js"; -import { Metric, metricsToNumber } from "../analysisConstants.js"; +import { + Metric, + metricsToNumber, +} from "../analysisConstants.js"; import { arrayAndAverageTeams } from "../coreAnalysis/arrayAndAverageTeams.js"; import { createAnalysisHandler } from "../analysisHandler.js"; diff --git a/src/handler/analysis/teamLookUp/multipleFlags.ts b/src/handler/analysis/teamLookUp/multipleFlags.ts index 972ef5ae..5b3a9f53 100644 --- a/src/handler/analysis/teamLookUp/multipleFlags.ts +++ b/src/handler/analysis/teamLookUp/multipleFlags.ts @@ -1,6 +1,9 @@ import z from "zod"; import { rankFlag } from "../rankFlag.js"; -import { metricsCategory, metricToName } from "../analysisConstants.js"; +import { + metricsCategory, + metricToName, +} from "../analysisConstants.js"; import { arrayAndAverageTeams } from "../coreAnalysis/arrayAndAverageTeams.js"; import { createAnalysisHandler } from "../analysisHandler.js"; diff --git a/src/handler/manager/addTournamentMatchesOneTime.ts b/src/handler/manager/addTournamentMatchesOneTime.ts deleted file mode 100644 index c930487c..00000000 --- a/src/handler/manager/addTournamentMatchesOneTime.ts +++ /dev/null @@ -1,3294 +0,0 @@ -import { Request, Response } from "express"; -import prismaClient from "../../prismaClient.js"; - -export const addTournamentMatchesOneTime = async ( - req: Request, - res: Response, -): Promise => { - try { - const rows = await prismaClient.teamMatchData.createMany({ - data: [ - { - key: "2024tuhc_qm1_3", - tournamentKey: "2024tuhc", - matchNumber: 1, - teamNumber: 5883, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm1_4", - tournamentKey: "2024tuhc", - matchNumber: 1, - teamNumber: 9490, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm1_5", - tournamentKey: "2024tuhc", - matchNumber: 1, - teamNumber: 7575, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm1_0", - tournamentKey: "2024tuhc", - matchNumber: 1, - teamNumber: 8058, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm1_1", - tournamentKey: "2024tuhc", - matchNumber: 1, - teamNumber: 9565, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm1_2", - tournamentKey: "2024tuhc", - matchNumber: 1, - teamNumber: 7522, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm2_3", - tournamentKey: "2024tuhc", - matchNumber: 2, - teamNumber: 8084, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm2_4", - tournamentKey: "2024tuhc", - matchNumber: 2, - teamNumber: 6024, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm2_5", - tournamentKey: "2024tuhc", - matchNumber: 2, - teamNumber: 8042, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm2_0", - tournamentKey: "2024tuhc", - matchNumber: 2, - teamNumber: 9464, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm2_1", - tournamentKey: "2024tuhc", - matchNumber: 2, - teamNumber: 6430, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm2_2", - tournamentKey: "2024tuhc", - matchNumber: 2, - teamNumber: 7035, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm3_3", - tournamentKey: "2024tuhc", - matchNumber: 3, - teamNumber: 9070, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm3_4", - tournamentKey: "2024tuhc", - matchNumber: 3, - teamNumber: 9247, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm3_5", - tournamentKey: "2024tuhc", - matchNumber: 3, - teamNumber: 9231, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm3_0", - tournamentKey: "2024tuhc", - matchNumber: 3, - teamNumber: 4191, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm3_1", - tournamentKey: "2024tuhc", - matchNumber: 3, - teamNumber: 9447, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm3_2", - tournamentKey: "2024tuhc", - matchNumber: 3, - teamNumber: 9609, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm4_3", - tournamentKey: "2024tuhc", - matchNumber: 4, - teamNumber: 9523, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm4_4", - tournamentKey: "2024tuhc", - matchNumber: 4, - teamNumber: 9025, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm4_5", - tournamentKey: "2024tuhc", - matchNumber: 4, - teamNumber: 7672, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm4_0", - tournamentKey: "2024tuhc", - matchNumber: 4, - teamNumber: 9281, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm4_1", - tournamentKey: "2024tuhc", - matchNumber: 4, - teamNumber: 8220, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm4_2", - tournamentKey: "2024tuhc", - matchNumber: 4, - teamNumber: 6064, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm5_3", - tournamentKey: "2024tuhc", - matchNumber: 5, - teamNumber: 9583, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm5_4", - tournamentKey: "2024tuhc", - matchNumber: 5, - teamNumber: 8308, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm5_5", - tournamentKey: "2024tuhc", - matchNumber: 5, - teamNumber: 9692, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm5_0", - tournamentKey: "2024tuhc", - matchNumber: 5, - teamNumber: 6415, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm5_1", - tournamentKey: "2024tuhc", - matchNumber: 5, - teamNumber: 7086, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm5_2", - tournamentKey: "2024tuhc", - matchNumber: 5, - teamNumber: 9690, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm6_3", - tournamentKey: "2024tuhc", - matchNumber: 6, - teamNumber: 9468, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm6_4", - tournamentKey: "2024tuhc", - matchNumber: 6, - teamNumber: 6874, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm6_5", - tournamentKey: "2024tuhc", - matchNumber: 6, - teamNumber: 8557, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm6_0", - tournamentKey: "2024tuhc", - matchNumber: 6, - teamNumber: 7444, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm6_1", - tournamentKey: "2024tuhc", - matchNumber: 6, - teamNumber: 6417, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm6_2", - tournamentKey: "2024tuhc", - matchNumber: 6, - teamNumber: 7050, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm7_3", - tournamentKey: "2024tuhc", - matchNumber: 7, - teamNumber: 6429, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm7_4", - tournamentKey: "2024tuhc", - matchNumber: 7, - teamNumber: 9591, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm7_5", - tournamentKey: "2024tuhc", - matchNumber: 7, - teamNumber: 6985, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm7_0", - tournamentKey: "2024tuhc", - matchNumber: 7, - teamNumber: 9625, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm7_1", - tournamentKey: "2024tuhc", - matchNumber: 7, - teamNumber: 2905, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm7_2", - tournamentKey: "2024tuhc", - matchNumber: 7, - teamNumber: 8500, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm8_3", - tournamentKey: "2024tuhc", - matchNumber: 8, - teamNumber: 3646, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm8_4", - tournamentKey: "2024tuhc", - matchNumber: 8, - teamNumber: 9502, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm8_5", - tournamentKey: "2024tuhc", - matchNumber: 8, - teamNumber: 8173, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm8_0", - tournamentKey: "2024tuhc", - matchNumber: 8, - teamNumber: 9469, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm8_1", - tournamentKey: "2024tuhc", - matchNumber: 8, - teamNumber: 6838, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm8_2", - tournamentKey: "2024tuhc", - matchNumber: 8, - teamNumber: 8777, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm9_3", - tournamentKey: "2024tuhc", - matchNumber: 9, - teamNumber: 8159, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm9_4", - tournamentKey: "2024tuhc", - matchNumber: 9, - teamNumber: 8214, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm9_5", - tournamentKey: "2024tuhc", - matchNumber: 9, - teamNumber: 8058, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm9_0", - tournamentKey: "2024tuhc", - matchNumber: 9, - teamNumber: 9436, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm9_1", - tournamentKey: "2024tuhc", - matchNumber: 9, - teamNumber: 8158, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm9_2", - tournamentKey: "2024tuhc", - matchNumber: 9, - teamNumber: 7035, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm10_3", - tournamentKey: "2024tuhc", - matchNumber: 10, - teamNumber: 6430, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm10_4", - tournamentKey: "2024tuhc", - matchNumber: 10, - teamNumber: 4191, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm10_5", - tournamentKey: "2024tuhc", - matchNumber: 10, - teamNumber: 8042, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm10_0", - tournamentKey: "2024tuhc", - matchNumber: 10, - teamNumber: 9583, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm10_1", - tournamentKey: "2024tuhc", - matchNumber: 10, - teamNumber: 7522, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm10_2", - tournamentKey: "2024tuhc", - matchNumber: 10, - teamNumber: 7575, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm11_3", - tournamentKey: "2024tuhc", - matchNumber: 11, - teamNumber: 5883, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm11_4", - tournamentKey: "2024tuhc", - matchNumber: 11, - teamNumber: 9231, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm11_5", - tournamentKey: "2024tuhc", - matchNumber: 11, - teamNumber: 8084, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm11_0", - tournamentKey: "2024tuhc", - matchNumber: 11, - teamNumber: 9070, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm11_1", - tournamentKey: "2024tuhc", - matchNumber: 11, - teamNumber: 9692, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm11_2", - tournamentKey: "2024tuhc", - matchNumber: 11, - teamNumber: 9523, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm12_3", - tournamentKey: "2024tuhc", - matchNumber: 12, - teamNumber: 9464, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm12_4", - tournamentKey: "2024tuhc", - matchNumber: 12, - teamNumber: 8557, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm12_5", - tournamentKey: "2024tuhc", - matchNumber: 12, - teamNumber: 9281, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm12_0", - tournamentKey: "2024tuhc", - matchNumber: 12, - teamNumber: 6415, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm12_1", - tournamentKey: "2024tuhc", - matchNumber: 12, - teamNumber: 6985, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm12_2", - tournamentKey: "2024tuhc", - matchNumber: 12, - teamNumber: 9247, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm13_3", - tournamentKey: "2024tuhc", - matchNumber: 13, - teamNumber: 9690, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm13_4", - tournamentKey: "2024tuhc", - matchNumber: 13, - teamNumber: 9025, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm13_5", - tournamentKey: "2024tuhc", - matchNumber: 13, - teamNumber: 9565, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm13_0", - tournamentKey: "2024tuhc", - matchNumber: 13, - teamNumber: 9609, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm13_1", - tournamentKey: "2024tuhc", - matchNumber: 13, - teamNumber: 8173, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm13_2", - tournamentKey: "2024tuhc", - matchNumber: 13, - teamNumber: 6024, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm14_3", - tournamentKey: "2024tuhc", - matchNumber: 14, - teamNumber: 8214, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm14_4", - tournamentKey: "2024tuhc", - matchNumber: 14, - teamNumber: 9625, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm14_5", - tournamentKey: "2024tuhc", - matchNumber: 14, - teamNumber: 6429, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm14_0", - tournamentKey: "2024tuhc", - matchNumber: 14, - teamNumber: 6064, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm14_1", - tournamentKey: "2024tuhc", - matchNumber: 14, - teamNumber: 9468, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm14_2", - tournamentKey: "2024tuhc", - matchNumber: 14, - teamNumber: 9469, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm15_3", - tournamentKey: "2024tuhc", - matchNumber: 15, - teamNumber: 9490, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm15_4", - tournamentKey: "2024tuhc", - matchNumber: 15, - teamNumber: 8500, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm15_5", - tournamentKey: "2024tuhc", - matchNumber: 15, - teamNumber: 9447, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm15_0", - tournamentKey: "2024tuhc", - matchNumber: 15, - teamNumber: 9502, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm15_1", - tournamentKey: "2024tuhc", - matchNumber: 15, - teamNumber: 7050, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm15_2", - tournamentKey: "2024tuhc", - matchNumber: 15, - teamNumber: 8159, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm16_3", - tournamentKey: "2024tuhc", - matchNumber: 16, - teamNumber: 9436, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm16_4", - tournamentKey: "2024tuhc", - matchNumber: 16, - teamNumber: 6417, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm16_5", - tournamentKey: "2024tuhc", - matchNumber: 16, - teamNumber: 9591, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm16_0", - tournamentKey: "2024tuhc", - matchNumber: 16, - teamNumber: 8777, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm16_1", - tournamentKey: "2024tuhc", - matchNumber: 16, - teamNumber: 8220, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm16_2", - tournamentKey: "2024tuhc", - matchNumber: 16, - teamNumber: 7086, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm17_3", - tournamentKey: "2024tuhc", - matchNumber: 17, - teamNumber: 8158, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm17_4", - tournamentKey: "2024tuhc", - matchNumber: 17, - teamNumber: 7672, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm17_5", - tournamentKey: "2024tuhc", - matchNumber: 17, - teamNumber: 3646, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm17_0", - tournamentKey: "2024tuhc", - matchNumber: 17, - teamNumber: 8308, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm17_1", - tournamentKey: "2024tuhc", - matchNumber: 17, - teamNumber: 7444, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm17_2", - tournamentKey: "2024tuhc", - matchNumber: 17, - teamNumber: 2905, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm18_3", - tournamentKey: "2024tuhc", - matchNumber: 18, - teamNumber: 6874, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm18_4", - tournamentKey: "2024tuhc", - matchNumber: 18, - teamNumber: 8084, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm18_5", - tournamentKey: "2024tuhc", - matchNumber: 18, - teamNumber: 9070, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm18_0", - tournamentKey: "2024tuhc", - matchNumber: 18, - teamNumber: 6838, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm18_1", - tournamentKey: "2024tuhc", - matchNumber: 18, - teamNumber: 7522, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm18_2", - tournamentKey: "2024tuhc", - matchNumber: 18, - teamNumber: 9281, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm19_3", - tournamentKey: "2024tuhc", - matchNumber: 19, - teamNumber: 6415, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm19_4", - tournamentKey: "2024tuhc", - matchNumber: 19, - teamNumber: 8173, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm19_5", - tournamentKey: "2024tuhc", - matchNumber: 19, - teamNumber: 9469, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm19_0", - tournamentKey: "2024tuhc", - matchNumber: 19, - teamNumber: 4191, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm19_1", - tournamentKey: "2024tuhc", - matchNumber: 19, - teamNumber: 6985, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm19_2", - tournamentKey: "2024tuhc", - matchNumber: 19, - teamNumber: 6064, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm20_3", - tournamentKey: "2024tuhc", - matchNumber: 20, - teamNumber: 9565, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm20_4", - tournamentKey: "2024tuhc", - matchNumber: 20, - teamNumber: 9583, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm20_5", - tournamentKey: "2024tuhc", - matchNumber: 20, - teamNumber: 6024, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm20_0", - tournamentKey: "2024tuhc", - matchNumber: 20, - teamNumber: 9502, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm20_1", - tournamentKey: "2024tuhc", - matchNumber: 20, - teamNumber: 8058, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm20_2", - tournamentKey: "2024tuhc", - matchNumber: 20, - teamNumber: 8557, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm21_3", - tournamentKey: "2024tuhc", - matchNumber: 21, - teamNumber: 9609, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm21_4", - tournamentKey: "2024tuhc", - matchNumber: 21, - teamNumber: 9591, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm21_5", - tournamentKey: "2024tuhc", - matchNumber: 21, - teamNumber: 8220, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm21_0", - tournamentKey: "2024tuhc", - matchNumber: 21, - teamNumber: 9692, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm21_1", - tournamentKey: "2024tuhc", - matchNumber: 21, - teamNumber: 9490, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm21_2", - tournamentKey: "2024tuhc", - matchNumber: 21, - teamNumber: 8214, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm22_3", - tournamentKey: "2024tuhc", - matchNumber: 22, - teamNumber: 9690, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm22_4", - tournamentKey: "2024tuhc", - matchNumber: 22, - teamNumber: 7050, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm22_5", - tournamentKey: "2024tuhc", - matchNumber: 22, - teamNumber: 9468, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm22_0", - tournamentKey: "2024tuhc", - matchNumber: 22, - teamNumber: 5883, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm22_1", - tournamentKey: "2024tuhc", - matchNumber: 22, - teamNumber: 9436, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm22_2", - tournamentKey: "2024tuhc", - matchNumber: 22, - teamNumber: 9464, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm23_3", - tournamentKey: "2024tuhc", - matchNumber: 23, - teamNumber: 8500, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm23_4", - tournamentKey: "2024tuhc", - matchNumber: 23, - teamNumber: 3646, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm23_5", - tournamentKey: "2024tuhc", - matchNumber: 23, - teamNumber: 8777, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm23_0", - tournamentKey: "2024tuhc", - matchNumber: 23, - teamNumber: 7575, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm23_1", - tournamentKey: "2024tuhc", - matchNumber: 23, - teamNumber: 6874, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm23_2", - tournamentKey: "2024tuhc", - matchNumber: 23, - teamNumber: 7672, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm24_3", - tournamentKey: "2024tuhc", - matchNumber: 24, - teamNumber: 7444, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm24_4", - tournamentKey: "2024tuhc", - matchNumber: 24, - teamNumber: 8158, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm24_5", - tournamentKey: "2024tuhc", - matchNumber: 24, - teamNumber: 6430, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm24_0", - tournamentKey: "2024tuhc", - matchNumber: 24, - teamNumber: 9447, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm24_1", - tournamentKey: "2024tuhc", - matchNumber: 24, - teamNumber: 6417, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm24_2", - tournamentKey: "2024tuhc", - matchNumber: 24, - teamNumber: 6429, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm25_3", - tournamentKey: "2024tuhc", - matchNumber: 25, - teamNumber: 8308, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm25_4", - tournamentKey: "2024tuhc", - matchNumber: 25, - teamNumber: 9625, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm25_5", - tournamentKey: "2024tuhc", - matchNumber: 25, - teamNumber: 9247, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm25_0", - tournamentKey: "2024tuhc", - matchNumber: 25, - teamNumber: 9523, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm25_1", - tournamentKey: "2024tuhc", - matchNumber: 25, - teamNumber: 6838, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm25_2", - tournamentKey: "2024tuhc", - matchNumber: 25, - teamNumber: 8159, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm26_3", - tournamentKey: "2024tuhc", - matchNumber: 26, - teamNumber: 7035, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm26_4", - tournamentKey: "2024tuhc", - matchNumber: 26, - teamNumber: 8042, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm26_5", - tournamentKey: "2024tuhc", - matchNumber: 26, - teamNumber: 7086, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm26_0", - tournamentKey: "2024tuhc", - matchNumber: 26, - teamNumber: 2905, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm26_1", - tournamentKey: "2024tuhc", - matchNumber: 26, - teamNumber: 9231, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm26_2", - tournamentKey: "2024tuhc", - matchNumber: 26, - teamNumber: 9025, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm27_3", - tournamentKey: "2024tuhc", - matchNumber: 27, - teamNumber: 9690, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm27_4", - tournamentKey: "2024tuhc", - matchNumber: 27, - teamNumber: 6985, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm27_5", - tournamentKey: "2024tuhc", - matchNumber: 27, - teamNumber: 9436, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm27_0", - tournamentKey: "2024tuhc", - matchNumber: 27, - teamNumber: 7522, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm27_1", - tournamentKey: "2024tuhc", - matchNumber: 27, - teamNumber: 9591, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm27_2", - tournamentKey: "2024tuhc", - matchNumber: 27, - teamNumber: 9502, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm28_3", - tournamentKey: "2024tuhc", - matchNumber: 28, - teamNumber: 6064, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm28_4", - tournamentKey: "2024tuhc", - matchNumber: 28, - teamNumber: 9692, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm28_5", - tournamentKey: "2024tuhc", - matchNumber: 28, - teamNumber: 8058, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm28_0", - tournamentKey: "2024tuhc", - matchNumber: 28, - teamNumber: 8557, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm28_1", - tournamentKey: "2024tuhc", - matchNumber: 28, - teamNumber: 3646, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm28_2", - tournamentKey: "2024tuhc", - matchNumber: 28, - teamNumber: 7050, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm29_3", - tournamentKey: "2024tuhc", - matchNumber: 29, - teamNumber: 6417, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm29_4", - tournamentKey: "2024tuhc", - matchNumber: 29, - teamNumber: 9609, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm29_5", - tournamentKey: "2024tuhc", - matchNumber: 29, - teamNumber: 8158, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm29_0", - tournamentKey: "2024tuhc", - matchNumber: 29, - teamNumber: 8500, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm29_1", - tournamentKey: "2024tuhc", - matchNumber: 29, - teamNumber: 5883, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm29_2", - tournamentKey: "2024tuhc", - matchNumber: 29, - teamNumber: 9583, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm30_3", - tournamentKey: "2024tuhc", - matchNumber: 30, - teamNumber: 6874, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm30_4", - tournamentKey: "2024tuhc", - matchNumber: 30, - teamNumber: 6429, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm30_5", - tournamentKey: "2024tuhc", - matchNumber: 30, - teamNumber: 8220, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm30_0", - tournamentKey: "2024tuhc", - matchNumber: 30, - teamNumber: 8159, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm30_1", - tournamentKey: "2024tuhc", - matchNumber: 30, - teamNumber: 8084, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm30_2", - tournamentKey: "2024tuhc", - matchNumber: 30, - teamNumber: 8173, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm31_3", - tournamentKey: "2024tuhc", - matchNumber: 31, - teamNumber: 9625, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm31_4", - tournamentKey: "2024tuhc", - matchNumber: 31, - teamNumber: 9464, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm31_5", - tournamentKey: "2024tuhc", - matchNumber: 31, - teamNumber: 9565, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm31_0", - tournamentKey: "2024tuhc", - matchNumber: 31, - teamNumber: 7672, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm31_1", - tournamentKey: "2024tuhc", - matchNumber: 31, - teamNumber: 7035, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm31_2", - tournamentKey: "2024tuhc", - matchNumber: 31, - teamNumber: 4191, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm32_3", - tournamentKey: "2024tuhc", - matchNumber: 32, - teamNumber: 9447, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm32_4", - tournamentKey: "2024tuhc", - matchNumber: 32, - teamNumber: 9231, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm32_5", - tournamentKey: "2024tuhc", - matchNumber: 32, - teamNumber: 6430, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm32_0", - tournamentKey: "2024tuhc", - matchNumber: 32, - teamNumber: 9468, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm32_1", - tournamentKey: "2024tuhc", - matchNumber: 32, - teamNumber: 8777, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm32_2", - tournamentKey: "2024tuhc", - matchNumber: 32, - teamNumber: 9281, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm33_3", - tournamentKey: "2024tuhc", - matchNumber: 33, - teamNumber: 7086, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm33_4", - tournamentKey: "2024tuhc", - matchNumber: 33, - teamNumber: 2905, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm33_5", - tournamentKey: "2024tuhc", - matchNumber: 33, - teamNumber: 6838, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm33_0", - tournamentKey: "2024tuhc", - matchNumber: 33, - teamNumber: 9523, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm33_1", - tournamentKey: "2024tuhc", - matchNumber: 33, - teamNumber: 7575, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm33_2", - tournamentKey: "2024tuhc", - matchNumber: 33, - teamNumber: 6415, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm34_3", - tournamentKey: "2024tuhc", - matchNumber: 34, - teamNumber: 6024, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm34_4", - tournamentKey: "2024tuhc", - matchNumber: 34, - teamNumber: 7444, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm34_5", - tournamentKey: "2024tuhc", - matchNumber: 34, - teamNumber: 8214, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm34_0", - tournamentKey: "2024tuhc", - matchNumber: 34, - teamNumber: 8308, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm34_1", - tournamentKey: "2024tuhc", - matchNumber: 34, - teamNumber: 9070, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm34_2", - tournamentKey: "2024tuhc", - matchNumber: 34, - teamNumber: 9490, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm35_3", - tournamentKey: "2024tuhc", - matchNumber: 35, - teamNumber: 9469, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm35_4", - tournamentKey: "2024tuhc", - matchNumber: 35, - teamNumber: 9247, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm35_5", - tournamentKey: "2024tuhc", - matchNumber: 35, - teamNumber: 9436, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm35_0", - tournamentKey: "2024tuhc", - matchNumber: 35, - teamNumber: 9025, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm35_1", - tournamentKey: "2024tuhc", - matchNumber: 35, - teamNumber: 8042, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm35_2", - tournamentKey: "2024tuhc", - matchNumber: 35, - teamNumber: 9692, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm36_3", - tournamentKey: "2024tuhc", - matchNumber: 36, - teamNumber: 9625, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm36_4", - tournamentKey: "2024tuhc", - matchNumber: 36, - teamNumber: 4191, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm36_5", - tournamentKey: "2024tuhc", - matchNumber: 36, - teamNumber: 8173, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm36_0", - tournamentKey: "2024tuhc", - matchNumber: 36, - teamNumber: 6417, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm36_1", - tournamentKey: "2024tuhc", - matchNumber: 36, - teamNumber: 5883, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm36_2", - tournamentKey: "2024tuhc", - matchNumber: 36, - teamNumber: 3646, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm37_3", - tournamentKey: "2024tuhc", - matchNumber: 37, - teamNumber: 7672, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm37_4", - tournamentKey: "2024tuhc", - matchNumber: 37, - teamNumber: 9583, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm37_5", - tournamentKey: "2024tuhc", - matchNumber: 37, - teamNumber: 6985, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm37_0", - tournamentKey: "2024tuhc", - matchNumber: 37, - teamNumber: 8159, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm37_1", - tournamentKey: "2024tuhc", - matchNumber: 37, - teamNumber: 6429, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm37_2", - tournamentKey: "2024tuhc", - matchNumber: 37, - teamNumber: 9231, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm38_3", - tournamentKey: "2024tuhc", - matchNumber: 38, - teamNumber: 8557, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm38_4", - tournamentKey: "2024tuhc", - matchNumber: 38, - teamNumber: 8500, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm38_5", - tournamentKey: "2024tuhc", - matchNumber: 38, - teamNumber: 6064, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm38_0", - tournamentKey: "2024tuhc", - matchNumber: 38, - teamNumber: 7086, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm38_1", - tournamentKey: "2024tuhc", - matchNumber: 38, - teamNumber: 8084, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm38_2", - tournamentKey: "2024tuhc", - matchNumber: 38, - teamNumber: 6430, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm39_3", - tournamentKey: "2024tuhc", - matchNumber: 39, - teamNumber: 8158, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm39_4", - tournamentKey: "2024tuhc", - matchNumber: 39, - teamNumber: 9070, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm39_5", - tournamentKey: "2024tuhc", - matchNumber: 39, - teamNumber: 6415, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm39_0", - tournamentKey: "2024tuhc", - matchNumber: 39, - teamNumber: 9490, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm39_1", - tournamentKey: "2024tuhc", - matchNumber: 39, - teamNumber: 8777, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm39_2", - tournamentKey: "2024tuhc", - matchNumber: 39, - teamNumber: 9565, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm40_3", - tournamentKey: "2024tuhc", - matchNumber: 40, - teamNumber: 6838, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm40_4", - tournamentKey: "2024tuhc", - matchNumber: 40, - teamNumber: 8214, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm40_5", - tournamentKey: "2024tuhc", - matchNumber: 40, - teamNumber: 6874, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm40_0", - tournamentKey: "2024tuhc", - matchNumber: 40, - teamNumber: 8058, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm40_1", - tournamentKey: "2024tuhc", - matchNumber: 40, - teamNumber: 8042, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm40_2", - tournamentKey: "2024tuhc", - matchNumber: 40, - teamNumber: 9690, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm41_3", - tournamentKey: "2024tuhc", - matchNumber: 41, - teamNumber: 7035, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm41_4", - tournamentKey: "2024tuhc", - matchNumber: 41, - teamNumber: 9523, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm41_5", - tournamentKey: "2024tuhc", - matchNumber: 41, - teamNumber: 7522, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm41_0", - tournamentKey: "2024tuhc", - matchNumber: 41, - teamNumber: 7050, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm41_1", - tournamentKey: "2024tuhc", - matchNumber: 41, - teamNumber: 9469, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm41_2", - tournamentKey: "2024tuhc", - matchNumber: 41, - teamNumber: 9447, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm42_3", - tournamentKey: "2024tuhc", - matchNumber: 42, - teamNumber: 9609, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm42_4", - tournamentKey: "2024tuhc", - matchNumber: 42, - teamNumber: 7575, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm42_5", - tournamentKey: "2024tuhc", - matchNumber: 42, - teamNumber: 9464, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm42_0", - tournamentKey: "2024tuhc", - matchNumber: 42, - teamNumber: 9591, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm42_1", - tournamentKey: "2024tuhc", - matchNumber: 42, - teamNumber: 9281, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm42_2", - tournamentKey: "2024tuhc", - matchNumber: 42, - teamNumber: 8308, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm43_3", - tournamentKey: "2024tuhc", - matchNumber: 43, - teamNumber: 2905, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm43_4", - tournamentKey: "2024tuhc", - matchNumber: 43, - teamNumber: 8220, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm43_5", - tournamentKey: "2024tuhc", - matchNumber: 43, - teamNumber: 6024, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm43_0", - tournamentKey: "2024tuhc", - matchNumber: 43, - teamNumber: 9247, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm43_1", - tournamentKey: "2024tuhc", - matchNumber: 43, - teamNumber: 9502, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm43_2", - tournamentKey: "2024tuhc", - matchNumber: 43, - teamNumber: 9468, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm44_3", - tournamentKey: "2024tuhc", - matchNumber: 44, - teamNumber: 7444, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm44_4", - tournamentKey: "2024tuhc", - matchNumber: 44, - teamNumber: 9490, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm44_5", - tournamentKey: "2024tuhc", - matchNumber: 44, - teamNumber: 9231, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm44_0", - tournamentKey: "2024tuhc", - matchNumber: 44, - teamNumber: 9025, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm44_1", - tournamentKey: "2024tuhc", - matchNumber: 44, - teamNumber: 9436, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm44_2", - tournamentKey: "2024tuhc", - matchNumber: 44, - teamNumber: 9625, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm45_3", - tournamentKey: "2024tuhc", - matchNumber: 45, - teamNumber: 9692, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm45_4", - tournamentKey: "2024tuhc", - matchNumber: 45, - teamNumber: 6415, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm45_5", - tournamentKey: "2024tuhc", - matchNumber: 45, - teamNumber: 6429, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm45_0", - tournamentKey: "2024tuhc", - matchNumber: 45, - teamNumber: 8042, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm45_1", - tournamentKey: "2024tuhc", - matchNumber: 45, - teamNumber: 7672, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm45_2", - tournamentKey: "2024tuhc", - matchNumber: 45, - teamNumber: 6838, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm46_3", - tournamentKey: "2024tuhc", - matchNumber: 46, - teamNumber: 7086, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm46_4", - tournamentKey: "2024tuhc", - matchNumber: 46, - teamNumber: 8557, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm46_5", - tournamentKey: "2024tuhc", - matchNumber: 46, - teamNumber: 5883, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm46_0", - tournamentKey: "2024tuhc", - matchNumber: 46, - teamNumber: 9447, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm46_1", - tournamentKey: "2024tuhc", - matchNumber: 46, - teamNumber: 7035, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm46_2", - tournamentKey: "2024tuhc", - matchNumber: 46, - teamNumber: 8214, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm47_3", - tournamentKey: "2024tuhc", - matchNumber: 47, - teamNumber: 9565, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm47_4", - tournamentKey: "2024tuhc", - matchNumber: 47, - teamNumber: 8308, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm47_5", - tournamentKey: "2024tuhc", - matchNumber: 47, - teamNumber: 9469, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm47_0", - tournamentKey: "2024tuhc", - matchNumber: 47, - teamNumber: 6430, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm47_1", - tournamentKey: "2024tuhc", - matchNumber: 47, - teamNumber: 6874, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm47_2", - tournamentKey: "2024tuhc", - matchNumber: 47, - teamNumber: 9591, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm48_3", - tournamentKey: "2024tuhc", - matchNumber: 48, - teamNumber: 6985, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm48_4", - tournamentKey: "2024tuhc", - matchNumber: 48, - teamNumber: 9468, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm48_5", - tournamentKey: "2024tuhc", - matchNumber: 48, - teamNumber: 7522, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm48_0", - tournamentKey: "2024tuhc", - matchNumber: 48, - teamNumber: 3646, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm48_1", - tournamentKey: "2024tuhc", - matchNumber: 48, - teamNumber: 9609, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm48_2", - tournamentKey: "2024tuhc", - matchNumber: 48, - teamNumber: 9523, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm49_3", - tournamentKey: "2024tuhc", - matchNumber: 49, - teamNumber: 9281, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm49_4", - tournamentKey: "2024tuhc", - matchNumber: 49, - teamNumber: 9247, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm49_5", - tournamentKey: "2024tuhc", - matchNumber: 49, - teamNumber: 7050, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm49_0", - tournamentKey: "2024tuhc", - matchNumber: 49, - teamNumber: 8173, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm49_1", - tournamentKey: "2024tuhc", - matchNumber: 49, - teamNumber: 7444, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm49_2", - tournamentKey: "2024tuhc", - matchNumber: 49, - teamNumber: 9583, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm50_3", - tournamentKey: "2024tuhc", - matchNumber: 50, - teamNumber: 8058, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm50_4", - tournamentKey: "2024tuhc", - matchNumber: 50, - teamNumber: 9070, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm50_5", - tournamentKey: "2024tuhc", - matchNumber: 50, - teamNumber: 8500, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm50_0", - tournamentKey: "2024tuhc", - matchNumber: 50, - teamNumber: 8220, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm50_1", - tournamentKey: "2024tuhc", - matchNumber: 50, - teamNumber: 9464, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm50_2", - tournamentKey: "2024tuhc", - matchNumber: 50, - teamNumber: 9025, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm51_3", - tournamentKey: "2024tuhc", - matchNumber: 51, - teamNumber: 4191, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm51_4", - tournamentKey: "2024tuhc", - matchNumber: 51, - teamNumber: 9690, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm51_5", - tournamentKey: "2024tuhc", - matchNumber: 51, - teamNumber: 8084, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm51_0", - tournamentKey: "2024tuhc", - matchNumber: 51, - teamNumber: 8777, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm51_1", - tournamentKey: "2024tuhc", - matchNumber: 51, - teamNumber: 2905, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm51_2", - tournamentKey: "2024tuhc", - matchNumber: 51, - teamNumber: 8158, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm52_3", - tournamentKey: "2024tuhc", - matchNumber: 52, - teamNumber: 6417, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm52_4", - tournamentKey: "2024tuhc", - matchNumber: 52, - teamNumber: 8159, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm52_5", - tournamentKey: "2024tuhc", - matchNumber: 52, - teamNumber: 7575, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm52_0", - tournamentKey: "2024tuhc", - matchNumber: 52, - teamNumber: 6024, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm52_1", - tournamentKey: "2024tuhc", - matchNumber: 52, - teamNumber: 6064, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm52_2", - tournamentKey: "2024tuhc", - matchNumber: 52, - teamNumber: 9502, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm53_3", - tournamentKey: "2024tuhc", - matchNumber: 53, - teamNumber: 9436, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm53_4", - tournamentKey: "2024tuhc", - matchNumber: 53, - teamNumber: 9523, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm53_5", - tournamentKey: "2024tuhc", - matchNumber: 53, - teamNumber: 9490, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm53_0", - tournamentKey: "2024tuhc", - matchNumber: 53, - teamNumber: 6429, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm53_1", - tournamentKey: "2024tuhc", - matchNumber: 53, - teamNumber: 8557, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm53_2", - tournamentKey: "2024tuhc", - matchNumber: 53, - teamNumber: 7672, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm54_3", - tournamentKey: "2024tuhc", - matchNumber: 54, - teamNumber: 9247, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm54_4", - tournamentKey: "2024tuhc", - matchNumber: 54, - teamNumber: 7035, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm54_5", - tournamentKey: "2024tuhc", - matchNumber: 54, - teamNumber: 9609, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm54_0", - tournamentKey: "2024tuhc", - matchNumber: 54, - teamNumber: 3646, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm54_1", - tournamentKey: "2024tuhc", - matchNumber: 54, - teamNumber: 6415, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm54_2", - tournamentKey: "2024tuhc", - matchNumber: 54, - teamNumber: 6874, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm55_3", - tournamentKey: "2024tuhc", - matchNumber: 55, - teamNumber: 9468, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm55_4", - tournamentKey: "2024tuhc", - matchNumber: 55, - teamNumber: 9447, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm55_5", - tournamentKey: "2024tuhc", - matchNumber: 55, - teamNumber: 8042, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm55_0", - tournamentKey: "2024tuhc", - matchNumber: 55, - teamNumber: 8173, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm55_1", - tournamentKey: "2024tuhc", - matchNumber: 55, - teamNumber: 8058, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm55_2", - tournamentKey: "2024tuhc", - matchNumber: 55, - teamNumber: 8308, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm56_3", - tournamentKey: "2024tuhc", - matchNumber: 56, - teamNumber: 6838, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm56_4", - tournamentKey: "2024tuhc", - matchNumber: 56, - teamNumber: 8158, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm56_5", - tournamentKey: "2024tuhc", - matchNumber: 56, - teamNumber: 5883, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm56_0", - tournamentKey: "2024tuhc", - matchNumber: 56, - teamNumber: 6985, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm56_1", - tournamentKey: "2024tuhc", - matchNumber: 56, - teamNumber: 6430, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm56_2", - tournamentKey: "2024tuhc", - matchNumber: 56, - teamNumber: 8220, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm57_3", - tournamentKey: "2024tuhc", - matchNumber: 57, - teamNumber: 7050, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm57_4", - tournamentKey: "2024tuhc", - matchNumber: 57, - teamNumber: 7575, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm57_5", - tournamentKey: "2024tuhc", - matchNumber: 57, - teamNumber: 9070, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm57_0", - tournamentKey: "2024tuhc", - matchNumber: 57, - teamNumber: 9469, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm57_1", - tournamentKey: "2024tuhc", - matchNumber: 57, - teamNumber: 9690, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm57_2", - tournamentKey: "2024tuhc", - matchNumber: 57, - teamNumber: 9625, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm58_3", - tournamentKey: "2024tuhc", - matchNumber: 58, - teamNumber: 9692, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm58_4", - tournamentKey: "2024tuhc", - matchNumber: 58, - teamNumber: 9565, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm58_5", - tournamentKey: "2024tuhc", - matchNumber: 58, - teamNumber: 8159, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm58_0", - tournamentKey: "2024tuhc", - matchNumber: 58, - teamNumber: 2905, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm58_1", - tournamentKey: "2024tuhc", - matchNumber: 58, - teamNumber: 9281, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm58_2", - tournamentKey: "2024tuhc", - matchNumber: 58, - teamNumber: 6417, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm59_3", - tournamentKey: "2024tuhc", - matchNumber: 59, - teamNumber: 8500, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm59_4", - tournamentKey: "2024tuhc", - matchNumber: 59, - teamNumber: 7086, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm59_5", - tournamentKey: "2024tuhc", - matchNumber: 59, - teamNumber: 7444, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm59_0", - tournamentKey: "2024tuhc", - matchNumber: 59, - teamNumber: 7522, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm59_1", - tournamentKey: "2024tuhc", - matchNumber: 59, - teamNumber: 6024, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm59_2", - tournamentKey: "2024tuhc", - matchNumber: 59, - teamNumber: 4191, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm60_3", - tournamentKey: "2024tuhc", - matchNumber: 60, - teamNumber: 9231, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm60_4", - tournamentKey: "2024tuhc", - matchNumber: 60, - teamNumber: 9502, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm60_5", - tournamentKey: "2024tuhc", - matchNumber: 60, - teamNumber: 8777, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm60_0", - tournamentKey: "2024tuhc", - matchNumber: 60, - teamNumber: 8214, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm60_1", - tournamentKey: "2024tuhc", - matchNumber: 60, - teamNumber: 6064, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm60_2", - tournamentKey: "2024tuhc", - matchNumber: 60, - teamNumber: 9464, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm61_3", - tournamentKey: "2024tuhc", - matchNumber: 61, - teamNumber: 9591, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm61_4", - tournamentKey: "2024tuhc", - matchNumber: 61, - teamNumber: 9025, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm61_5", - tournamentKey: "2024tuhc", - matchNumber: 61, - teamNumber: 3646, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm61_0", - tournamentKey: "2024tuhc", - matchNumber: 61, - teamNumber: 8084, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm61_1", - tournamentKey: "2024tuhc", - matchNumber: 61, - teamNumber: 9583, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm61_2", - tournamentKey: "2024tuhc", - matchNumber: 61, - teamNumber: 9447, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm62_3", - tournamentKey: "2024tuhc", - matchNumber: 62, - teamNumber: 7575, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm62_4", - tournamentKey: "2024tuhc", - matchNumber: 62, - teamNumber: 8308, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm62_5", - tournamentKey: "2024tuhc", - matchNumber: 62, - teamNumber: 9690, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm62_0", - tournamentKey: "2024tuhc", - matchNumber: 62, - teamNumber: 9490, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm62_1", - tournamentKey: "2024tuhc", - matchNumber: 62, - teamNumber: 6429, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm62_2", - tournamentKey: "2024tuhc", - matchNumber: 62, - teamNumber: 7035, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm63_3", - tournamentKey: "2024tuhc", - matchNumber: 63, - teamNumber: 8173, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm63_4", - tournamentKey: "2024tuhc", - matchNumber: 63, - teamNumber: 7672, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm63_5", - tournamentKey: "2024tuhc", - matchNumber: 63, - teamNumber: 2905, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm63_0", - tournamentKey: "2024tuhc", - matchNumber: 63, - teamNumber: 9070, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm63_1", - tournamentKey: "2024tuhc", - matchNumber: 63, - teamNumber: 6430, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm63_2", - tournamentKey: "2024tuhc", - matchNumber: 63, - teamNumber: 8557, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm64_3", - tournamentKey: "2024tuhc", - matchNumber: 64, - teamNumber: 9281, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm64_4", - tournamentKey: "2024tuhc", - matchNumber: 64, - teamNumber: 9469, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm64_5", - tournamentKey: "2024tuhc", - matchNumber: 64, - teamNumber: 5883, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm64_0", - tournamentKey: "2024tuhc", - matchNumber: 64, - teamNumber: 6024, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm64_1", - tournamentKey: "2024tuhc", - matchNumber: 64, - teamNumber: 8500, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm64_2", - tournamentKey: "2024tuhc", - matchNumber: 64, - teamNumber: 9436, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm65_3", - tournamentKey: "2024tuhc", - matchNumber: 65, - teamNumber: 8158, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm65_4", - tournamentKey: "2024tuhc", - matchNumber: 65, - teamNumber: 9625, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm65_5", - tournamentKey: "2024tuhc", - matchNumber: 65, - teamNumber: 9502, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm65_0", - tournamentKey: "2024tuhc", - matchNumber: 65, - teamNumber: 6874, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm65_1", - tournamentKey: "2024tuhc", - matchNumber: 65, - teamNumber: 7086, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm65_2", - tournamentKey: "2024tuhc", - matchNumber: 65, - teamNumber: 9692, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm66_3", - tournamentKey: "2024tuhc", - matchNumber: 66, - teamNumber: 9591, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm66_4", - tournamentKey: "2024tuhc", - matchNumber: 66, - teamNumber: 8159, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm66_5", - tournamentKey: "2024tuhc", - matchNumber: 66, - teamNumber: 4191, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm66_0", - tournamentKey: "2024tuhc", - matchNumber: 66, - teamNumber: 9025, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm66_1", - tournamentKey: "2024tuhc", - matchNumber: 66, - teamNumber: 6838, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm66_2", - tournamentKey: "2024tuhc", - matchNumber: 66, - teamNumber: 9468, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm67_3", - tournamentKey: "2024tuhc", - matchNumber: 67, - teamNumber: 6985, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm67_4", - tournamentKey: "2024tuhc", - matchNumber: 67, - teamNumber: 7050, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm67_5", - tournamentKey: "2024tuhc", - matchNumber: 67, - teamNumber: 8084, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm67_0", - tournamentKey: "2024tuhc", - matchNumber: 67, - teamNumber: 8214, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm67_1", - tournamentKey: "2024tuhc", - matchNumber: 67, - teamNumber: 9565, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm67_2", - tournamentKey: "2024tuhc", - matchNumber: 67, - teamNumber: 9247, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm68_3", - tournamentKey: "2024tuhc", - matchNumber: 68, - teamNumber: 8220, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm68_4", - tournamentKey: "2024tuhc", - matchNumber: 68, - teamNumber: 7522, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm68_5", - tournamentKey: "2024tuhc", - matchNumber: 68, - teamNumber: 6417, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm68_0", - tournamentKey: "2024tuhc", - matchNumber: 68, - teamNumber: 9231, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm68_1", - tournamentKey: "2024tuhc", - matchNumber: 68, - teamNumber: 9464, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm68_2", - tournamentKey: "2024tuhc", - matchNumber: 68, - teamNumber: 6415, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm69_3", - tournamentKey: "2024tuhc", - matchNumber: 69, - teamNumber: 8777, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm69_4", - tournamentKey: "2024tuhc", - matchNumber: 69, - teamNumber: 9523, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm69_5", - tournamentKey: "2024tuhc", - matchNumber: 69, - teamNumber: 8058, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm69_0", - tournamentKey: "2024tuhc", - matchNumber: 69, - teamNumber: 8042, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm69_1", - tournamentKey: "2024tuhc", - matchNumber: 69, - teamNumber: 9609, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm69_2", - tournamentKey: "2024tuhc", - matchNumber: 69, - teamNumber: 7444, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm70_3", - tournamentKey: "2024tuhc", - matchNumber: 70, - teamNumber: 6064, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm70_4", - tournamentKey: "2024tuhc", - matchNumber: 70, - teamNumber: 9447, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm70_5", - tournamentKey: "2024tuhc", - matchNumber: 70, - teamNumber: 2905, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm70_0", - tournamentKey: "2024tuhc", - matchNumber: 70, - teamNumber: 9583, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm70_1", - tournamentKey: "2024tuhc", - matchNumber: 70, - teamNumber: 9436, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm70_2", - tournamentKey: "2024tuhc", - matchNumber: 70, - teamNumber: 6874, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm71_3", - tournamentKey: "2024tuhc", - matchNumber: 71, - teamNumber: 9502, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm71_4", - tournamentKey: "2024tuhc", - matchNumber: 71, - teamNumber: 9281, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm71_5", - tournamentKey: "2024tuhc", - matchNumber: 71, - teamNumber: 9025, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm71_0", - tournamentKey: "2024tuhc", - matchNumber: 71, - teamNumber: 6429, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm71_1", - tournamentKey: "2024tuhc", - matchNumber: 71, - teamNumber: 5883, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm71_2", - tournamentKey: "2024tuhc", - matchNumber: 71, - teamNumber: 8308, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm72_3", - tournamentKey: "2024tuhc", - matchNumber: 72, - teamNumber: 6430, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm72_4", - tournamentKey: "2024tuhc", - matchNumber: 72, - teamNumber: 9690, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm72_5", - tournamentKey: "2024tuhc", - matchNumber: 72, - teamNumber: 9490, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm72_0", - tournamentKey: "2024tuhc", - matchNumber: 72, - teamNumber: 9247, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm72_1", - tournamentKey: "2024tuhc", - matchNumber: 72, - teamNumber: 3646, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm72_2", - tournamentKey: "2024tuhc", - matchNumber: 72, - teamNumber: 7086, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm73_3", - tournamentKey: "2024tuhc", - matchNumber: 73, - teamNumber: 7050, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm73_4", - tournamentKey: "2024tuhc", - matchNumber: 73, - teamNumber: 6415, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm73_5", - tournamentKey: "2024tuhc", - matchNumber: 73, - teamNumber: 6838, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm73_0", - tournamentKey: "2024tuhc", - matchNumber: 73, - teamNumber: 9231, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm73_1", - tournamentKey: "2024tuhc", - matchNumber: 73, - teamNumber: 6024, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm73_2", - tournamentKey: "2024tuhc", - matchNumber: 73, - teamNumber: 8158, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm74_3", - tournamentKey: "2024tuhc", - matchNumber: 74, - teamNumber: 7672, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm74_4", - tournamentKey: "2024tuhc", - matchNumber: 74, - teamNumber: 8058, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm74_5", - tournamentKey: "2024tuhc", - matchNumber: 74, - teamNumber: 6417, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm74_0", - tournamentKey: "2024tuhc", - matchNumber: 74, - teamNumber: 8084, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm74_1", - tournamentKey: "2024tuhc", - matchNumber: 74, - teamNumber: 9469, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm74_2", - tournamentKey: "2024tuhc", - matchNumber: 74, - teamNumber: 9591, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm75_3", - tournamentKey: "2024tuhc", - matchNumber: 75, - teamNumber: 7035, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm75_4", - tournamentKey: "2024tuhc", - matchNumber: 75, - teamNumber: 6064, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm75_5", - tournamentKey: "2024tuhc", - matchNumber: 75, - teamNumber: 9583, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm75_0", - tournamentKey: "2024tuhc", - matchNumber: 75, - teamNumber: 8220, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm75_1", - tournamentKey: "2024tuhc", - matchNumber: 75, - teamNumber: 9468, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm75_2", - tournamentKey: "2024tuhc", - matchNumber: 75, - teamNumber: 9070, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm76_3", - tournamentKey: "2024tuhc", - matchNumber: 76, - teamNumber: 7522, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm76_4", - tournamentKey: "2024tuhc", - matchNumber: 76, - teamNumber: 8777, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm76_5", - tournamentKey: "2024tuhc", - matchNumber: 76, - teamNumber: 9609, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm76_0", - tournamentKey: "2024tuhc", - matchNumber: 76, - teamNumber: 8557, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm76_1", - tournamentKey: "2024tuhc", - matchNumber: 76, - teamNumber: 8159, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm76_2", - tournamentKey: "2024tuhc", - matchNumber: 76, - teamNumber: 9625, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm77_3", - tournamentKey: "2024tuhc", - matchNumber: 77, - teamNumber: 9464, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm77_4", - tournamentKey: "2024tuhc", - matchNumber: 77, - teamNumber: 8173, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm77_5", - tournamentKey: "2024tuhc", - matchNumber: 77, - teamNumber: 6985, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm77_0", - tournamentKey: "2024tuhc", - matchNumber: 77, - teamNumber: 7575, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm77_1", - tournamentKey: "2024tuhc", - matchNumber: 77, - teamNumber: 9692, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm77_2", - tournamentKey: "2024tuhc", - matchNumber: 77, - teamNumber: 7444, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm78_3", - tournamentKey: "2024tuhc", - matchNumber: 78, - teamNumber: 8042, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm78_4", - tournamentKey: "2024tuhc", - matchNumber: 78, - teamNumber: 8214, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm78_5", - tournamentKey: "2024tuhc", - matchNumber: 78, - teamNumber: 9523, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm78_0", - tournamentKey: "2024tuhc", - matchNumber: 78, - teamNumber: 9565, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm78_1", - tournamentKey: "2024tuhc", - matchNumber: 78, - teamNumber: 4191, - matchType: "QUALIFICATION", - }, - { - key: "2024tuhc_qm78_2", - tournamentKey: "2024tuhc", - matchNumber: 78, - teamNumber: 8500, - matchType: "QUALIFICATION", - }, - ], - }); - res.status(200).send(rows); - } catch (error) { - console.error(error); - res.status(500).send(error); - } -}; diff --git a/src/handler/manager/addApiKey.ts b/src/handler/manager/apikey/addApiKey.ts similarity index 88% rename from src/handler/manager/addApiKey.ts rename to src/handler/manager/apikey/addApiKey.ts index 1499ea9d..beb7b593 100644 --- a/src/handler/manager/addApiKey.ts +++ b/src/handler/manager/apikey/addApiKey.ts @@ -1,8 +1,8 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; import { createHash, randomBytes } from "crypto"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const addApiKey = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/getApiKeys.ts b/src/handler/manager/apikey/getApiKeys.ts similarity index 88% rename from src/handler/manager/getApiKeys.ts rename to src/handler/manager/apikey/getApiKeys.ts index 49b956ca..31e59c81 100644 --- a/src/handler/manager/getApiKeys.ts +++ b/src/handler/manager/apikey/getApiKeys.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; import { UserRole } from "@prisma/client"; export const getApiKeys = async ( diff --git a/src/handler/manager/renameApiKey.ts b/src/handler/manager/apikey/renameApiKey.ts similarity index 91% rename from src/handler/manager/renameApiKey.ts rename to src/handler/manager/apikey/renameApiKey.ts index 131729e4..15c061ee 100644 --- a/src/handler/manager/renameApiKey.ts +++ b/src/handler/manager/apikey/renameApiKey.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; import { UserRole } from "@prisma/client"; export const renameApiKey = async ( diff --git a/src/handler/manager/revokeApiKey.ts b/src/handler/manager/apikey/revokeApiKey.ts similarity index 90% rename from src/handler/manager/revokeApiKey.ts rename to src/handler/manager/apikey/revokeApiKey.ts index b91b5716..9c43ce42 100644 --- a/src/handler/manager/revokeApiKey.ts +++ b/src/handler/manager/apikey/revokeApiKey.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; import { UserRole } from "@prisma/client"; export const revokeApiKey = async ( diff --git a/src/handler/manager/getMatches.ts b/src/handler/manager/getMatches.ts index 95a56e13..061155f8 100644 --- a/src/handler/manager/getMatches.ts +++ b/src/handler/manager/getMatches.ts @@ -3,18 +3,23 @@ import prismaClient from "../../prismaClient.js"; import z from "zod"; import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; import { addTournamentMatches } from "./addTournamentMatches.js"; +import { ReverseMatchTypeMap } from "./managerConstants.js"; +import { MatchType, Prisma } from "@prisma/client"; import { - MatchTypeMap, - MatchTypeToAbrivation, - ReverseMatchTypeMap, - ReverseScouterScheduleMap, - ScouterScheduleMap, -} from "./managerConstants.js"; + swrConstant, + ttlConstant, +} from "../analysis/analysisConstants.js"; import { dataSourceRuleSchema, dataSourceRuleToPrismaFilter, } from "../analysis/dataSourceRule.js"; +/** + * @param params.tournament tournament to pull from + * @param query.teams optional - limit to matches containing all these teams + * + * @returns list of matches organized by number and type, with data for teams/scouts/external reports + */ export const getMatches = async ( req: AuthenticatedRequest, res: Response, @@ -22,496 +27,409 @@ export const getMatches = async ( try { const user = req.user; let teams = null; - let isScouted = null; - //type check, convert isScouted to a boolean - if (req.query.isScouted != undefined) { - isScouted = req.query.isScouted === "true"; - } if (req.query.teams != undefined) { teams = JSON.parse(req.query.teams as string); } const params = z .object({ tournamentKey: z.string(), - teamNumbers: z.array(z.number()).nullable(), - isScouted: z.boolean().nullable(), + teamFilter: z.array(z.number()).nullable(), }) .safeParse({ tournamentKey: req.params.tournament, - teamNumbers: teams, - isScouted: isScouted, + teamFilter: teams, }); if (!params.success) { res.status(400).send(params); return; } - //get matches from tournament, check that tournament has been inserted. If not add it - const matchRows = await prismaClient.teamMatchData.findMany({ + if (params.data.teamFilter && params.data.teamFilter.length > 6) { + res.status(400).send("Too many team filters"); + return; + } + + // Check that matches from a tournament exist; if not, add them + const matchRow = await prismaClient.teamMatchData.findFirst({ where: { tournamentKey: params.data.tournamentKey, }, }); - if (matchRows.length === 0) { + if (!matchRow) { await addTournamentMatches(params.data.tournamentKey); } - //find scouted matches (using sourceTeam and isScouted ) - //get all matches regarless for ordinal number calculation later on - const qualMatches = await prismaClient.teamMatchData.findMany({ + // Assuming all elimination matches are not scouted, find the last scouted match (and pretend it is the last completed one) + const last = await prismaClient.teamMatchData.findFirst({ where: { tournamentKey: params.data.tournamentKey, - matchType: "QUALIFICATION", + matchType: MatchType.QUALIFICATION, + scoutReports: { + some: {}, + }, }, - orderBy: { - teamNumber: "asc", + orderBy: [{ matchNumber: "desc" }], + select: { + matchNumber: true, }, }); - if (qualMatches.length === 0) { - res - .status(404) - .send("The match schedule for this tournament hasn't been posted yet."); - return; + // Default to 0 + const lastFinishedMatch = last ? last.matchNumber : 0; + + // Filter to return a list of user's team's scout reports for each row, only valid if user has a team number + let includeTeamReports: Prisma.TeamMatchData$scoutReportsArgs | undefined = + undefined; + + const teamSourceRule = dataSourceRuleSchema(z.number()).parse( + req.user.teamSourceRule, + ); + + if (user.teamNumber) { + // make sure the user's teamSourceRule has their own team included + if (teamSourceRule.mode === "EXCLUDE") { + // if their source rule is exclude, make sure the user's team number isn't in items + teamSourceRule.items = teamSourceRule.items.filter( + (item) => item !== user.teamNumber, + ); + } else if ( + // if their mode is include, make sure the user's team number is on their list of items + teamSourceRule.mode === "INCLUDE" && + !teamSourceRule.items.includes(user.teamNumber) + ) { + teamSourceRule.items.push(user.teamNumber); + } + + includeTeamReports = { + where: { + scouter: { + sourceTeamNumber: user.teamNumber, + }, + }, + select: { + scouter: { + select: { + name: true, + uuid: true, + }, + }, + }, + }; } - const lastQualMatch = Number(qualMatches.length / 6); - //find non scouted matches (not scouted from user.sourceTeam) - const notScouted = await prismaClient.teamMatchData.findMany({ + const rawData = await prismaClient.teamMatchData.findMany({ + cacheStrategy: { + swr: swrConstant, + ttl: ttlConstant, + }, where: { tournamentKey: params.data.tournamentKey, - scoutReports: { - none: { - scouter: { - sourceTeamNumber: dataSourceRuleToPrismaFilter( - dataSourceRuleSchema(z.number()).parse(req.user.teamSourceRule), - ), + }, + select: { + matchNumber: true, + matchType: true, + teamNumber: true, + key: true, + _count: { + // Represents the total number of valid scout reports for this row + select: { + scoutReports: { + where: { + scouter: { + sourceTeamNumber: + dataSourceRuleToPrismaFilter(teamSourceRule), + }, + }, }, }, }, + scoutReports: includeTeamReports, }, - - orderBy: [{ matchType: "desc" }, { matchNumber: "asc" }], }); - //check to make sure each match has 6 rows, if not than 1 + rows have been scouted already - const groupedMatches = await notScouted.reduce((acc, match) => { - const key = `${match.matchNumber}-${match.matchType}`; - if (!acc[key]) { - acc[key] = []; - } - acc[key].push(match); + + /* + * SELECT matchNumber, matchType, teamNumber, key + * (SELECT COUNT(*) + * FROM scoutReports + * WHERE scouter.sourceTeamNumber IN (${[9143, 8033].join(",")})) AS _reports + * (SELECT COUNT(*) + * FROM scoutReports + * WHERE (NOT scouter.sourceTeamNumber = (${9143})) + * AND (scouter.sourceTeamNumber IN (${[9143, 8033].join(",")}))) AS _external + * FROM TeamMatchData + * WHERE tournamentKey = ${"2024casf"}; + */ + + // Group data by match (first layer, elimination matches are negative indices) and team (second layer, 0-5) + // !!!IMPORTANT: the scoutReports property only exists if user.teamNumber exists + let groupedData: { + matchNumber: number; + teamNumber: number; + matchType: MatchType; + key: string; + _count: { scoutReports: number }; + scoutReports: { scouter: { name: string; uuid: string } }[] | undefined; + }[][] = rawData.reduce((acc, curr) => { + // Positive indices are quals, negatives are elims + const i = + curr.matchNumber * (curr.matchType === MatchType.ELIMINATION ? -1 : 1); + acc[i] ??= []; + // Order match by team index [0-5] + acc[i][Number(curr.key.at(-1))] = curr; return acc; - }, {}); + }, []); - // find matches with less than 6 rows - const groupsToKeep = Object.keys(groupedMatches).filter( - (key) => groupedMatches[key].length >= 6, - ); + const lastQualMatch = groupedData.length - 1; - // remove unwanted matches - const nonScoutedMatches = notScouted.filter((match) => { - const key = `${match.matchNumber}-${match.matchType}`; - return groupsToKeep.includes(key); - }); + // If team filters are set, limit matches to those including all selected teams + if (params.data.teamFilter && params.data.teamFilter.length > 0) { + const tempArray: typeof groupedData = []; - const scoutedMatches = await prismaClient.teamMatchData.findMany({ - where: { - tournamentKey: params.data.tournamentKey, - key: { - notIn: nonScoutedMatches.map((item) => item.key), - }, - }, - }); - //get just the matchNumber + matchType for matches scouted and unscouted speratly - let matchKeyAndNumber = []; - if ( - params.data.isScouted === null || - params.data.isScouted === undefined || - params.data.isScouted - ) { - const matchKeyAndNumberScouted = await prismaClient.teamMatchData.groupBy( - { - by: ["matchNumber", "matchType"], - where: { - tournamentKey: params.data.tournamentKey, - key: { - in: scoutedMatches.map((item) => item.key), - }, - }, - orderBy: [{ matchType: "desc" }, { matchNumber: "asc" }], - }, - ); - matchKeyAndNumber = matchKeyAndNumber.concat( - matchKeyAndNumberScouted.map((match) => ({ ...match, scouted: true })), - ); + // For..in to iterate over positive and negative properties + for (const k in groupedData) { + const i = parseInt(k); + const match = groupedData[i]; + if ( + params.data.teamFilter.every((requiredTeam) => + match.find((team) => team.teamNumber === requiredTeam), + ) + ) { + // Check that all required teams are included in a match + tempArray[i] = match; + } + } + + groupedData = tempArray; } - if ( - params.data.isScouted === null || - params.data.isScouted === undefined || - !params.data.isScouted - ) { - const matchKeyAndNumberUnScouted = - await prismaClient.teamMatchData.groupBy({ - by: ["matchNumber", "matchType"], - where: { - tournamentKey: params.data.tournamentKey, - key: { - in: nonScoutedMatches.map((item) => item.key), - }, + + // Fetch data for matches and attach scouted and finished flags + const finalFormattedMatches: { + matchNumber: number; + matchType: number; + scouted: boolean; + finished: boolean; + team1: { + number: number; + scouters: { name: string; scouted: boolean }[]; + externalReports: number; + }; + team2: { + number: number; + scouters: { name: string; scouted: boolean }[]; + externalReports: number; + }; + team3: { + number: number; + scouters: { name: string; scouted: boolean }[]; + externalReports: number; + }; + team4: { + number: number; + scouters: { name: string; scouted: boolean }[]; + externalReports: number; + }; + team5: { + number: number; + scouters: { name: string; scouted: boolean }[]; + externalReports: number; + }; + team6: { + number: number; + scouters: { name: string; scouted: boolean }[]; + externalReports: number; + }; + }[] = []; + + // If no team number is set, there are no scouters and all reports are external + if (!user.teamNumber) { + for (const k in groupedData) { + const i = parseInt(k); + const match = groupedData[i]; + const currData = { + matchNumber: match[0].matchNumber, + matchType: ReverseMatchTypeMap[match[0].matchType], + scouted: match.some((team) => team._count.scoutReports >= 1), + finished: + match[0].matchType === MatchType.QUALIFICATION && + match[0].matchNumber <= lastFinishedMatch, + team1: { + number: match[0].teamNumber, + scouters: [], + externalReports: match[0]._count.scoutReports, }, - _count: { - _all: true, + team2: { + number: match[1].teamNumber, + scouters: [], + externalReports: match[1]._count.scoutReports, }, - orderBy: [{ matchType: "asc" }, { matchNumber: "asc" }], - }); - matchKeyAndNumber = matchKeyAndNumber.concat( - matchKeyAndNumberUnScouted.map((match) => ({ - ...match, - scouted: false, - })), - ); - } - //assuming scouted matches always come before non scouted, add sort to comfim that - let finalMatches = []; - if ( - params.data.teamNumbers && - params.data.teamNumbers.length > 0 && - params.data.teamNumbers.length <= 6 - ) { - for (const currMatchKeyAndNumber of matchKeyAndNumber) { - const currMatch = await prismaClient.teamMatchData.findMany({ - where: { - matchNumber: currMatchKeyAndNumber.matchNumber, - matchType: currMatchKeyAndNumber.matchType, - tournamentKey: params.data.tournamentKey, + team3: { + number: match[2].teamNumber, + scouters: [], + externalReports: match[2]._count.scoutReports, }, - }); - const currMatchTeamNumbers = currMatch.map((match) => match.teamNumber); - const allTeamsPresent = params.data.teamNumbers.every((teamNumber) => - currMatchTeamNumbers.includes(teamNumber), - ); - if (allTeamsPresent) { - finalMatches.push(currMatchKeyAndNumber); + team4: { + number: match[3].teamNumber, + scouters: [], + externalReports: match[3]._count.scoutReports, + }, + team5: { + number: match[4].teamNumber, + scouters: [], + externalReports: match[4]._count.scoutReports, + }, + team6: { + number: match[5].teamNumber, + scouters: [], + externalReports: match[5]._count.scoutReports, + }, + }; + + // Index = ordinal match number, 0 indexed + if (i > 0) { + finalFormattedMatches[i - 1] = currData; + } else { + finalFormattedMatches[lastQualMatch - i - 1] = currData; } } - } else if ( - params.data.teamNumbers === null || - params.data.teamNumbers === undefined || - params.data.teamNumbers.length === 0 - ) { - finalMatches = matchKeyAndNumber; + + res.status(200).send(finalFormattedMatches); + return; } - //sort - finalMatches.sort((a, b) => { - if (a.matchType < b.matchType) return 1; - if (a.matchType > b.matchType) return -1; - return a.matchNumber - b.matchNumber; + // Done here if user has no team number + + const scouterShifts = await prismaClient.scouterScheduleShift.findMany({ + where: { + tournamentKey: params.data.tournamentKey, + sourceTeamNumber: user.teamNumber, + }, + orderBy: [{ startMatchOrdinalNumber: "asc" }], + select: { + startMatchOrdinalNumber: true, + endMatchOrdinalNumber: true, + team1: { select: { name: true, uuid: true } }, + team2: { select: { name: true, uuid: true } }, + team3: { select: { name: true, uuid: true } }, + team4: { select: { name: true, uuid: true } }, + team5: { select: { name: true, uuid: true } }, + team6: { select: { name: true, uuid: true } }, + }, }); - const finalFormatedMatches = []; - //change into proper format once we know all the matches we are including - for (const element of finalMatches) { - let currMatch = await prismaClient.teamMatchData.findMany({ - where: { - matchNumber: element.matchNumber, - matchType: element.matchType, - tournamentKey: params.data.tournamentKey, - }, - }); - if (currMatch.length != 6) { - res - .status(400) - .send( - `Matches not added correctly, does not have 6 teams for match ${element.matchNumber} of type ${element.matchType}`, - ); - return; + let currShiftIndex = 0; + // For..in should iterate through array indices first, then other properties by insertion order + for (const k in groupedData) { + const i = parseInt(k); + const match = groupedData[i]; + const ordinalMatchNumber = i > 0 ? i : lastQualMatch - i; + + // Increment the scouter shift if we passed the upper bound + if ( + scouterShifts[currShiftIndex] && + ordinalMatchNumber > scouterShifts[currShiftIndex].endMatchOrdinalNumber + ) { + currShiftIndex++; } - //sort by 0, 1, 2, 3, 4, 5 in case its out of order - currMatch = currMatch.sort((a, b) => { - const lastDigitA = parseInt(a.key[a.key.length - 1]); - const lastDigitB = parseInt(b.key[b.key.length - 1]); - return lastDigitA - lastDigitB; - }); + + const matchScouters: { name: string; scouted: boolean }[][] = []; + for (let j = 0; j < 6; j++) { + // Add all complete scout reports from user's team + matchScouters[j] = match[j].scoutReports.map((e) => ({ + name: e.scouter.name, + scouted: true, + })); + + // If the current match number is within a scouter shift, add incomplete scout reports + if ( + scouterShifts[currShiftIndex] && + ordinalMatchNumber >= + scouterShifts[currShiftIndex].startMatchOrdinalNumber + ) { + // Sketchy but iterates through team1-6, could cause problems if schema is changed + for (const currScouter of scouterShifts[currShiftIndex][ + `team${j + 1}` + ]) { + // If the sourced scout reports do not include ones from the shift, add those as incomplete + if ( + !match[j].scoutReports.some( + (e) => e.scouter.uuid === currScouter.uuid, + ) + ) { + matchScouters[j].push({ name: currScouter.name, scouted: false }); + } + } + } + } + + // Scouted flag based on if any team in this match has at least 1 sourced scout report + // Finished flag is true if the match is a qualification before the last finished match + // Scouters array includes all scouters from user's team, and all incomplete reports from assigned scouting shifts + // External reports are the number of non-team scout reports, so [other team reports - user team reports] const currData = { - tournamentKey: params.data.tournamentKey, - matchNumber: element.matchNumber, - matchType: ReverseMatchTypeMap[element.matchType], - scouted: element.scouted, + matchNumber: match[0].matchNumber, + matchType: ReverseMatchTypeMap[match[0].matchType], + scouted: match.some((team) => team._count.scoutReports >= 1), + finished: + match[0].matchType === MatchType.QUALIFICATION && + match[0].matchNumber <= lastFinishedMatch, team1: { - number: currMatch[0].teamNumber, - alliance: "red", - scouters: [], - externalReports: 0, + number: match[0].teamNumber, + scouters: matchScouters[0], + externalReports: + match[0]._count.scoutReports - match[0].scoutReports.length, }, team2: { - number: currMatch[1].teamNumber, - alliance: "red", - scouters: [], - externalReports: 0, + number: match[1].teamNumber, + scouters: matchScouters[1], + externalReports: + match[1]._count.scoutReports - match[1].scoutReports.length, }, team3: { - number: currMatch[2].teamNumber, - alliance: "red", - scouters: [], - externalReports: 0, + number: match[2].teamNumber, + scouters: matchScouters[2], + externalReports: + match[2]._count.scoutReports - match[2].scoutReports.length, }, team4: { - number: currMatch[3].teamNumber, - alliance: "blue", - scouters: [], - externalReports: 0, + number: match[3].teamNumber, + scouters: matchScouters[3], + externalReports: + match[3]._count.scoutReports - match[3].scoutReports.length, }, team5: { - number: currMatch[4].teamNumber, - alliance: "blue", - scouters: [], - externalReports: 0, + number: match[4].teamNumber, + scouters: matchScouters[4], + externalReports: + match[4]._count.scoutReports - match[4].scoutReports.length, }, team6: { - number: currMatch[5].teamNumber, - alliance: "blue", - scouters: [], - externalReports: 0, + number: match[5].teamNumber, + scouters: matchScouters[5], + externalReports: + match[5]._count.scoutReports - match[5].scoutReports.length, }, }; - finalFormatedMatches.push(currData); - } - const promises = []; - if (user.teamNumber) { - const scouterShifts = await prismaClient.scouterScheduleShift.findMany({ - where: { - tournamentKey: params.data.tournamentKey, - sourceTeamNumber: user.teamNumber, - }, - orderBy: [{ startMatchOrdinalNumber: "asc" }], - include: { - team1: true, - team2: true, - team3: true, - team4: true, - team5: true, - team6: true, - }, - }); - if (scouterShifts.length !== 0) { - for (const element of finalFormatedMatches) { - let scoutersExist = true; - //if its an elimination match get the ordinal number, so that we can compare it to the scouterShift start/end - let matchNumber = element.matchNumber; - if (element.matchType === 1) { - matchNumber += lastQualMatch; - } - //move onto correct shift - let currIndex = 0; - while (scouterShifts[currIndex].endMatchOrdinalNumber < matchNumber) { - currIndex += 1; - if (currIndex >= scouterShifts.length) { - scoutersExist = false; - break; - } - } - if ( - scoutersExist && - scouterShifts[currIndex].startMatchOrdinalNumber > matchNumber - ) { - scoutersExist = false; - } - if (scoutersExist) { - promises.push( - addScoutedTeam(req, scouterShifts, currIndex, "team1", element), - ); - promises.push( - addScoutedTeam(req, scouterShifts, currIndex, "team2", element), - ); - promises.push( - addScoutedTeam(req, scouterShifts, currIndex, "team3", element), - ); - promises.push( - addScoutedTeam(req, scouterShifts, currIndex, "team4", element), - ); - promises.push( - addScoutedTeam(req, scouterShifts, currIndex, "team5", element), - ); - promises.push( - addScoutedTeam(req, scouterShifts, currIndex, "team6", element), - ); - } else { - promises.push(addScoutedTeamNotOnSchedule(req, "team1", element)); - promises.push(addScoutedTeamNotOnSchedule(req, "team2", element)); - promises.push(addScoutedTeamNotOnSchedule(req, "team3", element)); - promises.push(addScoutedTeamNotOnSchedule(req, "team4", element)); - promises.push(addScoutedTeamNotOnSchedule(req, "team5", element)); - promises.push(addScoutedTeamNotOnSchedule(req, "team6", element)); - } - if (element.scouted) { - promises.push(addExternalReports(req, element)); - } - } - } else { - for (const match of finalFormatedMatches) { - promises.push(addScoutedTeamNotOnSchedule(req, "team1", match)); - promises.push(addScoutedTeamNotOnSchedule(req, "team2", match)); - promises.push(addScoutedTeamNotOnSchedule(req, "team3", match)); - promises.push(addScoutedTeamNotOnSchedule(req, "team4", match)); - promises.push(addScoutedTeamNotOnSchedule(req, "team5", match)); - promises.push(addScoutedTeamNotOnSchedule(req, "team6", match)); - if (match.scouted) { - await addExternalReports(req, match); - } - } - } - } else { - for (const match of finalFormatedMatches) { - promises.push(addExternalReports(req, match)); - } - } - - await Promise.all(promises); - res.status(200).send(finalFormatedMatches); - } catch (error) { - res.status(500).send(error); - } -}; -//problem: will push to all 6 teams -async function addScoutedTeamNotOnSchedule( - req: AuthenticatedRequest, - team: string, - match, - scouterShifts = null, - currIndex = -1, -) { - try { - const key = - match.tournamentKey + - "_" + - MatchTypeToAbrivation[match.matchType] + - match.matchNumber + - "_" + - ReverseScouterScheduleMap[team]; - if (scouterShifts !== null && currIndex !== -1) { - const rows = await prismaClient.scoutReport.findMany({ - where: { - teamMatchData: { - key: key, - }, - scouterUuid: { - notIn: scouterShifts[currIndex][team].map((item) => item.uuid), - }, - scouter: { - sourceTeamNumber: req.user.teamNumber, - }, - }, - include: { - scouter: true, - }, - }); - for (const scoutReport of rows) { - await match[team].scouters.push({ - name: scoutReport.scouter.name, - scouted: true, - }); - } - } else { - const rows = await prismaClient.scoutReport.findMany({ - where: { - teamMatchData: { - key: key, - }, - scouter: { - sourceTeamNumber: req.user.teamNumber, - }, - }, - include: { - scouter: true, - }, - }); + // Ordered by ordinal match number, 0 indexed + finalFormattedMatches[ordinalMatchNumber - 1] = currData; + } - for (const scoutReport of rows) { - await match[team].scouters.push({ - name: scoutReport.scouter.name, - scouted: true, - }); - } + if (!params.data.teamFilter) { + res.status(200).send(finalFormattedMatches); + return; } - return true; - } catch (error) { - throw error; - } -} -async function addScoutedTeam( - req: AuthenticatedRequest, - scouterShifts, - currIndex: number, - team: string, - match, -) { - try { - const key = - match.tournamentKey + - "_" + - MatchTypeToAbrivation[match.matchType] + - match.matchNumber + - "_" + - ReverseScouterScheduleMap[team]; - for (const scouter of scouterShifts[currIndex][team]) { - const rows = await prismaClient.scoutReport.findMany({ - where: { - scouterUuid: scouter.uuid, - teamMatchKey: key, - }, - }); - if (rows !== null && rows.length > 0) { - for (const element of rows) { - await match[team].scouters.push({ - name: scouter.name, - scouted: true, - }); + // If teams are filtered, the array will be sparse and has to be condensed + const denseFormattedMatches: typeof finalFormattedMatches = []; + if (params.data.teamFilter) { + for (const match of finalFormattedMatches) { + if (match) { + denseFormattedMatches.push(match); } - } else { - await match[team].scouters.push({ name: scouter.name, scouted: false }); } } - await addScoutedTeamNotOnSchedule( - req, - team, - match, - scouterShifts, - currIndex, - ); - return true; + + res.status(200).send(denseFormattedMatches); } catch (error) { - throw error; + console.log(error); + res.status(500).send(error); } -} -async function addExternalReports(req: AuthenticatedRequest, match) { - //don't use null for "not" in prisma below - const teamNumber = req.user.teamNumber || 0; - const externalReports = await prismaClient.scoutReport.groupBy({ - by: ["teamMatchKey"], - _count: { - _all: true, - }, - where: { - teamMatchData: { - tournamentKey: match.tournamentKey, - matchType: MatchTypeMap[match.matchType], - matchNumber: match.matchNumber, - }, - scouter: { - sourceTeamNumber: dataSourceRuleToPrismaFilter( - dataSourceRuleSchema(z.number()).parse(req.user.teamSourceRule), - ), - }, - }, - }); - - await externalReports.forEach((externalReport) => { - const team = - ScouterScheduleMap[ - externalReport.teamMatchKey[externalReport.teamMatchKey.length - 1] - ]; - match[team].externalReports = externalReport._count._all; - }); - return true; -} +}; diff --git a/src/handler/manager/getMatchesFaster.ts b/src/handler/manager/getMatchesFaster.ts deleted file mode 100644 index 3a7972f2..00000000 --- a/src/handler/manager/getMatchesFaster.ts +++ /dev/null @@ -1,318 +0,0 @@ -import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; -import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; -import { addTournamentMatches } from "./addTournamentMatches.js"; -import { - MatchTypeMap, - MatchTypeToAbrivation, - ReverseMatchTypeMap, - ReverseScouterScheduleMap, - ScouterScheduleMap, -} from "./managerConstants"; -import { - dataSourceRuleSchema, - dataSourceRuleToArray, - dataSourceRuleToPrismaFilter, -} from "../analysis/dataSourceRule.js"; -import { allTeamNumbers } from "../analysis/analysisConstants.js"; -//maybe faster??? -export const getMatches = async ( - req: AuthenticatedRequest, - res: Response, -): Promise => { - try { - const user = req.user; - const teamNumber = user.teamNumber || 0; - - // parse and validate - const isScouted = - req.query.isScouted !== undefined ? req.query.isScouted === "true" : null; - const teams = - req.query.teams !== undefined - ? JSON.parse(req.query.teams as string) - : null; - - const params = z - .object({ - tournamentKey: z.string(), - teamNumbers: z.array(z.number()).nullable(), - isScouted: z.boolean().nullable(), - }) - .safeParse({ - tournamentKey: req.params.tournament, - teamNumbers: teams, - isScouted: isScouted, - }); - if (!params.success) { - res.status(400).send(params); - return; - } - //check that matches are added - const matchExists = await prismaClient.teamMatchData.findFirst({ - where: { tournamentKey: params.data.tournamentKey }, - }); - if (!matchExists) { - await addTournamentMatches(params.data.tournamentKey); - } - - //get all matches - const allMatches = await prismaClient.teamMatchData.findMany({ - where: { - tournamentKey: params.data.tournamentKey, - }, - include: { - scoutReports: { - include: { - scouter: true, - }, - }, - }, - }); - - if (allMatches.length === 0) { - res - .status(404) - .send("The match schedule for this tournament hasn't been posted yet."); - return; - } - - //match type - interface GroupedMatch { - matchNumber: number; - matchType: string; - tournamentKey: string; - teams: { - teamNumber: number; - alliance: string; - scouters: { name: string; scouted: boolean }[]; - externalReports: number; - teamPosition: string; // team1, team2, etc. - }[]; - scoutReports: (typeof allMatches)[0]["scoutReports"]; - } - - const groupedMatches = allMatches.reduce( - (acc, match) => { - const key = `${match.matchNumber}-${match.matchType}`; - if (!acc[key]) { - acc[key] = { - matchNumber: match.matchNumber, - matchType: match.matchType, - tournamentKey: match.tournamentKey, - teams: [], - scoutReports: [], - } as GroupedMatch; - } - - const teamPosition = - ScouterScheduleMap[match.key[match.key.length - 1]]; - const alliance = - parseInt(match.key[match.key.length - 1]) < 3 ? "red" : "blue"; - - acc[key].teams.push({ - teamNumber: match.teamNumber, - alliance: alliance, - scouters: [], - externalReports: 0, - teamPosition: teamPosition, - }); - - acc[key].scoutReports.push(...match.scoutReports); - return acc; - }, - {} as Record, - ); - - let finalMatches = Object.values(groupedMatches); - - //filter matches on team numbers (if needed) - if ( - params.data.teamNumbers && - params.data.teamNumbers.length > 0 && - params.data.teamNumbers.length <= 6 - ) { - finalMatches = finalMatches.filter((match) => { - const teamNumbers = match.teams.map((team) => team.teamNumber); - return params.data.teamNumbers!.every((num) => - teamNumbers.includes(num), - ); - }); - } - - const teamNumbers = await allTeamNumbers; - - //filter matches by scouted or not, if provided - if (params.data.isScouted !== null) { - finalMatches = finalMatches.filter((match) => { - const scouted = match.scoutReports.some((report) => - dataSourceRuleToArray( - dataSourceRuleSchema(z.number()).parse(req.user.teamSourceRule), - teamNumbers, - ).includes(report.scouter.sourceTeamNumber), - ); - return params.data.isScouted ? scouted : !scouted; - }); - } - - //sory matches by type, Qual first elim after - finalMatches.sort((a, b) => { - if (a.matchType < b.matchType) return 1; - if (a.matchType > b.matchType) return -1; - return a.matchNumber - b.matchNumber; - }); - - const finalFormatedMatches = finalMatches.map((match) => { - const teams = match.teams.sort((a, b) => - a.teamPosition.localeCompare(b.teamPosition), - ); - - return { - tournamentKey: match.tournamentKey, - matchNumber: match.matchNumber, - matchType: ReverseMatchTypeMap[match.matchType], - scouted: match.scoutReports.some((report) => - dataSourceRuleToArray( - dataSourceRuleSchema(z.number()).parse(user.teamSourceRule), - teamNumbers, - ).includes(report.scouter.sourceTeamNumber), - ), - team1: teams.find((team) => team.teamPosition === "team1"), - team2: teams.find((team) => team.teamPosition === "team2"), - team3: teams.find((team) => team.teamPosition === "team3"), - team4: teams.find((team) => team.teamPosition === "team4"), - team5: teams.find((team) => team.teamPosition === "team5"), - team6: teams.find((team) => team.teamPosition === "team6"), - }; - }); - - //get scouter shifts - let scouterShifts = []; - if (user.teamNumber) { - scouterShifts = await prismaClient.scouterScheduleShift.findMany({ - where: { - tournamentKey: params.data.tournamentKey, - sourceTeamNumber: user.teamNumber, - }, - include: { - team1: true, - team2: true, - team3: true, - team4: true, - team5: true, - team6: true, - }, - }); - } - - const scoutReports = await prismaClient.scoutReport.findMany({ - where: { - teamMatchData: { - tournamentKey: params.data.tournamentKey, - }, - scouter: { - sourceTeamNumber: user.teamNumber, // only include scouters from user's team - }, - }, - include: { - scouter: true, - teamMatchData: true, - }, - }); - - const externalReports = await prismaClient.scoutReport.groupBy({ - by: ["teamMatchKey"], - _count: { - _all: true, - }, - where: { - teamMatchData: { - tournamentKey: params.data.tournamentKey, - }, - scouter: { - sourceTeamNumber: dataSourceRuleToPrismaFilter( - dataSourceRuleSchema(z.number()).parse(req.user.teamSourceRule), - ), - }, - }, - }); - - const externalReportsMap = externalReports.reduce( - (acc, report) => { - acc[report.teamMatchKey] = report._count._all; - return acc; - }, - {} as Record, - ); - - const scouterShiftsMap = scouterShifts.reduce( - (acc, shift) => { - for (let i = 1; i <= 6; i++) { - const teamKey = `team${i}` as keyof typeof shift; - shift[teamKey]?.forEach((scouter) => { - acc[scouter.uuid] = scouter.name; - }); - } - return acc; - }, - {} as Record, - ); - - //update matches w scouter info - for (const match of finalFormatedMatches) { - for (let i = 1; i <= 6; i++) { - const teamKey = `team${i}` as keyof typeof match; - const team = match[teamKey]; - - if (!team) continue; - - //add scouters from user's team - const teamScoutReports = scoutReports.filter( - (report) => - report.teamMatchData.key.endsWith( - ReverseScouterScheduleMap[teamKey as string], - ) && - report.teamMatchData.matchNumber === match.matchNumber && - report.teamMatchData.matchType === MatchTypeMap[match.matchType], - ); - - team.scouters = teamScoutReports.map((report) => ({ - name: report.scouter.name, - scouted: true, - })); - - if (user.teamNumber) { - const assignedShifts = scouterShifts.filter( - (shift) => - shift.startMatchOrdinalNumber <= match.matchNumber && - shift.endMatchOrdinalNumber >= match.matchNumber, - ); - - const assignedScouters = assignedShifts - .flatMap((shift) => shift[teamKey] || []) - .filter((scouter) => scouter.sourceTeamNumber === user.teamNumber); - - assignedScouters.forEach((scouter) => { - if ( - !team.scouters.some( - (s) => s.name === scouter.name && s.scouted === true, - ) - ) { - team.scouters.push({ name: scouter.name, scouted: false }); - } - }); - } - - const teamMatchKey = `${match.tournamentKey}_${ - MatchTypeToAbrivation[match.matchType] - }${match.matchNumber}_${ReverseScouterScheduleMap[teamKey as string]}`; - team.externalReports = externalReportsMap[teamMatchKey] || 0; - } - } - - res.status(200).send(finalFormatedMatches); - } catch (error) { - console.log(error); - res.status(500).send(error); - } -}; diff --git a/src/handler/manager/getMatchesNew.ts b/src/handler/manager/getMatchesNew.ts deleted file mode 100644 index e246277c..00000000 --- a/src/handler/manager/getMatchesNew.ts +++ /dev/null @@ -1,432 +0,0 @@ -import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; -import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; -import { addTournamentMatches } from "./addTournamentMatches.js"; -import { ReverseMatchTypeMap } from "./managerConstants.js"; -import { MatchType, Prisma } from "@prisma/client"; -import { swrConstant, ttlConstant } from "../analysis/analysisConstants.js"; -import { - dataSourceRuleSchema, - dataSourceRuleToPrismaFilter, -} from "../analysis/dataSourceRule.js"; - -/** - * @param params.tournament tournament to pull from - * @param query.teams optional - limit to matches containing all these teams - * - * @returns list of matches organized by number and type, with data for teams/scouts/external reports - */ -export const getMatches = async ( - req: AuthenticatedRequest, - res: Response, -): Promise => { - try { - const user = req.user; - let teams = null; - if (req.query.teams != undefined) { - teams = JSON.parse(req.query.teams as string); - } - const params = z - .object({ - tournamentKey: z.string(), - teamFilter: z.array(z.number()).nullable(), - }) - .safeParse({ - tournamentKey: req.params.tournament, - teamFilter: teams, - }); - if (!params.success) { - res.status(400).send(params); - return; - } - - if (params.data.teamFilter && params.data.teamFilter.length > 6) { - res.status(400).send("Too many team filters"); - return; - } - - // Check that matches from a tournament exist; if not, add them - const matchRow = await prismaClient.teamMatchData.findFirst({ - where: { - tournamentKey: params.data.tournamentKey, - }, - }); - if (!matchRow) { - await addTournamentMatches(params.data.tournamentKey); - } - - // Assuming all elimination matches are not scouted, find the last scouted match (and pretend it is the last completed one) - const last = await prismaClient.teamMatchData.findFirst({ - where: { - tournamentKey: params.data.tournamentKey, - matchType: MatchType.QUALIFICATION, - scoutReports: { - some: {}, - }, - }, - orderBy: [{ matchNumber: "desc" }], - select: { - matchNumber: true, - }, - }); - // Default to 0 - const lastFinishedMatch = last ? last.matchNumber : 0; - - // Filter to return a list of user's team's scout reports for each row, only valid if user has a team number - let includeTeamReports: Prisma.TeamMatchData$scoutReportsArgs | undefined = - undefined; - - const teamSourceRule = dataSourceRuleSchema(z.number()).parse( - req.user.teamSourceRule, - ); - - if (user.teamNumber) { - // make sure the user's teamSourceRule has their own team included - if (teamSourceRule.mode === "EXCLUDE") { - // if their source rule is exclude, make sure the user's team number isn't in items - teamSourceRule.items = teamSourceRule.items.filter( - (item) => item !== user.teamNumber, - ); - } else if ( - // if their mode is include, make sure the user's team number is on their list of items - teamSourceRule.mode === "INCLUDE" && - !teamSourceRule.items.includes(user.teamNumber) - ) { - teamSourceRule.items.push(user.teamNumber); - } - - includeTeamReports = { - where: { - scouter: { - sourceTeamNumber: user.teamNumber, - }, - }, - select: { - scouter: { - select: { - name: true, - uuid: true, - }, - }, - }, - }; - } - - const rawData = await prismaClient.teamMatchData.findMany({ - cacheStrategy: { - swr: swrConstant, - ttl: ttlConstant, - }, - where: { - tournamentKey: params.data.tournamentKey, - }, - select: { - matchNumber: true, - matchType: true, - teamNumber: true, - key: true, - _count: { - // Represents the total number of valid scout reports for this row - select: { - scoutReports: { - where: { - scouter: { - sourceTeamNumber: - dataSourceRuleToPrismaFilter(teamSourceRule), - }, - }, - }, - }, - }, - scoutReports: includeTeamReports, - }, - }); - - /* - * SELECT matchNumber, matchType, teamNumber, key - * (SELECT COUNT(*) - * FROM scoutReports - * WHERE scouter.sourceTeamNumber IN (${[9143, 8033].join(",")})) AS _reports - * (SELECT COUNT(*) - * FROM scoutReports - * WHERE (NOT scouter.sourceTeamNumber = (${9143})) - * AND (scouter.sourceTeamNumber IN (${[9143, 8033].join(",")}))) AS _external - * FROM TeamMatchData - * WHERE tournamentKey = ${"2024casf"}; - */ - - // Group data by match (first layer, elimination matches are negative indices) and team (second layer, 0-5) - // !!!IMPORTANT: the scoutReports property only exists if user.teamNumber exists - let groupedData: { - matchNumber: number; - teamNumber: number; - matchType: MatchType; - key: string; - _count: { scoutReports: number }; - scoutReports: { scouter: { name: string; uuid: string } }[] | undefined; - }[][] = rawData.reduce((acc, curr) => { - // Positive indices are quals, negatives are elims - const i = - curr.matchNumber * (curr.matchType === MatchType.ELIMINATION ? -1 : 1); - acc[i] ??= []; - // Order match by team index [0-5] - acc[i][Number(curr.key.at(-1))] = curr; - return acc; - }, []); - - const lastQualMatch = groupedData.length - 1; - - // If team filters are set, limit matches to those including all selected teams - if (params.data.teamFilter && params.data.teamFilter.length > 0) { - const tempArray: typeof groupedData = []; - - // For..in to iterate over positive and negative properties - for (const k in groupedData) { - const i = parseInt(k); - const match = groupedData[i]; - if ( - params.data.teamFilter.every((requiredTeam) => - match.find((team) => team.teamNumber === requiredTeam), - ) - ) { - // Check that all required teams are included in a match - tempArray[i] = match; - } - } - - groupedData = tempArray; - } - - // Fetch data for matches and attach scouted and finished flags - const finalFormattedMatches: { - matchNumber: number; - matchType: number; - scouted: boolean; - finished: boolean; - team1: { - number: number; - scouters: { name: string; scouted: boolean }[]; - externalReports: number; - }; - team2: { - number: number; - scouters: { name: string; scouted: boolean }[]; - externalReports: number; - }; - team3: { - number: number; - scouters: { name: string; scouted: boolean }[]; - externalReports: number; - }; - team4: { - number: number; - scouters: { name: string; scouted: boolean }[]; - externalReports: number; - }; - team5: { - number: number; - scouters: { name: string; scouted: boolean }[]; - externalReports: number; - }; - team6: { - number: number; - scouters: { name: string; scouted: boolean }[]; - externalReports: number; - }; - }[] = []; - - // If no team number is set, there are no scouters and all reports are external - if (!user.teamNumber) { - for (const k in groupedData) { - const i = parseInt(k); - const match = groupedData[i]; - const currData = { - matchNumber: match[0].matchNumber, - matchType: ReverseMatchTypeMap[match[0].matchType], - scouted: match.some((team) => team._count.scoutReports >= 1), - finished: - match[0].matchType === MatchType.QUALIFICATION && - match[0].matchNumber <= lastFinishedMatch, - team1: { - number: match[0].teamNumber, - scouters: [], - externalReports: match[0]._count.scoutReports, - }, - team2: { - number: match[1].teamNumber, - scouters: [], - externalReports: match[1]._count.scoutReports, - }, - team3: { - number: match[2].teamNumber, - scouters: [], - externalReports: match[2]._count.scoutReports, - }, - team4: { - number: match[3].teamNumber, - scouters: [], - externalReports: match[3]._count.scoutReports, - }, - team5: { - number: match[4].teamNumber, - scouters: [], - externalReports: match[4]._count.scoutReports, - }, - team6: { - number: match[5].teamNumber, - scouters: [], - externalReports: match[5]._count.scoutReports, - }, - }; - - // Index = ordinal match number, 0 indexed - if (i > 0) { - finalFormattedMatches[i - 1] = currData; - } else { - finalFormattedMatches[lastQualMatch - i - 1] = currData; - } - } - - res.status(200).send(finalFormattedMatches); - return; - } - // Done here if user has no team number - - const scouterShifts = await prismaClient.scouterScheduleShift.findMany({ - where: { - tournamentKey: params.data.tournamentKey, - sourceTeamNumber: user.teamNumber, - }, - orderBy: [{ startMatchOrdinalNumber: "asc" }], - select: { - startMatchOrdinalNumber: true, - endMatchOrdinalNumber: true, - team1: { select: { name: true, uuid: true } }, - team2: { select: { name: true, uuid: true } }, - team3: { select: { name: true, uuid: true } }, - team4: { select: { name: true, uuid: true } }, - team5: { select: { name: true, uuid: true } }, - team6: { select: { name: true, uuid: true } }, - }, - }); - - let currShiftIndex = 0; - // For..in should iterate through array indices first, then other properties by insertion order - for (const k in groupedData) { - const i = parseInt(k); - const match = groupedData[i]; - const ordinalMatchNumber = i > 0 ? i : lastQualMatch - i; - - // Increment the scouter shift if we passed the upper bound - if ( - scouterShifts[currShiftIndex] && - ordinalMatchNumber > scouterShifts[currShiftIndex].endMatchOrdinalNumber - ) { - currShiftIndex++; - } - - const matchScouters: { name: string; scouted: boolean }[][] = []; - for (let j = 0; j < 6; j++) { - // Add all complete scout reports from user's team - matchScouters[j] = match[j].scoutReports.map((e) => ({ - name: e.scouter.name, - scouted: true, - })); - - // If the current match number is within a scouter shift, add incomplete scout reports - if ( - scouterShifts[currShiftIndex] && - ordinalMatchNumber >= - scouterShifts[currShiftIndex].startMatchOrdinalNumber - ) { - // Sketchy but iterates through team1-6, could cause problems if schema is changed - for (const currScouter of scouterShifts[currShiftIndex][ - `team${j + 1}` - ]) { - // If the sourced scout reports do not include ones from the shift, add those as incomplete - if ( - !match[j].scoutReports.some( - (e) => e.scouter.uuid === currScouter.uuid, - ) - ) { - matchScouters[j].push({ name: currScouter.name, scouted: false }); - } - } - } - } - - // Scouted flag based on if any team in this match has at least 1 sourced scout report - // Finished flag is true if the match is a qualification before the last finished match - // Scouters array includes all scouters from user's team, and all incomplete reports from assigned scouting shifts - // External reports are the number of non-team scout reports, so [other team reports - user team reports] - const currData = { - matchNumber: match[0].matchNumber, - matchType: ReverseMatchTypeMap[match[0].matchType], - scouted: match.some((team) => team._count.scoutReports >= 1), - finished: - match[0].matchType === MatchType.QUALIFICATION && - match[0].matchNumber <= lastFinishedMatch, - team1: { - number: match[0].teamNumber, - scouters: matchScouters[0], - externalReports: - match[0]._count.scoutReports - match[0].scoutReports.length, - }, - team2: { - number: match[1].teamNumber, - scouters: matchScouters[1], - externalReports: - match[1]._count.scoutReports - match[1].scoutReports.length, - }, - team3: { - number: match[2].teamNumber, - scouters: matchScouters[2], - externalReports: - match[2]._count.scoutReports - match[2].scoutReports.length, - }, - team4: { - number: match[3].teamNumber, - scouters: matchScouters[3], - externalReports: - match[3]._count.scoutReports - match[3].scoutReports.length, - }, - team5: { - number: match[4].teamNumber, - scouters: matchScouters[4], - externalReports: - match[4]._count.scoutReports - match[4].scoutReports.length, - }, - team6: { - number: match[5].teamNumber, - scouters: matchScouters[5], - externalReports: - match[5]._count.scoutReports - match[5].scoutReports.length, - }, - }; - - // Ordered by ordinal match number, 0 indexed - finalFormattedMatches[ordinalMatchNumber - 1] = currData; - } - - if (!params.data.teamFilter) { - res.status(200).send(finalFormattedMatches); - return; - } - - // If teams are filtered, the array will be sparse and has to be condensed - const denseFormattedMatches: typeof finalFormattedMatches = []; - if (params.data.teamFilter) { - for (const match of finalFormattedMatches) { - if (match) { - denseFormattedMatches.push(match); - } - } - } - - res.status(200).send(denseFormattedMatches); - } catch (error) { - console.log(error); - res.status(500).send(error); - } -}; diff --git a/src/handler/manager/getScouterSchedule.ts b/src/handler/manager/getScouterSchedule.ts deleted file mode 100644 index a46a7a2f..00000000 --- a/src/handler/manager/getScouterSchedule.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; -import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; -import SHA256 from "crypto-js/sha256.js"; - -export const getScouterSchedule = async ( - req: AuthenticatedRequest, - res: Response, -): Promise => { - try { - const params = z - .object({ - tournament: z.string(), - }) - .safeParse({ - tournament: req.params.tournament, - }); - if (!params.success) { - res.status(400).send(params); - return; - } - if (req.user.teamNumber === null) { - res.status(403).send("User is not affilated with a team"); - return; - } - const rows = await prismaClient.scouterScheduleShift.findMany({ - where: { - sourceTeamNumber: req.user.teamNumber, - tournamentKey: params.data.tournament, - }, - include: { - team1: { - select: { - name: true, - uuid: true, - }, - }, - team2: { - select: { - name: true, - uuid: true, - }, - }, - team3: { - select: { - name: true, - uuid: true, - }, - }, - team4: { - select: { - name: true, - uuid: true, - }, - }, - team5: { - select: { - name: true, - uuid: true, - }, - }, - team6: { - select: { - name: true, - uuid: true, - }, - }, - }, - orderBy: { - startMatchOrdinalNumber: "asc", - }, - }); - - res.status(200).send({ hash: hashJsonObject(rows), data: rows }); - } catch (error) { - console.error(error); - res.status(500).send(error); - } -}; -function hashJsonObject(json: object): string { - const jsonString = JSON.stringify(json); - - const hash = SHA256(jsonString); - - return hash.toString(); -} diff --git a/src/handler/manager/addMutablePicklist.ts b/src/handler/manager/mutablepicklists/addMutablePicklist.ts similarity index 90% rename from src/handler/manager/addMutablePicklist.ts rename to src/handler/manager/mutablepicklists/addMutablePicklist.ts index 1687d9d1..d79721a2 100644 --- a/src/handler/manager/addMutablePicklist.ts +++ b/src/handler/manager/mutablepicklists/addMutablePicklist.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const addMutablePicklist = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/deleteMutablePicklist.ts b/src/handler/manager/mutablepicklists/deleteMutablePicklist.ts similarity index 89% rename from src/handler/manager/deleteMutablePicklist.ts rename to src/handler/manager/mutablepicklists/deleteMutablePicklist.ts index 4657d3c0..73530688 100644 --- a/src/handler/manager/deleteMutablePicklist.ts +++ b/src/handler/manager/mutablepicklists/deleteMutablePicklist.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const deleteMutablePicklist = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/getMutablePicklists.ts b/src/handler/manager/mutablepicklists/getMutablePicklists.ts similarity index 86% rename from src/handler/manager/getMutablePicklists.ts rename to src/handler/manager/mutablepicklists/getMutablePicklists.ts index 483ce749..a0d81987 100644 --- a/src/handler/manager/getMutablePicklists.ts +++ b/src/handler/manager/mutablepicklists/getMutablePicklists.ts @@ -1,6 +1,6 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import prismaClient from "../../../prismaClient.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const getMutablePicklists = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/getSingleMutablePicklist.ts b/src/handler/manager/mutablepicklists/getSingleMutablePicklist.ts similarity index 85% rename from src/handler/manager/getSingleMutablePicklist.ts rename to src/handler/manager/mutablepicklists/getSingleMutablePicklist.ts index ceb6fc25..32a2aa52 100644 --- a/src/handler/manager/getSingleMutablePicklist.ts +++ b/src/handler/manager/mutablepicklists/getSingleMutablePicklist.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const getSingleMutablePicklist = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/updateMutablePicklist.ts b/src/handler/manager/mutablepicklists/updateMutablePicklist.ts similarity index 89% rename from src/handler/manager/updateMutablePicklist.ts rename to src/handler/manager/mutablepicklists/updateMutablePicklist.ts index bc75ba45..41b3b689 100644 --- a/src/handler/manager/updateMutablePicklist.ts +++ b/src/handler/manager/mutablepicklists/updateMutablePicklist.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const updateMutablePicklist = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/addUsername.ts b/src/handler/manager/onboarding/addUsername.ts similarity index 77% rename from src/handler/manager/addUsername.ts rename to src/handler/manager/onboarding/addUsername.ts index 346cff2d..c3e1b6fa 100644 --- a/src/handler/manager/addUsername.ts +++ b/src/handler/manager/onboarding/addUsername.ts @@ -1,6 +1,6 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import prismaClient from "../../../prismaClient.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const addUsername = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/addWebsite.ts b/src/handler/manager/onboarding/addWebsite.ts similarity index 81% rename from src/handler/manager/addWebsite.ts rename to src/handler/manager/onboarding/addWebsite.ts index 3f740b32..ddb2b94b 100644 --- a/src/handler/manager/addWebsite.ts +++ b/src/handler/manager/onboarding/addWebsite.ts @@ -1,8 +1,8 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; -import { sendSlackVerification } from "./sendSlackVerification.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; +import { sendSlackVerification } from "../sendSlackVerification.js"; export const addWebsite = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/approveTeamEmail.ts b/src/handler/manager/onboarding/approveTeamEmail.ts similarity index 96% rename from src/handler/manager/approveTeamEmail.ts rename to src/handler/manager/onboarding/approveTeamEmail.ts index 0a50611e..0b34ca8b 100644 --- a/src/handler/manager/approveTeamEmail.ts +++ b/src/handler/manager/onboarding/approveTeamEmail.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library"; diff --git a/src/handler/manager/checkCode.ts b/src/handler/manager/onboarding/checkCode.ts similarity index 88% rename from src/handler/manager/checkCode.ts rename to src/handler/manager/onboarding/checkCode.ts index 865093da..d03347fd 100644 --- a/src/handler/manager/checkCode.ts +++ b/src/handler/manager/onboarding/checkCode.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const checkCode = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/resendEmail.ts b/src/handler/manager/onboarding/resendEmail.ts similarity index 91% rename from src/handler/manager/resendEmail.ts rename to src/handler/manager/onboarding/resendEmail.ts index 9fe0b908..830fbf40 100644 --- a/src/handler/manager/resendEmail.ts +++ b/src/handler/manager/onboarding/resendEmail.ts @@ -1,6 +1,6 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import prismaClient from "../../../prismaClient.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; import { Resend } from "resend"; import { randomBytes } from "crypto"; import { DateTime } from "luxon"; diff --git a/src/handler/manager/addPicklist.ts b/src/handler/manager/picklists/addPicklist.ts similarity index 95% rename from src/handler/manager/addPicklist.ts rename to src/handler/manager/picklists/addPicklist.ts index 4cdff7ab..ad56ac09 100644 --- a/src/handler/manager/addPicklist.ts +++ b/src/handler/manager/picklists/addPicklist.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const addPicklist = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/deletePicklist.ts b/src/handler/manager/picklists/deletePicklist.ts similarity index 88% rename from src/handler/manager/deletePicklist.ts rename to src/handler/manager/picklists/deletePicklist.ts index 376fd5ea..dccfac5c 100644 --- a/src/handler/manager/deletePicklist.ts +++ b/src/handler/manager/picklists/deletePicklist.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const deletePicklist = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/getPicklists.ts b/src/handler/manager/picklists/getPicklists.ts similarity index 85% rename from src/handler/manager/getPicklists.ts rename to src/handler/manager/picklists/getPicklists.ts index a44f19b7..97d40460 100644 --- a/src/handler/manager/getPicklists.ts +++ b/src/handler/manager/picklists/getPicklists.ts @@ -1,6 +1,6 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import prismaClient from "../../../prismaClient.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const getPicklists = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/getSinglePicklist.ts b/src/handler/manager/picklists/getSinglePicklist.ts similarity index 91% rename from src/handler/manager/getSinglePicklist.ts rename to src/handler/manager/picklists/getSinglePicklist.ts index 44f2c9cc..10cbc878 100644 --- a/src/handler/manager/getSinglePicklist.ts +++ b/src/handler/manager/picklists/getSinglePicklist.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const getSinglePicklist = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/updatePicklist.ts b/src/handler/manager/picklists/updatePicklist.ts similarity index 95% rename from src/handler/manager/updatePicklist.ts rename to src/handler/manager/picklists/updatePicklist.ts index d89e1119..a6659c2e 100644 --- a/src/handler/manager/updatePicklist.ts +++ b/src/handler/manager/picklists/updatePicklist.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const updatePicklist = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/addRegisteredTeam.ts b/src/handler/manager/registeredteams/addRegisteredTeam.ts similarity index 91% rename from src/handler/manager/addRegisteredTeam.ts rename to src/handler/manager/registeredteams/addRegisteredTeam.ts index 210c5d1d..14b79af1 100644 --- a/src/handler/manager/addRegisteredTeam.ts +++ b/src/handler/manager/registeredteams/addRegisteredTeam.ts @@ -1,8 +1,8 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; -import { sendVerificationEmail } from "./resendEmail.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; +import { sendVerificationEmail } from "../onboarding/resendEmail.js"; export const addRegisteredTeam = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/approveRegisteredTeam.ts b/src/handler/manager/registeredteams/approveRegisteredTeam.ts similarity index 93% rename from src/handler/manager/approveRegisteredTeam.ts rename to src/handler/manager/registeredteams/approveRegisteredTeam.ts index 0586980b..c2854ba8 100644 --- a/src/handler/manager/approveRegisteredTeam.ts +++ b/src/handler/manager/registeredteams/approveRegisteredTeam.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; export const approveRegisteredTeam = async ( diff --git a/src/handler/manager/checkRegisteredTeam.ts b/src/handler/manager/registeredteams/checkRegisteredTeam.ts similarity index 94% rename from src/handler/manager/checkRegisteredTeam.ts rename to src/handler/manager/registeredteams/checkRegisteredTeam.ts index 1f0fac4e..e2a27556 100644 --- a/src/handler/manager/checkRegisteredTeam.ts +++ b/src/handler/manager/registeredteams/checkRegisteredTeam.ts @@ -1,7 +1,7 @@ -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; import { Response } from "express"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const checkRegisteredTeam = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/rejectRegisteredTeam.ts b/src/handler/manager/registeredteams/rejectRegisteredTeam.ts similarity index 93% rename from src/handler/manager/rejectRegisteredTeam.ts rename to src/handler/manager/registeredteams/rejectRegisteredTeam.ts index 5e3d2011..0fe7e800 100644 --- a/src/handler/manager/rejectRegisteredTeam.ts +++ b/src/handler/manager/registeredteams/rejectRegisteredTeam.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; export const rejectRegisteredTeam = async ( diff --git a/src/handler/manager/addNewScouter.ts b/src/handler/manager/scouters/addNewScouter.ts similarity index 94% rename from src/handler/manager/addNewScouter.ts rename to src/handler/manager/scouters/addNewScouter.ts index 0b3806bb..feae4d02 100644 --- a/src/handler/manager/addNewScouter.ts +++ b/src/handler/manager/scouters/addNewScouter.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; export const addNewScouter = async ( diff --git a/src/handler/manager/addScouterDashboard.ts b/src/handler/manager/scouters/addScouterDashboard.ts similarity index 86% rename from src/handler/manager/addScouterDashboard.ts rename to src/handler/manager/scouters/addScouterDashboard.ts index 8528a659..ae5ac496 100644 --- a/src/handler/manager/addScouterDashboard.ts +++ b/src/handler/manager/scouters/addScouterDashboard.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const addScouterDashboard = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/archiveScouter.ts b/src/handler/manager/scouters/archiveScouter.ts similarity index 87% rename from src/handler/manager/archiveScouter.ts rename to src/handler/manager/scouters/archiveScouter.ts index fffeca09..6c7b38b3 100644 --- a/src/handler/manager/archiveScouter.ts +++ b/src/handler/manager/scouters/archiveScouter.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; import { UserRole } from "@prisma/client"; export const archiveScouter = async ( diff --git a/src/handler/manager/changeNameScouter.ts b/src/handler/manager/scouters/changeNameScouter.ts similarity index 94% rename from src/handler/manager/changeNameScouter.ts rename to src/handler/manager/scouters/changeNameScouter.ts index 72d01004..b6c0d327 100644 --- a/src/handler/manager/changeNameScouter.ts +++ b/src/handler/manager/scouters/changeNameScouter.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; export const changeNameScouter = async ( diff --git a/src/handler/manager/checkCodeScouter.ts b/src/handler/manager/scouters/checkCodeScouter.ts similarity index 94% rename from src/handler/manager/checkCodeScouter.ts rename to src/handler/manager/scouters/checkCodeScouter.ts index e39a10dc..b08454c8 100644 --- a/src/handler/manager/checkCodeScouter.ts +++ b/src/handler/manager/scouters/checkCodeScouter.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; export const checkCodeScouter = async ( diff --git a/src/handler/manager/deleteScouter.ts b/src/handler/manager/scouters/deleteScouter.ts similarity index 94% rename from src/handler/manager/deleteScouter.ts rename to src/handler/manager/scouters/deleteScouter.ts index a07731e2..02075f33 100644 --- a/src/handler/manager/deleteScouter.ts +++ b/src/handler/manager/scouters/deleteScouter.ts @@ -1,8 +1,8 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; -import { invalidateCache } from "../../lib/clearCache.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; +import { invalidateCache } from "../../../lib/clearCache.js"; export const deleteScouter = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/emailTeamCode.ts b/src/handler/manager/scouters/emailTeamCode.ts similarity index 95% rename from src/handler/manager/emailTeamCode.ts rename to src/handler/manager/scouters/emailTeamCode.ts index 7bc6cc94..b7652cda 100644 --- a/src/handler/manager/emailTeamCode.ts +++ b/src/handler/manager/scouters/emailTeamCode.ts @@ -1,7 +1,7 @@ import { Request, Response } from "express"; import z from "zod"; import { Resend } from "resend"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; export const emailTeamCode = async ( req: Request, diff --git a/src/handler/manager/getScheduleForScouter.ts b/src/handler/manager/scouters/getScheduleForScouter.ts similarity index 95% rename from src/handler/manager/getScheduleForScouter.ts rename to src/handler/manager/scouters/getScheduleForScouter.ts index cf4fd109..51d05a07 100644 --- a/src/handler/manager/getScheduleForScouter.ts +++ b/src/handler/manager/scouters/getScheduleForScouter.ts @@ -1,9 +1,12 @@ import { Request, Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { MatchTypeMap, ScouterScheduleMap } from "./managerConstants.js"; +import { + MatchTypeMap, + ScouterScheduleMap, +} from "../managerConstants.js"; import SHA256 from "crypto-js/sha256.js"; -import { addTournamentMatches } from "./addTournamentMatches.js"; +import { addTournamentMatches } from "../addTournamentMatches.js"; export const getScheduleForScouter = async ( req: Request, diff --git a/src/handler/manager/getScouterTournaments.ts b/src/handler/manager/scouters/getScouterTournaments.ts similarity index 99% rename from src/handler/manager/getScouterTournaments.ts rename to src/handler/manager/scouters/getScouterTournaments.ts index 353a421c..626072a9 100644 --- a/src/handler/manager/getScouterTournaments.ts +++ b/src/handler/manager/scouters/getScouterTournaments.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; export const getScouterTournaments = async ( diff --git a/src/handler/manager/getScouters.ts b/src/handler/manager/scouters/getScouters.ts similarity index 84% rename from src/handler/manager/getScouters.ts rename to src/handler/manager/scouters/getScouters.ts index d86e81a5..8ef2a0c8 100644 --- a/src/handler/manager/getScouters.ts +++ b/src/handler/manager/scouters/getScouters.ts @@ -1,11 +1,11 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import prismaClient from "../../../prismaClient.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; import z from "zod"; export const getScouters = async ( req: AuthenticatedRequest, - res: Response + res: Response, ): Promise => { try { const params = z diff --git a/src/handler/manager/getScoutersOnTeam.ts b/src/handler/manager/scouters/getScoutersOnTeam.ts similarity index 94% rename from src/handler/manager/getScoutersOnTeam.ts rename to src/handler/manager/scouters/getScoutersOnTeam.ts index a3933c71..d7a393e7 100644 --- a/src/handler/manager/getScoutersOnTeam.ts +++ b/src/handler/manager/scouters/getScoutersOnTeam.ts @@ -1,10 +1,10 @@ import { Request, Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; export const getScoutersOnTeam = async ( req: Request, - res: Response + res: Response, ): Promise => { try { console.log(req.headers); diff --git a/src/handler/manager/getTournamentForScouterWithSchedule.ts b/src/handler/manager/scouters/getTournamentForScouterWithSchedule.ts similarity index 95% rename from src/handler/manager/getTournamentForScouterWithSchedule.ts rename to src/handler/manager/scouters/getTournamentForScouterWithSchedule.ts index f1f5dbc6..03905ca5 100644 --- a/src/handler/manager/getTournamentForScouterWithSchedule.ts +++ b/src/handler/manager/scouters/getTournamentForScouterWithSchedule.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; export const getTournamentForScouterWithSchedule = async ( diff --git a/src/handler/manager/scoutingLeadProgressPage.ts b/src/handler/manager/scouters/scoutingLeadProgressPage.ts similarity index 97% rename from src/handler/manager/scoutingLeadProgressPage.ts rename to src/handler/manager/scouters/scoutingLeadProgressPage.ts index 5f48ec45..5fb7598c 100644 --- a/src/handler/manager/scoutingLeadProgressPage.ts +++ b/src/handler/manager/scouters/scoutingLeadProgressPage.ts @@ -1,11 +1,11 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const scoutingLeadProgressPage = async ( req: AuthenticatedRequest, - res: Response + res: Response, ): Promise => { try { const params = z @@ -147,7 +147,7 @@ export const scoutingLeadProgressPage = async ( matchesScouted: matchesScoutedAtTournament.length, missedMatches: Math.max( 0, - totalAssignedScouterMatches - matchesScoutedAtTournament.length + totalAssignedScouterMatches - matchesScoutedAtTournament.length, ), }; result.push(currData); diff --git a/src/handler/manager/unarchiveScouter.ts b/src/handler/manager/scouters/unarchiveScouter.ts similarity index 87% rename from src/handler/manager/unarchiveScouter.ts rename to src/handler/manager/scouters/unarchiveScouter.ts index 4fd5576c..80bf7841 100644 --- a/src/handler/manager/unarchiveScouter.ts +++ b/src/handler/manager/scouters/unarchiveScouter.ts @@ -1,6 +1,6 @@ -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; import { UserRole } from "@prisma/client"; import { Response } from "express"; diff --git a/src/handler/manager/updateRoleToScoutingLead.ts b/src/handler/manager/scouters/updateRoleToScoutingLead.ts similarity index 92% rename from src/handler/manager/updateRoleToScoutingLead.ts rename to src/handler/manager/scouters/updateRoleToScoutingLead.ts index 50e7ae11..c0327c1c 100644 --- a/src/handler/manager/updateRoleToScoutingLead.ts +++ b/src/handler/manager/scouters/updateRoleToScoutingLead.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const updateRoleToScoutingLead = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/updateScouterName.ts b/src/handler/manager/scouters/updateScouterName.ts similarity index 91% rename from src/handler/manager/updateScouterName.ts rename to src/handler/manager/scouters/updateScouterName.ts index d9c9b3fd..8cfb95a5 100644 --- a/src/handler/manager/updateScouterName.ts +++ b/src/handler/manager/scouters/updateScouterName.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const updateScouterName = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/checkScouterShiftMatches.ts b/src/handler/manager/scoutershifts/checkScouterShiftMatches.ts similarity index 92% rename from src/handler/manager/checkScouterShiftMatches.ts rename to src/handler/manager/scoutershifts/checkScouterShiftMatches.ts index fedb2d13..635c5996 100644 --- a/src/handler/manager/checkScouterShiftMatches.ts +++ b/src/handler/manager/scoutershifts/checkScouterShiftMatches.ts @@ -1,5 +1,5 @@ -import prismaClient from "../../prismaClient.js"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import prismaClient from "../../../prismaClient.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; //uuid is when editing a shift so it doesnt check that its over lapping with itself export const checkScouterShiftMatches = async ( diff --git a/src/handler/manager/deleteScouterShift.ts b/src/handler/manager/scoutershifts/deleteScouterShift.ts similarity index 89% rename from src/handler/manager/deleteScouterShift.ts rename to src/handler/manager/scoutershifts/deleteScouterShift.ts index 3090f0f7..61447b99 100644 --- a/src/handler/manager/deleteScouterShift.ts +++ b/src/handler/manager/scoutershifts/deleteScouterShift.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const deleteScouterShift = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/updateScouterShift.ts b/src/handler/manager/scoutershifts/updateScouterShift.ts similarity index 94% rename from src/handler/manager/updateScouterShift.ts rename to src/handler/manager/scoutershifts/updateScouterShift.ts index 08326dfa..0552af0d 100644 --- a/src/handler/manager/updateScouterShift.ts +++ b/src/handler/manager/scoutershifts/updateScouterShift.ts @@ -1,9 +1,9 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; import { checkScouterShiftMatches } from "./checkScouterShiftMatches.js"; -import { checkOnlyOneInstanceOfScouter } from "./checkOnlyInstanceOfScouter.js"; +import { checkOnlyOneInstanceOfScouter } from "../checkOnlyInstanceOfScouter.js"; export const updateScouterShift = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/addScoutReport.ts b/src/handler/manager/scoutreports/addScoutReport.ts similarity index 97% rename from src/handler/manager/addScoutReport.ts rename to src/handler/manager/scoutreports/addScoutReport.ts index 1e17e4da..85863594 100644 --- a/src/handler/manager/addScoutReport.ts +++ b/src/handler/manager/scoutreports/addScoutReport.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; import { AlgaePickupMap, @@ -11,8 +11,8 @@ import { UnderShallowCageMap, RobotRoleMap, EventActionMap, -} from "./managerConstants.js"; -import { addTournamentMatches } from "./addTournamentMatches.js"; +} from "../managerConstants.js"; +import { addTournamentMatches } from "../addTournamentMatches.js"; import { EventAction, Position } from "@prisma/client"; import { AlgaePickup, @@ -23,8 +23,8 @@ import { RobotRole, UnderShallowCage, } from "@prisma/client"; -import { sendWarningToSlack } from "../slack/sendWarningNotification.js"; -import { invalidateCache } from "../../lib/clearCache.js"; +import { sendWarningToSlack } from "../../slack/sendWarningNotification.js"; +import { invalidateCache } from "../../../lib/clearCache.js"; export const addScoutReport = async ( req: Request, diff --git a/src/handler/manager/addScoutReportDashboard.ts b/src/handler/manager/scoutreports/addScoutReportDashboard.ts similarity index 95% rename from src/handler/manager/addScoutReportDashboard.ts rename to src/handler/manager/scoutreports/addScoutReportDashboard.ts index c2026ae4..66931842 100644 --- a/src/handler/manager/addScoutReportDashboard.ts +++ b/src/handler/manager/scoutreports/addScoutReportDashboard.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; import { CoralPickupMap, AlgaePickupMap, @@ -12,9 +12,9 @@ import { UnderShallowCageMap, RobotRoleMap, EventActionMap, -} from "./managerConstants.js"; -import { addTournamentMatches } from "./addTournamentMatches.js"; -import { totalPointsScoutingLead } from "../analysis/scoutingLead/totalPointsScoutingLead.js"; +} from "../managerConstants.js"; +import { addTournamentMatches } from "../addTournamentMatches.js"; +import { totalPointsScoutingLead } from "../../analysis/scoutingLead/totalPointsScoutingLead.js"; import { AlgaePickup, BargeResult, @@ -26,7 +26,7 @@ import { RobotRole, UnderShallowCage, } from "@prisma/client"; -import { invalidateCache } from "../../lib/clearCache.js"; +import { invalidateCache } from "../../../lib/clearCache.js"; export const addScoutReportDashboard = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/deleteScoutReport.ts b/src/handler/manager/scoutreports/deleteScoutReport.ts similarity index 88% rename from src/handler/manager/deleteScoutReport.ts rename to src/handler/manager/scoutreports/deleteScoutReport.ts index fde810f4..67cd56c5 100644 --- a/src/handler/manager/deleteScoutReport.ts +++ b/src/handler/manager/scoutreports/deleteScoutReport.ts @@ -1,8 +1,8 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; -import { invalidateCache } from "../../lib/clearCache.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; +import { invalidateCache } from "../../../lib/clearCache.js"; export const deleteScoutReport = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/getScoutReport.ts b/src/handler/manager/scoutreports/getScoutReport.ts similarity index 87% rename from src/handler/manager/getScoutReport.ts rename to src/handler/manager/scoutreports/getScoutReport.ts index a3330e29..db4cfe0d 100644 --- a/src/handler/manager/getScoutReport.ts +++ b/src/handler/manager/scoutreports/getScoutReport.ts @@ -1,7 +1,7 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const getScoutReport = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/addTeamSource.ts b/src/handler/manager/settings/addTeamSource.ts similarity index 85% rename from src/handler/manager/addTeamSource.ts rename to src/handler/manager/settings/addTeamSource.ts index 5361166d..26385a6f 100644 --- a/src/handler/manager/addTeamSource.ts +++ b/src/handler/manager/settings/addTeamSource.ts @@ -1,9 +1,9 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; -import { allTeamNumbers } from "../analysis/analysisConstants.js"; -import { arrayToRule } from "../../lib/migrateDataSources.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; +import { allTeamNumbers } from "../../analysis/analysisConstants.js"; +import { arrayToRule } from "../../../lib/migrateDataSources.js"; export const addTeamSource = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/addTournamentSource.ts b/src/handler/manager/settings/addTournamentSource.ts similarity index 75% rename from src/handler/manager/addTournamentSource.ts rename to src/handler/manager/settings/addTournamentSource.ts index 229e8d13..5beb9bf8 100644 --- a/src/handler/manager/addTournamentSource.ts +++ b/src/handler/manager/settings/addTournamentSource.ts @@ -1,9 +1,9 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; -import { allTournaments } from "../analysis/analysisConstants.js"; -import { arrayToRule } from "../../lib/migrateDataSources.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; +import { allTournaments } from "../../analysis/analysisConstants.js"; +import { arrayToRule } from "../../../lib/migrateDataSources.js"; export const addTournamentSource = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/getTeamSource.ts b/src/handler/manager/settings/getTeamSource.ts similarity index 82% rename from src/handler/manager/getTeamSource.ts rename to src/handler/manager/settings/getTeamSource.ts index 83e19525..7bd1b603 100644 --- a/src/handler/manager/getTeamSource.ts +++ b/src/handler/manager/settings/getTeamSource.ts @@ -1,11 +1,11 @@ import { Response } from "express"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; import { dataSourceRuleSchema, dataSourceRuleToArray, -} from "../analysis/dataSourceRule.js"; +} from "../../analysis/dataSourceRule.js"; import z from "zod"; -import { allTeamNumbers } from "../analysis/analysisConstants.js"; +import { allTeamNumbers } from "../../analysis/analysisConstants.js"; export const getTeamSource = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/getTournamentSource.ts b/src/handler/manager/settings/getTournamentSource.ts similarity index 73% rename from src/handler/manager/getTournamentSource.ts rename to src/handler/manager/settings/getTournamentSource.ts index e9c0e962..41748439 100644 --- a/src/handler/manager/getTournamentSource.ts +++ b/src/handler/manager/settings/getTournamentSource.ts @@ -1,10 +1,10 @@ import { Response } from "express"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; import { dataSourceRuleSchema, dataSourceRuleToArray, -} from "../analysis/dataSourceRule.js"; -import { allTournaments } from "../analysis/analysisConstants.js"; +} from "../../analysis/dataSourceRule.js"; +import { allTournaments } from "../../analysis/analysisConstants.js"; import z from "zod"; export const getTournamentSource = async ( diff --git a/src/handler/manager/updateSettings.ts b/src/handler/manager/settings/updateSettings.ts similarity index 80% rename from src/handler/manager/updateSettings.ts rename to src/handler/manager/settings/updateSettings.ts index 62a3a22b..d63cd200 100644 --- a/src/handler/manager/updateSettings.ts +++ b/src/handler/manager/settings/updateSettings.ts @@ -1,13 +1,13 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; -import { arrayToRule } from "../../lib/migrateDataSources.js"; +import { arrayToRule } from "../../../lib/migrateDataSources.js"; import { allTeamNumbers, allTournaments, -} from "../analysis/analysisConstants.js"; +} from "../../analysis/analysisConstants.js"; export const updateSettings = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/updateTeamEmail.ts b/src/handler/manager/settings/updateTeamEmail.ts similarity index 80% rename from src/handler/manager/updateTeamEmail.ts rename to src/handler/manager/settings/updateTeamEmail.ts index 6789be66..ccfc6e90 100644 --- a/src/handler/manager/updateTeamEmail.ts +++ b/src/handler/manager/settings/updateTeamEmail.ts @@ -1,8 +1,8 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; -import { sendVerificationEmail } from "./resendEmail.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; +import { sendVerificationEmail } from "../onboarding/resendEmail.js"; export const updateTeamEmail = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/addNotOnTeam.ts b/src/handler/manager/temp/addNotOnTeam.ts similarity index 78% rename from src/handler/manager/addNotOnTeam.ts rename to src/handler/manager/temp/addNotOnTeam.ts index 302321bc..ea8c6c32 100644 --- a/src/handler/manager/addNotOnTeam.ts +++ b/src/handler/manager/temp/addNotOnTeam.ts @@ -1,6 +1,6 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import prismaClient from "../../../prismaClient.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; export const addNotOnTeam = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/addScouterShift.ts b/src/handler/manager/tournament/addScouterShift.ts similarity index 91% rename from src/handler/manager/addScouterShift.ts rename to src/handler/manager/tournament/addScouterShift.ts index b69b8294..9e59de6b 100644 --- a/src/handler/manager/addScouterShift.ts +++ b/src/handler/manager/tournament/addScouterShift.ts @@ -1,10 +1,10 @@ import { Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; -import { AuthenticatedRequest } from "../../lib/middleware/requireAuth.js"; +import { AuthenticatedRequest } from "../../../lib/middleware/requireAuth.js"; import { UserRole } from "@prisma/client"; -import { checkOnlyOneInstanceOfScouter } from "./checkOnlyInstanceOfScouter.js"; -import { checkScouterShiftMatches } from "./checkScouterShiftMatches.js"; +import { checkOnlyOneInstanceOfScouter } from "../checkOnlyInstanceOfScouter.js"; +import { checkScouterShiftMatches } from "../scoutershifts/checkScouterShiftMatches.js"; export const addScouterShift = async ( req: AuthenticatedRequest, diff --git a/src/handler/manager/getTeamRankings.ts b/src/handler/manager/tournament/getTeamRankings.ts similarity index 97% rename from src/handler/manager/getTeamRankings.ts rename to src/handler/manager/tournament/getTeamRankings.ts index e514bef6..fd6ba5f9 100644 --- a/src/handler/manager/getTeamRankings.ts +++ b/src/handler/manager/tournament/getTeamRankings.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; export const getTeamRankings = async ( diff --git a/src/handler/manager/getTeamsInTournament.ts b/src/handler/manager/tournament/getTeamsInTournament.ts similarity index 95% rename from src/handler/manager/getTeamsInTournament.ts rename to src/handler/manager/tournament/getTeamsInTournament.ts index 7f10c466..9555b14a 100644 --- a/src/handler/manager/getTeamsInTournament.ts +++ b/src/handler/manager/tournament/getTeamsInTournament.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import prismaClient from "../../prismaClient.js"; +import prismaClient from "../../../prismaClient.js"; import z from "zod"; export const getTeamsInTournament = async ( diff --git a/src/handler/slack/addSlackWorkspace.ts b/src/handler/slack/addSlackWorkspace.ts index a2b1252f..a17b5603 100644 --- a/src/handler/slack/addSlackWorkspace.ts +++ b/src/handler/slack/addSlackWorkspace.ts @@ -48,7 +48,7 @@ export const addSlackWorkspace = async ( if (!teamRow) { res.status(404).send("Team not found"); - return + return; } await prismaClient.slackWorkspace.upsert({ diff --git a/src/handler/slack/sendWarningNotification.ts b/src/handler/slack/sendWarningNotification.ts index a20a4207..e1317be8 100644 --- a/src/handler/slack/sendWarningNotification.ts +++ b/src/handler/slack/sendWarningNotification.ts @@ -38,6 +38,14 @@ export async function sendWarningToSlack( ? report.scouter.name.trim() : `A Scouter from team ${report.scouter.sourceTeamNumber}`; + // Locate the upcoming match number for the workspace's team; fall back to a generic label if missing. + const partnerMatch = upcomingAlliancePartners.find( + ([partnerTeam]) => partnerTeam === channel.workspace.owner, + ); + const partnerMatchLabel = partnerMatch?.[1] + ? `Q${partnerMatch[1]}` + : "an upcoming match"; + let result; const thread = await prismaClient.slackNotificationThread.findFirst({ @@ -55,13 +63,13 @@ export async function sendWarningToSlack( if (warning == WarningType.AUTO_LEAVE) { result = await client.chat.postMessage({ channel: channel.channelId, - text: `Heads up! *${scouterName}* reported your alliance partner in *Q${upcomingAlliancePartners[upcomingAlliancePartners.map((x) => x[0]).findIndex((num) => num === matchNumber)][1]}*, team *${teamNumber}*, didn't leave during auto in *Q${matchNumber}*`, + text: `Heads up! *${scouterName}* reported your alliance partner in *${partnerMatchLabel}*, team *${teamNumber}*, didn't leave during auto in *Q${matchNumber}*`, }); } else if (warning == WarningType.BREAK) { result = await client.chat.postMessage({ channel: channel.channelId, // robotBrokeDesc needs to be filtered because old versions of Collection will send it as null, or it might be undefined - text: `Heads up! *${scouterName}* reported your alliance partner in *Q${upcomingAlliancePartners[upcomingAlliancePartners.map((x) => x[0]).findIndex((num) => num === matchNumber)][1]}*, team *${teamNumber}*, broke in *Q${matchNumber}*.\n${ + text: `Heads up! *${scouterName}* reported your alliance partner in *${partnerMatchLabel}*, team *${teamNumber}*, broke in *Q${matchNumber}*.\n${ report.robotBrokeDescription && report.robotBrokeDescription.trim() !== "" ? `> ${report.robotBrokeDescription}` @@ -139,6 +147,8 @@ async function getUpcomingAlliancePartners( tournamentKey, ); + const allianceByMatch = new Map(upcomingAlliances); + const upcomingTeams: TeamMatchData[] = await prismaClient.teamMatchData.findMany({ where: { @@ -155,11 +165,12 @@ async function getUpcomingAlliancePartners( const out: number[][] = []; for (const data of upcomingTeams) { - if ( - upcomingAlliances[ - upcomingAlliances.findIndex((x) => x[0] === data.matchNumber) - ][1] - ) { + const allianceIsRed = allianceByMatch.get(data.matchNumber); + if (allianceIsRed === undefined) { + continue; // skip unexpected data without alliance info + } + + if (allianceIsRed) { if (parseInt(data.key.at(-1)) >= 3) { out.push([data.teamNumber, data.matchNumber]); } diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index d813e07b..00000000 --- a/src/index.ts +++ /dev/null @@ -1,382 +0,0 @@ -import express from "express"; -import "dotenv/config"; -import bodyParser from "body-parser"; - -import { requireAuth } from "./lib/middleware/requireAuth.js"; - -import { addMutablePicklist } from "./handler/manager/addMutablePicklist.js"; - -import { addPicklist } from "./handler/manager/addPicklist.js"; -import { addRegisteredTeam } from "./handler/manager/addRegisteredTeam.js"; -import { addScouterShift } from "./handler/manager/addScouterShift.js"; -import { approveRegisteredTeam } from "./handler/manager/approveRegisteredTeam.js"; -import { checkRegisteredTeam } from "./handler/manager/checkRegisteredTeam.js"; -import { deleteScoutReport } from "./handler/manager/deleteScoutReport.js"; -import { deleteMutablePicklist } from "./handler/manager/deleteMutablePicklist.js"; -import { deletePicklist } from "./handler/manager/deletePicklist.js"; -import { deleteScouterShift } from "./handler/manager/deleteScouterShift.js"; -import { getMutablePicklists } from "./handler/manager/getMutablePicklists.js"; -import { getPicklists } from "./handler/manager/getPicklists.js"; -import { getScouterSchedule } from "./handler/manager/getScouterSchedule.js"; -import { getTeamsInTournament } from "./handler/manager/getTeamsInTournament.js"; -import { rejectRegisteredTeam } from "./handler/manager/rejectRegisteredTeam.js"; -import { getTournaments } from "./handler/manager/getTournaments.js"; -import { addUsername } from "./handler/manager/addUsername.js"; -import { getTeams } from "./handler/manager/getTeams.js"; -import { updateScouterShift } from "./handler/manager/updateScouterShift.js"; -import scheduleJobs from "./lib/scheduleJobs.js"; -import { checkCode } from "./handler/manager/checkCode.js"; -import { addTournamentSource } from "./handler/manager/addTournamentSource.js"; -import { addTeamSource } from "./handler/manager/addTeamSource.js"; -import { addScoutReport } from "./handler/manager/addScoutReport.js"; -import { getScoutReport } from "./handler/manager/getScoutReport.js"; -import { getMatches } from "./handler/manager/getMatchesNew.js"; -import { getSinglePicklist } from "./handler/manager/getSinglePicklist.js"; -import { getSingleMutablePicklist } from "./handler/manager/getSingleMutablePicklist.js"; -import { updatePicklist } from "./handler/manager/updatePicklist.js"; -import { updateMutablePicklist } from "./handler/manager/updateMutablePicklist.js"; -import { addWebsite } from "./handler/manager/addWebsite.js"; -import requireLovatSignature from "./lib/middleware/requireLovatSignature.js"; -import { approveTeamEmail } from "./handler/manager/approveTeamEmail.js"; -import rateLimit from "express-rate-limit"; -import { resendEmail } from "./handler/manager/resendEmail.js"; -import { getProfile } from "./handler/manager/getProfile.js"; -import { deleteUser } from "./handler/manager/deleteUser.js"; -import { getUsers } from "./handler/manager/getUsers.js"; -import { updateRoleToScoutingLead } from "./handler/manager/updateRoleToScoutingLead.js"; -import { detailsPage } from "./handler/analysis/teamLookUp/detailsPage.js"; -import { categoryMetrics } from "./handler/analysis/teamLookUp/categoryMetrics.js"; -import { breakdownMetrics } from "./handler/analysis/teamLookUp/breakdownMetrics.js"; -import { checkCodeScouter } from "./handler/manager/checkCodeScouter.js"; -import { changeNameScouter } from "./handler/manager/changeNameScouter.js"; -import { getScoutersOnTeam } from "./handler/manager/getScoutersOnTeam.js"; -import { getScheduleForScouter } from "./handler/manager/getScheduleForScouter.js"; -import { addNewScouter } from "./handler/manager/addNewScouter.js"; -import { updateNotes } from "./handler/manager/updateNotes.js"; -import { getTeamCode } from "./handler/manager/getTeamCode.js"; -import { getAnalysts } from "./handler/manager/getAnalysts.js"; -import { updateSettings } from "./handler/manager/updateSettings.js"; -import { getNotes } from "./handler/analysis/teamLookUp/getNotes.js"; -import { alliancePageResponse } from "./handler/analysis/alliancePredictions/alliancePageResponse.js"; -import { matchPrediction } from "./handler/analysis/alliancePredictions/matchPrediction.js"; -import { getTeamSource } from "./handler/manager/getTeamSource.js"; -import { getTournamentSource } from "./handler/manager/getTournamentSource.js"; -import { picklistShell } from "./handler/analysis/picklist/picklistShell.js"; -// import { scoutingLeadPage } from "./handler/analysis/scoutingLead/scoutingLeadPage.js"; -import { getScouterTournaments } from "./handler/manager/getScouterTournaments.js"; -import { getScouters } from "./handler/manager/getScouters.js"; -import { addScoutReportDashboard } from "./handler/manager/addScoutReportDashboard.js"; -import { matchPageSpecificScouter } from "./handler/analysis/specificMatchPage/matchPageSpecificScouter.js"; -import { scoutReportForMatch } from "./handler/analysis/specificMatchPage/scoutReportForMatch.js"; -import { timelineForScoutReport } from "./handler/analysis/specificMatchPage/timelineForScoutReport.js"; -import { getTournamentForScouterWithSchedule } from "./handler/manager/getTournamentForScouterWithSchedule.js"; -import { multipleFlags } from "./handler/analysis/teamLookUp/multipleFlags.js"; -import { updateTeamEmail } from "./handler/manager/updateTeamEmail.js"; -import { addNotOnTeam } from "./handler/manager/addNotOnTeam.js"; -import { updateScouterName } from "./handler/manager/updateScouterName.js"; -import { deleteScouter } from "./handler/manager/deleteScouter.js"; -import { scoutingLeadProgressPage } from "./handler/manager/scoutingLeadProgressPage.js"; -import { addScouterDashboard } from "./handler/manager/addScouterDashboard.js"; -import { scouterScoutReports } from "./handler/analysis/scoutingLead/scouterScoutReports.js"; -import { pitDisplay } from "./handler/manager/pitDisplay.js"; -import { getTeamCSV } from "./handler/manager/getTeamCSV.js"; -import { getTeamMatchCSV } from "./handler/manager/getTeamMatchCSV.js"; -import { getReportCSV } from "./handler/manager/getReportCSV.js"; -import { emailTeamCode } from "./handler/manager/emailTeamCode.js"; -import { breakdownDetails } from "./handler/analysis/teamLookUp/breakdownDetails.js"; -import { getTeamRankings } from "./handler/manager/getTeamRankings.js"; -import { getTeamTournamentStatus } from "./handler/manager/getTeamTournamentStatus.js"; -import { getMatchResults } from "./handler/manager/getMatchResults.js"; -import { addSlackWorkspace } from "./handler/slack/addSlackWorkspace.js"; -import { processCommand } from "./handler/slack/processCommands.js"; -import { processEvent } from "./handler/slack/processEvents.js"; -import { setupExpressErrorHandler } from "posthog-node"; -import { posthog } from "./posthogClient.js"; -import posthogReporter from "./lib/middleware/posthogMiddleware.js"; -import { requireSlackToken } from "./lib/middleware/requireSlackToken.js"; -import { migrateDataSources } from "./lib/migrateDataSources.js"; -import { archiveScouter } from "./handler/manager/archiveScouter.js"; -import { unarchiveScouter } from "./handler/manager/unarchiveScouter.js"; -import { onboardingRedirect } from "./handler/slack/onboardingRedirect.js"; -import cookieParser from "cookie-parser"; -import { clearCache } from "./lib/clearCache.js"; -// import { addTournamentMatchesOneTime } from "./handler/manager/addTournamentMatchesOneTime.js"; - -const resendEmailLimiter = rateLimit({ - windowMs: 2 * 60 * 1000, - max: 2, - message: - "Too many emails sent from this IP, please try again after 2 minutes", - validate: { trustProxy: false }, -}); - -const updateTeamEmails = rateLimit({ - windowMs: 2 * 60 * 1000, - max: 3, - message: - "Too many email updates sent from this IP, please try again after 2 minutes", - validate: { trustProxy: false }, -}); - -const app = express(); - -setupExpressErrorHandler(posthog, app); - -app.set("trust proxy", true); - -const port = process.env.PORT || 3000; - -app.use(bodyParser.json()); - -app.use(cookieParser()); - -app.get("/v1/slack-invite", onboardingRedirect); - -// add/update slack workspace -app.get("/v1/slack/add-workspace", requireSlackToken, addSlackWorkspace); - -// process slash commands -app.post( - "/v1/slack/command", - express.urlencoded({ extended: true }), - requireSlackToken, - processCommand -); - -app.post("/v1/slack/event", requireSlackToken, processEvent); - -app.post( - "/v1/manager/onboarding/verifyemail", - requireLovatSignature, - approveTeamEmail -); //tested - -// Log requests -app.use(posthogReporter); - -//general endpoints -app.get( - "/v1/manager/tournament/:tournament/teams", - requireAuth, - getTeamsInTournament -); -app.get( - "/v1/manager/tournament/:tournament/rankedTeams", - requireAuth, - getTeamRankings -); -app.get("/v1/manager/teams", requireAuth, getTeams); //tested -app.get("/v1/manager/tournaments", requireAuth, getTournaments); //tested - -//match schedule page -app.get("/v1/manager/matches/:tournament", requireAuth, getMatches); // should be able to filter by tournament, team, and whether or not they have been scouted. -// app.get('/API/isScouted') //what will be sent, and what should it return // We can hold off on this until it's time for the collection app - -//scout report -app.delete("/v1/manager/scoutreports/:uuid", requireAuth, deleteScoutReport); // tested -app.put("/v1/manager/notes/:uuid", requireAuth, updateNotes); -app.get("/v1/manager/scoutreports/:uuid", getScoutReport); //tested - -//scouter shift -app.post( - "/v1/manager/tournament/:tournament/scoutershifts", - requireAuth, - addScouterShift -); //tested , expecting only 1 at a time -// app.get('/manager/tournament/:tournament/scoutershifts',requireAuth, getScouterSchedule) //tested -app.post("/v1/manager/scoutershifts/:uuid", requireAuth, updateScouterShift); //tested -app.delete("/v1/manager/scoutershifts/:uuid", requireAuth, deleteScouterShift); //tested -app.get("/v1/manager/scoutershift/scouters", requireAuth, getScouters); - -//picklist (waiting to fully finish testing when I have a second user to play with) -app.post("/v1/manager/picklists", requireAuth, addPicklist); //tested -app.get("/v1/manager/picklists", requireAuth, getPicklists); //tested -app.delete("/v1/manager/picklists/:uuid", requireAuth, deletePicklist); //tested -app.get("/v1/manager/picklists/:uuid", requireAuth, getSinglePicklist); //tested -app.put("/v1/manager/picklists/:uuid", requireAuth, updatePicklist); //tested - -//mutable picklist (waiting to fully finish testing when I have a second user to play with) -app.post("/v1/manager/mutablepicklists", requireAuth, addMutablePicklist); // tested -app.delete( - "/v1/manager/mutablepicklists/:uuid", - requireAuth, - deleteMutablePicklist -); //tested -app.get("/v1/manager/mutablepicklists", requireAuth, getMutablePicklists); //tested -app.get( - "/v1/manager/mutablepicklists/:uuid", - requireAuth, - getSingleMutablePicklist -); //tested -app.put( - "/v1/manager/mutablepicklists/:uuid", - requireAuth, - updateMutablePicklist -); //tested - -// Also it would be nice to have an endpoint to subscribe to a mutable picklist, so that the client can get updates when it changes -// Websocket time? lol, ill add to wish list items, after this break yes - -//onboarding endpoints -app.get( - "/v1/manager/registeredteams/:team/registrationstatus", - requireAuth, - checkRegisteredTeam -); //tested -app.post("/v1/manager/onboarding/username", requireAuth, addUsername); //tested -app.post("/v1/manager/onboarding/teamcode", requireAuth, checkCode); //tested -app.post("/v1/manager/settings/teamsource", requireAuth, addTeamSource); //tested -app.post( - "/v1/manager/settings/tournamentsource", - requireAuth, - addTournamentSource -); -app.post("/v1/manager/onboarding/team", requireAuth, addRegisteredTeam); //tested, is the link correct? -app.post( - "/v1/manager/registeredteams/:team/approve", - requireLovatSignature, - approveRegisteredTeam -); //tested waiting for new middle ware -app.post( - "/v1/manager/registeredteams/:team/reject", - requireLovatSignature, - rejectRegisteredTeam -); // tested, waiting for new middle ware -app.post("/v1/manager/onboarding/teamwebsite", requireAuth, addWebsite); //tested - -app.post( - "/v1/manager/onboarding/resendverificationemail", - resendEmailLimiter, - requireAuth, - resendEmail -); //tested -app.get("/v1/manager/profile", requireAuth, getProfile); //tested -app.get("/v1/manager/users", requireAuth, getUsers); //tested -app.post("/v1/manager/noteam", requireAuth, addNotOnTeam); - -//dashboard app settings -app.delete("/v1/manager/user", requireAuth, deleteUser); //tested, is there more to do with Auth0 -app.post("/v1/manager/upgradeuser", requireAuth, updateRoleToScoutingLead); //tested, idk what to name, u can change -app.get("/v1/manager/analysts", requireAuth, getAnalysts); //use for list of people eligable to upgrade ^^^ -app.put("/v1/manager/settings", requireAuth, updateSettings); -app.get("/v1/manager/settings/teamsource", requireAuth, getTeamSource); -app.get( - "/v1/manager/settings/tournamentsource", - requireAuth, - getTournamentSource -); -app.put( - "/v1/manager/settings/teamemail", - updateTeamEmails, - requireAuth, - updateTeamEmail -); - -//scouting lead information/QR codes -app.get("/v1/manager/code", requireAuth, getTeamCode); -app.get( - "/v1/manager/tournament/:tournament/scoutershifts", - requireAuth, - getScouterSchedule -); //tested - -app.post( - "/v1/manager/dashboard/scoutreport", - requireAuth, - addScoutReportDashboard -); - -//scouter onboarding -app.post("/v1/manager/emailTeamCode", emailTeamCode); -app.get("/v1/manager/scouter/checkcode", checkCodeScouter); //tested change name/where request data is coming from/response format as needed -app.post("/v1/manager/unarchive/uuid/:uuid", requireAuth, unarchiveScouter); -app.post("/v1/manager/archive/uuid/:uuid", requireAuth, archiveScouter); -app.post("/v1/manager/name/uuid/:uuid", changeNameScouter); // tested, change name/where request data is coming from/response format as needed -app.get("/v1/manager/scouters", getScoutersOnTeam); //tested -app.post("/v1/manager/scouter", addNewScouter); //tested - -//collection app homepage (feel free to change request/response format as needed) -app.get("/v1/manager/scouters/:uuid/tournaments", getScouterTournaments); //tested, gets all tournaments (for settings) -app.get("/v1/manager/scouterschedules/:tournament", getScheduleForScouter); //tested -app.get("/v1/manager/scouter/tournaments", getTournamentForScouterWithSchedule); -app.post("/v1/manager/scoutreports", addScoutReport); //tested - -//analysis - -//team look up page -app.get("/v1/analysis/metric/:metric/team/:team", requireAuth, detailsPage); //tested, same format -app.get("/v1/analysis/category/team/:team", requireAuth, categoryMetrics); //tested, same format -app.get("/v1/analysis/breakdown/team/:team", requireAuth, breakdownMetrics); //tested, same format -app.get( - "/v1/analysis/breakdown/team/:team/:breakdown", - requireAuth, - breakdownDetails -); -app.get("/v1/analysis/notes/team/:team", requireAuth, getNotes); //tested -app.get("/v1/analysis/flag/team/:team", requireAuth, multipleFlags); //tested - -//my alliance page -app.get("/v1/analysis/alliance", requireAuth, alliancePageResponse); - -//match prediction -app.get("/v1/analysis/matchprediction", requireAuth, matchPrediction); -app.get("/v1/analysis/picklist", requireAuth, picklistShell); - -//scouting lead -app.put("/v1/manager/scoutername", requireAuth, updateScouterName); -app.delete("/v1/manager/scouterdashboard", requireAuth, deleteScouter); -app.get("/v1/manager/scouterspage", requireAuth, scoutingLeadProgressPage); -app.post("/v1/manager/scouterdashboard", requireAuth, addScouterDashboard); -app.get("/v1/manager/scouterreports", requireAuth, scouterScoutReports); - -//specific scoutreport - -app.get( - "/v1/analysis/metrics/scoutreport/:uuid", - requireAuth, - matchPageSpecificScouter -); -app.get( - "/v1/analysis/scoutreports/match/:match", - requireAuth, - scoutReportForMatch -); -app.get( - "/v1/analysis/timeline/scoutreport/:uuid", - requireAuth, - timelineForScoutReport -); - -//pit scouting -app.get("/v1/analysis/pitdisplay", pitDisplay); - -// app.get('/v1/addtourny', addTournamentMatchesOneTime) - -// csv export -app.get("/v1/analysis/csvplain", requireAuth, getTeamCSV); // tested -app.get("/v1/analysis/matchcsv", requireAuth, getTeamMatchCSV); -app.get("/v1/analysis/reportcsv", requireAuth, getReportCSV); - -// current tournament stats widget -app.get( - "/v1/manager/team-tournament-status", - requireAuth, - getTeamTournamentStatus -); - -// match results from scouting reports -app.get("/v1/manager/match-results-page", requireAuth, getMatchResults); - -// API key management -// app.get("/v1/manager/add-api-key", requireAuth, addApiKey); -// app.get("/v1/manager/revoke-api-key", requireAuth, revokeApiKey); -// app.get("/v1/manager/get-api-keys", requireAuth, getApiKeys); -// app.get("/v1/manager/rename-api-key", requireAuth, renameApiKey); - -await scheduleJobs(); - -await migrateDataSources(); - -await clearCache(); - -app.listen(port); diff --git a/src/lib/middleware/posthogMiddleware.ts b/src/lib/middleware/posthogMiddleware.ts index 6f6c59f1..38dcc42e 100644 --- a/src/lib/middleware/posthogMiddleware.ts +++ b/src/lib/middleware/posthogMiddleware.ts @@ -61,7 +61,7 @@ const posthogReporter = async ( $set: userProps, $pathname: req.route?.path, method: req.method, - cache: res.getHeader('X-Lovat-Cache'), + cache: res.getHeader("X-Lovat-Cache"), path: req.path, query: req.query, reqBody: req.body, diff --git a/src/lib/middleware/requireAuth.ts b/src/lib/middleware/requireAuth.ts index 22a07730..202443af 100644 --- a/src/lib/middleware/requireAuth.ts +++ b/src/lib/middleware/requireAuth.ts @@ -19,6 +19,7 @@ export const requireAuth = async ( res: Response, next: NextFunction, ): Promise => { + console.log("Authenticating request"); try { console.log(`${req.method} ${req.path}`); // Validate JWT diff --git a/src/routes/analysis/analysis.routes.ts b/src/routes/analysis/analysis.routes.ts new file mode 100644 index 00000000..0d5f20ff --- /dev/null +++ b/src/routes/analysis/analysis.routes.ts @@ -0,0 +1,26 @@ +import { alliancePageResponse } from "../../handler/analysis/alliancePredictions/alliancePageResponse.js"; +import { matchPrediction } from "../../handler/analysis/alliancePredictions/matchPrediction.js"; +import { picklistShell } from "../../handler/analysis/picklist/picklistShell.js"; +import { pitDisplay } from "../../handler/manager/pitDisplay.js"; +import { requireAuth } from "../../lib/middleware/requireAuth.js"; +import { Router } from "express"; +import teamLookup from "./teamLookup.routes.js" +import csv from "./csv.routes.js" +import scoutReport from "./scoutreport.routes.js" + +const router = Router(); + +router.get("/pitdisplay", pitDisplay); + +router.use(requireAuth); + +router.use(teamLookup); +router.use(csv); +router.use(scoutReport); + +router.get("/alliance", alliancePageResponse); + +router.get("/matchprediction", matchPrediction); +router.get("/picklist", picklistShell); + +export default router; diff --git a/src/routes/analysis/csv.routes.ts b/src/routes/analysis/csv.routes.ts new file mode 100644 index 00000000..f9f7b405 --- /dev/null +++ b/src/routes/analysis/csv.routes.ts @@ -0,0 +1,15 @@ +import { Router } from "express"; +import { requireAuth } from "../../lib/middleware/requireAuth.js"; +import { getReportCSV } from "../../handler/analysis/csv/getReportCSV.js"; +import { getTeamCSV } from "../../handler/analysis/csv/getTeamCSV.js"; +import { getTeamMatchCSV } from "../../handler/analysis/csv/getTeamMatchCSV.js"; + +const router = Router(); + +router.use(requireAuth); + +router.get("/csvplain", getTeamCSV); +router.get("/matchcsv", getTeamMatchCSV); +router.get("/reportcsv", getReportCSV); + +export default router; \ No newline at end of file diff --git a/src/routes/analysis/scoutreport.routes.ts b/src/routes/analysis/scoutreport.routes.ts new file mode 100644 index 00000000..3212a75a --- /dev/null +++ b/src/routes/analysis/scoutreport.routes.ts @@ -0,0 +1,15 @@ +import { Router } from "express"; +import { requireAuth } from "../../lib/middleware/requireAuth.js"; +import { matchPageSpecificScouter } from "../../handler/analysis/specificMatchPage/matchPageSpecificScouter"; +import { scoutReportForMatch } from "../../handler/analysis/specificMatchPage/scoutReportForMatch"; +import { timelineForScoutReport } from "../../handler/analysis/specificMatchPage/timelineForScoutReport"; + +const router = Router(); + +router.use(requireAuth); + +router.get("/metrics/scoutreport/:uuid", matchPageSpecificScouter); +router.get("/scoutreports/match/:match", scoutReportForMatch); +router.get("/timeline/scoutreport/:uuid", timelineForScoutReport); + +export default router; \ No newline at end of file diff --git a/src/routes/analysis/teamLookup.routes.ts b/src/routes/analysis/teamLookup.routes.ts new file mode 100644 index 00000000..ab7b5675 --- /dev/null +++ b/src/routes/analysis/teamLookup.routes.ts @@ -0,0 +1,21 @@ +import { Router } from "express"; +import { requireAuth } from "../../lib/middleware/requireAuth.js"; +import { breakdownDetails } from "../../handler/analysis/teamLookUp/breakdownDetails.js"; +import { breakdownMetrics } from "../../handler/analysis/teamLookUp/breakdownMetrics.js"; +import { categoryMetrics } from "../../handler/analysis/teamLookUp/categoryMetrics.js"; +import { detailsPage } from "../../handler/analysis/teamLookUp/detailsPage.js"; +import { getNotes } from "../../handler/analysis/teamLookUp/getNotes.js"; +import { multipleFlags } from "../../handler/analysis/teamLookUp/multipleFlags.js"; + +const router = Router(); + +router.use(requireAuth); + +router.get("/metric/:metric/team/:team", detailsPage); +router.get("/category/team/:team", categoryMetrics); +router.get("/breakdown/team/:team", breakdownMetrics); +router.get("/breakdown/team/:team/:breakdown", breakdownDetails); +router.get("/notes/team/:team", getNotes); +router.get("/flag/team/:team", multipleFlags); + +export default router; diff --git a/src/routes/index.ts b/src/routes/index.ts new file mode 100644 index 00000000..6287f132 --- /dev/null +++ b/src/routes/index.ts @@ -0,0 +1,16 @@ +import { Router } from "express"; + +import slackRouter from "./slack/slack.routes.js"; +import managerRouter from "./manager/manager.routes.js"; +import analysisRouter from "./analysis/analysis.routes.js"; +import { onboardingRedirect } from "../handler/slack/onboardingRedirect.js"; + +const router = Router(); + +router.use("/slack", slackRouter); +router.use("/manager", managerRouter); +router.use("/analysis", analysisRouter); + +router.get("/slack-invite", onboardingRedirect); + +export default router; diff --git a/src/routes/manager/apikey.routes.ts b/src/routes/manager/apikey.routes.ts new file mode 100644 index 00000000..e66aacc9 --- /dev/null +++ b/src/routes/manager/apikey.routes.ts @@ -0,0 +1,17 @@ +import { Router } from "express"; +import { requireAuth } from "../../lib/middleware/requireAuth.js"; +import { addApiKey } from "../../handler/manager/apikey/addApiKey.js"; +import { getApiKeys } from "../../handler/manager/apikey/getApiKeys.js"; +import { renameApiKey } from "../../handler/manager/apikey/renameApiKey.js"; +import { revokeApiKey } from "../../handler/manager/apikey/revokeApiKey.js"; + +const router = Router(); + +router.use(requireAuth); + +router.post("/", addApiKey); +router.delete("/", revokeApiKey); +router.get("/", getApiKeys); +router.patch("/", renameApiKey); + +export default router; diff --git a/src/routes/manager/manager.routes.ts b/src/routes/manager/manager.routes.ts new file mode 100644 index 00000000..c702c86f --- /dev/null +++ b/src/routes/manager/manager.routes.ts @@ -0,0 +1,69 @@ +import { Router } from "express"; + +import onboarding from "./onboarding.routes.js"; +import picklists from "./picklists.routes.js"; +import mutablepicklist from "./mutablepicklists.routes.js"; +import registeredteams from "./registeredteams.routes.js"; +import scouters from "./scouters.routes.js"; +import tournaments from "./tournaments.routes.js"; +import scoutreports from "./scoutreports.routes.js"; +import settings from "./settings.routes.js"; +//import apikey from "./apikey.routes.js"; + +import { getTournaments } from "../../handler/manager/getTournaments.js"; +import { getTeams } from "../../handler/manager/getTeams.js"; +import { requireAuth } from "../../lib/middleware/requireAuth.js"; +import { getMatches } from "../../handler/manager/getMatches.js"; +import { updateNotes } from "../../handler/manager/updateNotes.js"; +import { getScouters } from "../../handler/manager/scouters/getScouters.js"; +import { getProfile } from "../../handler/manager/getProfile.js"; +import { getUsers } from "../../handler/manager/getUsers.js"; +import { deleteUser } from "../../handler/manager/deleteUser.js"; +import { updateRoleToScoutingLead } from "../../handler/manager/scouters/updateRoleToScoutingLead.js"; +import { getAnalysts } from "../../handler/manager/getAnalysts.js"; +import { addNotOnTeam } from "../../handler/manager/temp/addNotOnTeam.js"; +import { getTeamCode } from "../../handler/manager/getTeamCode.js"; +import { addScoutReportDashboard } from "../../handler/manager/scoutreports/addScoutReportDashboard.js"; +import { getTeamTournamentStatus } from "../../handler/manager/getTeamTournamentStatus.js"; +import { getMatchResults } from "../../handler/manager/getMatchResults.js"; + +const router = Router(); + +router.use("/onboarding", onboarding); +router.use("/picklists", picklists); +router.use("/mutablepicklists", mutablepicklist); +router.use("/registeredteams", registeredteams); +router.use("/", scouters); +router.use("/tournament", tournaments); +router.use("/scoutreports", scoutreports); +router.use("/settings", settings); +//router.use("/apikey", apikey); + +router.get("/teams", requireAuth, getTeams); +router.get("/tournaments", requireAuth, getTournaments); + +router.get("/matches/:tournament", requireAuth, getMatches); + +router.put("/notes/:uuid", requireAuth, updateNotes); +router.get("/scoutershift/scouters", requireAuth, getScouters); + +router.get("/profile", requireAuth, getProfile); + +router.get("/users", requireAuth, getUsers); + +router.delete("/user", requireAuth, deleteUser); + +router.post("/upgradeuser", requireAuth, updateRoleToScoutingLead); +router.get("/analysts", requireAuth, getAnalysts); + +router.post("/noteam", requireAuth, addNotOnTeam); + +router.get("/code", requireAuth, getTeamCode); + +router.post("/dashboard/scoutreport", requireAuth, addScoutReportDashboard); + +router.get("/v1/manager/team-tournament-status", requireAuth, getTeamTournamentStatus); + +router.get("/v1/manager/match-results-page", requireAuth, getMatchResults); + +export default router; diff --git a/src/routes/manager/mutablepicklists.routes.ts b/src/routes/manager/mutablepicklists.routes.ts new file mode 100644 index 00000000..0e7ac396 --- /dev/null +++ b/src/routes/manager/mutablepicklists.routes.ts @@ -0,0 +1,31 @@ +import { Router } from "express"; +import { requireAuth } from "../../lib/middleware/requireAuth.js"; +import { addMutablePicklist } from "../../handler/manager/mutablepicklists/addMutablePicklist.js"; +import { deleteMutablePicklist } from "../../handler/manager/mutablepicklists/deleteMutablePicklist.js"; +import { getMutablePicklists } from "../../handler/manager/mutablepicklists/getMutablePicklists.js"; +import { getSingleMutablePicklist } from "../../handler/manager/mutablepicklists/getSingleMutablePicklist.js"; +import { updateMutablePicklist } from "../../handler/manager/mutablepicklists/updateMutablePicklist.js"; + +/* + +mutablepicklists.routes.ts + +POST /manager/mutablepicklists +GET /manager/mutablepicklists +GET /manager/mutablepicklists/:uuid +PUT /manager/mutablepicklists/:uuid +DELETE /manager/mutablepicklists/:uuid + +*/ + +const router = Router(); + +router.use(requireAuth); + +router.post("/", addMutablePicklist); +router.delete("/:uuid", deleteMutablePicklist); +router.get("/", getMutablePicklists); +router.get("/:uuid", getSingleMutablePicklist); +router.put("/:uuid", updateMutablePicklist); + +export default router; diff --git a/src/routes/manager/onboarding.routes.ts b/src/routes/manager/onboarding.routes.ts new file mode 100644 index 00000000..1402d106 --- /dev/null +++ b/src/routes/manager/onboarding.routes.ts @@ -0,0 +1,53 @@ +import { Router } from "express"; +import requireLovatSignature from "../../lib/middleware/requireLovatSignature.js"; +import { approveTeamEmail } from "../../handler/manager/onboarding/approveTeamEmail.js"; +import { addUsername } from "../../handler/manager/onboarding/addUsername.js"; +import { checkCode } from "../../handler/manager/onboarding/checkCode.js"; +import { requireAuth } from "../../lib/middleware/requireAuth.js"; +import { addRegisteredTeam } from "../../handler/manager/registeredteams/addRegisteredTeam.js"; +import rateLimit from "express-rate-limit"; +import { addWebsite } from "../../handler/manager/onboarding/addWebsite.js"; +import { resendEmail } from "../../handler/manager/onboarding/resendEmail.js"; + +/* + +onboarding.routes.ts + +POST /manager/onboarding/verifyemail +POST /manager/onboarding/username +POST /manager/onboarding/teamcode +POST /manager/onboarding/team +POST /manager/onboarding/teamwebsite +POST /manager/onboarding/resendverificationemail + +*/ + +const resendEmailLimiter = rateLimit({ + windowMs: 2 * 60 * 1000, + max: 2, + message: + "Too many emails sent from this IP, please try again after 2 minutes", + validate: { trustProxy: false }, +}); + +const router = Router(); + +router.post("/verifyemail", requireLovatSignature, approveTeamEmail); + +router.use(requireAuth); + +router.post("/username", addUsername); + +router.post("/teamcode", checkCode); + +router.post("/team", addRegisteredTeam); + +router.post("/teamwebsite", addWebsite); + +router.post( + "/resendverificationemail", + resendEmailLimiter, + resendEmail, +); + +export default router; diff --git a/src/routes/manager/picklists.routes.ts b/src/routes/manager/picklists.routes.ts new file mode 100644 index 00000000..d3943b1f --- /dev/null +++ b/src/routes/manager/picklists.routes.ts @@ -0,0 +1,35 @@ +import { Router } from "express"; +import { requireAuth } from "../../lib/middleware/requireAuth.js"; +import { addPicklist } from "../../handler/manager/picklists/addPicklist.js"; +import { deletePicklist } from "../../handler/manager/picklists/deletePicklist.js"; +import { getPicklists } from "../../handler/manager/picklists/getPicklists.js"; +import { getSinglePicklist } from "../../handler/manager/picklists/getSinglePicklist.js"; +import { updatePicklist } from "../../handler/manager/picklists/updatePicklist.js"; + +/* + +picklists.routes.ts + +POST /manager/picklists +GET /manager/picklists +GET /manager/picklists/:uuid +PUT /manager/picklists/:uuid +DELETE /manager/picklists/:uuid + +*/ + +const router = Router(); + +router.use(requireAuth); + +router.post("/", addPicklist); + +router.get("/", getPicklists); + +router.get("/:uuid", getSinglePicklist); + +router.put("/:uuid", updatePicklist); + +router.delete("/:uuid", deletePicklist); + +export default router; diff --git a/src/routes/manager/registeredteams.routes.ts b/src/routes/manager/registeredteams.routes.ts new file mode 100644 index 00000000..d6b0e43d --- /dev/null +++ b/src/routes/manager/registeredteams.routes.ts @@ -0,0 +1,16 @@ +import { Router } from "express"; +import { requireAuth } from "../../lib/middleware/requireAuth.js"; +import { rejectRegisteredTeam } from "../../handler/manager/registeredteams/rejectRegisteredTeam.js"; +import { approveRegisteredTeam } from "../../handler/manager/registeredteams/approveRegisteredTeam.js"; +import { checkRegisteredTeam } from "../../handler/manager/registeredteams/checkRegisteredTeam.js"; +import requireLovatSignature from "../../lib/middleware/requireLovatSignature.js"; + +const router = Router(); + +router.get("/:team/registrationstatus", requireAuth, checkRegisteredTeam); + +router.use(requireLovatSignature); +router.post("/:team/approve", approveRegisteredTeam); +router.post("/:team/reject", rejectRegisteredTeam); + +export default router; diff --git a/src/routes/manager/scouters.routes.ts b/src/routes/manager/scouters.routes.ts new file mode 100644 index 00000000..cb56337f --- /dev/null +++ b/src/routes/manager/scouters.routes.ts @@ -0,0 +1,39 @@ +import { Router } from "express"; +import { requireAuth } from "../../lib/middleware/requireAuth.js"; +import { addNewScouter } from "../../handler/manager/scouters/addNewScouter.js"; +import { archiveScouter } from "../../handler/manager/scouters/archiveScouter.js"; +import { changeNameScouter } from "../../handler/manager/scouters/changeNameScouter.js"; +import { checkCodeScouter } from "../../handler/manager/scouters/checkCodeScouter.js"; +import { emailTeamCode } from "../../handler/manager/scouters/emailTeamCode.js"; +import { getScheduleForScouter } from "../../handler/manager/scouters/getScheduleForScouter.js"; +import { getScoutersOnTeam } from "../../handler/manager/scouters/getScoutersOnTeam.js"; +import { getScouterTournaments } from "../../handler/manager/scouters/getScouterTournaments.js"; +import { getTournamentForScouterWithSchedule } from "../../handler/manager/scouters/getTournamentForScouterWithSchedule.js"; +import { unarchiveScouter } from "../../handler/manager/scouters/unarchiveScouter.js"; +import { addScouterDashboard } from "../../handler/manager/scouters/addScouterDashboard.js"; +import { scouterScoutReports } from "../../handler/analysis/scoutingLead/scouterScoutReports.js"; +import { deleteScouter } from "../../handler/manager/scouters/deleteScouter.js"; +import { scoutingLeadProgressPage } from "../../handler/manager/scouters/scoutingLeadProgressPage.js"; +import { updateScouterName } from "../../handler/manager/scouters/updateScouterName.js"; + +const router = Router(); +router.post("/emailTeamCode", emailTeamCode); +router.get("/scouter/checkcode", checkCodeScouter); +router.post("/name/uuid/:uuid", changeNameScouter); +router.get("/scouters", getScoutersOnTeam); +router.post("/scouter", addNewScouter); + +router.get("/scouters/:uuid/tournaments", getScouterTournaments); +router.get("/scouterschedules/:tournament", getScheduleForScouter); +router.get("/scouter/tournaments", getTournamentForScouterWithSchedule); + +router.post("/unarchive/uuid/:uuid", requireAuth, unarchiveScouter); +router.post("/archive/uuid/:uuid", requireAuth, archiveScouter); + +router.put("/scoutername", requireAuth, updateScouterName); +router.delete("/scouterdashboard", requireAuth, deleteScouter); +router.get("/scouterspage", requireAuth, scoutingLeadProgressPage); +router.post("/scouterdashboard", requireAuth, addScouterDashboard); +router.get("/scouterreports", requireAuth, scouterScoutReports); + +export default router; diff --git a/src/routes/manager/scoutershifts.routes.ts b/src/routes/manager/scoutershifts.routes.ts new file mode 100644 index 00000000..75f7de09 --- /dev/null +++ b/src/routes/manager/scoutershifts.routes.ts @@ -0,0 +1,14 @@ +import { Router } from "express"; +import { requireAuth } from "../../lib/middleware/requireAuth.js"; +import { updateScouterShift } from "../../handler/manager/scoutershifts/updateScouterShift.js"; +import { deleteScouterShift } from "../../handler/manager/scoutershifts/deleteScouterShift.js"; + +const router = Router(); + +router.use(requireAuth); + +router.post("/:uuid", updateScouterShift); + +router.delete("/:uuid", deleteScouterShift); + +export default router; diff --git a/src/routes/manager/scoutreports.routes.ts b/src/routes/manager/scoutreports.routes.ts new file mode 100644 index 00000000..04a30867 --- /dev/null +++ b/src/routes/manager/scoutreports.routes.ts @@ -0,0 +1,17 @@ +import { Router } from "express"; +import { requireAuth } from "../../lib/middleware/requireAuth.js"; +import { addScoutReport } from "../../handler/manager/scoutreports/addScoutReport.js"; +import { deleteScoutReport } from "../../handler/manager/scoutreports/deleteScoutReport.js"; +import { getScoutReport } from "../../handler/manager/scoutreports/getScoutReport.js"; + +const router = Router(); + +router.post("/", addScoutReport); + +router.use(requireAuth); + +router.get("/:uuid", getScoutReport); + +router.delete("/:uuid", deleteScoutReport); + +export default router; diff --git a/src/routes/manager/settings.routes.ts b/src/routes/manager/settings.routes.ts new file mode 100644 index 00000000..a084d39b --- /dev/null +++ b/src/routes/manager/settings.routes.ts @@ -0,0 +1,33 @@ +import { Router } from "express"; +import { requireAuth } from "../../lib/middleware/requireAuth.js"; +import { updateSettings } from "../../handler/manager/settings/updateSettings.js"; +import rateLimit from "express-rate-limit"; +import { updateTeamEmail } from "../../handler/manager/settings/updateTeamEmail.js"; +import { getTeamSource } from "../../handler/manager/settings/getTeamSource.js"; +import { addTeamSource } from "../../handler/manager/settings/addTeamSource.js"; +import { getTournamentSource } from "../../handler/manager/settings/getTournamentSource.js"; +import { addTournamentSource } from "../../handler/manager/settings/addTournamentSource.js"; + +const updateTeamEmails = rateLimit({ + windowMs: 2 * 60 * 1000, + max: 3, + message: + "Too many email updates sent from this IP, please try again after 2 minutes", + validate: { trustProxy: false }, +}); + +const router = Router(); + +router.use(requireAuth); + +router.put("/", updateSettings); + +router.get("/teamsource", getTeamSource); +router.post("/teamsource", addTeamSource); + +router.get("/tournamentsource", getTournamentSource); +router.post("/tournamentsource", addTournamentSource); + +router.put("/teamemail", updateTeamEmails, updateTeamEmail); + +export default router; diff --git a/src/routes/manager/tournaments.routes.ts b/src/routes/manager/tournaments.routes.ts new file mode 100644 index 00000000..c747191f --- /dev/null +++ b/src/routes/manager/tournaments.routes.ts @@ -0,0 +1,28 @@ +import { Router } from "express"; +import { requireAuth } from "../../lib/middleware/requireAuth.js"; +import { getTeamsInTournament } from "../../handler/manager/tournament/getTeamsInTournament.js"; +import { getTeamRankings } from "../../handler/manager/tournament/getTeamRankings.js"; +import { addScouterShift } from "../../handler/manager/tournament/addScouterShift.js"; + +/* + +tournaments.routes.ts + +GET /manager/tournaments +GET /manager/tournament/:tournament/teams +GET /manager/tournament/:tournament/rankedTeams +GET /manager/tournament/:tournament/scoutershifts + +*/ + +const router = Router(); + +router.use(requireAuth); + +router.get("/:tournament/teams", getTeamsInTournament); + +router.get("/:tournament/rankedTeams", getTeamRankings); + +router.post("/:tournament/scoutershifts", addScouterShift); + +export default router; diff --git a/src/routes/slack/slack.routes.ts b/src/routes/slack/slack.routes.ts new file mode 100644 index 00000000..83fbfdbb --- /dev/null +++ b/src/routes/slack/slack.routes.ts @@ -0,0 +1,27 @@ +import { Router } from "express"; +import express from "express"; + +import { requireSlackToken } from "../../lib/middleware/requireSlackToken.js"; +import { addSlackWorkspace } from "../../handler/slack/addSlackWorkspace.js"; +import { processCommand } from "../../handler/slack/processCommands.js"; +import { processEvent } from "../../handler/slack/processEvents.js"; + +/* + +slack.routes.ts + +GET /slack/add-workspace +POST /slack/command +POST /slack/event + +*/ + +const router = Router(); +router.use(requireSlackToken); +router.get("/add-workspace", addSlackWorkspace); + +router.post("/command", express.urlencoded({ extended: true }), processCommand); + +router.post("/event", processEvent); + +export default router; diff --git a/src/server.ts b/src/server.ts new file mode 100644 index 00000000..39b68a80 --- /dev/null +++ b/src/server.ts @@ -0,0 +1,14 @@ +import { app } from "./app.js"; +import scheduleJobs from "./lib/scheduleJobs.js"; +import { migrateDataSources } from "./lib/migrateDataSources.js"; +import { clearCache } from "./lib/clearCache.js"; + +const port = process.env.PORT || 3000; + +await scheduleJobs(); +await migrateDataSources(); +await clearCache(); + +app.listen(port, () => { + console.log(`Server running on :${port}`); +});