mirror of
https://github.com/zkldi/Tachi.git
synced 2026-10-02 03:48:14 +03:00
checkpoint: 27
This commit is contained in:
@@ -17,7 +17,7 @@ export default function UGPTStatContainer({
|
||||
const searchParams = new URLSearchParams();
|
||||
|
||||
searchParams.set("mode", stat.mode);
|
||||
searchParams.set("property", stat.property);
|
||||
searchParams.set("property", stat.metric);
|
||||
|
||||
if (stat.mode === "chart") {
|
||||
searchParams.set("chartID", stat.chartID);
|
||||
|
||||
@@ -48,13 +48,13 @@ export default function UGPTStatCreator({
|
||||
if (values.mode === "chart") {
|
||||
stat = {
|
||||
mode: "chart",
|
||||
property: values.property as ShowcaseStatDetails["property"],
|
||||
metric: values.property as ShowcaseStatDetails["metric"],
|
||||
chartID: values.chartID ?? "",
|
||||
};
|
||||
} else if (values.mode === "folder") {
|
||||
stat = {
|
||||
mode: "folder",
|
||||
property: values.property as "lamp" | "score" | "percent" | "grade",
|
||||
metric: values.property as "lamp" | "score" | "percent" | "grade",
|
||||
folderID: values.folderID ?? "",
|
||||
gte,
|
||||
};
|
||||
|
||||
@@ -266,7 +266,7 @@ function StatDelta({
|
||||
v1: number;
|
||||
v2?: number;
|
||||
mode: "folder" | "chart";
|
||||
property: UGPTPreferenceStatsReturn["stat"]["property"];
|
||||
property: UGPTPreferenceStatsReturn["stat"]["metric"];
|
||||
game: Game;
|
||||
playtype: Playtype;
|
||||
}) {
|
||||
@@ -397,15 +397,15 @@ export function StatDisplay({
|
||||
<h4>{FormatChart(game, song, chart)}</h4>
|
||||
</Link>
|
||||
<h4>
|
||||
{UppercaseFirst(stat.property)}:{" "}
|
||||
{FormatPropertyGTE(game, playtype, stat.property, result.value)}
|
||||
{UppercaseFirst(stat.metric)}:{" "}
|
||||
{FormatPropertyGTE(game, playtype, stat.metric, result.value)}
|
||||
</h4>
|
||||
{user && user.id !== reqUser.id && (
|
||||
<StatDelta
|
||||
v1={statData.result.value}
|
||||
v2={compareData?.result.value}
|
||||
mode={stat.mode}
|
||||
property={stat.property}
|
||||
property={stat.metric}
|
||||
game={game}
|
||||
playtype={playtype}
|
||||
/>
|
||||
@@ -431,8 +431,8 @@ export function StatDisplay({
|
||||
<h4>{headerStr}</h4>
|
||||
</Link>
|
||||
<h5>
|
||||
{UppercaseFirst(stat.property)} >={" "}
|
||||
{FormatPropertyGTE(game, playtype, stat.property, stat.gte)}
|
||||
{UppercaseFirst(stat.metric)} >={" "}
|
||||
{FormatPropertyGTE(game, playtype, stat.metric, stat.gte)}
|
||||
</h5>
|
||||
<h4>
|
||||
{result.value}
|
||||
@@ -447,7 +447,7 @@ export function StatDisplay({
|
||||
v1={statData.result.value}
|
||||
v2={compareData?.result.value}
|
||||
mode={stat.mode}
|
||||
property={stat.property}
|
||||
property={stat.metric}
|
||||
game={game}
|
||||
playtype={playtype}
|
||||
/>
|
||||
|
||||
@@ -20,7 +20,6 @@ import type {
|
||||
GamePTConfig,
|
||||
Playtype,
|
||||
Playtypes,
|
||||
ProvidedMetrics,
|
||||
} from "../types/game-config";
|
||||
import type { INTERNAL_GAME_CONFIG, INTERNAL_GAME_PT_CONFIG } from "../types/internals";
|
||||
import type { ConfScoreMetric } from "../types/metrics";
|
||||
|
||||
@@ -39,7 +39,11 @@ function prSchemaFnWrap(schema: PrudenceSchema) {
|
||||
};
|
||||
}
|
||||
|
||||
const PR_GAME_STATS = (game: Game, playtype: Playtypes[Game], gptConfig: INTERNAL_GAME_PT_CONFIG) => ({
|
||||
const PR_GAME_STATS = (
|
||||
game: Game,
|
||||
playtype: Playtypes[Game],
|
||||
gptConfig: INTERNAL_GAME_PT_CONFIG
|
||||
) => ({
|
||||
userID: p.isPositiveNonZeroInteger,
|
||||
game: p.is(game),
|
||||
playtype: p.is(playtype),
|
||||
@@ -77,7 +81,9 @@ const extractGPTIDString = (self: unknown) => {
|
||||
|
||||
// Playtype might be undefined in the case where the string contains no colon.
|
||||
if (playtype === undefined || !IsValidPlaytype(game, playtype)) {
|
||||
throw new Error(`Expected valid playtype -- got ${playtype} from gptString ${s.gptString}.`);
|
||||
throw new Error(
|
||||
`Expected valid playtype -- got ${playtype} from gptString ${s.gptString}.`
|
||||
);
|
||||
}
|
||||
|
||||
return { game, playtype };
|
||||
@@ -652,7 +658,6 @@ const PRE_SCHEMAS = {
|
||||
status: p.nullable(p.isBoundedString(3, 140)),
|
||||
customPfpLocation: "?string",
|
||||
customBannerLocation: "?string",
|
||||
clan: p.nullable(p.isBoundedString(2, 4)),
|
||||
lastSeen: p.isPositiveInteger,
|
||||
badges: [p.isIn("beta", "alpha", "devTeam")],
|
||||
authLevel: p.isBoundedInteger(UserAuthLevels.BANNED, UserAuthLevels.ADMIN),
|
||||
|
||||
@@ -319,7 +319,6 @@ export interface UserDocument {
|
||||
status: string | null;
|
||||
customPfpLocation: string | null;
|
||||
customBannerLocation: string | null;
|
||||
clan: string | null; // todo
|
||||
badges: Array<UserBadges>;
|
||||
authLevel: UserAuthLevels;
|
||||
}
|
||||
@@ -609,14 +608,20 @@ export type ShowcaseStatDetails = ShowcaseStatChart | ShowcaseStatFolder;
|
||||
export interface ShowcaseStatFolder {
|
||||
mode: "folder";
|
||||
folderID: string;
|
||||
property: "grade" | "lamp" | "percent" | "score";
|
||||
|
||||
// should be a valid metric for the showcase this game is for
|
||||
// this is not checked by the typesystem though. sorry!
|
||||
metric: string;
|
||||
gte: number;
|
||||
}
|
||||
|
||||
export interface ShowcaseStatChart {
|
||||
mode: "chart";
|
||||
chartID: string;
|
||||
property: "grade" | "lamp" | "percent" | "playcount" | "score";
|
||||
|
||||
// should be a valid metric for the showcase this game is for
|
||||
// this is not checked by the typesystem though. sorry!
|
||||
metric: string;
|
||||
}
|
||||
|
||||
export interface UGPTSettingsDocument<GPT extends GPTString = GPTString> {
|
||||
|
||||
@@ -24,12 +24,18 @@ interface ConfDecimalScoreMetricNormal {
|
||||
type: "DECIMAL";
|
||||
|
||||
validate: (v: number) => string | true;
|
||||
|
||||
// This exists to allow DecimalScoreMetric.chartDependentMax.
|
||||
chartDependentMax?: never;
|
||||
}
|
||||
|
||||
interface ConfIntegerScoreMetricNormal {
|
||||
type: "INTEGER";
|
||||
|
||||
validate: (v: number) => string | true;
|
||||
|
||||
// see above
|
||||
chartDependentMax?: never;
|
||||
}
|
||||
|
||||
interface ConfDecimalScoreMetricChartDependent {
|
||||
|
||||
Vendored
+8
-2
@@ -2,7 +2,8 @@
|
||||
import CreateLogCtx from "lib/logger/logger";
|
||||
import { TachiConfig } from "lib/setup/config";
|
||||
import monk from "monk";
|
||||
import { Random20Hex } from "utils/misc";
|
||||
import { GAME_PT_CONFIGS } from "tachi-common";
|
||||
import { DedupeArr, Random20Hex } from "utils/misc";
|
||||
import type { Databases } from "./db";
|
||||
import type { IndexOptions } from "mongodb";
|
||||
import type { IMonkManager } from "monk";
|
||||
@@ -20,6 +21,8 @@ function index(fields: Record<string, unknown>, options?: IndexOptions) {
|
||||
|
||||
const UNIQUE = { unique: true };
|
||||
|
||||
const allDefaultMetrics = DedupeArr(Object.values(GAME_PT_CONFIGS).map((e) => e.defaultMetric));
|
||||
|
||||
// NOTE: INDEXES REMOVED FROM HERE WILL **NOT** AUTOMATICALLY UPDATE.
|
||||
// YOU NEED TO RUN src/scripts/set-indexes.ts --reset TO REMOVE INDEXES.
|
||||
// (indexes added will automatically apply on tachi-server boot, though).
|
||||
@@ -34,7 +37,10 @@ const staticIndexes: Partial<Record<Databases, Array<Index>>> = {
|
||||
],
|
||||
"personal-bests": [
|
||||
index({ chartID: 1, userID: 1 }, UNIQUE),
|
||||
index({ chartID: 1, [`scoreData.${gptConfig.defaultMetric}`]: 1 }),
|
||||
|
||||
// one index for every default metric, why not.
|
||||
...allDefaultMetrics.map((e) => index({ chartID: 1, [`scoreData.${e}`]: 1 })),
|
||||
|
||||
index({ userID: 1, game: 1, playtype: 1 }),
|
||||
|
||||
// activity
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { CreatePBDoc, UpdateChartRanking } from "./create-pb-doc";
|
||||
import db from "external/mongo/db";
|
||||
import { GetGPTString } from "tachi-common";
|
||||
import { GetChartForIDGuaranteed } from "utils/db";
|
||||
import type { PBScoreDocumentNoRank } from "./create-pb-doc";
|
||||
import type { KtLogger } from "lib/logger/logger";
|
||||
import type { Game, integer, Playtype } from "tachi-common";
|
||||
@@ -18,10 +20,16 @@ export async function ProcessPBs(
|
||||
return;
|
||||
}
|
||||
|
||||
const gpt = GetGPTString(game, playtype);
|
||||
|
||||
const promises = [];
|
||||
|
||||
for (const chartID of chartIDs) {
|
||||
promises.push(CreatePBDoc(userID, chartID, logger));
|
||||
promises.push(
|
||||
GetChartForIDGuaranteed(game, chartID).then((chart) =>
|
||||
CreatePBDoc(gpt, userID, chart, logger)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const pbDocsReturn = await Promise.all(promises);
|
||||
@@ -49,7 +57,18 @@ export async function ProcessPBs(
|
||||
pbDocs.map((e) => ({
|
||||
updateOne: {
|
||||
filter: { chartID: e.chartID, userID: e.userID },
|
||||
update: { $set: e },
|
||||
update: {
|
||||
$set: {
|
||||
...e,
|
||||
|
||||
// stub out ranking data with some invalid nonsense.
|
||||
rankingData: {
|
||||
outOf: 0,
|
||||
rank: 0,
|
||||
rivalRank: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
upsert: true,
|
||||
},
|
||||
})),
|
||||
|
||||
@@ -2,7 +2,7 @@ import { InternalFailure } from "../common/converter-failures";
|
||||
import { GPT_SERVER_IMPLEMENTATIONS } from "game-implementations/game-implementations";
|
||||
import { GetGPTConfig } from "tachi-common";
|
||||
import type { DryScore, DryScoreData } from "../common/types";
|
||||
import type { GPTDerivers } from "./types";
|
||||
import type { GPTDerivers } from "game-implementations/types";
|
||||
import type { KtLogger } from "lib/logger/logger";
|
||||
import type {
|
||||
ChartDocument,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CreateScoreCalcData } from "../calculated-data/score";
|
||||
import { CreateFullScoreData } from "./derivers";
|
||||
import { CreateScoreCalcData } from "../calculated-data/score";
|
||||
import { GetGPTString } from "tachi-common";
|
||||
import type { DryScore } from "../common/types";
|
||||
import type { KtLogger } from "lib/logger/logger";
|
||||
@@ -22,7 +22,7 @@ export function HydrateScore(
|
||||
|
||||
const scoreData = CreateFullScoreData(gpt, dryScore.scoreData, chart, logger);
|
||||
|
||||
const calculatedData = CreateScoreCalcData(dryScore, chart);
|
||||
const calculatedData = CreateScoreCalcData(dryScore.game, dryScore.scoreData, chart);
|
||||
|
||||
const score: ScoreDocument = {
|
||||
...dryScore,
|
||||
|
||||
@@ -10,6 +10,7 @@ import type { DryScore } from "../../../framework/common/types";
|
||||
import type { ConverterFunction } from "../../common/types";
|
||||
import type { S3Score } from "./types";
|
||||
import type { Difficulties, Playtypes, Versions } from "tachi-common";
|
||||
import type { GetEnumValue } from "tachi-common/types/metrics";
|
||||
import type { EmptyObject } from "utils/types";
|
||||
|
||||
export function ParseDifficulty(diff: S3Score["diff"]): {
|
||||
|
||||
@@ -76,7 +76,7 @@ export default async function UpdateScore(
|
||||
logger.verbose("Received Update Score request.");
|
||||
|
||||
// eslint-disable-next-line require-atomic-updates
|
||||
newScore.calculatedData = CreateScoreCalcData(newScore, chart);
|
||||
newScore.calculatedData = CreateScoreCalcData(newScore.game, newScore.scoreData, chart);
|
||||
|
||||
try {
|
||||
// Having _id defined will cause this to throw, causing it to not apply
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import db from "external/mongo/db";
|
||||
import { GetGPTConfig } from "tachi-common";
|
||||
import { GetFolderChartIDs } from "utils/folder";
|
||||
import type {
|
||||
integer,
|
||||
ShowcaseStatDetails,
|
||||
GPTString,
|
||||
ShowcaseStatChart,
|
||||
ShowcaseStatDetails,
|
||||
ShowcaseStatFolder,
|
||||
integer,
|
||||
} from "tachi-common";
|
||||
|
||||
export function EvaluateShowcaseStat(
|
||||
gpt: GPTString,
|
||||
details: ShowcaseStatDetails,
|
||||
userID: integer
|
||||
): Promise<{
|
||||
@@ -16,9 +19,9 @@ export function EvaluateShowcaseStat(
|
||||
}> {
|
||||
switch (details.mode) {
|
||||
case "chart":
|
||||
return EvaluateShowcaseChartStat(details, userID);
|
||||
return EvaluateShowcaseChartStat(gpt, details, userID);
|
||||
case "folder":
|
||||
return EvaluateShowcaseFolderStat(details, userID);
|
||||
return EvaluateShowcaseFolderStat(gpt, details, userID);
|
||||
|
||||
default:
|
||||
// @ts-expect-error This should never happen anyway -- this ignore ignores a 'never' result.
|
||||
@@ -26,13 +29,17 @@ export function EvaluateShowcaseStat(
|
||||
}
|
||||
}
|
||||
|
||||
async function EvaluateShowcaseChartStat(details: ShowcaseStatChart, userID: integer) {
|
||||
async function EvaluateShowcaseChartStat(
|
||||
gpt: GPTString,
|
||||
details: ShowcaseStatChart,
|
||||
userID: integer
|
||||
) {
|
||||
// requires special handling
|
||||
if (details.property === "playcount") {
|
||||
if (details.metric === "playcount") {
|
||||
return { value: await db.scores.count({ chartID: details.chartID, userID }) };
|
||||
}
|
||||
|
||||
const mongoProp = PropToMongoProp(details.property);
|
||||
const mongoProp = PropToMongoProp(gpt, details.metric);
|
||||
|
||||
const pb = await db["personal-bests"].findOne(
|
||||
{ chartID: details.chartID, userID },
|
||||
@@ -43,12 +50,30 @@ async function EvaluateShowcaseChartStat(details: ShowcaseStatChart, userID: int
|
||||
return { value: null };
|
||||
}
|
||||
|
||||
const scProp = PropToScoreDataProp(details.property);
|
||||
const metric = details.metric;
|
||||
|
||||
return { value: pb.scoreData[scProp] };
|
||||
const gptConfig = GetGPTConfig(gpt);
|
||||
|
||||
const scoreMetricConfig = gptConfig.providedMetrics[metric] ?? gptConfig.derivedMetrics[metric];
|
||||
|
||||
if (!scoreMetricConfig) {
|
||||
throw new Error(`Invalid metric of ${metric} passed for game ${gpt}.`);
|
||||
}
|
||||
|
||||
if (scoreMetricConfig.type === "ENUM") {
|
||||
// @ts-expect-error guaranteed to be correct
|
||||
return { value: pb.scoreData.enumIndexes[metric] };
|
||||
}
|
||||
|
||||
// @ts-expect-error guaranteed to be correct
|
||||
return { value: pb.scoreData[metric] };
|
||||
}
|
||||
|
||||
async function EvaluateShowcaseFolderStat(details: ShowcaseStatFolder, userID: integer) {
|
||||
async function EvaluateShowcaseFolderStat(
|
||||
gpt: GPTString,
|
||||
details: ShowcaseStatFolder,
|
||||
userID: integer
|
||||
) {
|
||||
let chartIDs;
|
||||
|
||||
if (Array.isArray(details.folderID)) {
|
||||
@@ -57,7 +82,7 @@ async function EvaluateShowcaseFolderStat(details: ShowcaseStatFolder, userID: i
|
||||
chartIDs = await GetFolderChartIDs(details.folderID);
|
||||
}
|
||||
|
||||
const mongoProp = PropToMongoProp(details.property);
|
||||
const mongoProp = PropToMongoProp(gpt, details.metric);
|
||||
|
||||
const value = await db["personal-bests"].count({
|
||||
userID,
|
||||
@@ -70,28 +95,18 @@ async function EvaluateShowcaseFolderStat(details: ShowcaseStatFolder, userID: i
|
||||
return { value, outOf: chartIDs.length };
|
||||
}
|
||||
|
||||
function PropToMongoProp(prop: "grade" | "lamp" | "percent" | "score") {
|
||||
switch (prop) {
|
||||
case "score":
|
||||
return "scoreData.score";
|
||||
case "lamp":
|
||||
return "scoreData.lampIndex";
|
||||
case "grade":
|
||||
return "scoreData.gradeIndex";
|
||||
case "percent":
|
||||
return [`scoreData.${gptConfig.defaultMetric}`];
|
||||
}
|
||||
}
|
||||
function PropToMongoProp(gpt: GPTString, metric: string) {
|
||||
const gptConfig = GetGPTConfig(gpt);
|
||||
|
||||
function PropToScoreDataProp(prop: "grade" | "lamp" | "percent" | "score") {
|
||||
switch (prop) {
|
||||
case "score":
|
||||
return "score";
|
||||
case "lamp":
|
||||
return "lampIndex";
|
||||
case "grade":
|
||||
return "gradeIndex";
|
||||
case "percent":
|
||||
return "percent";
|
||||
const scoreMetricConfig = gptConfig.providedMetrics[metric] ?? gptConfig.derivedMetrics[metric];
|
||||
|
||||
if (!scoreMetricConfig) {
|
||||
throw new Error(`Invalid metric of ${metric} passed for game ${gpt}.`);
|
||||
}
|
||||
|
||||
if (scoreMetricConfig.type === "ENUM") {
|
||||
return `scoreData.enumIndexes.${metric}`;
|
||||
}
|
||||
|
||||
return `scoreData.${metric}`;
|
||||
}
|
||||
|
||||
@@ -31,13 +31,13 @@ t.test("#EvalulateUsersStatsShowcase", (t) => {
|
||||
{
|
||||
folderID: TestingIIDXFolderSP10.folderID,
|
||||
mode: "folder",
|
||||
property: "lamp",
|
||||
metric: "lamp",
|
||||
gte: IIDX_LAMPS.HARD_CLEAR,
|
||||
},
|
||||
{
|
||||
chartID: Testing511SPA.chartID,
|
||||
mode: "chart",
|
||||
property: "score",
|
||||
metric: "score",
|
||||
},
|
||||
],
|
||||
gameSpecific: {
|
||||
|
||||
@@ -2,7 +2,8 @@ import { EvaluateShowcaseStat } from "./evaluator";
|
||||
import { GetRelatedStatDocuments } from "./get-related";
|
||||
import db from "external/mongo/db";
|
||||
import CreateLogCtx from "lib/logger/logger";
|
||||
import type { integer, Game, Playtype, ShowcaseStatDetails } from "tachi-common";
|
||||
import { GetGPTString } from "tachi-common";
|
||||
import type { integer, Game, Playtype, ShowcaseStatDetails, GPTString } from "tachi-common";
|
||||
|
||||
const logger = CreateLogCtx(__filename);
|
||||
|
||||
@@ -34,16 +35,23 @@ export async function EvaluateUsersStatsShowcase(
|
||||
);
|
||||
}
|
||||
|
||||
const gpt = GetGPTString(game, playtype);
|
||||
|
||||
const results = await Promise.all(
|
||||
settings.preferences.stats.map((details) => EvaluateStats(details, userID, game))
|
||||
settings.preferences.stats.map((details) => EvaluateStats(gpt, details, userID, game))
|
||||
);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
async function EvaluateStats(details: ShowcaseStatDetails, userID: integer, game: Game) {
|
||||
async function EvaluateStats(
|
||||
gpt: GPTString,
|
||||
details: ShowcaseStatDetails,
|
||||
userID: integer,
|
||||
game: Game
|
||||
) {
|
||||
const [result, related] = await Promise.all([
|
||||
EvaluateShowcaseStat(details, userID),
|
||||
EvaluateShowcaseStat(gpt, details, userID),
|
||||
GetRelatedStatDocuments(details, game),
|
||||
]);
|
||||
|
||||
|
||||
@@ -18,19 +18,19 @@ t.test("#RemoveStaleFolderShowcaseStats", (t) => {
|
||||
{
|
||||
mode: "chart",
|
||||
chartID: "foo",
|
||||
property: "grade",
|
||||
metric: "grade",
|
||||
},
|
||||
{
|
||||
mode: "folder",
|
||||
folderID: "REMOVED_FOLDER",
|
||||
gte: 1,
|
||||
property: "lamp",
|
||||
metric: "lamp",
|
||||
},
|
||||
{
|
||||
mode: "folder",
|
||||
folderID: "NORMAL_FOLDER",
|
||||
gte: 1,
|
||||
property: "lamp",
|
||||
metric: "lamp",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -42,13 +42,13 @@ t.test("#RemoveStaleFolderShowcaseStats", (t) => {
|
||||
{
|
||||
mode: "chart",
|
||||
chartID: "foo",
|
||||
property: "grade",
|
||||
metric: "grade",
|
||||
},
|
||||
{
|
||||
mode: "folder",
|
||||
folderID: "REMOVED_FOLDER",
|
||||
gte: 1,
|
||||
property: "lamp",
|
||||
metric: "lamp",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import db from "external/mongo/db";
|
||||
import { FormatGame, GetGamePTConfig, GetSpecificGPTConfig } from "tachi-common";
|
||||
import { FormatGame, GetGPTString, GetGamePTConfig, GetSpecificGPTConfig } from "tachi-common";
|
||||
import { GetFolderForIDGuaranteed, HumaniseChartID } from "utils/db";
|
||||
import { GetFolderChartIDs } from "utils/folder";
|
||||
import { FormatMaxDP, HumanisedJoinArray } from "utils/misc";
|
||||
@@ -11,7 +11,9 @@ export async function CreateGoalTitle(
|
||||
game: Game,
|
||||
playtype: Playtype
|
||||
) {
|
||||
const formattedCriteria = FormatCriteria(criteria, game, playtype);
|
||||
const gptString = GetGPTString(game, playtype);
|
||||
|
||||
const formattedCriteria = FormatCriteria(criteria, gptString);
|
||||
|
||||
const datasetName = await FormatCharts(charts, criteria, game);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import db from "external/mongo/db";
|
||||
import fjsh from "fast-json-stable-hash";
|
||||
import { SubscribeFailReasons } from "lib/constants/err-codes";
|
||||
import CreateLogCtx from "lib/logger/logger";
|
||||
import { FormatGame, GenericFormatGradeDelta, GetGamePTConfig } from "tachi-common";
|
||||
import { FormatGame, GetGamePTConfig } from "tachi-common";
|
||||
import { GetFolderChartIDs } from "utils/folder";
|
||||
import { IsNullish } from "utils/misc";
|
||||
import type { KtLogger } from "lib/logger/logger";
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import bcrypt from "bcryptjs";
|
||||
import db from "external/mongo/db";
|
||||
import CreateLogCtx from "lib/logger/logger";
|
||||
import { Environment, ServerConfig } from "lib/setup/config";
|
||||
import { ServerConfig } from "lib/setup/config";
|
||||
import { p } from "prudence";
|
||||
import { UserAuthLevels } from "tachi-common";
|
||||
import nodeFetch from "utils/fetch";
|
||||
import { Random20Hex } from "utils/misc";
|
||||
import { CreateURLWithParams } from "utils/url";
|
||||
import { FormatUserDoc } from "utils/user";
|
||||
import type { integer, UserDocument, UserSettings } from "tachi-common";
|
||||
import type { integer, UserDocument, UserSettingsDocument } from "tachi-common";
|
||||
import type { PrivateUserInfoDocument } from "utils/types";
|
||||
|
||||
const logger = CreateLogCtx(__filename);
|
||||
@@ -60,7 +60,7 @@ export async function AddNewInvite(user: UserDocument) {
|
||||
return result;
|
||||
}
|
||||
|
||||
export const DEFAULT_USER_SETTINGS: UserSettings["preferences"] = {
|
||||
export const DEFAULT_USER_SETTINGS: UserSettingsDocument["preferences"] = {
|
||||
developerMode: false,
|
||||
advancedMode: false,
|
||||
invisible: false,
|
||||
@@ -87,7 +87,6 @@ export async function AddNewUser(
|
||||
username,
|
||||
usernameLowercase: username.toLowerCase(),
|
||||
about: "I'm a fairly nondescript person.",
|
||||
clan: null,
|
||||
socialMedia: {},
|
||||
status: null,
|
||||
customBannerLocation: null,
|
||||
@@ -119,13 +118,13 @@ export function InsertPrivateUserInfo(userID: integer, hashedPassword: string, e
|
||||
|
||||
export function InsertDefaultUserSettings(userID: integer) {
|
||||
logger.verbose(`Inserting default settings for ${userID}.`);
|
||||
const userSettings: UserSettings = {
|
||||
const UserSettingsDocument: UserSettingsDocument = {
|
||||
userID,
|
||||
following: [],
|
||||
preferences: DEFAULT_USER_SETTINGS,
|
||||
};
|
||||
|
||||
return db["user-settings"].insert(userSettings);
|
||||
return db["user-settings"].insert(UserSettingsDocument);
|
||||
}
|
||||
|
||||
export async function ValidateCaptcha(
|
||||
@@ -168,7 +167,11 @@ export async function ValidateCaptcha(
|
||||
return gcr.success;
|
||||
}
|
||||
|
||||
export function MountAuthCookie(req: Express.Request, user: UserDocument, settings: UserSettings) {
|
||||
export function MountAuthCookie(
|
||||
req: Express.Request,
|
||||
user: UserDocument,
|
||||
settings: UserSettingsDocument
|
||||
) {
|
||||
req.session.tachi = {
|
||||
user,
|
||||
settings,
|
||||
|
||||
@@ -13,7 +13,7 @@ import db from "external/mongo/db";
|
||||
import { SendEmail } from "lib/email/client";
|
||||
import { EmailFormatResetPassword, EmailFormatVerifyEmail } from "lib/email/formats";
|
||||
import CreateLogCtx from "lib/logger/logger";
|
||||
import { Environment, ServerConfig, TachiConfig } from "lib/setup/config";
|
||||
import { Environment, ServerConfig } from "lib/setup/config";
|
||||
import { p } from "prudence";
|
||||
import prValidate from "server/middleware/prudence-validate";
|
||||
import {
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { Router } from "express";
|
||||
import { GetPBsForJubility } from "lib/score-import/framework/calculated-data/profile";
|
||||
import { GetPBsForJubility } from "game-implementations/games/jubeat";
|
||||
import { GetRelevantSongsAndCharts } from "utils/db";
|
||||
import { GetUser } from "utils/req-tachi-data";
|
||||
|
||||
|
||||
+2
-3
@@ -4,8 +4,7 @@ import db from "external/mongo/db";
|
||||
import CreateLogCtx from "lib/logger/logger";
|
||||
import { p } from "prudence";
|
||||
import { RequirePermissions } from "server/middleware/auth";
|
||||
import { GetGamePTConfig } from "tachi-common";
|
||||
import { PR_GAMESPECIFIC_SETTINGS } from "tachi-common/lib/schemas";
|
||||
import { GetGamePTConfig, PrudenceZodShim } from "tachi-common";
|
||||
import { FormatPrError, optNull } from "utils/prudence";
|
||||
import { GetUGPT } from "utils/req-tachi-data";
|
||||
import { FormatUserDoc } from "utils/user";
|
||||
@@ -31,7 +30,7 @@ router.patch(
|
||||
|
||||
const gptConfig = GetGamePTConfig(game, playtype);
|
||||
|
||||
const gameSpecificSchema = PR_GAMESPECIFIC_SETTINGS(game);
|
||||
const gameSpecificSchema = PrudenceZodShim(gptConfig.preferences);
|
||||
|
||||
const err = p(req.safeBody, {
|
||||
preferredScoreAlg: p.optional(p.nullable(p.isIn(gptConfig.scoreRatingAlgs))),
|
||||
|
||||
+3
-3
@@ -30,13 +30,13 @@ const SetFolders = async () => {
|
||||
{
|
||||
folderID: TestingIIDXFolderSP10.folderID,
|
||||
mode: "folder",
|
||||
property: "lamp",
|
||||
metric: "lamp",
|
||||
gte: IIDX_LAMPS.HARD_CLEAR,
|
||||
},
|
||||
{
|
||||
chartID: Testing511SPA.chartID,
|
||||
mode: "chart",
|
||||
property: "score",
|
||||
metric: "score",
|
||||
},
|
||||
],
|
||||
gameSpecific: {
|
||||
@@ -96,7 +96,7 @@ t.test("GET /api/v1/users/:userID/games/:game/:playtype/showcase", (t) => {
|
||||
{
|
||||
mode: "folder",
|
||||
folderID: TestingIIDXFolderSP10.folderID,
|
||||
property: "score",
|
||||
metric: "score",
|
||||
gte: 1480,
|
||||
},
|
||||
],
|
||||
|
||||
+6
-4
@@ -6,7 +6,7 @@ import { EvaluateUsersStatsShowcase } from "lib/showcase/get-stats";
|
||||
import { p } from "prudence";
|
||||
import { RequirePermissions } from "server/middleware/auth";
|
||||
import { RequireAuthedAsUser } from "server/router/api/v1/users/_userID/middleware";
|
||||
import { FormatGame, GetGamePTConfig } from "tachi-common";
|
||||
import { FormatGame, GetGPTString, GetGamePTConfig } from "tachi-common";
|
||||
import { IsRecord } from "utils/misc";
|
||||
import { FormatPrError } from "utils/prudence";
|
||||
import { GetUGPT } from "utils/req-tachi-data";
|
||||
@@ -103,7 +103,7 @@ router.get("/custom", async (req, res) => {
|
||||
|
||||
stat = {
|
||||
mode: "folder",
|
||||
property: req.query.property as "grade" | "lamp" | "percent" | "score",
|
||||
metric: req.query.property as "grade" | "lamp" | "percent" | "score",
|
||||
folderID,
|
||||
gte: Number(req.query.gte),
|
||||
};
|
||||
@@ -137,7 +137,7 @@ router.get("/custom", async (req, res) => {
|
||||
|
||||
stat = {
|
||||
mode: "chart",
|
||||
property: req.query.property as "grade" | "lamp" | "percent" | "playcount" | "score",
|
||||
metric: req.query.property as "grade" | "lamp" | "percent" | "playcount" | "score",
|
||||
chartID: req.query.chartID as string,
|
||||
};
|
||||
} else {
|
||||
@@ -147,7 +147,9 @@ router.get("/custom", async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const result = await EvaluateShowcaseStat(stat, user.id);
|
||||
const gpt = GetGPTString(game, playtype);
|
||||
|
||||
const result = await EvaluateShowcaseStat(gpt, stat, user.id);
|
||||
|
||||
const related = await GetRelatedStatDocuments(stat, game);
|
||||
|
||||
|
||||
@@ -830,7 +830,6 @@ export const FakeOtherUser: UserDocument = {
|
||||
about: "",
|
||||
authLevel: 0,
|
||||
badges: [],
|
||||
clan: null,
|
||||
customBannerLocation: null,
|
||||
customPfpLocation: null,
|
||||
joinDate: 0,
|
||||
|
||||
@@ -40,7 +40,7 @@ export async function RecalcAllScores(filter = {}) {
|
||||
modifiedUsers.add(`${c.game}-${c.playtype}-${c.userID}`);
|
||||
modifiedUserIDs.add(c.userID);
|
||||
|
||||
const calculatedData = CreateScoreCalcData(c, chart);
|
||||
const calculatedData = CreateScoreCalcData(c.game, c.scoreData, chart);
|
||||
|
||||
return { scoreID: c.scoreID, calculatedData };
|
||||
},
|
||||
|
||||
@@ -43,11 +43,7 @@ export function FilterChartsAndSongs(
|
||||
}
|
||||
|
||||
export function GetScoreIDsFromComposed(pb: PBScoreDocument) {
|
||||
const arr = [pb.composedFrom.lampPB, pb.composedFrom.scorePB];
|
||||
|
||||
if (pb.composedFrom.other) {
|
||||
arr.push(...pb.composedFrom.other.map((e) => e.scoreID));
|
||||
}
|
||||
const arr = pb.composedFrom.map((e) => e.scoreID);
|
||||
|
||||
return DedupeArr(arr);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user