diff --git a/server/CHANGELOG.md b/server/CHANGELOG.md index 08c4cc5c2..7786e6cd6 100644 --- a/server/CHANGELOG.md +++ b/server/CHANGELOG.md @@ -15,6 +15,16 @@ not generally be shown to end users. # Changelog +# 2.1.9 + +- [ENH] Add an endpoint on UGPT/folder/:folderID/stats. This returns lamp and grade distributions for this ugpt:folder combo. +- [ENH] The UGPT Folder timeline endpoint now also returns the folder it worked on. + +***** + +- [BUG] OAuth2 tokens are now properly expired. +- [BUG] ForceStaticImport is no longer always on, even if off. + # 2.1.4 - [BUG] IIDX, BMS and PMS scores can no longer get an invalid grade if they are exactly 77.7777...% diff --git a/server/package.json b/server/package.json index 51ba8f90b..57b983f5f 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "tachi-server", - "version": "2.1.8", + "version": "2.1.9", "description": "A score tracking server.", "main": "js/index.js", "private": true, diff --git a/server/src/lib/constants/version.ts b/server/src/lib/constants/version.ts index b905797e0..c39914d46 100644 --- a/server/src/lib/constants/version.ts +++ b/server/src/lib/constants/version.ts @@ -4,7 +4,7 @@ const MAJOR = 2; const MINOR = 1; -const PATCH = 8; +const PATCH = 9; // As is with all front-facing zkldi projects, the version names for tachi-server // are from an album I like. In this case, the album is Portishead - Dummy. @@ -34,6 +34,4 @@ export const VERSION_INFO = { export const VERSION_STR = `${MAJOR}.${MINOR}.${PATCH}`; -export function FormatVersion() { - return `v${VERSION_STR} (${VERSION_INFO.name})`; -} +export const VERSION_PRETTY = `v${VERSION_STR} (${VERSION_INFO.name})`; diff --git a/server/src/main.ts b/server/src/main.ts index 0d83e16e8..f600ab784 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -10,6 +10,7 @@ import fs from "fs"; import http from "http"; import https from "https"; import { LoadDefaultClients } from "lib/builtin-clients/builtin-clients"; +import { VERSION_PRETTY } from "lib/constants/version"; import { HandleSIGTERMGracefully } from "lib/handlers/sigterm"; import CreateLogCtx from "lib/logger/logger"; import { Environment, ServerConfig, TachiConfig } from "lib/setup/config"; @@ -17,11 +18,10 @@ import path from "path"; import server from "server/server"; import fetch from "utils/fetch"; import { InitaliseFolderChartLookup } from "utils/folder"; -import { FormatVersion } from "./lib/constants/version"; const logger = CreateLogCtx(__filename); -logger.info(`Booting ${TachiConfig.NAME} - ${FormatVersion()} [ENV: ${Environment.nodeEnv}]`, { +logger.info(`Booting ${TachiConfig.NAME} - ${VERSION_PRETTY} [ENV: ${Environment.nodeEnv}]`, { bootInfo: true, }); logger.info(`Log level is set to ${ServerConfig.LOGGER_CONFIG.LOG_LEVEL}.`, { bootInfo: true }); diff --git a/server/src/server/router/api/v1/status/router.test.ts b/server/src/server/router/api/v1/status/router.test.ts index 2b7e67156..48cf61256 100644 --- a/server/src/server/router/api/v1/status/router.test.ts +++ b/server/src/server/router/api/v1/status/router.test.ts @@ -1,4 +1,4 @@ -import { FormatVersion } from "lib/constants/version"; +import { VERSION_PRETTY } from "lib/constants/version"; import { CreateFakeAuthCookie } from "test-utils/fake-auth"; import mockApi from "test-utils/mock-api"; import t from "tap"; @@ -16,7 +16,7 @@ t.test("GET /api/v1/status", async (t) => { "Should be roughly the current time (5 seconds lenience)" ); t.type(res.body.body.startTime, "number", "Should return a number for startTime."); - t.equal(res.body.body.version, FormatVersion()); + t.equal(res.body.body.version, VERSION_PRETTY); t.equal(res.body.body.whoami, 1); t.end(); @@ -33,7 +33,7 @@ t.test("GET /api/v1/status", async (t) => { "Should be roughly the current time (5 seconds lenience)" ); t.type(res.body.body.startTime, "number", "Should return a number for startTime."); - t.equal(res.body.body.version, FormatVersion()); + t.equal(res.body.body.version, VERSION_PRETTY); t.equal(res.body.body.whoami, 1); t.end(); @@ -54,7 +54,7 @@ t.test("POST /api/v1/status", async (t) => { Math.abs(Date.now() - res.body.body.serverTime) < 5_000, "Should be roughly the current time (5 seconds lenience)" ); - t.equal(res.body.body.version, FormatVersion()); + t.equal(res.body.body.version, VERSION_PRETTY); t.equal(res.body.body.whoami, 1); t.type(res.body.body.startTime, "number", "Should return a number for startTime."); @@ -73,7 +73,7 @@ t.test("POST /api/v1/status", async (t) => { Math.abs(Date.now() - res.body.body.serverTime) < 5_000, "Should be roughly the current time (5 seconds lenience)" ); - t.equal(res.body.body.version, FormatVersion()); + t.equal(res.body.body.version, VERSION_PRETTY); t.equal(res.body.body.whoami, 1); t.type(res.body.body.startTime, "number", "Should return a number for startTime."); diff --git a/server/src/server/router/api/v1/status/router.ts b/server/src/server/router/api/v1/status/router.ts index 4a37e8d6c..970bc0120 100644 --- a/server/src/server/router/api/v1/status/router.ts +++ b/server/src/server/router/api/v1/status/router.ts @@ -1,6 +1,6 @@ import { Router } from "express"; import { SYMBOL_TachiAPIAuth } from "lib/constants/tachi"; -import { FormatVersion } from "lib/constants/version"; +import { VERSION_PRETTY } from "lib/constants/version"; const router: Router = Router({ mergeParams: true }); @@ -23,7 +23,7 @@ router.get("/", (req, res) => { body: { serverTime: Date.now(), startTime, - version: FormatVersion(), + version: VERSION_PRETTY, whoami: req[SYMBOL_TachiAPIAuth].userID, // converts {foo: true, bar: false, baz: true} into [foo, baz] permissions: Object.entries(req[SYMBOL_TachiAPIAuth].permissions) @@ -52,7 +52,7 @@ router.post("/", (req, res) => { body: { serverTime: Date.now(), startTime, - version: FormatVersion(), + version: VERSION_PRETTY, whoami: req[SYMBOL_TachiAPIAuth].userID, // converts {foo: true, bar: false, baz: true} into [foo, baz] permissions: Object.entries(req[SYMBOL_TachiAPIAuth].permissions) 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 a02e3b2eb..8c0712159 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 @@ -3,7 +3,7 @@ import db from "external/mongo/db"; import { SYMBOL_TachiData } from "lib/constants/tachi"; import { FilterQuery } from "mongodb"; import { GetGamePTConfig, ScoreDocument } from "tachi-common"; -import { GetFolderCharts, GetPBsOnFolder } from "utils/folder"; +import { GetFolderCharts, GetGradeLampDistributionForFolder, GetPBsOnFolder } from "utils/folder"; import { ParseStrPositiveInt } from "utils/string-checks"; import { GetFolderFromParam } from "../../../../../../../games/_game/_playtype/folders/middleware"; import { RequireSelfRequestFromUser } from "../../../../../middleware"; @@ -35,6 +35,27 @@ router.get("/", async (req, res) => { }); }); +/** + * Returns a users stats on this folder. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/folders/:folderID/stats + */ +router.get("/stats", async (req, res) => { + const folder = req[SYMBOL_TachiData]!.folderDoc!; + const user = req[SYMBOL_TachiData]!.requestedUser!; + + const stats = await GetGradeLampDistributionForFolder(user.id, folder); + + return res.status(200).json({ + success: true, + description: `Returned statistics for ${folder.title}.`, + body: { + folder, + stats, + }, + }); +}); + /** * Add a folder to the list of recently-viewed folders. This can only * be performed by a session-level token, to stop rogue API keys from causing @@ -162,6 +183,7 @@ router.get("/timeline", async (req, res) => { songs, charts, scores, + folder, }, }); });