GPT Milestone Endpoints

This commit is contained in:
zkldi
2022-03-31 01:18:19 +01:00
parent ee86fb1af7
commit 4cfdecfded
7 changed files with 128 additions and 16 deletions
+1 -1
View File
@@ -84,7 +84,7 @@
"rimraf": "3.0.2",
"safe-json-stringify": "1.2.0",
"seq-logging": "1.1.1",
"tachi-common": "0.7.7",
"tachi-common": "0.7.8",
"ts-node": "10.4.0",
"tsconfig-paths": "3.12.0",
"typescript": "4.5.5",
+4 -4
View File
@@ -65,7 +65,7 @@ specifiers:
safe-json-stringify: 1.2.0
seq-logging: 1.1.1
supertest: 6.2.2
tachi-common: 0.7.7
tachi-common: 0.7.8
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.7.7
tachi-common: 0.7.8
ts-node: 10.4.0_2615db9039ce432b4abf2fc39ef336ec
tsconfig-paths: 3.12.0
typescript: 4.5.5
@@ -5363,8 +5363,8 @@ packages:
engines: {node: '>= 0.4'}
dev: true
/tachi-common/0.7.7:
resolution: {integrity: sha512-WsV4bCKdhackC24aTt7vdJTz/IEdRHiSm3+NeDWlU3AOmdMQV8YTcMCjeNscTr4yoccjpRNNG/avs+h/fFLDeg==}
/tachi-common/0.7.8:
resolution: {integrity: sha512-rDT+scIl1WQacdPrEIvM7fenRvkdjEQwMJMBDz1Pf/VQoYvyBeRL0rxjHrd26L8qkg1yPhwVKhs9DZUMnt4QzA==}
dependencies:
'@types/mongodb': 3.6.18
dev: false
+2 -9
View File
@@ -59,7 +59,7 @@ export function CalculateMilestoneOutOf(milestone: MilestoneDocument) {
if (milestone.criteria.type === "all") {
return goalIDs.length;
} else if (milestone.criteria.type === "abs") {
} else if (milestone.criteria.type === "total") {
if (milestone.criteria.value === null) {
throw new Error(
`Invalid milestone ${milestone.milestoneID} - abs and null are not compatible.`
@@ -67,17 +67,10 @@ export function CalculateMilestoneOutOf(milestone: MilestoneDocument) {
}
return milestone.criteria.value!;
} else if (milestone.criteria.type === "proportion") {
if (milestone.criteria.value === null) {
throw new Error(
`Invalid milestone ${milestone.milestoneID} - proportion and null are not compatible.`
);
}
return Math.floor(milestone.criteria.value * goalIDs.length);
}
throw new Error(
// @ts-expect-error Yeah obviously this shouldn't happen. Mayaswell throw though.
`Invalid milestone.criteria.type of ${milestone.criteria.type} -- milestoneID ${milestone.milestoneID}`
);
}
@@ -108,7 +108,7 @@ router.get("/:goalID", ResolveGoalID, async (req, res) => {
*
* @param userID - The userID to evaluate this goal against. Must be a player of this GPT.
*
* @name GET /api/v1/games/:game/:playtype/targets/goals/:goalID/evaluate
* @name GET /api/v1/games/:game/:playtype/targets/goals/:goalID/evaluate-for
*/
router.get(
"/:goalID/evaluate-for",
@@ -0,0 +1,117 @@
import { RequestHandler, Router } from "express";
import db from "external/mongo/db";
import { SYMBOL_TachiAPIAuth, SYMBOL_TachiData } from "lib/constants/tachi";
import { EvaluateMilestoneProgress, GetGoalsInMilestone } from "lib/targets/milestones";
import prValidate from "server/middleware/prudence-validate";
import { FormatGame } from "tachi-common";
import { AssignToReqTachiData } from "utils/req-tachi-data";
import { GetUsersWithIDs, ResolveUser } from "utils/user";
const router: Router = Router({ mergeParams: true });
const ResolveMilestoneID: RequestHandler = async (req, res, next) => {
const game = req[SYMBOL_TachiData]!.game!;
const playtype = req[SYMBOL_TachiData]!.playtype!;
const milestoneID = req.params.milestoneID;
const milestone = await db.milestones.findOne({
milestoneID,
game,
playtype,
});
if (!milestone) {
return res.status(404).json({
success: false,
description: `A milestone with ID ${milestoneID} doesn't exist.`,
});
}
AssignToReqTachiData(req, { milestoneDoc: milestone });
return next();
};
/**
* Retrieve information about this milestone and who is subscribed to it.
*
* @name GET /api/v1/games/:game/:playtype/targets/milestones/:milestoneID
*/
router.get("/:milestoneID", ResolveMilestoneID, async (req, res) => {
const milestone = req[SYMBOL_TachiData]!.milestoneDoc!;
const milestoneSubs = await db["milestone-subs"].find({
milestoneID: milestone.milestoneID,
});
const users = await GetUsersWithIDs(milestoneSubs.map((e) => e.userID));
const goals = await GetGoalsInMilestone(milestone);
return res.status(200).json({
success: true,
description: `Retrieved information about ${milestone.name}.`,
body: {
milestone,
milestoneSubs,
users,
goals,
},
});
});
/**
* Evaluates a milestone upon a user, even if they aren't subscribed to it.
*
* @param userID - The userID to evaluate this goal against. Must be a player of this GPT.
*
* @name GET /api/v1/games/:game/:playtype/targets/milestones/:milestone-id/evaluate-for
*/
router.get(
"/:milestoneID/evaluate-for",
ResolveMilestoneID,
prValidate({ userID: "string" }),
async (req, res) => {
const game = req[SYMBOL_TachiData]!.game!;
const playtype = req[SYMBOL_TachiData]!.playtype!;
const userID = req.query.userID as string;
const user = await ResolveUser(userID);
if (!user) {
return res.status(404).json({
success: false,
description: `The user ${userID} does not exist.`,
});
}
const hasPlayed = await db["game-stats"].findOne({
game,
playtype,
userID: user.id,
});
if (!hasPlayed) {
return res.status(400).json({
success: false,
description: `The user ${user.username} hasn't played ${FormatGame(
game,
playtype
)}.`,
});
}
const milestone = req[SYMBOL_TachiData]!.milestoneDoc!;
const milestoneProgress = await EvaluateMilestoneProgress(user.id, milestone);
return res.status(200).json({
success: true,
description: `Evaluated ${milestone.name} for ${user.username}.`,
body: milestoneProgress,
});
}
);
export default router;
@@ -1,8 +1,10 @@
import { Router } from "express";
import goalsRouter from "./goals/router";
import milestonesRouter from "./milestones/router";
const router: Router = Router({ mergeParams: true });
router.use("/goals", goalsRouter);
router.use("/milestones", milestonesRouter);
export default router;
@@ -18,7 +18,7 @@ const router: Router = Router({ mergeParams: true });
const logger = CreateLogCtx(__filename);
/**
* Retrieves this users' set goals.
* Retrieves this users' set goals for this GPT.
*
* @name GET /api/v1/users/:userID/games/:game/:playtype/targets/goals
*/