feat: clan motd (#1134)
All checks were successful
Build / build (22) (push) Successful in 39s
Build / build (18) (push) Successful in 1m0s
Build / build (20) (push) Successful in 1m3s
Build Docker image / docker (push) Successful in 34s

Reviewed-on: #1134
This commit is contained in:
Sainan 2025-03-09 07:47:32 -07:00
parent 814f4cfdad
commit 0ffa9c6bc4
8 changed files with 77 additions and 1 deletions

12
package-lock.json generated
View File

@ -10,6 +10,7 @@
"license": "GNU", "license": "GNU",
"dependencies": { "dependencies": {
"copyfiles": "^2.4.1", "copyfiles": "^2.4.1",
"crc-32": "^1.2.2",
"express": "^5", "express": "^5",
"mongoose": "^8.11.0", "mongoose": "^8.11.0",
"warframe-public-export-plus": "^0.5.42", "warframe-public-export-plus": "^0.5.42",
@ -1249,6 +1250,17 @@
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/crc-32": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
"integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
"bin": {
"crc32": "bin/crc32.njs"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/create-require": { "node_modules/create-require": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",

View File

@ -17,6 +17,7 @@
"@types/express": "^5", "@types/express": "^5",
"@types/morgan": "^1.9.9", "@types/morgan": "^1.9.9",
"copyfiles": "^2.4.1", "copyfiles": "^2.4.1",
"crc-32": "^1.2.2",
"express": "^5", "express": "^5",
"mongoose": "^8.11.0", "mongoose": "^8.11.0",
"morgan": "^1.10.0", "morgan": "^1.10.0",

View File

@ -26,6 +26,8 @@ const getGuildController: RequestHandler = async (req, res) => {
res.json({ res.json({
_id: toOid(guild._id), _id: toOid(guild._id),
Name: guild.Name, Name: guild.Name,
MOTD: guild.MOTD,
LongMOTD: guild.LongMOTD,
Members: [ Members: [
{ {
_id: { $oid: req.query.accountId }, _id: { $oid: req.query.accountId },

View File

@ -0,0 +1,30 @@
import { Guild } from "@/src/models/guildModel";
import { getInventory } from "@/src/services/inventoryService";
import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService";
import { RequestHandler } from "express";
export const setGuildMotdController: RequestHandler = async (req, res) => {
const account = await getAccountForRequest(req);
const inventory = await getInventory(account._id.toString());
const guild = (await Guild.findOne({ _id: inventory.GuildId! }))!;
// TODO: Check permissions
const IsLongMOTD = "longMOTD" in req.query;
const MOTD = req.body ? String(req.body) : undefined;
if (IsLongMOTD) {
if (MOTD) {
guild.LongMOTD = {
message: MOTD,
authorName: getSuffixedName(account)
};
} else {
guild.LongMOTD = undefined;
}
} else {
guild.MOTD = MOTD ?? "";
}
await guild.save();
res.json({ IsLongMOTD, MOTD });
};

View File

@ -3,7 +3,8 @@ import {
IDojoComponentDatabase, IDojoComponentDatabase,
ITechProjectDatabase, ITechProjectDatabase,
ITechProjectClient, ITechProjectClient,
IDojoDecoDatabase IDojoDecoDatabase,
ILongMOTD
} from "@/src/types/guildTypes"; } from "@/src/types/guildTypes";
import { Document, Model, model, Schema, Types } from "mongoose"; import { Document, Model, model, Schema, Types } from "mongoose";
import { fusionTreasuresSchema, typeCountSchema } from "./inventoryModels/inventoryModel"; import { fusionTreasuresSchema, typeCountSchema } from "./inventoryModels/inventoryModel";
@ -59,9 +60,19 @@ techProjectSchema.set("toJSON", {
} }
}); });
const longMOTDSchema = new Schema<ILongMOTD>(
{
message: String,
authorName: String
},
{ _id: false }
);
const guildSchema = new Schema<IGuildDatabase>( const guildSchema = new Schema<IGuildDatabase>(
{ {
Name: { type: String, required: true }, Name: { type: String, required: true },
MOTD: { type: String, default: "" },
LongMOTD: { type: longMOTDSchema, default: undefined },
DojoComponents: { type: [dojoComponentSchema], default: [] }, DojoComponents: { type: [dojoComponentSchema], default: [] },
DojoCapacity: { type: Number, default: 100 }, DojoCapacity: { type: Number, default: 100 },
DojoEnergy: { type: Number, default: 5 }, DojoEnergy: { type: Number, default: 5 },

View File

@ -79,6 +79,7 @@ import { setActiveShipController } from "@/src/controllers/api/setActiveShipCont
import { setBootLocationController } from "@/src/controllers/api/setBootLocationController"; import { setBootLocationController } from "@/src/controllers/api/setBootLocationController";
import { setDojoComponentMessageController } from "@/src/controllers/api/setDojoComponentMessageController"; import { setDojoComponentMessageController } from "@/src/controllers/api/setDojoComponentMessageController";
import { setEquippedInstrumentController } from "@/src/controllers/api/setEquippedInstrumentController"; import { setEquippedInstrumentController } from "@/src/controllers/api/setEquippedInstrumentController";
import { setGuildMotdController } from "@/src/controllers/api/setGuildMotdController";
import { setPlacedDecoInfoController } from "@/src/controllers/api/setPlacedDecoInfoController"; import { setPlacedDecoInfoController } from "@/src/controllers/api/setPlacedDecoInfoController";
import { setShipCustomizationsController } from "@/src/controllers/api/setShipCustomizationsController"; import { setShipCustomizationsController } from "@/src/controllers/api/setShipCustomizationsController";
import { setShipFavouriteLoadoutController } from "@/src/controllers/api/setShipFavouriteLoadoutController"; import { setShipFavouriteLoadoutController } from "@/src/controllers/api/setShipFavouriteLoadoutController";
@ -138,6 +139,7 @@ apiRouter.get("/queueDojoComponentDestruction.php", queueDojoComponentDestructio
apiRouter.get("/setActiveQuest.php", setActiveQuestController); apiRouter.get("/setActiveQuest.php", setActiveQuestController);
apiRouter.get("/setActiveShip.php", setActiveShipController); apiRouter.get("/setActiveShip.php", setActiveShipController);
apiRouter.get("/setBootLocation.php", setBootLocationController); apiRouter.get("/setBootLocation.php", setBootLocationController);
apiRouter.get("/setGuildMotd.php", setGuildMotdController);
apiRouter.get("/setSupportedSyndicate.php", setSupportedSyndicateController); apiRouter.get("/setSupportedSyndicate.php", setSupportedSyndicateController);
apiRouter.get("/startLibraryDailyTask.php", startLibraryDailyTaskController); apiRouter.get("/startLibraryDailyTask.php", startLibraryDailyTaskController);
apiRouter.get("/startLibraryPersonalTarget.php", startLibraryPersonalTargetController); apiRouter.get("/startLibraryPersonalTarget.php", startLibraryPersonalTargetController);
@ -197,6 +199,7 @@ apiRouter.post("/saveSettings.php", saveSettingsController);
apiRouter.post("/sell.php", sellController); apiRouter.post("/sell.php", sellController);
apiRouter.post("/setDojoComponentMessage.php", setDojoComponentMessageController); apiRouter.post("/setDojoComponentMessage.php", setDojoComponentMessageController);
apiRouter.post("/setEquippedInstrument.php", setEquippedInstrumentController); apiRouter.post("/setEquippedInstrument.php", setEquippedInstrumentController);
apiRouter.post("/setGuildMotd.php", setGuildMotdController);
apiRouter.post("/setPlacedDecoInfo.php", setPlacedDecoInfoController); apiRouter.post("/setPlacedDecoInfo.php", setPlacedDecoInfoController);
apiRouter.post("/setShipCustomizations.php", setShipCustomizationsController); apiRouter.post("/setShipCustomizations.php", setShipCustomizationsController);
apiRouter.post("/setShipFavouriteLoadout.php", setShipFavouriteLoadoutController); apiRouter.post("/setShipFavouriteLoadout.php", setShipFavouriteLoadoutController);

View File

@ -8,6 +8,7 @@ import { PersonalRooms } from "@/src/models/personalRoomsModel";
import { Request } from "express"; import { Request } from "express";
import { config } from "@/src/services/configService"; import { config } from "@/src/services/configService";
import { createStats } from "@/src/services/statsService"; import { createStats } from "@/src/services/statsService";
import crc32 from "crc-32";
export const isCorrectPassword = (requestPassword: string, databasePassword: string): boolean => { export const isCorrectPassword = (requestPassword: string, databasePassword: string): boolean => {
return requestPassword === databasePassword; return requestPassword === databasePassword;
@ -99,3 +100,11 @@ export const isAdministrator = (account: TAccountDocument): boolean => {
} }
return !!config.administratorNames.find(x => x == account.DisplayName); return !!config.administratorNames.find(x => x == account.DisplayName);
}; };
const platform_magics = [753, 639, 247, 37, 60];
export const getSuffixedName = (account: TAccountDocument): string => {
const name = account.DisplayName;
const platformId = 0;
const suffix = ((crc32.str(name.toLowerCase() + "595") >>> 0) + platform_magics[platformId]) % 1000;
return name + "#" + suffix.toString().padStart(3, "0");
};

View File

@ -5,6 +5,8 @@ import { IFusionTreasure, IMiscItem, ITypeCount } from "@/src/types/inventoryTyp
export interface IGuildDatabase { export interface IGuildDatabase {
_id: Types.ObjectId; _id: Types.ObjectId;
Name: string; Name: string;
MOTD: string;
LongMOTD?: ILongMOTD;
DojoComponents: IDojoComponentDatabase[]; DojoComponents: IDojoComponentDatabase[];
DojoCapacity: number; DojoCapacity: number;
@ -27,6 +29,12 @@ export interface IGuildDatabase {
CeremonyResetDate?: Date; CeremonyResetDate?: Date;
} }
export interface ILongMOTD {
message: string;
authorName: string;
//authorGuildName: "";
}
export interface IGuildVault { export interface IGuildVault {
DojoRefundRegularCredits?: number; DojoRefundRegularCredits?: number;
DojoRefundMiscItems?: IMiscItem[]; DojoRefundMiscItems?: IMiscItem[];