diff --git a/server/package.json b/server/package.json index e89012acd..fbde78867 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.8", + "tachi-common": "0.7.9", "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 1534ed770..61cdaa85f 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.8 + tachi-common: 0.7.9 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.8 + tachi-common: 0.7.9 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.8: - resolution: {integrity: sha512-rDT+scIl1WQacdPrEIvM7fenRvkdjEQwMJMBDz1Pf/VQoYvyBeRL0rxjHrd26L8qkg1yPhwVKhs9DZUMnt4QzA==} + /tachi-common/0.7.9: + resolution: {integrity: sha512-q6JMyACbHb7rDSGPv+cZZHZP1XxyQIvuhnQU5jRKYQfn4LkMm6ticHUN7gjSNAVHnwR05VQnulrkc+SOcnn3nQ==} dependencies: '@types/mongodb': 3.6.18 dev: false diff --git a/server/src/server/router/api/v1/games/_game/_playtype/targets/goals/router.ts b/server/src/server/router/api/v1/games/_game/_playtype/targets/goals/router.ts index f30571f43..0d24f0a59 100644 --- a/server/src/server/router/api/v1/games/_game/_playtype/targets/goals/router.ts +++ b/server/src/server/router/api/v1/games/_game/_playtype/targets/goals/router.ts @@ -26,9 +26,7 @@ router.get("/recently-achieved", async (req, res) => { game, playtype, achieved: true, - // exclude stuff where timeAchieved == timeSet, as they're not really - // goals but rather consequences of milestone assignment. - $expr: { $ne: ["$timeAchieved", "$timeSet"] }, + wasInstantlyAchieved: false, }, { sort: { diff --git a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/folders/_folderID/router.ts b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/folders/_folderID/router.ts index a22964c41..7631870e5 100644 --- a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/folders/_folderID/router.ts +++ b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/folders/_folderID/router.ts @@ -4,6 +4,7 @@ import { SYMBOL_TachiData } from "lib/constants/tachi"; import { FilterQuery } from "mongodb"; import { GetGamePTConfig, ScoreDocument } from "tachi-common"; import { GetFolderCharts, GetGradeLampDistributionForFolder, GetPBsOnFolder } from "utils/folder"; +import { GetUGPT } from "utils/req-tachi-data"; import { ParseStrPositiveInt } from "utils/string-checks"; import { GetFolderFromParam } from "../../../../../../../games/_game/_playtype/folders/middleware"; import { RequireSelfRequestFromUser } from "../../../../../middleware"; @@ -18,7 +19,8 @@ router.use(GetFolderFromParam); * @name GET /api/v1/users/:userID/games/:game/:playtype/folders/:folderID */ router.get("/", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; + const { user } = GetUGPT(req); + const folder = req[SYMBOL_TachiData]!.folderDoc!; const { songs, charts, pbs } = await GetPBsOnFolder(user.id, folder); @@ -41,8 +43,9 @@ router.get("/", async (req, res) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/folders/:folderID/stats */ router.get("/stats", async (req, res) => { + const { user } = GetUGPT(req); + const folder = req[SYMBOL_TachiData]!.folderDoc!; - const user = req[SYMBOL_TachiData]!.requestedUser!; const stats = await GetGradeLampDistributionForFolder(user.id, folder); @@ -64,7 +67,8 @@ router.get("/stats", async (req, res) => { * @name POST /api/v1/users/:userID/games/:game/:playtype/folders/:folderID/viewed */ router.post("/viewed", RequireSelfRequestFromUser, async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; + const { user } = GetUGPT(req); + const folder = req[SYMBOL_TachiData]!.folderDoc!; await db["recent-folder-views"].update( @@ -101,10 +105,9 @@ router.post("/viewed", RequireSelfRequestFromUser, async (req, res) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/folders/:folderID/timeline */ router.get("/timeline", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; + const { user, game, playtype } = GetUGPT(req); + const folder = req[SYMBOL_TachiData]!.folderDoc!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; const gptConfig = GetGamePTConfig(game, playtype); const intIndex = ParseStrPositiveInt(req.query.criteriaValue); diff --git a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/folders/router.ts b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/folders/router.ts index 343a5cf25..e02f0195f 100644 --- a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/folders/router.ts +++ b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/folders/router.ts @@ -4,6 +4,7 @@ import { SYMBOL_TachiData } from "lib/constants/tachi"; import { SearchCollection } from "lib/search/search"; import { GetGradeLampDistributionForFolders, GetRecentlyViewedFolders } from "utils/folder"; import { IsString } from "utils/misc"; +import { GetUGPT } from "utils/req-tachi-data"; import folderIDRouter from "./_folderID/router"; const router: Router = Router({ mergeParams: true }); @@ -21,9 +22,7 @@ const router: Router = Router({ mergeParams: true }); * @name GET /api/v1/users/:userID/games/:game/:playtype/folders */ router.get("/", async (req, res) => { - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; - const user = req[SYMBOL_TachiData]!.requestedUser!; + const { game, playtype, user } = GetUGPT(req); if (!IsString(req.query.search)) { return res.status(400).json({ @@ -60,9 +59,7 @@ router.get("/", async (req, res) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/folders/recent */ router.get("/recent", async (req, res) => { - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; - const user = req[SYMBOL_TachiData]!.requestedUser!; + const { game, playtype, user } = GetUGPT(req); const { views, folders } = await GetRecentlyViewedFolders(user.id, game, playtype); diff --git a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/pbs/router.ts b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/pbs/router.ts index 3e3889062..037b5c64e 100644 --- a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/pbs/router.ts +++ b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/pbs/router.ts @@ -6,6 +6,7 @@ import { GetGamePTConfig } from "tachi-common"; import { GetRelevantSongsAndCharts } from "utils/db"; import { IsValidScoreAlg } from "utils/misc"; import { GetAdjacentAbove, GetAdjacentBelow } from "utils/queries/pbs"; +import { GetUGPT } from "utils/req-tachi-data"; import { FilterChartsAndSongs, GetScoreIDsFromComposed } from "utils/scores"; import { GetUsersWithIDs } from "utils/user"; @@ -19,9 +20,7 @@ const router: Router = Router({ mergeParams: true }); * @name GET /api/v1/users/:userID/games/:game/:playtype/pbs */ router.get("/", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); if (typeof req.query.search !== "string") { return res.status(400).json({ @@ -71,9 +70,7 @@ router.get("/", async (req, res) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/pbs/all */ router.get("/all", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); const pbs = await db["personal-bests"].find({ userID: user.id, @@ -99,9 +96,8 @@ router.get("/all", async (req, res) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/pbs/best */ router.get("/best", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); + const gptConfig = GetGamePTConfig(game, playtype); if (req.query.alg && !IsValidScoreAlg(gptConfig, req.query.alg)) { @@ -152,9 +148,7 @@ router.get("/best", async (req, res) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/pbs/:chartID */ router.get("/:chartID", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); const chart = await db.charts[game].findOne({ chartID: req.params.chartID, @@ -215,9 +209,7 @@ router.get("/:chartID", async (req, res) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/pbs/:chartID/leaderboard-adjacent */ router.get("/:chartID/leaderboard-adjacent", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); const chart = await db.charts[game].findOne({ chartID: req.params.chartID, diff --git a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/router.ts b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/router.ts index 63dad1226..ee0a19d12 100644 --- a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/router.ts +++ b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/router.ts @@ -3,6 +3,7 @@ import db from "external/mongo/db"; import { SYMBOL_TachiData } from "lib/constants/tachi"; import { GetGamePTConfig, integer, PBScoreDocument, UserGameStatsSnapshot } from "tachi-common"; import { IsString } from "utils/misc"; +import { GetUGPT } from "utils/req-tachi-data"; import { CheckStrProfileAlg } from "utils/string-checks"; import { GetAllRankings, @@ -29,10 +30,9 @@ router.use(CheckUserPlayedGamePlaytype); * @name GET /api/v1/users/:userID/games/:game/:playtype */ router.get("/", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; + const { game, playtype, user } = GetUGPT(req); + const stats = req[SYMBOL_TachiData]!.requestedUserGameStats!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; const [totalScores, firstScore, mostRecentScore, rankingData] = await Promise.all([ db.scores.count({ @@ -87,10 +87,9 @@ router.get("/", async (req, res) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/history */ router.get("/history", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; + const { game, playtype, user } = GetUGPT(req); + const stats = req[SYMBOL_TachiData]!.requestedUserGameStats!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; const snapshots = (await db["game-stats-snapshots"].find( { @@ -133,9 +132,7 @@ router.get("/history", async (req, res) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/most-played */ router.get("/most-played", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { game, playtype, user } = GetUGPT(req); const mostPlayed: { playcount: integer; songID: integer; _id: string }[] = await db.scores.aggregate([ @@ -208,10 +205,9 @@ router.get("/most-played", async (req, res) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/leaderboard-adjacent */ router.get("/leaderboard-adjacent", async (req, res) => { - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { game, playtype, user } = GetUGPT(req); + const gptConfig = GetGamePTConfig(game, playtype); - const user = req[SYMBOL_TachiData]!.requestedUser!; let alg = gptConfig.defaultProfileRatingAlg; if (IsString(req.query.alg)) { diff --git a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/scores/router.ts b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/scores/router.ts index 9c1eaa46c..5cfc28dd7 100644 --- a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/scores/router.ts +++ b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/scores/router.ts @@ -3,6 +3,7 @@ import db from "external/mongo/db"; import { SYMBOL_TachiData } from "lib/constants/tachi"; import { SearchGameSongsAndCharts } from "lib/search/search"; import { GetRelevantSongsAndCharts } from "utils/db"; +import { GetUGPT } from "utils/req-tachi-data"; import { FilterChartsAndSongs } from "utils/scores"; const router: Router = Router({ mergeParams: true }); @@ -13,9 +14,7 @@ const router: Router = Router({ mergeParams: true }); * @name GET /api/v1/users/:userID/games/:game/:playtype/scores */ router.get("/", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); if (typeof req.query.search !== "string") { return res.status(400).json({ @@ -62,9 +61,7 @@ router.get("/", async (req, res) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/scores/recent */ router.get("/recent", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); const recentScores = await db.scores.find( { @@ -99,9 +96,7 @@ router.get("/recent", async (req, res) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/scores/:chartID */ router.get("/:chartID", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); const chart = await db.charts[game].findOne({ chartID: req.params.chartID, diff --git a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/sessions/router.ts b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/sessions/router.ts index e2f540cea..77a68fc9b 100644 --- a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/sessions/router.ts +++ b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/sessions/router.ts @@ -13,9 +13,8 @@ const router: Router = Router({ mergeParams: true }); * @name GET /api/v1/users/:userID/games/:game/:playtype/sessions */ router.get("/", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); + if (typeof req.query.search !== "string") { return res.status(400).json({ @@ -41,9 +40,8 @@ router.get("/", async (req, res) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/sessions/best */ router.get("/best", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); + const gptConfig = GetGamePTConfig(game, playtype); let alg = gptConfig.defaultSessionRatingAlg; @@ -89,9 +87,8 @@ router.get("/best", async (req, res) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/sessions/highlighted */ router.get("/highlighted", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); + const sessions = await db.sessions.find( { userID: user.id, game, playtype, highlight: true }, @@ -111,9 +108,8 @@ router.get("/highlighted", async (req, res) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/sessions/recent */ router.get("/recent", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); + const sessions = await db.sessions.find( { userID: user.id, game, playtype }, @@ -133,9 +129,8 @@ router.get("/recent", async (req, res) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/sessions/last */ router.get("/last", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); + const session = await db.sessions.findOne( { userID: user.id, game, playtype }, diff --git a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/settings/router.ts b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/settings/router.ts index f6c1fde0d..1800e532c 100644 --- a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/settings/router.ts +++ b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/settings/router.ts @@ -6,6 +6,7 @@ import p from "prudence"; import { RequirePermissions } from "server/middleware/auth"; import { GetGamePTConfig } from "tachi-common"; import { FormatPrError, optNull } from "utils/prudence"; +import { GetUGPT } from "utils/req-tachi-data"; import { FormatUserDoc } from "utils/user"; import { RequireAuthedAsUser } from "../../../../middleware"; @@ -25,9 +26,7 @@ router.patch( RequireAuthedAsUser, RequirePermissions("customise_profile"), async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); const gptConfig = GetGamePTConfig(game, playtype); @@ -170,9 +169,7 @@ router.patch( * @name GET /api/v1/users/:userID/games/:game/:playtype/settings */ router.get("/", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); const settings = await db["game-settings"].findOne({ userID: user.id, diff --git a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/showcase/router.ts b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/showcase/router.ts index f2189279e..d26c6d748 100644 --- a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/showcase/router.ts +++ b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/showcase/router.ts @@ -9,6 +9,7 @@ import { RequirePermissions } from "server/middleware/auth"; import { RequireAuthedAsUser } from "server/router/api/v1/users/_userID/middleware"; import { GetGamePTConfig, ShowcaseStatDetails } from "tachi-common"; import { FormatPrError } from "utils/prudence"; +import { GetUGPT } from "utils/req-tachi-data"; import { ResolveUser } from "utils/user"; const router: Router = Router({ mergeParams: true }); @@ -20,9 +21,7 @@ const router: Router = Router({ mergeParams: true }); * @name GET /api/v1/users/:userID/games/:game/:playtype/showcase */ router.get("/", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); let projectUser; @@ -60,9 +59,7 @@ router.get("/", async (req, res) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/showcase/custom */ router.get("/custom", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); let stat: ShowcaseStatDetails; @@ -164,9 +161,7 @@ router.get("/custom", async (req, res) => { * @name PUT /api/v1/users/:userID/games/:game/:playtype/showcase */ router.put("/", RequireAuthedAsUser, RequirePermissions("customise_profile"), async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); const gptConfig = GetGamePTConfig(game, playtype); diff --git a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/tables/router.ts b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/tables/router.ts index b811916ab..c4f10feb3 100644 --- a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/tables/router.ts +++ b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/tables/router.ts @@ -1,6 +1,7 @@ import { Router } from "express"; import { SYMBOL_TachiData } from "lib/constants/tachi"; import { GetFoldersFromTable, GetGradeLampDistributionForFolders } from "utils/folder"; +import { GetUGPT } from "utils/req-tachi-data"; // @todo maybe refactor where middleware is stored to avoid paths this ugly. import { GetTableFromParam } from "../../../../../../games/_game/_playtype/tables/middleware"; @@ -12,8 +13,9 @@ const router: Router = Router({ mergeParams: true }); * @name GET /api/v1/users/:userID/games/:game/:playtype/tables/:tableID */ router.get("/:tableID", GetTableFromParam, async (req, res) => { + const { user } = GetUGPT(req); + const table = req[SYMBOL_TachiData]!.tableDoc!; - const user = req[SYMBOL_TachiData]!.requestedUser!; const folders = await GetFoldersFromTable(table); 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 dc69e0eed..698f58e65 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 @@ -7,7 +7,7 @@ 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 { AssignToReqTachiData, GetUGPT } from "utils/req-tachi-data"; import { GetGoalForIDGuaranteed, GetMilestoneForIDGuaranteed } from "utils/db"; import { RequireAuthedAsUser } from "../../../../../middleware"; import { SubscribeFailReasons } from "lib/constants/err-codes"; @@ -23,9 +23,7 @@ const logger = CreateLogCtx(__filename); * @name GET /api/v1/users/:userID/games/:game/:playtype/targets/goals */ router.get("/", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); const goalSubs = await db["goal-subs"].find({ userID: user.id, @@ -127,9 +125,7 @@ router.post( }, }), async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); const existingGoalsCount = await db["goal-subs"].count({ userID: user.id, @@ -188,9 +184,7 @@ router.post( ); const GetGoalSubscription: RequestHandler = async (req, res, next) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); const goalSub = await db["goal-subs"].findOne({ userID: user.id, @@ -217,7 +211,8 @@ const GetGoalSubscription: RequestHandler = async (req, res, next) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/targets/goals/:goalID */ router.get("/:goalID", GetGoalSubscription, async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; + const { user } = GetUGPT(req); + const goalSub = req[SYMBOL_TachiData]!.goalSubDoc!; let milestones: MilestoneDocument[] = []; @@ -255,9 +250,7 @@ router.delete( prValidate({ goalID: "string" }), async (req, res) => { const goalID = req.params.goalID; - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); const goalSub = await db["goal-subs"].findOne({ goalID, diff --git a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/milestones/router.ts b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/milestones/router.ts index 6ec77b3b3..376209e02 100644 --- a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/milestones/router.ts +++ b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/milestones/router.ts @@ -10,7 +10,7 @@ import { UnsubscribeFromMilestone, } from "lib/targets/milestones"; import { RequirePermissions } from "server/middleware/auth"; -import { AssignToReqTachiData } from "utils/req-tachi-data"; +import { AssignToReqTachiData, GetUGPT } from "utils/req-tachi-data"; import { FormatUserDoc } from "utils/user"; import { RequireAuthedAsUser } from "../../../../../middleware"; @@ -24,9 +24,7 @@ const router: Router = Router({ mergeParams: true }); * @name GET /api/v1/users/:userID/games/:game/:playtype/targets/milestones */ router.get("/", async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); const milestoneSubs = await db["milestone-subs"].find({ userID: user.id, @@ -49,9 +47,7 @@ router.get("/", async (req, res) => { }); const GetMilestoneSubscription: RequestHandler = async (req, res, next) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); const milestoneSub = await db["milestone-subs"].findOne({ userID: user.id, @@ -101,7 +97,8 @@ const GetMilestone: RequestHandler = async (req, res, next) => { * @name GET /api/v1/users/:userID/games/:game/:playtype/targets/milestones/:milestoneID */ router.get("/:milestoneID", GetMilestone, GetMilestoneSubscription, async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; + const { user } = GetUGPT(req); + const milestoneSub = req[SYMBOL_TachiData]!.milestoneSubDoc!; const milestone = req[SYMBOL_TachiData]!.milestoneDoc!; @@ -134,9 +131,7 @@ router.put( GetMilestone, RequirePermissions("manage_targets"), async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; - const game = req[SYMBOL_TachiData]!.game!; - const playtype = req[SYMBOL_TachiData]!.playtype!; + const { user, game, playtype } = GetUGPT(req); const existingMilestonesCount = await db["milestone-subs"].count({ userID: user.id, @@ -200,7 +195,7 @@ router.delete( GetMilestone, RequirePermissions("manage_targets"), async (req, res) => { - const user = req[SYMBOL_TachiData]!.requestedUser!; + const { user } = GetUGPT(req); const milestone = req[SYMBOL_TachiData]!.milestoneDoc!; logger.info( diff --git a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/router.ts b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/router.ts index 9ba386131..842e2aa9b 100644 --- a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/router.ts +++ b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/router.ts @@ -1,10 +1,137 @@ import { Router } from "express"; +import db from "external/mongo/db"; +import { SYMBOL_TachiData } from "lib/constants/tachi"; +import { GetUGPT } from "utils/req-tachi-data"; import goalsRouter from "./goals/router"; import milestonesRouter from "./milestones/router"; const router: Router = Router({ mergeParams: true }); +/** + * Return a user's recently achieved goals and milestones. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/targets/recently-achieved + */ +router.get("/recently-achieved", async (req, res) => { + const { game, playtype, user } = GetUGPT(req); + + const userID = user.id; + + const recentlyAchievedGoalSubs = await db["goal-subs"].find( + { + game, + playtype, + achieved: true, + wasInstantlyAchieved: false, + userID, + }, + { + sort: { + timeAchieved: -1, + }, + limit: 50, + } + ); + + const recentlyAchievedMilestoneSubs = await db["milestone-subs"].find( + { + game, + playtype, + achieved: true, + wasInstantlyAchieved: false, + userID, + }, + { + sort: { + timeAchieved: -1, + }, + limit: 10, + } + ); + + const goals = await db.goals.find({ + goalID: { $in: recentlyAchievedGoalSubs.map((e) => e.goalID) }, + }); + + const milestones = await db.milestones.find({ + milestoneID: { $in: recentlyAchievedMilestoneSubs.map((e) => e.milestoneID) }, + }); + + return res.status(200).json({ + success: true, + description: `Returned ${user.username}'s recently achieved targets.`, + body: { + goals, + milestones, + goalSubs: recentlyAchievedGoalSubs, + milestoneSubs: recentlyAchievedMilestoneSubs, + user, + }, + }); +}); + +/** + * Returns a user's recently interacted with (raised, etc.) goals and milestones. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/targets/recently-interacted + */ +router.get("/recently-interacted", async (req, res) => { + const { game, playtype, user } = GetUGPT(req); + + const userID = user.id; + + const recentlyAchievedGoalSubs = await db["goal-subs"].find( + { + game, + playtype, + wasInstantlyAchieved: false, + userID, + lastInteraction: { $ne: null }, + }, + { + sort: { + lastInteraction: -1, + }, + limit: 50, + } + ); + + const recentlyAchievedMilestoneSubs = await db["milestone-subs"].find( + { + game, + playtype, + wasInstantlyAchieved: false, + userID, + }, + { + sort: { + lastInteraction: -1, + }, + limit: 10, + } + ); + + const goals = await db.goals.find({ + goalID: { $in: recentlyAchievedGoalSubs.map((e) => e.goalID) }, + }); + + const milestones = await db.milestones.find({ + milestoneID: { $in: recentlyAchievedMilestoneSubs.map((e) => e.milestoneID) }, + }); + + return res.status(200).json({ + success: true, + description: `Returned ${user.username}'s recently achieved targets.`, + body: { + goals, + milestones, + goalSubs: recentlyAchievedGoalSubs, + milestoneSubs: recentlyAchievedMilestoneSubs, + user, + }, + }); +}); + router.use("/goals", goalsRouter); -router.use("/milestones", milestonesRouter); export default router; diff --git a/server/src/utils/req-tachi-data.ts b/server/src/utils/req-tachi-data.ts index 8cf867399..c287486a6 100644 --- a/server/src/utils/req-tachi-data.ts +++ b/server/src/utils/req-tachi-data.ts @@ -2,6 +2,7 @@ import { SYMBOL_TachiData } from "lib/constants/tachi"; import { Request } from "express"; import { TachiRequestData } from "./types"; import deepmerge from "deepmerge"; +import CreateLogCtx from "lib/logger/logger"; export function AssignToReqTachiData(req: Request, data: Partial) { if (!req[SYMBOL_TachiData]) { @@ -10,3 +11,40 @@ export function AssignToReqTachiData(req: Request, data: Partial