feat: guild log #1158

Closed
Master wants to merge 7 commits from (deleted):main into main
7 changed files with 188 additions and 10 deletions

View File

@ -0,0 +1,41 @@
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { getDojoClient, getGuildForRequest, getGuildLogForRequest } from "@/src/services/guildService";
import { IOid } from "@/src/types/commonTypes";
import { RequestHandler } from "express";
import { Types } from "mongoose";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
export const createGuildDojoController: RequestHandler = async (req, res) => {
const guild = await getGuildForRequest(req);
const guildLog = await getGuildLogForRequest(req);
const payload = getJSONfromString(String(req.body)) as ICreateGuildDojoRequest;
// Populate dojo info if not present
var componentId = new Types.ObjectId();
if (!guild.DojoComponents || guild.DojoComponents.length == 0) {
guild.DojoComponents?.push({
_id: componentId,
pf: payload.SpawnComponent.pf,
ppf: "",
CompletionTime: new Date(Date.now()),
DecoCapacity: 600
});
await guild.save();
guildLog.RoomChanges.push({
dateTime: new Date(Date.now()),
entryType: 1,
details: payload.SpawnComponent.pf
});
await guildLog.save();
}
res.json(await getDojoClient(guild, 0, componentId));
};
export interface ICreateGuildDojoRequest {
SpawnComponent: ICreateGuildDojoSpawnComponent;
}
export interface ICreateGuildDojoSpawnComponent {
id: IOid;
pf: string;
ppf: string;
}

View File

@ -1,11 +1,15 @@
import { getGuildForGuildId, getGuildLog } from "@/src/services/guildService";
import { getInventory } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
export const getGuildLogController: RequestHandler = (_req, res) => { export const getGuildLogController: RequestHandler = async (req, res) => {
res.json({ const accountId = await getAccountIdForRequest(req);
RoomChanges: [], const inventory = await getInventory(accountId);
TechChanges: [], const guild = await getGuildForGuildId(inventory.GuildId?.toString() ?? "");
RosterActivity: [], if (!guild) {
StandingsUpdates: [], res.status(400).json({ error: "guild was undefined" });
ClassChanges: [] return;
}); }
res.json(await getGuildLog(accountId, guild));
}; };

View File

@ -1,6 +1,6 @@
import { RequestHandler } from "express"; import { RequestHandler } from "express";
import { IDojoComponentClient } from "@/src/types/guildTypes"; import { IDojoComponentClient } from "@/src/types/guildTypes";
import { getDojoClient, getGuildForRequest, processDojoBuildMaterialsGathered } from "@/src/services/guildService"; import { getDojoClient, getGuildForRequest, getGuildLogForRequest, processDojoBuildMaterialsGathered } from "@/src/services/guildService";
import { Types } from "mongoose"; import { Types } from "mongoose";
import { ExportDojoRecipes } from "warframe-public-export-plus"; import { ExportDojoRecipes } from "warframe-public-export-plus";
import { config } from "@/src/services/configService"; import { config } from "@/src/services/configService";
@ -12,6 +12,7 @@ interface IStartDojoRecipeRequest {
export const startDojoRecipeController: RequestHandler = async (req, res) => { export const startDojoRecipeController: RequestHandler = async (req, res) => {
const guild = await getGuildForRequest(req); const guild = await getGuildForRequest(req);
const guildLog = await getGuildLogForRequest(req);
// At this point, we know that a member of the guild is making this request. Assuming they are allowed to start a build. // At this point, we know that a member of the guild is making this request. Assuming they are allowed to start a build.
const request = JSON.parse(String(req.body)) as IStartDojoRecipeRequest; const request = JSON.parse(String(req.body)) as IStartDojoRecipeRequest;
@ -33,6 +34,12 @@ export const startDojoRecipeController: RequestHandler = async (req, res) => {
DecoCapacity: room?.decoCapacity DecoCapacity: room?.decoCapacity
}) - 1 }) - 1
]; ];
guildLog.RoomChanges.push({
dateTime: new Date(Date.now()),
entryType: 2,
details: request.PlacedComponent.pf
});
await guildLog.save();
if (config.noDojoRoomBuildStage) { if (config.noDojoRoomBuildStage) {
component.CompletionTime = new Date(Date.now()); component.CompletionTime = new Date(Date.now());
if (room) { if (room) {

View File

@ -5,6 +5,9 @@ import {
ITechProjectClient, ITechProjectClient,
IDojoDecoDatabase, IDojoDecoDatabase,
ILongMOTD, ILongMOTD,
IGuildLogDatabase,
IGuildLogItemDatabase,
IGuildLogItemClient,
IGuildMemberDatabase IGuildMemberDatabase
} from "@/src/types/guildTypes"; } from "@/src/types/guildTypes";
import { Document, Model, model, Schema, Types } from "mongoose"; import { Document, Model, model, Schema, Types } from "mongoose";
@ -125,3 +128,62 @@ const guildMemberSchema = new Schema<IGuildMemberDatabase>({
guildMemberSchema.index({ accountId: 1, guildId: 1 }, { unique: true }); guildMemberSchema.index({ accountId: 1, guildId: 1 }, { unique: true });
export const GuildMember = model<IGuildMemberDatabase>("GuildMember", guildMemberSchema); export const GuildMember = model<IGuildMemberDatabase>("GuildMember", guildMemberSchema);
const guildLogItemSchema = new Schema<IGuildLogItemDatabase>(
{
dateTime: Date,
entryType: Number,
details: String
},
{ _id: false }
);
guildLogItemSchema.set("toJSON", {
virtuals: true,
transform(_doc, obj) {
const db = obj as IGuildLogItemDatabase;
const client = obj as IGuildLogItemClient;
if (db.dateTime) {
client.dateTime = toMongoDate(db.dateTime);
}
}
});
const guildLogSchema = new Schema<IGuildLogDatabase>(
{
accountId: Types.ObjectId,
guildId: Types.ObjectId,
RoomChanges: [guildLogItemSchema],
TechChanges: [guildLogItemSchema],
RosterActivity: [guildLogItemSchema],
StandingsUpdates: [guildLogItemSchema],
ClassChanges: [guildLogItemSchema]
},
{ id: false }
);
guildLogSchema.index({ accountId: 1, guildId: 1 }, { unique: true });
type GuildLogDocumentProps = {
RoomChanges: Types.DocumentArray<IGuildLogItemDatabase>;
TechChanges: Types.DocumentArray<IGuildLogItemDatabase>;
RosterActivity: Types.DocumentArray<IGuildLogItemDatabase>;
StandingsUpdates: Types.DocumentArray<IGuildLogItemDatabase>;
ClassChanges: Types.DocumentArray<IGuildLogItemDatabase>;
};
// eslint-disable-next-line @typescript-eslint/ban-types
type GuildLogModel = Model<IGuildLogDatabase, {}, GuildLogDocumentProps>;
export const GuildLog = model<IGuildLogDatabase, GuildLogModel>("GuildLog", guildLogSchema);
export type TGuildLogDatabaseDocument = Document<unknown, {}, IGuildLogDatabase> &
Omit<
IGuildLogDatabase & {
_id: Types.ObjectId;
} & {
__v: number;
},
keyof GuildLogDocumentProps
> &
GuildLogDocumentProps;

View File

@ -20,6 +20,7 @@ import { contributeGuildClassController } from "@/src/controllers/api/contribute
import { contributeToDojoComponentController } from "@/src/controllers/api/contributeToDojoComponentController"; import { contributeToDojoComponentController } from "@/src/controllers/api/contributeToDojoComponentController";
import { contributeToVaultController } from "@/src/controllers/api/contributeToVaultController"; import { contributeToVaultController } from "@/src/controllers/api/contributeToVaultController";
import { createGuildController } from "@/src/controllers/api/createGuildController"; import { createGuildController } from "@/src/controllers/api/createGuildController";
import { createGuildDojoController } from "@/src/controllers/api/createGuildDojoController";
import { creditsController } from "@/src/controllers/api/creditsController"; import { creditsController } from "@/src/controllers/api/creditsController";
import { declineGuildInviteController } from "@/src/controllers/api/declineGuildInviteController"; import { declineGuildInviteController } from "@/src/controllers/api/declineGuildInviteController";
import { deleteSessionController } from "@/src/controllers/api/deleteSessionController"; import { deleteSessionController } from "@/src/controllers/api/deleteSessionController";
@ -169,6 +170,7 @@ apiRouter.post("/contributeGuildClass.php", contributeGuildClassController);
apiRouter.post("/contributeToDojoComponent.php", contributeToDojoComponentController); apiRouter.post("/contributeToDojoComponent.php", contributeToDojoComponentController);
apiRouter.post("/contributeToVault.php", contributeToVaultController); apiRouter.post("/contributeToVault.php", contributeToVaultController);
apiRouter.post("/createGuild.php", createGuildController); apiRouter.post("/createGuild.php", createGuildController);
apiRouter.post("/createGuildDojo.php", createGuildDojoController);
apiRouter.post("/destroyDojoDeco.php", destroyDojoDecoController); apiRouter.post("/destroyDojoDeco.php", destroyDojoDecoController);
apiRouter.post("/dojoComponentRush.php", dojoComponentRushController); apiRouter.post("/dojoComponentRush.php", dojoComponentRushController);
apiRouter.post("/drones.php", dronesController); apiRouter.post("/drones.php", dronesController);

View File

@ -1,7 +1,13 @@
import { Request } from "express"; import { Request } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService"; import { getAccountIdForRequest } from "@/src/services/loginService";
import { addRecipes, getInventory } from "@/src/services/inventoryService"; import { addRecipes, getInventory } from "@/src/services/inventoryService";
import { Guild, GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel"; import {
Guild,
GuildLog,
GuildMember,
TGuildDatabaseDocument,
TGuildLogDatabaseDocument
} from "@/src/models/guildModel";
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel"; import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
import { import {
IDojoClient, IDojoClient,
@ -329,3 +335,37 @@ export const createUniqueClanName = async (name: string): Promise<string> => {
} while (discriminator != initialDiscriminator); } while (discriminator != initialDiscriminator);
throw new Error(`clan name is so unoriginal it's already been done 1000 times: ${name}`); throw new Error(`clan name is so unoriginal it's already been done 1000 times: ${name}`);
}; };
export const getGuildLogForRequest = async (req: Request): Promise<TGuildLogDatabaseDocument> => {
const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId);
const guildId = inventory.GuildId!.toString();
const guildLog = await GuildLog.findOne({ _id: guildId });
if (!guildLog) {
throw new Error("Account thinks it is in a guild that doesn't exist");
}
return guildLog;
};
export const getGuildLog = async (accountId: string, guild: TGuildDatabaseDocument) => {
const guildLog = await GuildLog.findOne({ guildId: guild._id });
if (!guildLog) {
return await GuildLog.insertOne({
_id: new Types.ObjectId(),
accountId: accountId,
guildId: guild._id,
RoomChanges: [],
TechChanges: [],
RosterActivity: [],
StandingsUpdates: [],
ClassChanges: []
});
}
return {
RoomChanges: guildLog!.RoomChanges,
TechChanges: guildLog!.TechChanges,
RosterActivity: guildLog!.RosterActivity,
StandingsUpdates: guildLog!.StandingsUpdates,
ClassChanges: guildLog!.ClassChanges
};
};

View File

@ -160,3 +160,25 @@ export interface ITechProjectClient {
export interface ITechProjectDatabase extends Omit<ITechProjectClient, "CompletionDate"> { export interface ITechProjectDatabase extends Omit<ITechProjectClient, "CompletionDate"> {
CompletionDate?: Date; CompletionDate?: Date;
} }
export interface IGuildLogItemClient {
dateTime: IMongoDate;
entryType: number;
details: string;
}
export interface IGuildLogDatabase {
accountId: Types.ObjectId;
guildId: Types.ObjectId;
RoomChanges: IGuildLogItemDatabase[];
TechChanges: IGuildLogItemDatabase[];
RosterActivity: IGuildLogItemDatabase[];
StandingsUpdates: IGuildLogItemDatabase[];
ClassChanges: IGuildLogItemDatabase[];
}
export interface IGuildLogItemDatabase extends Omit<IGuildLogItemClient, "id" | "dateTime"> {
dateTime: Date;
entryType: number;
details: string;
}