Return a users most recently used imports on an endpoint.

Fixes #642
This commit is contained in:
zkldi
2022-02-01 15:43:04 +00:00
parent c67e908bf9
commit ef43ae35fb
2 changed files with 125 additions and 3 deletions
@@ -1,9 +1,11 @@
import db from "external/mongo/db";
import { UserGameStats } from "tachi-common";
import { ONE_DAY, ONE_YEAR } from "lib/constants/time";
import { UserGameStats, ImportTypes, ImportDocument, Game } from "tachi-common";
import t from "tap";
import { CreateFakeAuthCookie } from "test-utils/fake-auth";
import mockApi from "test-utils/mock-api";
import ResetDBState from "test-utils/resets";
import { Random20Hex } from "utils/misc";
import { PasswordCompare } from "../../auth/auth";
t.test("GET /api/v1/users/:userID", (t) => {
@@ -368,3 +370,90 @@ t.test("GET /api/v1/users/:userID/game-stats", (t) => {
t.end();
});
t.test("GET /api/v1/users/:userID/recent-imports", async (t) => {
t.beforeEach(ResetDBState);
function mkImport(
game: Game,
importType: ImportTypes,
timeFinished: number,
userIntent: boolean
): ImportDocument {
return {
classDeltas: [],
createdSessions: [],
errors: [],
game,
importType,
importID: Random20Hex(),
goalInfo: [],
idStrings: [],
milestoneInfo: [],
playtypes: [],
scoreIDs: [],
timeFinished,
timeStarted: 0,
userID: 1,
userIntent,
};
}
t.test("Should work cross game and ignore imports without userIntent.", async (t) => {
await db.imports.insert([
mkImport("iidx", "api/arc-iidx", Date.now() - ONE_DAY, true),
mkImport("iidx", "api/arc-iidx", Date.now() - ONE_DAY, true),
mkImport("sdvx", "api/arc-sdvx", Date.now() - ONE_DAY, false),
mkImport("iidx", "api/arc-iidx", Date.now() - ONE_DAY, false),
mkImport("sdvx", "api/arc-sdvx", Date.now() - ONE_DAY, true),
]);
const res = await mockApi.get("/api/v1/users/1/recent-imports");
t.equal(res.statusCode, 200);
t.strictSame(res.body.body, [
{
importType: "api/arc-iidx",
count: 2,
},
{
importType: "api/arc-sdvx",
count: 1,
},
]);
t.end();
});
t.test("Should ignore imports that were too long ago.", async (t) => {
await db.imports.insert([
mkImport("iidx", "api/arc-iidx", Date.now() - ONE_DAY, true),
mkImport("iidx", "ir/fervidex", Date.now() - ONE_YEAR, true),
mkImport("iidx", "ir/fervidex", Date.now() - ONE_YEAR, true),
mkImport("iidx", "ir/fervidex", Date.now() - ONE_YEAR, true),
mkImport("iidx", "ir/fervidex", Date.now() - ONE_YEAR, true),
mkImport("sdvx", "api/arc-sdvx", Date.now() - ONE_DAY, true),
mkImport("sdvx", "api/arc-sdvx", Date.now() - ONE_DAY, true),
]);
const res = await mockApi.get("/api/v1/users/1/recent-imports");
t.equal(res.statusCode, 200);
t.strictSame(res.body.body, [
{
importType: "api/arc-sdvx",
count: 2,
},
{
importType: "api/arc-iidx",
count: 1,
},
]);
t.end();
});
t.end();
});
@@ -1,12 +1,13 @@
import { Router } from "express";
import db from "external/mongo/db";
import { SYMBOL_TachiData } from "lib/constants/tachi";
import { ONE_MONTH } from "lib/constants/time";
import CreateLogCtx from "lib/logger/logger";
import p from "prudence";
import prValidate from "server/middleware/prudence-validate";
import { UserGameStats } from "tachi-common";
import { ImportTypes, integer, UserGameStats } from "tachi-common";
import { DeleteUndefinedProps, StripUrl } from "utils/misc";
import { optNull, optNullFluffStrField } from "utils/prudence";
import { optNullFluffStrField } from "utils/prudence";
import {
GetRecentlyViewedFoldersAnyGPT,
GetRecentPlaycount,
@@ -341,6 +342,38 @@ router.post(
}
);
/**
* Get the recent import types this user has used.
*/
router.get("/recent-imports", async (req, res) => {
const user = req[SYMBOL_TachiData]!.requestedUser!;
const recentImports = (await db.imports.aggregate([
{
$match: {
userID: user.id,
timeFinished: { $gt: Date.now() - ONE_MONTH },
userIntent: true,
},
},
{
$group: {
_id: "$importType",
count: { $sum: 1 },
},
},
])) as { _id: ImportTypes; count: integer }[];
// rename _id to importType.
const imports = recentImports.map((e) => ({ importType: e._id, count: e.count }));
return res.status(200).json({
success: true,
description: `Found ${recentImports.length} imports.`,
body: imports.sort((a, b) => b.count - a.count),
});
});
router.use("/games/:game/:playtype", gamePTRouter);
router.use("/pfp", pfpRouter);
router.use("/banner", bannerRouter);