From ea7d36e2aea347e757b7c0add7593dfb27bf4cc1 Mon Sep 17 00:00:00 2001 From: zkldi <20380519+zkldi@users.noreply.github.com> Date: Fri, 22 Apr 2022 21:13:26 +0100 Subject: [PATCH] BREAKING: make batch-manual classes take strings instead of ints --- server/package.json | 2 +- server/pnpm-lock.yaml | 8 +-- .../common/batch-manual/class-handler.ts | 70 +++++++++++++++++++ .../common/batch-manual/parser.ts | 19 +++-- 4 files changed, 89 insertions(+), 10 deletions(-) create mode 100644 server/src/lib/score-import/import-types/common/batch-manual/class-handler.ts diff --git a/server/package.json b/server/package.json index 15f42a519..e28a668e5 100644 --- a/server/package.json +++ b/server/package.json @@ -85,7 +85,7 @@ "rimraf": "3.0.2", "safe-json-stringify": "1.2.0", "seq-logging": "1.1.1", - "tachi-common": "0.9.3", + "tachi-common": "0.10.1", "ts-node": "10.4.0", "tsconfig-paths": "3.12.0", "typescript": "4.5.5", diff --git a/server/pnpm-lock.yaml b/server/pnpm-lock.yaml index a1193339c..8e95b2c24 100644 --- a/server/pnpm-lock.yaml +++ b/server/pnpm-lock.yaml @@ -65,7 +65,7 @@ specifiers: safe-json-stringify: 1.2.0 seq-logging: 1.1.1 supertest: 6.2.2 - tachi-common: 0.9.3 + tachi-common: 0.10.1 tap: 15.1.6 ts-node: 10.4.0 tsconfig-paths: 3.12.0 @@ -112,7 +112,7 @@ dependencies: rimraf: 3.0.2 safe-json-stringify: 1.2.0 seq-logging: 1.1.1 - tachi-common: 0.9.3 + tachi-common: 0.10.1 ts-node: 10.4.0_2615db9039ce432b4abf2fc39ef336ec tsconfig-paths: 3.12.0 typescript: 4.5.5 @@ -5364,8 +5364,8 @@ packages: engines: {node: '>= 0.4'} dev: true - /tachi-common/0.9.3: - resolution: {integrity: sha512-7wM+WAfdt0EJw5Bahu5puL0Am/5Nmop68maEyHwHZXTZDQoOqREYxv9+5+Co/wvdcApTZ2T3ctWl1UaPBQyhyQ==} + /tachi-common/0.10.1: + resolution: {integrity: sha512-FAKSQUokg6em9NIu+dYCk78XG1wBx8nF0yoiR5Cjpz21b8y20bkyEAsysSJRPYjKfSxMbFGZ3ghFNvq3BggTmQ==} dependencies: '@types/express-serve-static-core': 4.17.28 '@types/mongodb': 3.6.18 diff --git a/server/src/lib/score-import/import-types/common/batch-manual/class-handler.ts b/server/src/lib/score-import/import-types/common/batch-manual/class-handler.ts new file mode 100644 index 000000000..2b50364c8 --- /dev/null +++ b/server/src/lib/score-import/import-types/common/batch-manual/class-handler.ts @@ -0,0 +1,70 @@ +import ScoreImportFatalError from "lib/score-import/framework/score-importing/score-import-error"; +import { ClassHandler } from "lib/score-import/framework/user-game-stats/types"; +import { GamePTConfig, GetGamePTConfig, IDStrings } from "tachi-common"; +import { GameClasses, GameClassSets } from "tachi-common/js/game-classes"; + +// Note: This is tested by batch-manuals parser.test.ts. +export function CreateBatchManualClassHandler( + classes: Record +): ClassHandler { + return (game, playtype, userID, ratings, logger) => { + const gptConfig = GetGamePTConfig(game, playtype); + + const newObj: Partial> = {}; + + for (const [s, classID] of Object.entries(classes)) { + const set = s as GameClassSets[IDStrings]; + + const index = ClassIDToIndex(gptConfig, set, classID); + + if (index === null) { + logger.warn( + `User passed invalid class of ${classID} for set ${set}. Expected any of ${gptConfig.classHumanisedFormat[ + set + ] + .map((e) => e.id) + .join(", ")}` + ); + + throw new ScoreImportFatalError( + 400, + `Invalid class of ${classID} for set ${set}. Expected any of ${gptConfig.classHumanisedFormat[ + set + ] + .map((e) => e.id) + .join(", ")}` + ); + } + + newObj[set] = index; + } + + return newObj; + }; +} + +/** + * Given a gpt classes ID, return its index value. + * + * Returns null if the classID doesn't exist. + * @returns + */ +function ClassIDToIndex( + gptConfig: GamePTConfig, + classSet: GameClassSets[IDStrings], + classID: string +) { + const classes = gptConfig.classHumanisedFormat[classSet]; + + for (let i = 0; i < classes.length; i++) { + const classInfo = classes[i]; + + // Object.entries on an array returns [string, T], counterintuitively. + // Ah well. We'll just iterate over it like this. + if (classInfo.id === classID) { + return i; + } + } + + return null; +} 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 0850b442c..ffecb7ac8 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 @@ -1,5 +1,4 @@ import deepmerge from "deepmerge"; -import { IIDXDans, SDVXDans, WACCA_STAGEUPS } from "lib/constants/classes"; import { KtLogger } from "lib/logger/logger"; import { TachiConfig } from "lib/setup/config"; import p, { PrudenceSchema, ValidSchemaValue } from "prudence"; @@ -15,6 +14,7 @@ import { import { FormatPrError } from "utils/prudence"; import ScoreImportFatalError from "../../../framework/score-importing/score-import-error"; import { ParserFunctionReturns } from "../types"; +import { CreateBatchManualClassHandler } from "./class-handler"; import { BatchManualContext } from "./types"; const optNull = (v: ValidSchemaValue) => p.optional(p.nullable(v)); @@ -201,20 +201,27 @@ const PR_BatchManualScore = (game: Game, playtype: Playtypes[Game]): PrudenceSch }; }; +// both iidx sp and dp share dans. +const IIDXStringDans = GetGamePTConfig("iidx", "SP").classHumanisedFormat.dan.map((e) => e.id); +const SDVXStringDans = GetGamePTConfig("sdvx", "Single").classHumanisedFormat.dan.map((e) => e.id); +const WaccaStringStageUps = GetGamePTConfig("wacca", "Single").classHumanisedFormat.stageUp.map( + (e) => e.id +); + 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.isBoundedInteger(IIDXDans.KYU_7, IIDXDans.KAIDEN)), + dan: optNull(p.isIn(IIDXStringDans)), }; case "sdvx": return { - dan: optNull(p.isBoundedInteger(SDVXDans.DAN_1, SDVXDans.INF)), + dan: optNull(p.isIn(SDVXStringDans)), }; case "wacca": return { - stageUp: optNull(p.isBoundedInteger(WACCA_STAGEUPS.I, WACCA_STAGEUPS.XIV)), + stageUp: optNull(p.isIn(WaccaStringStageUps)), }; default: return {}; @@ -321,6 +328,8 @@ export function ParseBatchManualFromObject( iterable: batchManual.scores, // if classes are provided, use those as a class handler. Otherwise, we // don't care. - classHandler: batchManual.classes ? () => batchManual.classes! : null, + classHandler: batchManual.classes + ? CreateBatchManualClassHandler(batchManual.classes!) + : null, }; }