From 73c7011e89d66cb164da82baf9ef51eae157e2cd Mon Sep 17 00:00:00 2001 From: zkldi <20380519+zkldi@users.noreply.github.com> Date: Wed, 30 Mar 2022 04:18:43 +0100 Subject: [PATCH] Refactor to my slightly unhinged push/pull parentMilestones system --- server/package.json | 2 +- server/pnpm-lock.yaml | 8 ++-- .../framework/goals/goals.test.ts | 8 +--- server/src/lib/targets/goals.ts | 7 ++-- server/src/lib/targets/milestones.ts | 40 ++++++++++++------- .../_game/_playtype/targets/goals/router.ts | 21 +++++----- server/src/test-utils/test-data.ts | 4 +- 7 files changed, 49 insertions(+), 41 deletions(-) diff --git a/server/package.json b/server/package.json index 29b19fb05..191f87408 100644 --- a/server/package.json +++ b/server/package.json @@ -84,7 +84,7 @@ "rimraf": "3.0.2", "safe-json-stringify": "1.2.0", "seq-logging": "1.1.1", - "tachi-common": "0.7.6", + "tachi-common": "0.7.7", "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 a2871c6c0..ff0e79f75 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.7.6 + tachi-common: 0.7.7 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.6 + tachi-common: 0.7.7 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.6: - resolution: {integrity: sha512-stdhYYWvHMGmaqnIszmymAbIhwZcMXXXP4hhosayZzCaWlzZENqXA21wAwrFn+BiazWpTLdSn46KP+94Jg06OA==} + /tachi-common/0.7.7: + resolution: {integrity: sha512-WsV4bCKdhackC24aTt7vdJTz/IEdRHiSm3+NeDWlU3AOmdMQV8YTcMCjeNscTr4yoccjpRNNG/avs+h/fFLDeg==} dependencies: '@types/mongodb': 3.6.18 dev: false diff --git a/server/src/lib/score-import/framework/goals/goals.test.ts b/server/src/lib/score-import/framework/goals/goals.test.ts index 935ec6d99..a19c60483 100644 --- a/server/src/lib/score-import/framework/goals/goals.test.ts +++ b/server/src/lib/score-import/framework/goals/goals.test.ts @@ -131,9 +131,7 @@ t.test("#GetRelevantGoals", (t) => { progressHuman: "NO DATA", timeSet: Date.now(), userID: 1, - from: { - origin: "manual", - }, + parentMilestones: [], })) ); }); @@ -196,9 +194,7 @@ t.test("#UpdateGoalsForUser", (t) => { timeAchieved: null, timeSet: 0, userID: 1, - from: { - origin: "manual", - }, + parentMilestones: [], }; t.test("Should correctly update goals when user achieves goal.", async (t) => { diff --git a/server/src/lib/targets/goals.ts b/server/src/lib/targets/goals.ts index b2c820585..fb8dd594f 100644 --- a/server/src/lib/targets/goals.ts +++ b/server/src/lib/targets/goals.ts @@ -7,7 +7,6 @@ import { Game, GetGamePTConfig, GoalDocument, - GoalOrigin, integer, PBScoreDocument, Playtypes, @@ -284,7 +283,7 @@ export async function ConstructGoal( export async function SubscribeToGoal( userID: integer, goalDocument: GoalDocument, - origin: GoalOrigin, + parentMilestone?: string, cancelIfAchieved = true ) { const goalExists = await db.goals.findOne({ goalID: goalDocument.goalID }); @@ -324,7 +323,9 @@ export async function SubscribeToGoal( lastInteraction: Date.now(), timeAchieved: result.achieved ? Date.now() : null, timeSet: Date.now(), - from: origin, + // if this goal subscription came from a milestone, add the milestone to + // the list of parents. + parentMilestones: parentMilestone ? [parentMilestone] : [], game: goalDocument.game, playtype: goalDocument.playtype, goalID: goalDocument.goalID, diff --git a/server/src/lib/targets/milestones.ts b/server/src/lib/targets/milestones.ts index 210d57359..b99fae9e9 100644 --- a/server/src/lib/targets/milestones.ts +++ b/server/src/lib/targets/milestones.ts @@ -221,14 +221,11 @@ export async function SubscribeToMilestone( // evaluating goals is fairly cheap though. await Promise.all( result.goals.map(async (goal) => { - const res = await SubscribeToGoal( - userID, - goal, - { milestoneID: milestone.milestoneID, origin: "milestone" }, - false - ); + const res = await SubscribeToGoal(userID, goal, milestone.milestoneID, false); - // If the user is already subscribed to this goal, maybe manually + // If the user is already subscribed to this goal -- i.e. manually or as part + // of another milestone + // add this milestoneID to the list of parents instead. if (res === SubscribeFailReasons.ALREADY_SUBSCRIBED) { await db["goal-subs"].update( { @@ -236,9 +233,8 @@ export async function SubscribeToMilestone( milestoneID: milestone.milestoneID, }, { - $set: { - origin: "milestone", - milestoneID: milestone.milestoneID, + $push: { + parentMilestones: milestone.milestoneID, }, } ); @@ -256,16 +252,30 @@ export async function SubscribeToMilestone( export async function UnsubscribeFromMilestone(userID: integer, milestone: MilestoneDocument) { const goalIDs = GetGoalIDsFromMilestone(milestone); - // Remove all attached goals subs to this milestone. - // This is a bit of a pain, since it means users can remove goals they legitimately - // have assigned on their own by subscribing to a milestone that also has that goal - // then unsubscribing. - // ah well. + // Pull this milestone ID from all of the goalSubscriptions that have it. + // since it's no longer going to be their parent. + await db["goal-subs"].update( + { + goalID: { $in: goalIDs }, + userID, + parentMilestones: milestone.milestoneID, + }, + { + $pull: { + parentMilestones: milestone.milestoneID, + }, + } + ); + + // then, remove all of the ones that now have no parent blocking their demise. + // that's pretty morbid, jesus christ. await db["goal-subs"].remove({ goalID: { $in: goalIDs }, userID, + parentMilestones: { $size: 0 }, }); + // remove the user's milestone sub, aswell. await db["milestone-subs"].remove({ userID, milestoneID: milestone.milestoneID, diff --git a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.ts b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.ts index 44fab8802..387c4348e 100644 --- a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.ts +++ b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.ts @@ -3,13 +3,14 @@ import db from "external/mongo/db"; import { SYMBOL_TachiData } from "lib/constants/tachi"; import prValidate from "server/middleware/prudence-validate"; import p from "prudence"; -import { GoalDocument } from "tachi-common"; -import { ConstructGoal, SubscribeFailReasons, SubscribeToGoal } from "lib/targets/goals"; +import { GoalDocument, MilestoneDocument } from "tachi-common"; +import { ConstructGoal, SubscribeToGoal } from "lib/targets/goals"; import CreateLogCtx from "lib/logger/logger"; import { RequirePermissions } from "server/middleware/auth"; import { AssignToReqTachiData } from "utils/req-tachi-data"; import { GetGoalForIDGuaranteed, GetMilestoneForIDGuaranteed } from "utils/db"; import { RequireAuthedAsUser } from "../../../../../middleware"; +import { SubscribeFailReasons } from "lib/constants/err-codes"; const router: Router = Router({ mergeParams: true }); @@ -158,7 +159,7 @@ router.post( }); } - const goalSub = await SubscribeToGoal(user.id, goal, { origin: "manual" }); + const goalSub = await SubscribeToGoal(user.id, goal); if (goalSub === SubscribeFailReasons.ALREADY_SUBSCRIBED) { return res.status(409).json({ @@ -218,10 +219,12 @@ router.get("/:goalID", GetGoalSubscription, async (req, res) => { const user = req[SYMBOL_TachiData]!.requestedUser!; const goalSub = req[SYMBOL_TachiData]!.goalSubDoc!; - let milestone = null; + let milestones: MilestoneDocument[] = []; - if (goalSub.from.origin === "milestone") { - milestone = await GetMilestoneForIDGuaranteed(goalSub.from.milestoneID); + if (goalSub.parentMilestones.length !== 0) { + milestones = await Promise.all( + goalSub.parentMilestones.map((e) => GetMilestoneForIDGuaranteed(e)) + ); } const goal = await GetGoalForIDGuaranteed(goalSub.goalID); @@ -232,7 +235,7 @@ router.get("/:goalID", GetGoalSubscription, async (req, res) => { body: { goal, goalSub, - milestone, + milestones, user, }, }); @@ -269,10 +272,10 @@ router.delete( }); } - if (goalSub.from.origin === "milestone") { + if (goalSub.parentMilestones.length) { return res.status(400).json({ success: false, - description: `This goal is from a milestone. You can't remove it directly, only by removing the parent milestone.`, + description: `This goal is part of a milestone you are subscribed to. It can only be removed by unsubscribing from the relevant milestones.`, }); } diff --git a/server/src/test-utils/test-data.ts b/server/src/test-utils/test-data.ts index 020ed3413..b40ff3703 100644 --- a/server/src/test-utils/test-data.ts +++ b/server/src/test-utils/test-data.ts @@ -436,9 +436,7 @@ export const HC511UserGoal: GoalSubscriptionDocument = { progressHuman: "NO DATA", timeSet: 0, userID: 1, - from: { - origin: "manual", - }, + parentMilestones: [], }; export const TestingIIDXFolderSP10: FolderDocument = {