From 46759628ed53f69ba2f6cc386bd9e7773180e16c Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Sun, 30 Mar 2025 22:47:58 +0200 Subject: [PATCH] chore: handle account switching guilds --- .../api/confirmGuildInvitationController.ts | 51 ++++++++++------ src/controllers/api/createGuildController.ts | 17 ++++-- .../api/removeFromGuildController.ts | 19 +----- src/services/guildService.ts | 60 ++++++++++++------- 4 files changed, 87 insertions(+), 60 deletions(-) diff --git a/src/controllers/api/confirmGuildInvitationController.ts b/src/controllers/api/confirmGuildInvitationController.ts index 2685be99..c03a4285 100644 --- a/src/controllers/api/confirmGuildInvitationController.ts +++ b/src/controllers/api/confirmGuildInvitationController.ts @@ -1,23 +1,47 @@ import { Guild, GuildMember } from "@/src/models/guildModel"; -import { getGuildClient, updateInventoryForConfirmedGuildJoin } from "@/src/services/guildService"; +import { deleteGuild, getGuildClient, removeDojoKeyItems } from "@/src/services/guildService"; +import { addRecipes, combineInventoryChanges, getInventory } from "@/src/services/inventoryService"; import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService"; +import { IInventoryChanges } from "@/src/types/purchaseTypes"; import { RequestHandler } from "express"; import { Types } from "mongoose"; export const confirmGuildInvitationController: RequestHandler = async (req, res) => { const account = await getAccountForRequest(req); - const guildMember = await GuildMember.findOne({ + const invitedGuildMember = await GuildMember.findOne({ accountId: account._id, guildId: req.query.clanId as string }); - if (guildMember) { - guildMember.status = 0; - await guildMember.save(); + if (invitedGuildMember) { + let inventoryChanges: IInventoryChanges = {}; - await updateInventoryForConfirmedGuildJoin( - account._id.toString(), - new Types.ObjectId(req.query.clanId as string) - ); + // If this account is already in a guild, we need to do cleanup first. + const guildMember = await GuildMember.findOneAndDelete({ accountId: account._id, status: 0 }); + if (guildMember) { + const inventory = await getInventory(account._id.toString(), "LevelKeys Recipes"); + inventoryChanges = removeDojoKeyItems(inventory); + await inventory.save(); + + if (guildMember.rank == 0) { + await deleteGuild(guildMember.guildId); + } + } + + // Now that we're sure this account is not in a guild right now, we can just proceed with the normal updates. + invitedGuildMember.status = 0; + await invitedGuildMember.save(); + + const inventory = await getInventory(account._id.toString(), "GuildId LevelKeys Recipes"); + inventory.GuildId = new Types.ObjectId(req.query.clanId as string); + const recipeChanges = [ + { + ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint", + ItemCount: 1 + } + ]; + addRecipes(inventory, recipeChanges); + combineInventoryChanges(inventoryChanges, { Recipes: recipeChanges }); + await inventory.save(); const guild = (await Guild.findById(req.query.clanId as string))!; @@ -31,14 +55,7 @@ export const confirmGuildInvitationController: RequestHandler = async (req, res) res.json({ ...(await getGuildClient(guild, account._id.toString())), - InventoryChanges: { - Recipes: [ - { - ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint", - ItemCount: 1 - } - ] - } + InventoryChanges: inventoryChanges }); } else { res.end(); diff --git a/src/controllers/api/createGuildController.ts b/src/controllers/api/createGuildController.ts index d8757545..4d3e21c9 100644 --- a/src/controllers/api/createGuildController.ts +++ b/src/controllers/api/createGuildController.ts @@ -2,11 +2,8 @@ import { RequestHandler } from "express"; import { getAccountIdForRequest } from "@/src/services/loginService"; import { getJSONfromString } from "@/src/helpers/stringHelpers"; import { Guild, GuildMember } from "@/src/models/guildModel"; -import { - createUniqueClanName, - getGuildClient, - updateInventoryForConfirmedGuildJoin -} from "@/src/services/guildService"; +import { createUniqueClanName, getGuildClient } from "@/src/services/guildService"; +import { addRecipes, getInventory } from "@/src/services/inventoryService"; export const createGuildController: RequestHandler = async (req, res) => { const accountId = await getAccountIdForRequest(req); @@ -26,7 +23,15 @@ export const createGuildController: RequestHandler = async (req, res) => { rank: 0 }); - await updateInventoryForConfirmedGuildJoin(accountId, guild._id); + const inventory = await getInventory(accountId, "GuildId Recipes"); + inventory.GuildId = guild._id; + addRecipes(inventory, [ + { + ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint", + ItemCount: 1 + } + ]); + await inventory.save(); res.json({ ...(await getGuildClient(guild, accountId)), diff --git a/src/controllers/api/removeFromGuildController.ts b/src/controllers/api/removeFromGuildController.ts index 705d597f..3571e1e1 100644 --- a/src/controllers/api/removeFromGuildController.ts +++ b/src/controllers/api/removeFromGuildController.ts @@ -1,7 +1,7 @@ import { GuildMember } from "@/src/models/guildModel"; import { Inbox } from "@/src/models/inboxModel"; import { Account } from "@/src/models/loginModel"; -import { deleteGuild, getGuildForRequest, hasGuildPermission } from "@/src/services/guildService"; +import { deleteGuild, getGuildForRequest, hasGuildPermission, removeDojoKeyItems } from "@/src/services/guildService"; import { getInventory } from "@/src/services/inventoryService"; import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService"; import { GuildPermission } from "@/src/types/guildTypes"; @@ -22,22 +22,9 @@ export const removeFromGuildController: RequestHandler = async (req, res) => { await deleteGuild(guild._id); } else { if (guildMember.status == 0) { - const inventory = await getInventory(payload.userId); + const inventory = await getInventory(payload.userId, "GuildId LevelKeys Recipes"); inventory.GuildId = undefined; - - // Remove clan key or blueprint from kicked member - const itemIndex = inventory.LevelKeys.findIndex(x => x.ItemType == "/Lotus/Types/Keys/DojoKey"); - if (itemIndex != -1) { - inventory.LevelKeys.splice(itemIndex, 1); - } else { - const recipeIndex = inventory.Recipes.findIndex( - x => x.ItemType == "/Lotus/Types/Keys/DojoKeyBlueprint" - ); - if (recipeIndex != -1) { - inventory.Recipes.splice(recipeIndex, 1); - } - } - + removeDojoKeyItems(inventory); await inventory.save(); } else if (guildMember.status == 2) { // Delete the inbox message for the invite diff --git a/src/services/guildService.ts b/src/services/guildService.ts index de4400b9..658b0f27 100644 --- a/src/services/guildService.ts +++ b/src/services/guildService.ts @@ -1,6 +1,6 @@ import { Request } from "express"; import { getAccountIdForRequest } from "@/src/services/loginService"; -import { addRecipes, getInventory } from "@/src/services/inventoryService"; +import { getInventory } from "@/src/services/inventoryService"; import { Guild, GuildAd, GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel"; import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel"; import { @@ -25,6 +25,7 @@ import { Account } from "../models/loginModel"; import { getRandomInt } from "./rngService"; import { Inbox } from "../models/inboxModel"; import { ITypeCount } from "../types/inventoryTypes/inventoryTypes"; +import { IInventoryChanges } from "../types/purchaseTypes"; export const getGuildForRequest = async (req: Request): Promise => { const accountId = await getAccountIdForRequest(req); @@ -350,26 +351,6 @@ export const fillInInventoryDataForGuildMember = async (member: IGuildMemberClie member.ActiveAvatarImageType = inventory.ActiveAvatarImageType; }; -export const updateInventoryForConfirmedGuildJoin = async ( - accountId: string, - guildId: Types.ObjectId -): Promise => { - const inventory = await getInventory(accountId, "GuildId Recipes"); - - // Set GuildId - inventory.GuildId = guildId; - - // Give clan key blueprint - addRecipes(inventory, [ - { - ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint", - ItemCount: 1 - } - ]); - - await inventory.save(); -}; - export const createUniqueClanName = async (name: string): Promise => { const initialDiscriminator = getRandomInt(0, 999); let discriminator = initialDiscriminator; @@ -518,8 +499,45 @@ const setGuildTier = async (guild: TGuildDatabaseDocument, newTier: number): Pro } }; +export const removeDojoKeyItems = (inventory: TInventoryDatabaseDocument): IInventoryChanges => { + const inventoryChanges: IInventoryChanges = {}; + + const itemIndex = inventory.LevelKeys.findIndex(x => x.ItemType == "/Lotus/Types/Keys/DojoKey"); + if (itemIndex != -1) { + inventoryChanges.LevelKeys = [ + { + ItemType: "/Lotus/Types/Keys/DojoKey", + ItemCount: inventory.LevelKeys[itemIndex].ItemCount * -1 + } + ]; + inventory.LevelKeys.splice(itemIndex, 1); + } + + const recipeIndex = inventory.Recipes.findIndex(x => x.ItemType == "/Lotus/Types/Keys/DojoKeyBlueprint"); + if (recipeIndex != -1) { + inventoryChanges.Recipes = [ + { + ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint", + ItemCount: inventory.Recipes[recipeIndex].ItemCount * -1 + } + ]; + inventory.Recipes.splice(recipeIndex, 1); + } + + return inventoryChanges; +}; + export const deleteGuild = async (guildId: Types.ObjectId): Promise => { await Guild.deleteOne({ _id: guildId }); + + const guildMembers = await GuildMember.find({ guildId, status: 0 }, "accountId"); + for (const member of guildMembers) { + const inventory = await getInventory(member.accountId.toString(), "GuildId LevelKeys Recipes"); + inventory.GuildId = undefined; + removeDojoKeyItems(inventory); + await inventory.save(); + } + await GuildMember.deleteMany({ guildId }); // If guild sent any invites, delete those inbox messages as well.