Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 2 additions & 48 deletions apps/scouting/backend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,55 +21,9 @@ const app = express();
const defaultPort = 4590;
const port = process.env.BACKEND_PORT ?? defaultPort;

app.use(express.json());
app.use("/api/v1", apiRouter);

app.listen(port, () => {
console.log(`Production server running at http://localhost:${port}`);
});

const coralCounter: GameEventsCounter<CoralEvent> = {
L1: 0,
L2: 0,
L3: 0,
L4: 0,
};

const algaeCounter: GameEventsCounter<AlgaeEvent> = {
Processor: 0,
Net: 0,
};

const coral: GameObject<CoralEvent> = {
name: "coral",
gameEvents: coralCounter,
};

const algae: GameObject<AlgaeEvent> = {
name: "algae",
gameEvents: algaeCounter,
};

const scoringCalculator: ScoringCalculator<AllPossibleGameEvents> = {
gameObjectsScoringData: [],
};

addGameEvent(coral, "L1");
addGameEvent(coral, "L2");
addGameEvent(algae, "Net");

const coralWithPoints: GameObjectWithPoints<CoralEvent> = {
gameObject: coral,
calculatePoints: calculatePointsCoral,
calculateRP: calculateRPCoral,
};

const algaeWithPoints: GameObjectWithPoints<AlgaeEvent> = {
gameObject: algae,
calculatePoints: calculatePointsAlgae,
calculateRP: calculateRPAlgae,
};

addScoring(scoringCalculator, coralWithPoints);
addScoring(scoringCalculator, algaeWithPoints);

console.log(scoringCalculator);
});
20 changes: 20 additions & 0 deletions apps/scouting/backend/src/middleware/verification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// בס"ד
import type { RequestHandler } from "express";
import { isLeft } from "fp-ts/lib/Either";
import { StatusCodes } from "http-status-codes";
import { PathReporter } from "io-ts/lib/PathReporter";
import type { Props, TypeC } from "io-ts";

export const verifyBody =
<U extends Props>(typeToCheck: TypeC<U>): RequestHandler =>
(req, res, next): void => {
const result = typeToCheck.decode(req.body);

if (isLeft(result)) {
res
.status(StatusCodes.NOT_ACCEPTABLE)
.json({ errors: PathReporter.report(result) });
} else {
next();
}
};
4 changes: 3 additions & 1 deletion apps/scouting/backend/src/routes/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// בס"ד
import { Router } from "express";
import { StatusCodes } from "http-status-codes";
import { tbaRouter } from "./tba";

export const apiRouter = Router();

apiRouter.use("/tba", tbaRouter);
apiRouter.get("/health", (req, res) => {
res.status(StatusCodes.OK).send({ message: "Healthy!" });
});
});
43 changes: 43 additions & 0 deletions apps/scouting/backend/src/routes/tba.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// בס"ד
import axios, { type AxiosRequestConfig } from "axios";
import { Router } from "express";
import { verifyBody } from "../middleware/verification";
import {
type TBAMatch,
type TBAMatchesProps,
matchesProps,
} from "../../../common/types/TBAMatch";
import { StatusCodes } from "http-status-codes";
import type { ScoreBreakdown2025 } from "../../../common/types/ScoreBreakdown2025";
import type { BodiedRequest } from "../../../common/types/Express";

export const tbaRouter = Router();

const TBA_KEY = process.env.TBA_API_KEY ?? "yourtbakey";

const fetchTba = async <T>(
route: string,
config?: AxiosRequestConfig
): Promise<T> => {
return axios
.get(`https://www.thebluealliance.com/api/v3${route}`, {
headers: { "X-TBA-Auth-Key": TBA_KEY },
...config,
})
.then((value) => value.data as T);

Check warning

Code scanning / ESLint

Disallow type assertions that narrow a type Warning

Unsafe assertion from any detected: consider using type guards or a safer assertion.
};

tbaRouter.post(
"/matches",
verifyBody(matchesProps),
(req: BodiedRequest<TBAMatchesProps>, res) => {
fetchTba<TBAMatch<ScoreBreakdown2025>>(`/event/${req.body.event}/matches`)
.then((value) => {
console.log(value);
res.status(StatusCodes.OK).json({ value });
})
.catch((error: unknown) => {
console.error(error);
});
}
);
7 changes: 7 additions & 0 deletions apps/scouting/common/types/Express.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// בס"ד

import type { Request } from "express";

export interface BodiedRequest<Body> extends Request {
body: Body;
}
57 changes: 57 additions & 0 deletions apps/scouting/common/types/ScoreBreakdown2025.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// בס"ד

type YesNo = "Yes" | "No";

type Climb = "Park" | "DeepCage" | "ShallowCage" | "None";

interface ReefRow {
nodeA: boolean;
nodeB: boolean;
nodeC: boolean;
nodeD: boolean;
nodeE: boolean;
}
interface Reef {
botRow: ReefRow;
midRow: ReefRow;
tba_botRowCount: number;
tba_midRowCount: number;
tba_topRowCount: number;
topRow: ReefRow;
trough: number;
}
export interface ScoreBreakdown2025 {
adjustPoints: number;
algaePoints: number;
autoBonusAchieved: boolean;
autoCoralCount: number;
autoCoralPoints: number;
autoLineRobot1: YesNo;
autoLineRobot2: YesNo;
autoLineRobot3: YesNo;
autoMobilityPoints: number;
autoPoints: number;
autoReef: Reef;
bargeBonusAchieved: boolean;
coopertitionCriteriaMet: boolean;
coralBonusAchieved: boolean;
endGameBargePoints: number;
endGameRobot1: Climb;
endGameRobot2: Climb;
endGameRobot3: Climb;
foulCount: number;
foulPoints: number;
g206Penalty: boolean;
g410Penalty: boolean;
g418Penalty: boolean;
g428Penalty: boolean;
netAlgaeCount: number;
rp: number;
techFoulCount: number;
teleopCoralCount: number;
teleopCoralPoints: number;
teleopPoints: number;
teleopReef: Reef;
totalPoints: number;
wallAlgaeCount: number;
}
46 changes: 46 additions & 0 deletions apps/scouting/common/types/TBAMatch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// בס"ד
import * as t from "io-ts";
import type { AtMost } from "./Utils";

export const matchesProps = t.type({
event: t.string,
});

export type TBAMatchesProps = t.TypeOf<typeof matchesProps>;

// eslint-disable-next-line @typescript-eslint/no-unused-vars
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cheater!!!!

const maxTeamsInAlliance = 3;
type TeamKeys = AtMost<string, typeof maxTeamsInAlliance>;

export interface TBAAlliance {
score: number;
team_keys: TeamKeys;
surrogate_team_keys: TeamKeys;
dq_team_keys: TeamKeys;
}


export interface TBAMatch<AllianceBreakdown, MiscBreakdown = {}> {
key: "string";
comp_level: "qm";
set_number: number;
match_number: number;
alliances: {
red: TBAAlliance;
blue: TBAAlliance;
};
winning_alliance: "red" | "blue" | ""; // "" is a tie
event_key: string;
time: number;
actual_time: number;
predicted_time: number;
post_result_time: number;
score_breakdown: {
red: AllianceBreakdown;
blue: AllianceBreakdown;
} & MiscBreakdown;
videos: {
type: string;
key: string;
}[];
}
13 changes: 13 additions & 0 deletions apps/scouting/common/types/Utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// בס"ד


type AtMostUnion<T extends unknown[]> =
T extends [infer _, ...infer Rest]
? T | AtMostUnion<Rest>
: [];


export type AtMost<T, N extends number, Result extends unknown[] = []> =
Result['length'] extends N
? Result | AtMostUnion<Result>
: AtMost<T, N, [T, ...Result]>;
7 changes: 6 additions & 1 deletion apps/scouting/frontend/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import tailwindcss from "@tailwindcss/vite";

// https://vite.dev/config/
export default defineConfig({
server: { port: 80 },
server: { port: 80, proxy: {
'/api/v1': {
target: "http://localhost:4590",
changeOrigin: true,
}
} },
plugins: [
react({
babel: {
Expand Down
13 changes: 12 additions & 1 deletion eslint.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,18 @@ export default defineConfig([
"no-unused-expressions": "off",
"@typescript-eslint/no-unused-expressions": "warn",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "warn",
"@typescript-eslint/no-unused-vars": [
"warn",
{
args: "all",
argsIgnorePattern: "^_",
caughtErrors: "all",
caughtErrorsIgnorePattern: "^_",
destructuredArrayIgnorePattern: "^_",
varsIgnorePattern: "^_",
ignoreRestSiblings: true,
},
],
"no-use-before-define": "off",
"@typescript-eslint/no-use-before-define": "error",
"no-useless-constructor": "off",
Expand Down
Loading
Loading