rename all instances of ktchi to tachi and change how config works

This commit is contained in:
zkldi
2021-06-08 14:21:09 +01:00
parent 2f943115c0
commit 9602877baf
49 changed files with 317 additions and 254 deletions
+3
View File
@@ -9,6 +9,9 @@ coverage
.setup_env
failed-tests.txt
# config files
conf.json5
scripts/arc-db-sync/charts.json
scripts/arc-db-sync/songs.json
scripts/validate-database-errs/*
+4 -4
View File
@@ -1,6 +1,6 @@
import { Session, SessionData } from "express-session";
import { SYMBOL_KtchiData } from "../../src/lib/constants/ktchi";
import { KtchiRequestData, KtchiSessionData } from "../../src/utils/types";
import { SYMBOL_TachiData } from "../../src/lib/constants/tachi";
import { TachiRequestData, TachiSessionData } from "../../src/utils/types";
export {};
@@ -8,7 +8,7 @@ export {};
declare module "express-session" {
// Inject additional properties on express-session
interface SessionData {
ktchi: KtchiSessionData;
tachi: TachiSessionData;
}
}
@@ -17,7 +17,7 @@ declare global {
interface Request {
session: Session & Partial<SessionData>;
[SYMBOL_KtchiData]?: Partial<KtchiRequestData>;
[SYMBOL_TachiData]?: Partial<TachiRequestData>;
}
}
}
+2 -1
View File
@@ -54,7 +54,7 @@
"express-session": "^1.17.2",
"fast-json-stable-hash": "^1.0.2",
"fast-xml-parser": "^3.19.0",
"tachi-common": "github:zkldi/tachi-common",
"json5": "^2.2.0",
"mkdirp": "^1.0.4",
"mongodb": "3.6.3",
"monk": "^7.3.4",
@@ -63,6 +63,7 @@
"prudence": "^0.9.6",
"redis": "^3.1.2",
"rimraf": "^3.0.2",
"tachi-common": "github:zkldi/tachi-common",
"typescript": "^4.3.2",
"winston": "^3.3.3"
},
+2 -1
View File
@@ -33,6 +33,7 @@ specifiers:
express-session: ^1.17.2
fast-json-stable-hash: ^1.0.2
fast-xml-parser: ^3.19.0
json5: ^2.2.0
mkdirp: ^1.0.4
mongodb: 3.6.3
monk: ^7.3.4
@@ -64,6 +65,7 @@ dependencies:
express-session: 1.17.2
fast-json-stable-hash: 1.0.2
fast-xml-parser: 3.19.0
json5: 2.2.0
mkdirp: 1.0.4
mongodb: 3.6.3
monk: 7.3.4
@@ -2561,7 +2563,6 @@ packages:
hasBin: true
dependencies:
minimist: 1.2.5
dev: true
/jsprim/1.4.1:
resolution: {integrity: sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=}
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { TierlistParent, Game } from "tachi-common";
import { gameHuman, validPlaytypes } from "tachi-common/js/config";
import db from "../../src/db/db";
import db from "../../src/external/mongo/db";
import MigrateRecords from "./migrate";
function ConvertFn(c: any): TierlistParent {
+3 -3
View File
@@ -39,7 +39,7 @@ async function MergeIDs() {
}
// eslint-disable-next-line no-await-in-loop
const ktchiChart = await FindChartWithPTDFVersion(
const tachiChart = await FindChartWithPTDFVersion(
"iidx",
song.id,
playtype,
@@ -47,7 +47,7 @@ async function MergeIDs() {
version
);
if (!ktchiChart) {
if (!tachiChart) {
logger.error(
`Could not find chart ${songTitle} ${playtype} ${difficulty} ${version}.`
);
@@ -59,7 +59,7 @@ async function MergeIDs() {
db.charts.iidx as unknown as ICollection<ChartDocument<"iidx:SP" | "iidx:DP">>
).update(
{
_id: ktchiChart._id,
_id: tachiChart._id,
},
{
$set: {
+9 -9
View File
@@ -60,24 +60,24 @@ async function UpdatePoyashiData() {
const [playtype, diff] = res;
const ktchiSong = await FindSongOnTitle("iidx", d.title);
const tachiSong = await FindSongOnTitle("iidx", d.title);
if (!ktchiSong) {
if (!tachiSong) {
logger.warn(`Cannot find song ${d.title}?`);
continue;
}
const ktchiChart = (await FindChartWithPTDFVersion(
const tachiChart = (await FindChartWithPTDFVersion(
"iidx",
ktchiSong.id,
tachiSong.id,
playtype as "SP" | "DP",
diff as Difficulties["iidx:DP" | "iidx:SP"],
"28"
)) as ChartDocument<"iidx:SP" | "iidx:DP">;
if (!ktchiChart) {
if (!tachiChart) {
logger.warn(
`Cannot find chart ${ktchiSong.title} (${ktchiSong.id}) ${playtype}, ${diff}?`
`Cannot find chart ${tachiSong.title} (${tachiSong.id}) ${playtype}, ${diff}?`
);
continue;
}
@@ -86,21 +86,21 @@ async function UpdatePoyashiData() {
if (kavg < 0) {
logger.warn(
`${ktchiSong.title} (${playtype} ${diff}). Invalid kavg ${d.avg}, Skipping.`
`${tachiSong.title} (${playtype} ${diff}). Invalid kavg ${d.avg}, Skipping.`
);
continue;
}
const kesd = ESDCore.CalculateESD(
config.judgementWindows.iidx.SP,
kavg / (ktchiChart.data.notecount * 2)
kavg / (tachiChart.data.notecount * 2)
);
realData.push({
coef: d.coef === -1 ? null : d.coef,
kavg: Number(d.avg),
wr: Number(d.wr),
chartID: ktchiChart.chartID,
chartID: tachiChart.chartID,
kesd,
});
}
+2 -2
View File
@@ -26,7 +26,7 @@ import {
BMSCourseDocument,
} from "tachi-common";
import monk from "monk";
import { MONGO_BASE_URL } from "../../lib/env/env";
import { MONGO_BASE_URL } from "../../lib/setup/config";
import CreateLogCtx from "../../lib/logger/logger";
import { OrphanScoreDocument } from "../../lib/score-import/import-types/common/types";
@@ -39,7 +39,7 @@ let dbName = "ktblackdb";
/* istanbul ignore next */
if (process.env.NODE_ENV === "test") {
if (process.env.KTBSV_PARALLEL_TESTS) {
if (process.env.TACHI_PARALLEL_TESTS) {
dbName = `test-ephemeral-${process.pid}`;
} else {
dbName = `testingdb`;
+1 -1
View File
@@ -1,6 +1,6 @@
import fs from "fs";
import path from "path";
import { KTCDN_ROOT } from "../env/env";
import { KTCDN_ROOT } from "../setup/config";
import CreateLogCtx from "../logger/logger";
import { promisify } from "util";
import mkdirp from "mkdirp";
-1
View File
@@ -1 +0,0 @@
export const SYMBOL_KtchiData = Symbol("ktchi-request-patch");
+1
View File
@@ -0,0 +1 @@
export const SYMBOL_TachiData = Symbol("tachi-request-patch");
-32
View File
@@ -1,32 +0,0 @@
// barrel file for re-exporting env variables.
import dotenv from "dotenv";
dotenv.config();
const envVars = [
"KTBSV_MONGO_BASE_URL",
"KTBSV_LOG_LEVEL",
"KTBSV_CAPTCHA_SECRET_KEY",
"KTBSV_SESSION_SECRET",
"KTBSV_FLO_API_URL",
"KTBSV_EAG_API_URL",
"KTBSV_ARC_API_URL",
"KTBSV_ARC_AUTH_TOKEN",
"KTCDN_ROOT",
];
for (const eVar of envVars) {
/* istanbul ignore next */
if (!process.env[eVar]) {
throw new Error(`${eVar} was not defined.`);
}
}
export const MONGO_BASE_URL = process.env.KTBSV_MONGO_BASE_URL!;
export const LOG_LEVEL = process.env.KTBSV_LOG_LEVEL!;
export const SESSION_SECRET = process.env.KTBSV_SESSION_SECRET!;
export const CAPTCHA_SECRET_KEY = process.env.KTBSV_CAPTCHA_SECRET_KEY!;
export const FLO_API_URL = process.env.KTBSV_FLO_API_URL!;
export const EAG_API_URL = process.env.KTBSV_EAG_API_URL!;
export const ARC_API_URL = process.env.KTBSV_ARC_API_URL!;
export const ARC_AUTH_TOKEN = process.env.KTBSV_ARC_AUTH_TOKEN!;
export const KTCDN_ROOT = process.env.KTCDN_ROOT!;
@@ -13,8 +13,9 @@ export class ConverterFailure {
}
/**
* SkipScoreFailure - This score could not be processed because Kamaitachi does not
* SkipScoreFailure - This score could not be processed because we do not
* support it. This is not an error, but is not a success either.
* An example scenario would be something like a 5KEY score being imported from SSS.
*/
export class SkipScoreFailure extends ConverterFailure {}
@@ -43,7 +44,7 @@ export class KTDataNotFoundFailure<T extends ImportTypes> extends ConverterFailu
}
/**
* InvalidScoreError - This score provided invalid data that Kamaitachi
* InvalidScoreError - This score provided invalid data that we
* can not accept.
*/
export class InvalidScoreFailure extends ConverterFailure {}
@@ -3,7 +3,7 @@ import nodeFetch from "../../../../../utils/fetch";
import { TraverseKaiAPI } from "../../common/api-kai/traverse-api";
import { ParserFunctionReturnsAsync } from "../../common/types";
import { EmptyObject } from "../../../../../utils/types";
import { ARC_API_URL, ARC_AUTH_TOKEN } from "../../../../env/env";
import { ARC_API_URL, ARC_AUTH_TOKEN } from "../../../../setup/config";
export function ParseArcDDR(
arcProfileID: string,
@@ -1,7 +1,7 @@
import nodeFetch from "../../../../../utils/fetch";
import { HasOwnProperty } from "../../../../../utils/misc";
import { IIDXClasses } from "../../../../constants/classes";
import { ARC_API_URL } from "../../../../env/env";
import { ARC_API_URL } from "../../../../setup/config";
import { ClassHandler } from "../../../framework/user-game-stats/types";
export async function CreateArcIIDXClassHandler(
@@ -3,7 +3,7 @@ import nodeFetch from "../../../../../utils/fetch";
import { TraverseKaiAPI } from "../../common/api-kai/traverse-api";
import { ParserFunctionReturnsAsync } from "../../common/types";
import { EmptyObject } from "../../../../../utils/types";
import { ARC_API_URL, ARC_AUTH_TOKEN } from "../../../../env/env";
import { ARC_API_URL, ARC_AUTH_TOKEN } from "../../../../setup/config";
import { CreateArcIIDXClassHandler } from "./class-handler";
export async function ParseArcIIDX(
@@ -3,7 +3,7 @@ import nodeFetch from "../../../../../utils/fetch";
import { TraverseKaiAPI } from "../../common/api-kai/traverse-api";
import { ParserFunctionReturnsAsync } from "../../common/types";
import { EmptyObject } from "../../../../../utils/types";
import { ARC_API_URL, ARC_AUTH_TOKEN } from "../../../../env/env";
import { ARC_API_URL, ARC_AUTH_TOKEN } from "../../../../setup/config";
export function ParseArcSDVX(
arcProfileID: string,
@@ -4,7 +4,7 @@ import { KaiAuthDocument } from "tachi-common";
import { KaiContext } from "../types";
import { TraverseKaiAPI } from "../traverse-api";
import { ParserFunctionReturnsAsync } from "../../types";
import { FLO_API_URL, EAG_API_URL } from "../../../../../env/env";
import { FLO_API_URL, EAG_API_URL } from "../../../../../setup/config";
export function ParseKaiIIDX(
service: "FLO" | "EAG",
@@ -4,7 +4,7 @@ import { KaiAuthDocument } from "tachi-common";
import { KaiContext } from "../types";
import { TraverseKaiAPI } from "../traverse-api";
import { ParserFunctionReturnsAsync } from "../../types";
import { EAG_API_URL, FLO_API_URL } from "../../../../../env/env";
import { EAG_API_URL, FLO_API_URL } from "../../../../../setup/config";
export function ParseKaiSDVX(
service: "FLO" | "EAG",
@@ -57,9 +57,9 @@ const ConvertEamIIDXCSV: ConverterFunction<IIDXEamusementCSVData, IIDXEamusement
// @optimisable - This is actually a multi-fetch. Since eam-csv scores
// are batched up into (song, chart1, chart2, chart3 ...) rows
// we actually already have fetched this song a second ago.
const ktchiSong = await FindSongOnTitle("iidx", data.title);
const tachiSong = await FindSongOnTitle("iidx", data.title);
if (!ktchiSong) {
if (!tachiSong) {
throw new KTDataNotFoundFailure(
`Could not find song for ${data.title}.`,
importType,
@@ -68,21 +68,21 @@ const ConvertEamIIDXCSV: ConverterFunction<IIDXEamusementCSVData, IIDXEamusement
);
}
const HUMANISED_CHART_TITLE = `${ktchiSong.title} (${context.playtype} ${eamScore.difficulty} [v${context.importVersion}])`;
const HUMANISED_CHART_TITLE = `${tachiSong.title} (${context.playtype} ${eamScore.difficulty} [v${context.importVersion}])`;
if (isLegacyLeggendaria) {
eamScore.difficulty = "LEGGENDARIA";
}
const ktchiChart = (await FindChartWithPTDFVersion(
const tachiChart = (await FindChartWithPTDFVersion(
"iidx",
ktchiSong.id,
tachiSong.id,
context.playtype,
eamScore.difficulty,
context.importVersion
)) as ChartDocument<"iidx:SP" | "iidx:DP">;
if (!ktchiChart) {
if (!tachiChart) {
throw new KTDataNotFoundFailure(
`Could not find chart for ${HUMANISED_CHART_TITLE}`,
"file/eamusement-iidx-csv",
@@ -96,7 +96,7 @@ const ConvertEamIIDXCSV: ConverterFunction<IIDXEamusementCSVData, IIDXEamusement
`${HUMANISED_CHART_TITLE} - Invalid EX score of ${eamScore.exscore}`
);
const MAX_EX = ktchiChart.data.notecount * 2;
const MAX_EX = tachiChart.data.notecount * 2;
if (exscore > MAX_EX) {
throw new InvalidScoreFailure(
@@ -129,7 +129,7 @@ const ConvertEamIIDXCSV: ConverterFunction<IIDXEamusementCSVData, IIDXEamusement
);
}
const { percent, grade } = GenericGetGradeAndPercent("iidx", exscore, ktchiChart);
const { percent, grade } = GenericGetGradeAndPercent("iidx", exscore, tachiChart);
const timestamp = ParseDateFromString(data.timestamp);
@@ -171,8 +171,8 @@ const ConvertEamIIDXCSV: ConverterFunction<IIDXEamusementCSVData, IIDXEamusement
logger.info(`Skipped assigning BP for score. Had unexpected value of ${eamScore.bp}.`);
}
// ts thinks ktchiSong might be null. It's not, though!
return { chart: ktchiChart, dryScore, song: ktchiSong };
// ts thinks tachiSong might be null. It's not, though!
return { chart: tachiChart, dryScore, song: tachiSong };
};
export default ConvertEamIIDXCSV;
@@ -7,10 +7,10 @@ import { InternalFailure } from "../../../framework/common/converter-failures";
import {
ConverterIRFervidex,
SplitFervidexChartRef,
KtchifyAssist,
KtchifyGauge,
KtchifyRandom,
KtchifyRange,
TachifyAssist,
TachifyGauge,
TachifyRandom,
TachifyRange,
} from "./converter";
import { FervidexScore } from "./types";
import deepmerge from "deepmerge";
@@ -37,47 +37,47 @@ t.test("#SplitFervidexChartRef", (t) => {
t.end();
});
t.test("#KtchifyAssist", (t) => {
t.equal(KtchifyAssist("ASCR_LEGACY"), "FULL ASSIST");
t.equal(KtchifyAssist("AUTO_SCRATCH"), "AUTO SCRATCH");
t.equal(KtchifyAssist("FULL_ASSIST"), "FULL ASSIST");
t.equal(KtchifyAssist("LEGACY_NOTE"), "LEGACY NOTE");
t.equal(KtchifyAssist(null), "NO ASSIST");
t.equal(KtchifyAssist(undefined), "NO ASSIST");
t.test("#TachifyAssist", (t) => {
t.equal(TachifyAssist("ASCR_LEGACY"), "FULL ASSIST");
t.equal(TachifyAssist("AUTO_SCRATCH"), "AUTO SCRATCH");
t.equal(TachifyAssist("FULL_ASSIST"), "FULL ASSIST");
t.equal(TachifyAssist("LEGACY_NOTE"), "LEGACY NOTE");
t.equal(TachifyAssist(null), "NO ASSIST");
t.equal(TachifyAssist(undefined), "NO ASSIST");
t.end();
});
t.test("#KtchifyGauge", (t) => {
t.equal(KtchifyGauge("ASSISTED_EASY"), "ASSISTED EASY");
t.equal(KtchifyGauge("EASY"), "EASY");
t.equal(KtchifyGauge("HARD"), "HARD");
t.equal(KtchifyGauge("EX_HARD"), "EX HARD");
t.equal(KtchifyGauge(null), "NORMAL");
t.equal(KtchifyGauge(undefined), "NORMAL");
t.test("#TachifyGauge", (t) => {
t.equal(TachifyGauge("ASSISTED_EASY"), "ASSISTED EASY");
t.equal(TachifyGauge("EASY"), "EASY");
t.equal(TachifyGauge("HARD"), "HARD");
t.equal(TachifyGauge("EX_HARD"), "EX HARD");
t.equal(TachifyGauge(null), "NORMAL");
t.equal(TachifyGauge(undefined), "NORMAL");
t.end();
});
t.test("#KtchifyRange", (t) => {
t.equal(KtchifyRange("HIDDEN_PLUS"), "HIDDEN+");
t.equal(KtchifyRange("LIFT"), "LIFT");
t.equal(KtchifyRange("LIFT_SUD_PLUS"), "LIFT SUD+");
t.equal(KtchifyRange("SUDDEN_PLUS"), "SUDDEN+");
t.equal(KtchifyRange("SUD_PLUS_HID_PLUS"), "SUD+ HID+");
t.equal(KtchifyRange(null), "NONE");
t.equal(KtchifyRange(undefined), "NONE");
t.test("#TachifyRange", (t) => {
t.equal(TachifyRange("HIDDEN_PLUS"), "HIDDEN+");
t.equal(TachifyRange("LIFT"), "LIFT");
t.equal(TachifyRange("LIFT_SUD_PLUS"), "LIFT SUD+");
t.equal(TachifyRange("SUDDEN_PLUS"), "SUDDEN+");
t.equal(TachifyRange("SUD_PLUS_HID_PLUS"), "SUD+ HID+");
t.equal(TachifyRange(null), "NONE");
t.equal(TachifyRange(undefined), "NONE");
t.end();
});
t.test("#KtchifyRandom", (t) => {
t.equal(KtchifyRandom("MIRROR"), "MIRROR");
t.equal(KtchifyRandom("R_RANDOM"), "R-RANDOM");
t.equal(KtchifyRandom("S_RANDOM"), "S-RANDOM");
t.equal(KtchifyRandom("RANDOM"), "RANDOM");
t.equal(KtchifyRandom(null), "NONRAN");
t.equal(KtchifyRandom(undefined), "NONRAN");
t.test("#TachifyRandom", (t) => {
t.equal(TachifyRandom("MIRROR"), "MIRROR");
t.equal(TachifyRandom("R_RANDOM"), "R-RANDOM");
t.equal(TachifyRandom("S_RANDOM"), "S-RANDOM");
t.equal(TachifyRandom("RANDOM"), "RANDOM");
t.equal(TachifyRandom(null), "NONRAN");
t.equal(TachifyRandom(undefined), "NONRAN");
t.end();
});
@@ -25,7 +25,7 @@ export const FERVIDEX_LAMP_LOOKUP = {
7: "FULL COMBO",
};
export function KtchifyAssist(
export function TachifyAssist(
assist: FervidexScore["option"]["assist"]
): DryScore<"iidx:SP" | "iidx:DP">["scoreMeta"]["assist"] {
switch (assist) {
@@ -43,7 +43,7 @@ export function KtchifyAssist(
}
}
export function KtchifyGauge(
export function TachifyGauge(
gauge: FervidexScore["option"]["gauge"]
): DryScore<"iidx:SP" | "iidx:DP">["scoreMeta"]["gauge"] {
switch (gauge) {
@@ -61,7 +61,7 @@ export function KtchifyGauge(
}
}
export function KtchifyRange(
export function TachifyRange(
gauge: FervidexScore["option"]["range"]
): DryScore<"iidx:SP" | "iidx:DP">["scoreMeta"]["range"] {
switch (gauge) {
@@ -81,7 +81,7 @@ export function KtchifyRange(
}
}
export function KtchifyRandom(
export function TachifyRandom(
gauge: FervidexScore["option"]["style"]
): DryScore<"iidx:SP" | "iidx:DP">["scoreMeta"]["random"] {
switch (gauge) {
@@ -209,10 +209,10 @@ export const ConverterIRFervidex: ConverterFunction<FervidexScore, FervidexConte
},
},
scoreMeta: {
assist: KtchifyAssist(data.option.assist),
gauge: KtchifyGauge(data.option.gauge),
random: KtchifyRandom(data.option.style),
range: KtchifyRange(data.option.range),
assist: TachifyAssist(data.option.assist),
gauge: TachifyGauge(data.option.gauge),
random: TachifyRandom(data.option.style),
range: TachifyRange(data.option.range),
},
};
+89
View File
@@ -0,0 +1,89 @@
// barrel file for re-exporting env variables.
import dotenv from "dotenv";
import JSON5 from "json5";
import fs from "fs";
import p from "prudence";
import { FormatPrError } from "../../utils/prudence";
import { integer } from "tachi-common";
dotenv.config(); // imports things like NODE_ENV from a local .env file if one is present.
// reads from $pwd/conf.json5
const confFile = fs.readFileSync("./conf.json5", "utf-8");
const config = JSON5.parse(confFile);
function isValidURL(self: unknown) {
if (typeof self !== "string") {
return `Expected URL, received type ${typeof self}`;
}
try {
new URL(self);
return true;
} catch (err) {
return `Invalid URL ${self}.`;
}
}
export interface TachiConfig {
MONGO_BASE_URL: string;
LOG_LEVEL: "debug" | "verbose" | "info" | "warn" | "error" | "severe" | "crit";
CAPTCHA_SECRET_KEY: string;
SESSION_SECRET: string;
FLO_API_URL: string;
EAG_API_URL: string;
ARC_API_URL: string;
ARC_AUTH_TOKEN: string;
CDN_ROOT: string;
TYPE: "ktchi" | "btchi";
PORT: integer;
INFO: {
NAME: string;
};
}
const err = p(config, {
MONGO_BASE_URL: "string",
LOG_LEVEL: p.isIn("debug", "verbose", "info", "warn", "error", "severe", "crit"),
CAPTCHA_SECRET_KEY: "string",
SESSION_SECRET: "string",
FLO_API_URL: isValidURL,
EAG_API_URL: isValidURL,
ARC_API_URL: isValidURL,
ARC_AUTH_TOKEN: "string",
CDN_ROOT: "string",
PORT: p.isPositiveInteger,
TYPE: p.isIn("ktchi", "btchi"),
});
if (err) {
throw FormatPrError(err, "Invalid conf.json5 file.");
}
const KTCHI_INFO: TachiConfig["INFO"] = {
NAME: "Kamaitachi",
};
const BTCHI_INFO: TachiConfig["INFO"] = {
NAME: "Bokutachi",
};
if (config.TYPE === "ktchi") {
config.INFO = KTCHI_INFO;
} else {
config.INFO = BTCHI_INFO;
}
const tachiConfig = config as TachiConfig;
export const MONGO_BASE_URL = tachiConfig.MONGO_BASE_URL;
export const LOG_LEVEL = tachiConfig.LOG_LEVEL;
export const SESSION_SECRET = tachiConfig.SESSION_SECRET;
export const CAPTCHA_SECRET_KEY = tachiConfig.CAPTCHA_SECRET_KEY;
export const FLO_API_URL = tachiConfig.FLO_API_URL;
export const EAG_API_URL = tachiConfig.EAG_API_URL;
export const ARC_API_URL = tachiConfig.ARC_API_URL;
export const ARC_AUTH_TOKEN = tachiConfig.ARC_AUTH_TOKEN;
export const KTCDN_ROOT = tachiConfig.CDN_ROOT;
export const CONF_INFO = tachiConfig.INFO;
+1 -1
View File
@@ -1,7 +1,7 @@
import CreateLogCtx from "./lib/logger/logger";
import server from "./server/server";
import serverConfig from "./server/server-config";
import { LOG_LEVEL } from "./lib/env/env";
import { LOG_LEVEL } from "./lib/setup/config";
import { FormatVersion } from "./lib/constants/version";
const logger = CreateLogCtx(__filename);
@@ -6,7 +6,7 @@ t.test("#RequireLoggedIn", (t) => {
t.test("Should reject users that are not logged in.", async (t) => {
const { res } = await expMiddlewareMock(RequireLoggedIn, {
session: {
ktchi: null,
tachi: null,
},
});
@@ -23,7 +23,7 @@ t.test("#RequireLoggedIn", (t) => {
t.test("Should allow users that are logged in.", async (t) => {
const { res } = await expMiddlewareMock(RequireLoggedIn, {
session: {
ktchi: {
tachi: {
userID: 1,
},
},
@@ -4,7 +4,7 @@ import CreateLogCtx from "../../lib/logger/logger";
const logger = CreateLogCtx(__filename);
export function RequireLoggedIn(req: Request, res: Response, next: NextFunction) {
if (!req.session.ktchi?.userID) {
if (!req.session.tachi?.userID) {
logger.info(`Received unauthorised request from ${req.ip} from ${req.originalUrl}`);
return res.status(401).json({
+1 -1
View File
@@ -12,7 +12,7 @@ import { GetNextCounterValue } from "../../../../../utils/db";
import CreateLogCtx from "../../../../../lib/logger/logger";
import { FormatUserDoc } from "../../../../../utils/user";
import nodeFetch from "../../../../../utils/fetch";
import { CAPTCHA_SECRET_KEY } from "../../../../../lib/env/env";
import { CAPTCHA_SECRET_KEY } from "../../../../../lib/setup/config";
const logger = CreateLogCtx(__filename);
@@ -33,7 +33,7 @@ router.post("/status", RequireLoggedIn, (req, res) =>
success: true,
description: "Logged In.",
body: {
userID: req.session.ktchi!.userID,
userID: req.session.tachi!.userID,
},
})
);
@@ -56,8 +56,8 @@ router.post(
}
),
async (req, res) => {
if (req.session.ktchi?.userID) {
logger.info(`Dual log-in attempted from ${req.session.ktchi.userID}`);
if (req.session.tachi?.userID) {
logger.info(`Dual log-in attempted from ${req.session.tachi.userID}`);
return res.status(409).json({
success: false,
description: `You are already logged in as someone.`,
@@ -107,7 +107,7 @@ router.post(
});
}
req.session.ktchi = {
req.session.tachi = {
userID: requestedUser.id,
};
@@ -55,7 +55,7 @@ router.post(
const inputParser = (logger: KtLogger) =>
ResolveFileUploadData(importType, req.file, req.body, logger);
const userDoc = await GetUserWithIDGuaranteed(req.session.ktchi!.userID);
const userDoc = await GetUserWithIDGuaranteed(req.session.tachi!.userID);
// The <any, any> here is deliberate - TS picks the IIDX-CSV generic values
// for this function call because it sees them first
@@ -11,7 +11,7 @@ const router: Router = Router({ mergeParams: true });
* @name POST /ir/barbatos/score/submit
*/
router.post("/score/submit", RequireLoggedIn, async (req, res) => {
const userDoc = await GetUserWithIDGuaranteed(req.session.ktchi!.userID);
const userDoc = await GetUserWithIDGuaranteed(req.session.tachi!.userID);
const responseData = await ExpressWrappedScoreImportMain(
userDoc,
@@ -2,14 +2,14 @@ import t from "tap";
import { ValidateAuthToken, ValidateIRClientVersion } from "./auth";
import expMiddlewareMock from "express-request-mock";
import ResetDBState from "../../../../test-utils/resets";
import { SYMBOL_KtchiData } from "../../../../lib/constants/ktchi";
import { SYMBOL_TachiData } from "../../../../lib/constants/tachi";
import { CloseAllConnections } from "../../../../test-utils/close-connections";
t.test("#ValidateIRClientVersion", (t) => {
t.test("Should reject clients that are not supported", async (t) => {
const { res } = await expMiddlewareMock(ValidateIRClientVersion, {
headers: {
"X-KtchiIR-Version": "1.2.0",
"X-TachiIR-Version": "1.2.0",
},
});
@@ -17,7 +17,7 @@ t.test("#ValidateIRClientVersion", (t) => {
t.equal(res.statusCode, 400);
t.equal(json.success, false);
t.match(json.description, /Invalid KtchiIR client version/u);
t.match(json.description, /Invalid TachiIR client version/u);
t.end();
});
@@ -29,7 +29,7 @@ t.test("#ValidateIRClientVersion", (t) => {
t.equal(res.statusCode, 400);
t.equal(json.success, false);
t.match(json.description, /Invalid KtchiIR client version/u);
t.match(json.description, /Invalid TachiIR client version/u);
t.end();
});
@@ -37,7 +37,7 @@ t.test("#ValidateIRClientVersion", (t) => {
t.test("Should accept 2.0.0", async (t) => {
const { res } = await expMiddlewareMock(ValidateIRClientVersion, {
headers: {
"X-KtchiIR-Version": "2.0.0",
"X-TachiIR-Version": "2.0.0",
},
});
@@ -106,9 +106,9 @@ t.test("#ValidateAuthToken", (t) => {
t.equal(res.statusCode, 200);
t.hasStrict(
req[SYMBOL_KtchiData]?.beatorajaAuthDoc,
req[SYMBOL_TachiData]?.beatorajaAuthDoc,
{ token: "token", userID: 1 },
"Should attach the authDoc to the request KtchiData"
"Should attach the authDoc to the request TachiData"
);
t.end();
@@ -2,7 +2,7 @@ import { GenericAuthDocument } from "tachi-common";
import { RequestHandler } from "express";
import db from "../../../../external/mongo/db";
import { SplitAuthorizationHeader } from "../../../../utils/misc";
import { AssignToReqKtchiData } from "../../../../utils/req-ktchi-data";
import { AssignToReqTachiData } from "../../../../utils/req-tachi-data";
export const ValidateAuthToken: RequestHandler = async (req, res, next) => {
const header = req.header("Authorization");
@@ -34,18 +34,18 @@ export const ValidateAuthToken: RequestHandler = async (req, res, next) => {
});
}
AssignToReqKtchiData(req, { beatorajaAuthDoc });
AssignToReqTachiData(req, { beatorajaAuthDoc });
return next();
};
export const ValidateIRClientVersion: RequestHandler = (req, res, next) => {
const header = req.header("X-KtchiIR-Version");
const header = req.header("X-TachiIR-Version");
if (header !== "2.0.0") {
return res.status(400).json({
success: false,
description: "Invalid KtchiIR client version.",
description: "Invalid TachiIR client version.",
});
}
@@ -2,7 +2,7 @@ import t from "tap";
import db from "../../../../../external/mongo/db";
import ResetDBState from "../../../../../test-utils/resets";
import { GetKTDataJSON } from "../../../../../test-utils/test-data";
import { KtchiPBScoreToBeatorajaFormat } from "./convert-scores";
import { TachiPBScoreToBeatorajaFormat } from "./convert-scores";
import { ScoreDocument, PBScoreDocument } from "tachi-common";
import { Random20Hex } from "../../../../../utils/misc";
import deepmerge from "deepmerge";
@@ -25,7 +25,7 @@ const pbScore = {
userID: 1,
} as unknown as PBScoreDocument<"bms:7K" | "bms:14K">;
t.test("#KtchiPBScoreToBeatorajaFormat", (t) => {
t.test("#TachiPBScoreToBeatorajaFormat", (t) => {
t.beforeEach(ResetDBState);
t.beforeEach(async () => {
await db.scores.insert(
@@ -48,7 +48,7 @@ t.test("#KtchiPBScoreToBeatorajaFormat", (t) => {
});
t.test("Should convert score.", async (t) => {
const res = await KtchiPBScoreToBeatorajaFormat(pbScore, gazerChart, 1);
const res = await TachiPBScoreToBeatorajaFormat(pbScore, gazerChart, 1);
t.strictSame(
res,
@@ -73,7 +73,7 @@ t.test("#KtchiPBScoreToBeatorajaFormat", (t) => {
});
t.test("Should emplace username if requestingUserID is not the pbscore owner", async (t) => {
const res = await KtchiPBScoreToBeatorajaFormat(pbScore, gazerChart, 2);
const res = await TachiPBScoreToBeatorajaFormat(pbScore, gazerChart, 2);
t.strictSame(
res,
@@ -110,7 +110,7 @@ t.test("#KtchiPBScoreToBeatorajaFormat", (t) => {
},
} as ScoreDocument);
const res = await KtchiPBScoreToBeatorajaFormat(pbScore, gazerChart, 2);
const res = await TachiPBScoreToBeatorajaFormat(pbScore, gazerChart, 2);
t.strictSame(
res,
@@ -147,7 +147,7 @@ t.test("#KtchiPBScoreToBeatorajaFormat", (t) => {
},
} as ScoreDocument);
const res = await KtchiPBScoreToBeatorajaFormat(
const res = await TachiPBScoreToBeatorajaFormat(
deepmerge(pbScore, { playtype: "14K" }),
gazerChart,
2
@@ -178,7 +178,7 @@ t.test("#KtchiPBScoreToBeatorajaFormat", (t) => {
t.test("Should throw severe if no lampPB exists.", async (t) => {
await db.scores.remove({ scoreID: "mock_lampPB" });
t.rejects(() => KtchiPBScoreToBeatorajaFormat(pbScore, gazerChart, 2), {
t.rejects(() => TachiPBScoreToBeatorajaFormat(pbScore, gazerChart, 2), {
message: /User 1's PB on.*has no lampPB/u,
} as any);
@@ -39,14 +39,14 @@ export type BeatorajaIRScoreFormat = BeatorajaPartialScoreFormat & BeatorajaScor
const logger = CreateLogCtx(__filename);
/**
* Converts a Kamaitachi Score PB into the beatoraja IR format.
* Converts a Tachi Score PB into the beatoraja IR format.
* @param pbScore - The PB score to convert.
* @param chart - The chart document the PB score belongs to.
* @param requestingUserID - The user who requested this conversion. This is
* because beatoraja uses the empty string to dictate that the score was from
* the requesting user.
*/
export async function KtchiPBScoreToBeatorajaFormat(
export async function TachiPBScoreToBeatorajaFormat(
pbScore: PBScoreDocument<"bms:7K" | "bms:14K">,
chart: ChartDocument<"bms:7K" | "bms:14K">,
requestingUserID: integer
@@ -67,7 +67,7 @@ export async function KtchiPBScoreToBeatorajaFormat(
);
}
return KtchiScoreDataToBeatorajaFormat(
return TachiScoreDataToBeatorajaFormat(
pbScore,
chart.data.hashSHA256,
username,
@@ -79,7 +79,7 @@ export async function KtchiPBScoreToBeatorajaFormat(
}
/**
* Converts various data from Kamaitachi to the beatoraja format.
* Converts various data from Tachi to the beatoraja format.
* @param pbScore - The users PB Score document for this chart.
* @param sha256 - The SHA256 for this chart.
* @param username - The users name. Beatoraja uses the special value "" to indicate the user is the current player.
@@ -89,7 +89,7 @@ export async function KtchiPBScoreToBeatorajaFormat(
* @param random - What random modifier was used.
* @returns A Beatoraja Score Document.
*/
function KtchiScoreDataToBeatorajaFormat(
function TachiScoreDataToBeatorajaFormat(
pbScore: PBScoreDocument<"bms:7K" | "bms:14K">,
sha256: string,
username: string,
@@ -35,7 +35,7 @@ t.test("GET /ir/beatoraja/charts/:chartSHA256/scores", (t) => {
const res = await mockApi
.get(`/ir/beatoraja/charts/${GAZER_SHA256}/scores`)
.set("X-KtchiIR-Version", "2.0.0")
.set("X-TachiIR-Version", "2.0.0")
.set("Authorization", "Bearer token");
t.equal(res.status, 200);
@@ -46,7 +46,7 @@ t.test("GET /ir/beatoraja/charts/:chartSHA256/scores", (t) => {
t.test("Should return 404 if chart doesnt exist", async (t) => {
const res = await mockApi
.get(`/ir/beatoraja/charts/INVALID/scores`)
.set("X-KtchiIR-Version", "2.0.0")
.set("X-TachiIR-Version", "2.0.0")
.set("Authorization", "Bearer token");
t.equal(res.status, 404);
@@ -1,9 +1,9 @@
import { ChartDocument, PBScoreDocument } from "tachi-common";
import { Router, RequestHandler } from "express";
import db from "../../../../../external/mongo/db";
import { SYMBOL_KtchiData } from "../../../../../lib/constants/ktchi";
import { KtchiPBScoreToBeatorajaFormat } from "./convert-scores";
import { AssignToReqKtchiData } from "../../../../../utils/req-ktchi-data";
import { SYMBOL_TachiData } from "../../../../../lib/constants/tachi";
import { TachiPBScoreToBeatorajaFormat } from "./convert-scores";
import { AssignToReqTachiData } from "../../../../../utils/req-tachi-data";
const router: Router = Router({ mergeParams: true });
@@ -19,7 +19,7 @@ const GetChartDocument: RequestHandler = async (req, res, next) => {
});
}
AssignToReqKtchiData(req, { beatorajaChartDoc: chart });
AssignToReqTachiData(req, { beatorajaChartDoc: chart });
return next();
};
@@ -31,7 +31,7 @@ router.use(GetChartDocument);
* @name GET /ir/beatoraja/chart/:chartSHA256/scores
*/
router.get("/scores", async (req, res) => {
const chart = req[SYMBOL_KtchiData]!.beatorajaChartDoc!;
const chart = req[SYMBOL_TachiData]!.beatorajaChartDoc!;
const scores = (await db["score-pbs"].find({
chartID: chart.chartID,
@@ -41,7 +41,7 @@ router.get("/scores", async (req, res) => {
// @optimisable - This should be solved with a couple queries and a hashmap.
const beatorajaScores = await Promise.all(
scores.map((e) =>
KtchiPBScoreToBeatorajaFormat(e, chart, req[SYMBOL_KtchiData]!.beatorajaAuthDoc!.userID)
TachiPBScoreToBeatorajaFormat(e, chart, req[SYMBOL_TachiData]!.beatorajaAuthDoc!.userID)
)
);
@@ -16,7 +16,7 @@ t.test("POST /ir/beatoraja/login", (t) => {
username: "test_zkldi",
password: "password",
})
.set("X-KtchiIR-Version", "2.0.0");
.set("X-TachiIR-Version", "2.0.0");
t.equal(res.status, 200);
t.match(res.body.body.token, /^[0-9a-f]{40}$/u, "Should return a 20 byte long token.");
@@ -31,7 +31,7 @@ t.test("POST /ir/beatoraja/login", (t) => {
username: "test_zkldi",
password: "invalid",
})
.set("X-KtchiIR-Version", "2.0.0");
.set("X-TachiIR-Version", "2.0.0");
t.equal(res.status, 401);
t.equal(res.body.success, false);
@@ -40,14 +40,14 @@ t.test("POST /ir/beatoraja/login", (t) => {
t.end();
});
t.test("Should reject X-KtchiIR-Versions", async (t) => {
t.test("Should reject X-TachiIR-Versions", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/login")
.send({
username: "test_zkldi",
password: "password",
})
.set("X-KtchiIR-Version", "1.2.0");
.set("X-TachiIR-Version", "1.2.0");
t.equal(res.status, 400);
t.equal(res.body.success, false);
@@ -72,7 +72,7 @@ t.test("POST /ir/beatoraja/login", (t) => {
username: "invalid",
password: "password",
})
.set("X-KtchiIR-Version", "2.0.0");
.set("X-TachiIR-Version", "2.0.0");
t.equal(res.status, 404);
t.equal(res.body.success, false);
@@ -85,7 +85,7 @@ t.test("POST /ir/beatoraja/login", (t) => {
const res = await mockApi
.post("/ir/beatoraja/login")
.send({})
.set("X-KtchiIR-Version", "2.0.0");
.set("X-TachiIR-Version", "2.0.0");
t.equal(res.status, 400);
t.equal(res.body.success, false);
@@ -97,7 +97,7 @@ t.test("POST /ir/beatoraja/login", (t) => {
username: { $where: "for(;;){}" },
password: 123,
})
.set("X-KtchiIR-Version", "2.0.0");
.set("X-TachiIR-Version", "2.0.0");
t.equal(res2.status, 400);
t.equal(res2.body.success, false);
@@ -117,7 +117,7 @@ t.test("POST /ir/beatoraja/submit-score", (t) => {
t.test("Should import a valid score.", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-score")
.set("X-KtchiIR-Version", "2.0.0")
.set("X-TachiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(scoreReq);
@@ -154,7 +154,7 @@ t.test("POST /ir/beatoraja/submit-score", (t) => {
t.test("Should return an error if invalid client.", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-score")
.set("X-KtchiIR-Version", "2.0.0")
.set("X-TachiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(deepmerge(scoreReq, { client: "INVALID" }));
@@ -169,7 +169,7 @@ t.test("POST /ir/beatoraja/submit-score", (t) => {
t.test("Should return an error if invalid score.", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-score")
.set("X-KtchiIR-Version", "2.0.0")
.set("X-TachiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(deepmerge(scoreReq, { score: { exscore: -1 } }));
@@ -184,7 +184,7 @@ t.test("POST /ir/beatoraja/submit-score", (t) => {
t.test("Should return an error if invalid chart.", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-score")
.set("X-KtchiIR-Version", "2.0.0")
.set("X-TachiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(deepmerge(scoreReq, { chart: { title: null } }));
@@ -258,7 +258,7 @@ t.test("POST /ir/beatoraja/submit-course", (t) => {
t.test("Should accept a valid clear", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("X-TachiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(courseScore);
@@ -276,7 +276,7 @@ t.test("POST /ir/beatoraja/submit-course", (t) => {
t.test("Should silently reject a fail", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("X-TachiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(deepmerge(courseScore, { score: { clear: "Failed" } }));
@@ -290,7 +290,7 @@ t.test("POST /ir/beatoraja/submit-course", (t) => {
t.test("Should reject scores with no charts", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("X-TachiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(deepmerge(courseScore, { course: { charts: [] } }, { arrayMerge: (d, s) => s }));
@@ -304,7 +304,7 @@ t.test("POST /ir/beatoraja/submit-course", (t) => {
t.test("Should reject scores with invalid chart documents", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("X-TachiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(deepmerge(courseScore, { course: { charts: [1, 2, 3, 4] } }));
@@ -318,7 +318,7 @@ t.test("POST /ir/beatoraja/submit-course", (t) => {
t.test("Should reject scores with too many chart documents", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("X-TachiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(
deepmerge(courseScore, {
@@ -336,7 +336,7 @@ t.test("POST /ir/beatoraja/submit-course", (t) => {
t.test("Should reject scores not on LN mode", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("X-TachiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(
deepmerge(courseScore, {
@@ -356,7 +356,7 @@ t.test("POST /ir/beatoraja/submit-course", (t) => {
t.test("Should reject too few constraints", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("X-TachiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(
deepmerge(
@@ -380,7 +380,7 @@ t.test("POST /ir/beatoraja/submit-course", (t) => {
t.test("Should reject non-array constraints", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("X-TachiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(
deepmerge(
@@ -404,7 +404,7 @@ t.test("POST /ir/beatoraja/submit-course", (t) => {
t.test("Should reject too many constraints", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("X-TachiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(
deepmerge(
@@ -428,7 +428,7 @@ t.test("POST /ir/beatoraja/submit-course", (t) => {
t.test("Should reject invalid constraints", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("X-TachiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(
deepmerge(
@@ -452,7 +452,7 @@ t.test("POST /ir/beatoraja/submit-course", (t) => {
t.test("Should reject invalid constraints for 3", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("X-TachiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(
deepmerge(
@@ -1,6 +1,6 @@
import { Router } from "express";
import db from "../../../../external/mongo/db";
import { SYMBOL_KtchiData } from "../../../../lib/constants/ktchi";
import { SYMBOL_TachiData } from "../../../../lib/constants/tachi";
import CreateLogCtx, { KtLogger } from "../../../../lib/logger/logger";
import { ExpressWrappedScoreImportMain } from "../../../../lib/score-import/framework/express-wrapper";
import { ParseBeatorajaSingle } from "../../../../lib/score-import/import-types/ir/beatoraja/parser";
@@ -77,7 +77,7 @@ router.use(ValidateAuthToken);
* @name POST /ir/beatoraja/submit-score
*/
router.post("/submit-score", async (req, res) => {
const userDoc = await GetUserWithIDGuaranteed(req[SYMBOL_KtchiData]!.beatorajaAuthDoc!.userID);
const userDoc = await GetUserWithIDGuaranteed(req[SYMBOL_TachiData]!.beatorajaAuthDoc!.userID);
const ParserFunction = (logger: KtLogger) => ParseBeatorajaSingle(req.body, logger);
@@ -220,7 +220,7 @@ router.post("/submit-course", async (req, res) => {
});
}
const userID = req[SYMBOL_KtchiData]!.beatorajaAuthDoc!.userID;
const userID = req[SYMBOL_TachiData]!.beatorajaAuthDoc!.userID;
const result = await UpdateClassIfGreater(
userID,
@@ -11,7 +11,7 @@ const router: Router = Router({ mergeParams: true });
* @name POST /ir/chunitachi/score/submit
*/
router.post("/import", RequireLoggedIn, async (req, res) => {
const userDoc = await GetUserWithIDGuaranteed(req.session.ktchi!.userID);
const userDoc = await GetUserWithIDGuaranteed(req.session.tachi!.userID);
if (req.body?.head?.game !== "chunithm") {
return res.status(400).json({
@@ -11,7 +11,7 @@ const router: Router = Router({ mergeParams: true });
* @name POST /ir/direct-manual/import
*/
router.post("/import", RequireLoggedIn, async (req, res) => {
const userDoc = await GetUserWithIDGuaranteed(req.session.ktchi!.userID);
const userDoc = await GetUserWithIDGuaranteed(req.session.tachi!.userID);
const intent = req.header("X-User-Intent");
+11 -11
View File
@@ -19,7 +19,7 @@ const ValidateFervidexHeader: RequestHandler = (req, res, next) => {
if (!agent) {
logger.debug(
`Rejected fervidex client with no agent from user ${req.session.ktchi!.userID}.`
`Rejected fervidex client with no agent from user ${req.session.tachi!.userID}.`
);
return res.status(400).json({
success: false,
@@ -30,7 +30,7 @@ const ValidateFervidexHeader: RequestHandler = (req, res, next) => {
if (!agent.startsWith("fervidex/")) {
logger.info(
`Rejected fervidex client with invalid agent ${agent} from user ${
req.session.ktchi!.userID
req.session.tachi!.userID
}.`
);
return res.status(400).json({
@@ -44,7 +44,7 @@ const ValidateFervidexHeader: RequestHandler = (req, res, next) => {
if (!versions.every((e) => !Number.isNaN(e))) {
logger.info(
`Rejected fervidex client with agent ${agent} for NaN-like versions from user ${
req.session.ktchi!.userID
req.session.tachi!.userID
}.`
);
return res.status(400).json({
@@ -55,7 +55,7 @@ const ValidateFervidexHeader: RequestHandler = (req, res, next) => {
// version.minor
if (versions[1] < 3) {
logger.debug(`Rejected outdated fervidex client from user ${req.session.ktchi!.userID}.`);
logger.debug(`Rejected outdated fervidex client from user ${req.session.tachi!.userID}.`);
return res.status(400).json({
success: false,
description: `Versions of fervidex < 1.3.0 are not supported.`,
@@ -69,7 +69,7 @@ const RequireInf2ModelHeader: RequestHandler = (req, res, next) => {
const swModel = req.header("X-Software-Model");
if (!swModel) {
logger.debug(`Rejected empty X-Software-Model from user ${req.session.ktchi!.userID}.`);
logger.debug(`Rejected empty X-Software-Model from user ${req.session.tachi!.userID}.`);
return res.status(400).json({
success: false,
description: `Invalid X-Software-Model.`,
@@ -80,7 +80,7 @@ const RequireInf2ModelHeader: RequestHandler = (req, res, next) => {
const softID = ParseEA3SoftID(swModel);
if (softID.model !== MODEL_INFINITAS_2) {
logger.debug(`Rejected non-inf2 model from user ${req.session.ktchi!.userID}.`);
logger.debug(`Rejected non-inf2 model from user ${req.session.tachi!.userID}.`);
return res.status(400).send({
success: false,
description: "This endpoint is only available for INF2 clients.",
@@ -101,7 +101,7 @@ const ValidateModelHeader: RequestHandler = (req, res, next) => {
const swModel = req.header("X-Software-Model");
if (!swModel) {
logger.debug(`Rejected empty X-Software Model from user ${req.session.ktchi!.userID}.`);
logger.debug(`Rejected empty X-Software Model from user ${req.session.tachi!.userID}.`);
return res.status(400).json({
success: false,
description: `Invalid X-Software-Model.`,
@@ -125,7 +125,7 @@ const ValidateModelHeader: RequestHandler = (req, res, next) => {
if (softID.ext !== EXT_HEROIC_VERSE) {
logger.info(
`Rejected invalid Software Model ${softID.ext} from user ${
req.session.ktchi!.userID
req.session.tachi!.userID
}.`
);
return res.status(400).json({
@@ -155,7 +155,7 @@ router.use(RequireLoggedIn, ValidateFervidexHeader, ValidateModelHeader);
* @name POST /ir/fervidex/profile/submit
*/
router.post("/profile/submit", RequireInf2ModelHeader, async (req, res) => {
const userDoc = await GetUserWithIDGuaranteed(req.session.ktchi!.userID);
const userDoc = await GetUserWithIDGuaranteed(req.session.tachi!.userID);
const headers = {
// guaranteed to exist because of RequireInf2ModelHeader
@@ -180,7 +180,7 @@ router.post("/profile/submit", RequireInf2ModelHeader, async (req, res) => {
* @name POST /ir/fervidex/score/submit
*/
router.post("/score/submit", ValidateModelHeader, async (req, res) => {
const userDoc = await GetUserWithIDGuaranteed(req.session.ktchi!.userID);
const userDoc = await GetUserWithIDGuaranteed(req.session.tachi!.userID);
const model = req.header("X-Software-Model");
@@ -243,7 +243,7 @@ router.post("/class/submit", ValidateModelHeader, async (req, res) => {
const playtype: Playtypes["iidx"] = req.body.play_style === 0 ? "SP" : "DP";
const r = await UpdateClassIfGreater(
req.session.ktchi!.userID,
req.session.tachi!.userID,
"iidx",
playtype,
"dan",
+13 -13
View File
@@ -1,6 +1,6 @@
import { Router, RequestHandler } from "express";
import { FindChartOnSHA256 } from "../../../../utils/queries/charts";
import { SYMBOL_KtchiData } from "../../../../lib/constants/ktchi";
import { SYMBOL_TachiData } from "../../../../lib/constants/tachi";
import db from "../../../../external/mongo/db";
import {
ChartDocument,
@@ -10,13 +10,13 @@ import {
} from "tachi-common";
import { AssertStrAsPositiveNonZeroInt } from "../../../../lib/score-import/framework/common/string-asserts";
import CreateLogCtx, { KtLogger } from "../../../../lib/logger/logger";
import { CreatePOSTScoresResponseBody, KtchiScoreToServerScore } from "./usc";
import { CreatePOSTScoresResponseBody, TachiScoreToServerScore } from "./usc";
import { ExpressWrappedScoreImportMain } from "../../../../lib/score-import/framework/express-wrapper";
import { GetUserWithID } from "../../../../utils/user";
import { ParseIRUSC } from "../../../../lib/score-import/import-types/ir/usc/parser";
import { USCIR_MAX_LEADERBOARD_N } from "../../../../lib/constants/usc-ir";
import { CreateMulterSingleUploadMiddleware } from "../../../middleware/multer-upload";
import { AssignToReqKtchiData } from "../../../../utils/req-ktchi-data";
import { AssignToReqTachiData } from "../../../../utils/req-tachi-data";
import { StoreCDN } from "../../../../lib/cdn/cdn";
import { ONE_MEGABYTE } from "../../../../lib/constants/filesize";
import crypto from "crypto";
@@ -70,7 +70,7 @@ const ValidateUSCRequest: RequestHandler = async (req, res, next) => {
});
}
AssignToReqKtchiData(req, { uscAuthDoc });
AssignToReqTachiData(req, { uscAuthDoc });
return next();
};
@@ -97,7 +97,7 @@ router.get("/", (req, res) =>
const RetrieveChart: RequestHandler = async (req, res, next) => {
const chart = await FindChartOnSHA256("usc", req.params.chartHash);
AssignToReqKtchiData(req, {
AssignToReqTachiData(req, {
uscChartDoc: (chart ?? undefined) as ChartDocument<"usc:Single"> | undefined,
});
@@ -110,7 +110,7 @@ const RetrieveChart: RequestHandler = async (req, res, next) => {
* @name GET /ir/usc/charts/:chartHash
*/
router.get("/charts/:chartHash", RetrieveChart, (req, res) => {
const chart = req[SYMBOL_KtchiData]!.uscChartDoc;
const chart = req[SYMBOL_TachiData]!.uscChartDoc;
if (!chart) {
return res.status(200).json({
@@ -131,7 +131,7 @@ router.get("/charts/:chartHash", RetrieveChart, (req, res) => {
* @name GET /ir/usc/charts/:chartHash/record
*/
router.get("/charts/:chartHash/record", RetrieveChart, async (req, res) => {
const chart = req[SYMBOL_KtchiData]!.uscChartDoc;
const chart = req[SYMBOL_TachiData]!.uscChartDoc;
// spec ambigious here
@@ -154,7 +154,7 @@ router.get("/charts/:chartHash/record", RetrieveChart, async (req, res) => {
});
}
const serverScore = await KtchiScoreToServerScore(serverRecord);
const serverScore = await TachiScoreToServerScore(serverRecord);
return res.status(200).json({
statusCode: STATUS_CODES.SUCCESS,
@@ -169,7 +169,7 @@ router.get("/charts/:chartHash/record", RetrieveChart, async (req, res) => {
* @name GET /ir/usc/charts/:chartHash/leaderboard
*/
router.get("/charts/:chartHash/leaderboard", RetrieveChart, async (req, res) => {
const chart = req[SYMBOL_KtchiData]!.uscChartDoc!;
const chart = req[SYMBOL_TachiData]!.uscChartDoc!;
if (!(typeof req.query.mode === "string" && ["best", "rivals"].includes(req.query.mode))) {
return res.status(200).json({
@@ -221,7 +221,7 @@ router.get("/charts/:chartHash/leaderboard", RetrieveChart, async (req, res) =>
}
)) as PBScoreDocument<"usc:Single">[];
const serverScores = await Promise.all(bestScores.map(KtchiScoreToServerScore));
const serverScores = await Promise.all(bestScores.map(TachiScoreToServerScore));
return res.status(200).json({
statusCode: STATUS_CODES.SUCCESS,
@@ -262,10 +262,10 @@ router.post("/scores", async (req, res) => {
});
}
const userDoc = await GetUserWithID(req[SYMBOL_KtchiData]!.uscAuthDoc!.userID);
const userDoc = await GetUserWithID(req[SYMBOL_TachiData]!.uscAuthDoc!.userID);
if (!userDoc) {
logger.severe(`User ${req[SYMBOL_KtchiData]!.uscAuthDoc!.userID} as no parent userDoc?`);
logger.severe(`User ${req[SYMBOL_TachiData]!.uscAuthDoc!.userID} as no parent userDoc?`);
return res.status(200).json({
statusCode: STATUS_CODES.SERVER_ERROR,
description: "An internal server error has occured.",
@@ -334,7 +334,7 @@ router.post(
}
const correspondingScore = await db.scores.findOne({
userID: req[SYMBOL_KtchiData]!.uscAuthDoc!.userID,
userID: req[SYMBOL_TachiData]!.uscAuthDoc!.userID,
game: "usc",
scoreID: req.body.identifier,
});
+7 -7
View File
@@ -1,7 +1,7 @@
import t from "tap";
import db from "../../../../external/mongo/db";
import ResetDBState from "../../../../test-utils/resets";
import { CreatePOSTScoresResponseBody, KtchiScoreToServerScore } from "./usc";
import { CreatePOSTScoresResponseBody, TachiScoreToServerScore } from "./usc";
import { ChartDocument, PBScoreDocument, ScoreDocument } from "tachi-common";
import deepmerge from "deepmerge";
import { CloseAllConnections } from "../../../../test-utils/close-connections";
@@ -51,13 +51,13 @@ const mockScoreDocument = {
},
} as ScoreDocument;
t.test("#KtchiScoreToServerScore", (t) => {
t.test("#TachiScoreToServerScore", (t) => {
t.beforeEach(ResetDBState);
t.test("Should correctly convert a ktchiScore to a serverScore", async (t) => {
t.test("Should correctly convert a tachiScore to a serverScore", async (t) => {
await db.scores.insert(mockScoreDocument as ScoreDocument);
const res = await KtchiScoreToServerScore(mockScorePB);
const res = await TachiScoreToServerScore(mockScorePB);
t.strictSame(
res,
@@ -82,7 +82,7 @@ t.test("#KtchiScoreToServerScore", (t) => {
t.test("Should work for timestamped scores", async (t) => {
await db.scores.insert(mockScoreDocument);
const res = await KtchiScoreToServerScore(
const res = await TachiScoreToServerScore(
deepmerge(mockScorePB, { timeAchieved: 1_621_844_762_995 })
);
@@ -107,7 +107,7 @@ t.test("#KtchiScoreToServerScore", (t) => {
});
t.test("Should throw if user document does not exist.", (t) => {
t.rejects(() => KtchiScoreToServerScore(deepmerge(mockScorePB, { userID: 2 } as any)), {
t.rejects(() => TachiScoreToServerScore(deepmerge(mockScorePB, { userID: 2 } as any)), {
message: /User 2 from PB on chart.*has no user document\?/u,
} as any);
@@ -115,7 +115,7 @@ t.test("#KtchiScoreToServerScore", (t) => {
});
t.test("Should throw if scorePB document does not exist.", (t) => {
t.rejects(() => KtchiScoreToServerScore(mockScorePB), {
t.rejects(() => TachiScoreToServerScore(mockScorePB), {
message:
/Score USC_EXAMPLE_SCORE_PB_ID does not exist, but is referenced in 1's PBDoc on/u,
} as any);
+19 -19
View File
@@ -26,15 +26,15 @@ export const KT_LAMP_TO_USC: Record<
* returns sentinel values in the case that certain
* fields are null.
*/
export async function KtchiScoreToServerScore(
ktchiScore: PBScoreDocument<"usc:Single">
export async function TachiScoreToServerScore(
tachiScore: PBScoreDocument<"usc:Single">
): Promise<USCServerScore> {
// @optimisable
// Repeated calls to this may pre-emptively provide usernames
// and score PBs.
const userDoc = await db.users.findOne(
{
id: ktchiScore.userID,
id: tachiScore.userID,
},
{
projection: {
@@ -45,35 +45,35 @@ export async function KtchiScoreToServerScore(
if (!userDoc) {
logger.severe(
`User ${ktchiScore.userID} from PB on chart ${ktchiScore.chartID} has no user document?`
`User ${tachiScore.userID} from PB on chart ${tachiScore.chartID} has no user document?`
);
throw new Error(
`User ${ktchiScore.userID} from PB on chart ${ktchiScore.chartID} has no user document?`
`User ${tachiScore.userID} from PB on chart ${tachiScore.chartID} has no user document?`
);
}
const scorePB = (await db.scores.findOne({
scoreID: ktchiScore.composedFrom.scorePB,
scoreID: tachiScore.composedFrom.scorePB,
})) as ScoreDocument<"usc:Single"> | null;
if (!scorePB) {
logger.severe(
`Score ${ktchiScore.composedFrom.scorePB} does not exist, but is referenced in ${ktchiScore.userID}'s PBDoc on ${ktchiScore.chartID}?`
`Score ${tachiScore.composedFrom.scorePB} does not exist, but is referenced in ${tachiScore.userID}'s PBDoc on ${tachiScore.chartID}?`
);
throw new Error(
`Score ${ktchiScore.composedFrom.scorePB} does not exist, but is referenced in ${ktchiScore.userID}'s PBDoc on ${ktchiScore.chartID}?`
`Score ${tachiScore.composedFrom.scorePB} does not exist, but is referenced in ${tachiScore.userID}'s PBDoc on ${tachiScore.chartID}?`
);
}
return {
score: ktchiScore.scoreData.score,
timestamp: MStoS(ktchiScore.timeAchieved ?? 0),
crit: ktchiScore.scoreData.hitData.critical ?? 0,
near: ktchiScore.scoreData.hitData.near ?? 0,
error: ktchiScore.scoreData.hitData.miss ?? 0,
ranking: ktchiScore.rankingData.rank,
lamp: KT_LAMP_TO_USC[ktchiScore.scoreData.lamp],
score: tachiScore.scoreData.score,
timestamp: MStoS(tachiScore.timeAchieved ?? 0),
crit: tachiScore.scoreData.hitData.critical ?? 0,
near: tachiScore.scoreData.hitData.near ?? 0,
error: tachiScore.scoreData.hitData.miss ?? 0,
ranking: tachiScore.rankingData.rank,
lamp: KT_LAMP_TO_USC[tachiScore.scoreData.lamp],
username: userDoc.username,
noteMod: scorePB.scoreMeta.noteMod ?? "NORMAL",
gaugeMod: scorePB.scoreMeta.gaugeMod ?? "NORMAL",
@@ -162,10 +162,10 @@ export async function CreatePOSTScoresResponseBody(
)) as PBScoreDocument<"usc:Single">[];
const [score, serverRecord, adjacentAbove, adjacentBelow] = await Promise.all([
KtchiScoreToServerScore(scorePB),
KtchiScoreToServerScore(ktServerRecord),
Promise.all(adjAbove.map(KtchiScoreToServerScore)),
Promise.all(adjBelow.map(KtchiScoreToServerScore)),
TachiScoreToServerScore(scorePB),
TachiScoreToServerScore(ktServerRecord),
Promise.all(adjAbove.map(TachiScoreToServerScore)),
Promise.all(adjBelow.map(TachiScoreToServerScore)),
]);
const originalScore = (await db.scores.findOne({
+1 -1
View File
@@ -4,7 +4,7 @@ import CreateLogCtx from "../lib/logger/logger";
import expressSession from "express-session";
import { integer } from "tachi-common";
import { RedisClient } from "../external/redis/redis";
import { SESSION_SECRET } from "../lib/env/env";
import { SESSION_SECRET } from "../lib/setup/config";
import connectRedis from "connect-redis";
const logger = CreateLogCtx(__filename);
+1 -1
View File
@@ -7,7 +7,7 @@ import path from "path";
import CreateLogCtx from "../lib/logger/logger";
// im installing an entire library for rm rf...
import rimraf from "rimraf";
import { KTCDN_ROOT } from "../lib/env/env";
import { KTCDN_ROOT } from "../lib/setup/config";
const logger = CreateLogCtx(__filename);
-12
View File
@@ -1,12 +0,0 @@
import { SYMBOL_KtchiData } from "../lib/constants/ktchi";
import { Request } from "express";
import { KtchiRequestData } from "./types";
import deepmerge from "deepmerge";
export function AssignToReqKtchiData(req: Request, data: Partial<KtchiRequestData>) {
if (!req[SYMBOL_KtchiData]) {
req[SYMBOL_KtchiData] = data;
} else {
req[SYMBOL_KtchiData] = deepmerge(req[SYMBOL_KtchiData]!, data);
}
}
+12
View File
@@ -0,0 +1,12 @@
import { SYMBOL_TachiData } from "../lib/constants/tachi";
import { Request } from "express";
import { TachiRequestData } from "./types";
import deepmerge from "deepmerge";
export function AssignToReqTachiData(req: Request, data: Partial<TachiRequestData>) {
if (!req[SYMBOL_TachiData]) {
req[SYMBOL_TachiData] = data;
} else {
req[SYMBOL_TachiData] = deepmerge(req[SYMBOL_TachiData]!, data);
}
}
+7 -7
View File
@@ -3,26 +3,26 @@ import { integer, GenericAuthDocument, ChartDocument } from "tachi-common";
declare module "express-session" {
// Inject additional properties on express-session
interface SessionData {
ktchi: KtchiSessionData;
tachi: TachiSessionData;
}
}
export interface KtchiSessionData {
export interface TachiSessionData {
userID: integer;
}
export interface KTFailResponse {
export interface TachiAPIFailResponse {
success: false;
description: string;
}
export interface KTSuccessResponse {
export interface TachiAPISuccessResponse {
success: true;
description: string;
body: Record<string, unknown>;
}
export type KTReponse = KTFailResponse | KTSuccessResponse;
export type TachiAPIReponse = TachiAPIFailResponse | TachiAPISuccessResponse;
/**
* Clarity type for empty objects - such as in context.
@@ -30,9 +30,9 @@ export type KTReponse = KTFailResponse | KTSuccessResponse;
export type EmptyObject = Record<string, never>;
/**
* Data that may be monkey-patched onto req.ktchi. This holds things such as middleware results.
* Data that may be monkey-patched onto req.tachi. This holds things such as middleware results.
*/
export interface KtchiRequestData {
export interface TachiRequestData {
uscAuthDoc?: GenericAuthDocument;
uscChartDoc?: ChartDocument<"usc:Single">;