diff --git a/src/controllers/api/customObstacleCourseLeaderboardController.ts b/src/controllers/api/customObstacleCourseLeaderboardController.ts new file mode 100644 index 00000000..9b768def --- /dev/null +++ b/src/controllers/api/customObstacleCourseLeaderboardController.ts @@ -0,0 +1,48 @@ +import { getJSONfromString } from "@/src/helpers/stringHelpers"; +import { Guild } from "@/src/models/guildModel"; +import { getAccountForRequest } from "@/src/services/loginService"; +import { logger } from "@/src/utils/logger"; +import { RequestHandler } from "express"; + +export const customObstacleCourseLeaderboardController: RequestHandler = async (req, res) => { + const data = getJSONfromString(String(req.body)); + const guild = (await Guild.findById(data.g, "DojoComponents"))!; + const component = guild.DojoComponents.id(data.c)!; + if (req.query.act == "f") { + res.json({ + results: component.Leaderboard ?? [] + }); + } else if (req.query.act == "p") { + const account = await getAccountForRequest(req); + component.Leaderboard ??= []; + const entry = component.Leaderboard.find(x => x.n == account.DisplayName); + if (entry) { + entry.s = data.s!; + } else { + component.Leaderboard.push({ + s: data.s!, + n: account.DisplayName, + r: 0 + }); + } + component.Leaderboard.sort((a, b) => a.s - b.s); // In this case, the score is the time in milliseconds, so smaller is better. + if (component.Leaderboard.length > 10) { + component.Leaderboard.shift(); + } + let r = 0; + for (const entry of component.Leaderboard) { + entry.r = ++r; + } + await guild.save(); + res.status(200).end(); + } else { + logger.debug(`data provided to ${req.path}: ${String(req.body)}`); + throw new Error(`unknown customObstacleCourseLeaderboard act: ${String(req.query.act)}`); + } +}; + +interface ICustomObstacleCourseLeaderboardRequest { + g: string; + c: string; + s?: number; // act=p +} diff --git a/src/models/guildModel.ts b/src/models/guildModel.ts index d0f7c501..bfd3e4d3 100644 --- a/src/models/guildModel.ts +++ b/src/models/guildModel.ts @@ -9,7 +9,8 @@ import { IGuildRank, IGuildLogRoomChange, IGuildLogEntryRoster, - IGuildLogEntryContributable + IGuildLogEntryContributable, + IDojoLeaderboardEntry } from "@/src/types/guildTypes"; import { Document, Model, model, Schema, Types } from "mongoose"; import { fusionTreasuresSchema, typeCountSchema } from "./inventoryModels/inventoryModel"; @@ -25,6 +26,15 @@ const dojoDecoSchema = new Schema({ RushPlatinum: Number }); +const dojoLeaderboardEntrySchema = new Schema( + { + s: Number, + r: Number, + n: String + }, + { _id: false } +); + const dojoComponentSchema = new Schema({ pf: { type: String, required: true }, ppf: String, @@ -40,7 +50,8 @@ const dojoComponentSchema = new Schema({ RushPlatinum: Number, DestructionTime: Date, Decos: [dojoDecoSchema], - DecoCapacity: Number + DecoCapacity: Number, + Leaderboard: { type: [dojoLeaderboardEntrySchema], default: undefined } }); const techProjectSchema = new Schema( diff --git a/src/routes/api.ts b/src/routes/api.ts index e2f1dbea..6489cfc8 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -24,6 +24,7 @@ import { contributeToVaultController } from "@/src/controllers/api/contributeToV import { createGuildController } from "@/src/controllers/api/createGuildController"; import { creditsController } from "@/src/controllers/api/creditsController"; import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController"; +import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController"; import { declineGuildInviteController } from "@/src/controllers/api/declineGuildInviteController"; import { deleteSessionController } from "@/src/controllers/api/deleteSessionController"; import { destroyDojoDecoController } from "@/src/controllers/api/destroyDojoDecoController"; @@ -183,6 +184,7 @@ apiRouter.post("/contributeToDojoComponent.php", contributeToDojoComponentContro apiRouter.post("/contributeToVault.php", contributeToVaultController); apiRouter.post("/createGuild.php", createGuildController); apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController); +apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController); apiRouter.post("/destroyDojoDeco.php", destroyDojoDecoController); apiRouter.post("/dojoComponentRush.php", dojoComponentRushController); apiRouter.post("/drones.php", dronesController); diff --git a/src/types/guildTypes.ts b/src/types/guildTypes.ts index 7d10b57d..da444a2b 100644 --- a/src/types/guildTypes.ts +++ b/src/types/guildTypes.ts @@ -152,6 +152,7 @@ export interface IDojoComponentDatabase CompletionLogPending?: boolean; DestructionTime?: Date; Decos?: IDojoDecoDatabase[]; + Leaderboard?: IDojoLeaderboardEntry[]; } export interface IDojoDecoClient { @@ -212,3 +213,9 @@ export interface IGuildLogEntryNumber { entryType: number; details: number; } + +export interface IDojoLeaderboardEntry { + s: number; // score + r: number; // rank + n: string; // displayName +}