diff --git a/server/src/lib/constants/classes.ts b/server/src/lib/constants/classes.ts index e72b2d500..144e49f70 100644 --- a/server/src/lib/constants/classes.ts +++ b/server/src/lib/constants/classes.ts @@ -189,6 +189,23 @@ export enum CHUNITHM_COLOURS { RAINBOW, } +export enum WACCA_STAGEUPS { + I, + II, + III, + IV, + V, + VI, + VII, + VIII, + IX, + X, + XI, + XII, + XIII, + XIV, +} + export enum WACCA_COLOURS { ASH, NAVY, diff --git a/server/src/lib/score-import/import-types/common/batch-manual/parser.test.ts b/server/src/lib/score-import/import-types/common/batch-manual/parser.test.ts index d9634bb59..a977b8da5 100644 --- a/server/src/lib/score-import/import-types/common/batch-manual/parser.test.ts +++ b/server/src/lib/score-import/import-types/common/batch-manual/parser.test.ts @@ -3,6 +3,7 @@ import CreateLogCtx from "lib/logger/logger"; import { BatchManual } from "tachi-common"; import t from "tap"; import { EscapeStringRegexp } from "utils/misc"; +import { IIDXDans, WACCA_STAGEUPS } from "lib/constants/classes"; import ScoreImportFatalError from "../../../framework/score-importing/score-import-error"; import { ParseBatchManualFromObject as ParserFn } from "./parser"; @@ -324,6 +325,27 @@ t.test("#ParserFn", (t) => { t.end(); }); + t.test("With class", (t) => { + const res = ParserFn( + { + meta: baseBatchManual.meta, + scores: [baseBatchManualScore], + classes: { dan: 18 }, + } as BatchManual, + "file/batch-manual", + logger + ); + + t.not(res.classHandler, null); + + t.same( + res.classHandler!("iidx", "SP", 1, {}, logger), + { dan: IIDXDans.KAIDEN }, + ); + + t.end(); + }); + t.end(); }); @@ -482,6 +504,36 @@ t.test("#ParserFn", (t) => { t.end(); }); + t.test("Invalid class", (t) => { + // Out of bounds. (18 is kaiden) + const fn = () => ParserFn( + { + meta: baseBatchManual.meta, + scores: [baseBatchManualScore], + classes: { dan: 19 }, + } as BatchManual, + "file/batch-manual", + logger + ); + + t.throws(fn, mockErr("classes.dan | Expected a number between 0 and 18. | Received 19 [number]")); + + // Wrong game. + const fn2 = () => ParserFn( + { + meta: baseBatchManual.meta, + scores: [baseBatchManualScore], + classes: { stageUp: 9 }, + } as BatchManual, + "file/batch-manual", + logger + ); + + t.throws(fn2, mockErr("classes | Unexpected properties inside object: stageUp")); + + t.end(); + }); + t.end(); }); diff --git a/server/src/lib/score-import/import-types/common/batch-manual/parser.ts b/server/src/lib/score-import/import-types/common/batch-manual/parser.ts index 70c551c88..908cd98ae 100644 --- a/server/src/lib/score-import/import-types/common/batch-manual/parser.ts +++ b/server/src/lib/score-import/import-types/common/batch-manual/parser.ts @@ -12,7 +12,13 @@ import { Playtypes, } from "tachi-common"; import { FormatPrError } from "utils/prudence"; +import { + IIDXDans, + SDVXDans, + WACCA_STAGEUPS, +} from "lib/constants/classes"; import ScoreImportFatalError from "../../../framework/score-importing/score-import-error"; +import { ScoreClasses } from "../../../framework/user-game-stats/types"; import { ParserFunctionReturns } from "../types"; import { BatchManualContext } from "./types"; @@ -200,6 +206,26 @@ const PR_BatchManualScore = (game: Game, playtype: Playtypes[Game]): PrudenceSch }; }; +const PR_BatchManualClasses = (game: Game): PrudenceSchema => { + switch (game) { + // This can be implemented for any non-static class (i.e. dans). + case "iidx": + return { + dan: optNull(p.isBetween(IIDXDans.KYU_7, IIDXDans.KAIDEN)) + }; + case "sdvx": + return { + dan: optNull(p.isBetween(SDVXDans.DAN_1, SDVXDans.INF)) + }; + case "wacca": + return { + stageUp: optNull(p.isBetween(WACCA_STAGEUPS.I, WACCA_STAGEUPS.XIV)) + }; + default: + return {}; + } +}; + const PR_BatchManual = (game: Game, playtype: Playtypes[Game]): PrudenceSchema => ({ meta: { service: p.isBoundedString(3, 15), @@ -208,6 +234,7 @@ const PR_BatchManual = (game: Game, playtype: Playtypes[Game]): PrudenceSchema = version: "*?string", }, scores: [PR_BatchManualScore(game, playtype)], + classes: optNull(PR_BatchManualClasses(game)), }); /** @@ -286,7 +313,7 @@ export function ParseBatchManualFromObject( throw new ScoreImportFatalError(400, FormatPrError(err, "Invalid BATCH-MANUAL")); } - const batchManual = object as BatchManual; + const batchManual = object as BatchManual & {classes: ScoreClasses}; return { game, @@ -297,6 +324,6 @@ export function ParseBatchManualFromObject( version: batchManual.meta.version ?? null, }, iterable: batchManual.scores, - classHandler: null, + classHandler: (..._) => batchManual.classes, }; }