forked from OpenWF/SpaceNinjaServer
		
	feat: clan applications (#1410)
Reviewed-on: OpenWF/SpaceNinjaServer#1410 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									4a3a3de300
								
							
						
					
					
						commit
						1a4ad8b7a5
					
				@ -3,82 +3,107 @@ import { Account } from "@/src/models/loginModel";
 | 
				
			|||||||
import { fillInInventoryDataForGuildMember, hasGuildPermission } from "@/src/services/guildService";
 | 
					import { fillInInventoryDataForGuildMember, hasGuildPermission } from "@/src/services/guildService";
 | 
				
			||||||
import { createMessage } from "@/src/services/inboxService";
 | 
					import { createMessage } from "@/src/services/inboxService";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "@/src/services/inventoryService";
 | 
				
			||||||
import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService";
 | 
					import { getAccountForRequest, getAccountIdForRequest, getSuffixedName } from "@/src/services/loginService";
 | 
				
			||||||
import { IOid } from "@/src/types/commonTypes";
 | 
					import { IOid } from "@/src/types/commonTypes";
 | 
				
			||||||
import { GuildPermission, IGuildMemberClient } from "@/src/types/guildTypes";
 | 
					import { GuildPermission, IGuildMemberClient } from "@/src/types/guildTypes";
 | 
				
			||||||
 | 
					import { logger } from "@/src/utils/logger";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import { RequestHandler } from "express";
 | 
				
			||||||
import { ExportFlavour } from "warframe-public-export-plus";
 | 
					import { ExportFlavour } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const addToGuildController: RequestHandler = async (req, res) => {
 | 
					export const addToGuildController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const payload = JSON.parse(String(req.body)) as IAddToGuildRequest;
 | 
					    const payload = JSON.parse(String(req.body)) as IAddToGuildRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const account = await Account.findOne({ DisplayName: payload.UserName });
 | 
					    if ("UserName" in payload) {
 | 
				
			||||||
    if (!account) {
 | 
					        // Clan recruiter sending an invite
 | 
				
			||||||
        res.status(400).json("Username does not exist");
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const inventory = await getInventory(account._id.toString(), "Settings");
 | 
					        const account = await Account.findOne({ DisplayName: payload.UserName });
 | 
				
			||||||
    // TODO: Also consider GIFT_MODE_FRIENDS once friends are implemented
 | 
					        if (!account) {
 | 
				
			||||||
    if (inventory.Settings?.GuildInvRestriction == "GIFT_MODE_NONE") {
 | 
					            res.status(400).json("Username does not exist");
 | 
				
			||||||
        res.status(400).json("Invite restricted");
 | 
					            return;
 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const guild = (await Guild.findById(payload.GuildId.$oid, "Name Ranks"))!;
 | 
					 | 
				
			||||||
    const senderAccount = await getAccountForRequest(req);
 | 
					 | 
				
			||||||
    if (!(await hasGuildPermission(guild, senderAccount._id.toString(), GuildPermission.Recruiter))) {
 | 
					 | 
				
			||||||
        res.status(400).json("Invalid permission");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (
 | 
					 | 
				
			||||||
        await GuildMember.exists({
 | 
					 | 
				
			||||||
            accountId: account._id,
 | 
					 | 
				
			||||||
            guildId: payload.GuildId.$oid
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
        res.status(400).json("User already invited to clan");
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    await GuildMember.insertOne({
 | 
					 | 
				
			||||||
        accountId: account._id,
 | 
					 | 
				
			||||||
        guildId: payload.GuildId.$oid,
 | 
					 | 
				
			||||||
        status: 2 // outgoing invite
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const senderInventory = await getInventory(senderAccount._id.toString(), "ActiveAvatarImageType");
 | 
					 | 
				
			||||||
    await createMessage(account._id.toString(), [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            sndr: getSuffixedName(senderAccount),
 | 
					 | 
				
			||||||
            msg: "/Lotus/Language/Menu/Mailbox_ClanInvite_Body",
 | 
					 | 
				
			||||||
            arg: [
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    Key: "clan",
 | 
					 | 
				
			||||||
                    Tag: guild.Name
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            sub: "/Lotus/Language/Menu/Mailbox_ClanInvite_Title",
 | 
					 | 
				
			||||||
            icon: ExportFlavour[senderInventory.ActiveAvatarImageType].icon,
 | 
					 | 
				
			||||||
            contextInfo: payload.GuildId.$oid,
 | 
					 | 
				
			||||||
            highPriority: true,
 | 
					 | 
				
			||||||
            acceptAction: "GUILD_INVITE",
 | 
					 | 
				
			||||||
            declineAction: "GUILD_INVITE",
 | 
					 | 
				
			||||||
            hasAccountAction: true
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    ]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const member: IGuildMemberClient = {
 | 
					        const inventory = await getInventory(account._id.toString(), "Settings");
 | 
				
			||||||
        _id: { $oid: account._id.toString() },
 | 
					        // TODO: Also consider GIFT_MODE_FRIENDS once friends are implemented
 | 
				
			||||||
        DisplayName: account.DisplayName,
 | 
					        if (inventory.Settings?.GuildInvRestriction == "GIFT_MODE_NONE") {
 | 
				
			||||||
        Rank: 7,
 | 
					            res.status(400).json("Invite restricted");
 | 
				
			||||||
        Status: 2
 | 
					            return;
 | 
				
			||||||
    };
 | 
					        }
 | 
				
			||||||
    await fillInInventoryDataForGuildMember(member);
 | 
					
 | 
				
			||||||
    res.json({ NewMember: member });
 | 
					        const guild = (await Guild.findById(payload.GuildId.$oid, "Name Ranks"))!;
 | 
				
			||||||
 | 
					        const senderAccount = await getAccountForRequest(req);
 | 
				
			||||||
 | 
					        if (!(await hasGuildPermission(guild, senderAccount._id.toString(), GuildPermission.Recruiter))) {
 | 
				
			||||||
 | 
					            res.status(400).json("Invalid permission");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (
 | 
				
			||||||
 | 
					            await GuildMember.exists({
 | 
				
			||||||
 | 
					                accountId: account._id,
 | 
				
			||||||
 | 
					                guildId: payload.GuildId.$oid
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            res.status(400).json("User already invited to clan");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await GuildMember.insertOne({
 | 
				
			||||||
 | 
					            accountId: account._id,
 | 
				
			||||||
 | 
					            guildId: payload.GuildId.$oid,
 | 
				
			||||||
 | 
					            status: 2 // outgoing invite
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const senderInventory = await getInventory(senderAccount._id.toString(), "ActiveAvatarImageType");
 | 
				
			||||||
 | 
					        await createMessage(account._id, [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                sndr: getSuffixedName(senderAccount),
 | 
				
			||||||
 | 
					                msg: "/Lotus/Language/Menu/Mailbox_ClanInvite_Body",
 | 
				
			||||||
 | 
					                arg: [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        Key: "clan",
 | 
				
			||||||
 | 
					                        Tag: guild.Name
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                sub: "/Lotus/Language/Menu/Mailbox_ClanInvite_Title",
 | 
				
			||||||
 | 
					                icon: ExportFlavour[senderInventory.ActiveAvatarImageType].icon,
 | 
				
			||||||
 | 
					                contextInfo: payload.GuildId.$oid,
 | 
				
			||||||
 | 
					                highPriority: true,
 | 
				
			||||||
 | 
					                acceptAction: "GUILD_INVITE",
 | 
				
			||||||
 | 
					                declineAction: "GUILD_INVITE",
 | 
				
			||||||
 | 
					                hasAccountAction: true
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const member: IGuildMemberClient = {
 | 
				
			||||||
 | 
					            _id: { $oid: account._id.toString() },
 | 
				
			||||||
 | 
					            DisplayName: account.DisplayName,
 | 
				
			||||||
 | 
					            Rank: 7,
 | 
				
			||||||
 | 
					            Status: 2
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        await fillInInventoryDataForGuildMember(member);
 | 
				
			||||||
 | 
					        res.json({ NewMember: member });
 | 
				
			||||||
 | 
					    } else if ("RequestMsg" in payload) {
 | 
				
			||||||
 | 
					        // Player applying to join a clan
 | 
				
			||||||
 | 
					        const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            await GuildMember.insertOne({
 | 
				
			||||||
 | 
					                accountId,
 | 
				
			||||||
 | 
					                guildId: payload.GuildId.$oid,
 | 
				
			||||||
 | 
					                status: 1, // incoming invite
 | 
				
			||||||
 | 
					                RequestMsg: payload.RequestMsg,
 | 
				
			||||||
 | 
					                RequestExpiry: new Date(Date.now() + 14 * 86400 * 1000) // TOVERIFY: I can't find any good information about this with regards to live, but 2 weeks seem reasonable.
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        } catch (e) {
 | 
				
			||||||
 | 
					            // Assuming this is "E11000 duplicate key error" due to the guildId-accountId unique index.
 | 
				
			||||||
 | 
					            res.status(400).send("Already requested");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        res.end();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        logger.error(`data provided to ${req.path}: ${String(req.body)}`);
 | 
				
			||||||
 | 
					        res.status(400).end();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IAddToGuildRequest {
 | 
					interface IAddToGuildRequest {
 | 
				
			||||||
    UserName: string;
 | 
					    UserName?: string;
 | 
				
			||||||
    GuildId: IOid;
 | 
					    GuildId: IOid;
 | 
				
			||||||
 | 
					    RequestMsg?: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,18 +1,76 @@
 | 
				
			|||||||
 | 
					import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
				
			||||||
import { Guild, GuildMember } from "@/src/models/guildModel";
 | 
					import { Guild, GuildMember } from "@/src/models/guildModel";
 | 
				
			||||||
import { deleteGuild, getGuildClient, removeDojoKeyItems } from "@/src/services/guildService";
 | 
					import { Account } from "@/src/models/loginModel";
 | 
				
			||||||
 | 
					import { deleteGuild, getGuildClient, hasGuildPermission, removeDojoKeyItems } from "@/src/services/guildService";
 | 
				
			||||||
import { addRecipes, combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
 | 
					import { addRecipes, combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
 | 
				
			||||||
import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService";
 | 
					import { getAccountForRequest, getAccountIdForRequest, getSuffixedName } from "@/src/services/loginService";
 | 
				
			||||||
 | 
					import { GuildPermission } from "@/src/types/guildTypes";
 | 
				
			||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import { RequestHandler } from "express";
 | 
				
			||||||
import { Types } from "mongoose";
 | 
					import { Types } from "mongoose";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const confirmGuildInvitationController: RequestHandler = async (req, res) => {
 | 
					export const confirmGuildInvitationController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
					    if (req.body) {
 | 
				
			||||||
 | 
					        // POST request: Clan representative accepting invite(s).
 | 
				
			||||||
 | 
					        const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
					        const guild = (await Guild.findById(req.query.clanId as string, "Ranks RosterActivity"))!;
 | 
				
			||||||
 | 
					        if (!(await hasGuildPermission(guild, accountId, GuildPermission.Recruiter))) {
 | 
				
			||||||
 | 
					            res.status(400).json("Invalid permission");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const payload = getJSONfromString<{ userId: string }>(String(req.body));
 | 
				
			||||||
 | 
					        const filter: { accountId?: string; status: number } = { status: 1 };
 | 
				
			||||||
 | 
					        if (payload.userId != "all") {
 | 
				
			||||||
 | 
					            filter.accountId = payload.userId;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const guildMembers = await GuildMember.find(filter);
 | 
				
			||||||
 | 
					        const newMembers: string[] = [];
 | 
				
			||||||
 | 
					        for (const guildMember of guildMembers) {
 | 
				
			||||||
 | 
					            guildMember.status = 0;
 | 
				
			||||||
 | 
					            guildMember.RequestMsg = undefined;
 | 
				
			||||||
 | 
					            guildMember.RequestExpiry = undefined;
 | 
				
			||||||
 | 
					            await guildMember.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Remove other pending applications for this account
 | 
				
			||||||
 | 
					            await GuildMember.deleteMany({ accountId: guildMember.accountId, status: 1 });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Update inventory of new member
 | 
				
			||||||
 | 
					            const inventory = await getInventory(guildMember.accountId.toString(), "GuildId Recipes");
 | 
				
			||||||
 | 
					            inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
 | 
				
			||||||
 | 
					            addRecipes(inventory, [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
 | 
				
			||||||
 | 
					                    ItemCount: 1
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					            await inventory.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Add join to clan log
 | 
				
			||||||
 | 
					            const account = (await Account.findOne({ _id: guildMember.accountId }))!;
 | 
				
			||||||
 | 
					            guild.RosterActivity ??= [];
 | 
				
			||||||
 | 
					            guild.RosterActivity.push({
 | 
				
			||||||
 | 
					                dateTime: new Date(),
 | 
				
			||||||
 | 
					                entryType: 6,
 | 
				
			||||||
 | 
					                details: getSuffixedName(account)
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            newMembers.push(account._id.toString());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        await guild.save();
 | 
				
			||||||
 | 
					        res.json({
 | 
				
			||||||
 | 
					            NewMembers: newMembers
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // GET request: A player accepting an invite they got in their inbox.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const account = await getAccountForRequest(req);
 | 
					    const account = await getAccountForRequest(req);
 | 
				
			||||||
    const invitedGuildMember = await GuildMember.findOne({
 | 
					    const invitedGuildMember = await GuildMember.findOne({
 | 
				
			||||||
        accountId: account._id,
 | 
					        accountId: account._id,
 | 
				
			||||||
        guildId: req.query.clanId as string
 | 
					        guildId: req.query.clanId as string
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    if (invitedGuildMember) {
 | 
					    if (invitedGuildMember && invitedGuildMember.status == 2) {
 | 
				
			||||||
        let inventoryChanges: IInventoryChanges = {};
 | 
					        let inventoryChanges: IInventoryChanges = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // If this account is already in a guild, we need to do cleanup first.
 | 
					        // If this account is already in a guild, we need to do cleanup first.
 | 
				
			||||||
@ -31,6 +89,10 @@ export const confirmGuildInvitationController: RequestHandler = async (req, res)
 | 
				
			|||||||
        invitedGuildMember.status = 0;
 | 
					        invitedGuildMember.status = 0;
 | 
				
			||||||
        await invitedGuildMember.save();
 | 
					        await invitedGuildMember.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Remove pending applications for this account
 | 
				
			||||||
 | 
					        await GuildMember.deleteMany({ accountId: account._id, status: 1 });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Update inventory of new member
 | 
				
			||||||
        const inventory = await getInventory(account._id.toString(), "GuildId LevelKeys Recipes");
 | 
					        const inventory = await getInventory(account._id.toString(), "GuildId LevelKeys Recipes");
 | 
				
			||||||
        inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
 | 
					        inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
 | 
				
			||||||
        const recipeChanges = [
 | 
					        const recipeChanges = [
 | 
				
			||||||
@ -45,6 +107,7 @@ export const confirmGuildInvitationController: RequestHandler = async (req, res)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const guild = (await Guild.findById(req.query.clanId as string))!;
 | 
					        const guild = (await Guild.findById(req.query.clanId as string))!;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add join to clan log
 | 
				
			||||||
        guild.RosterActivity ??= [];
 | 
					        guild.RosterActivity ??= [];
 | 
				
			||||||
        guild.RosterActivity.push({
 | 
					        guild.RosterActivity.push({
 | 
				
			||||||
            dateTime: new Date(),
 | 
					            dateTime: new Date(),
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,9 @@ export const createGuildController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
    const payload = getJSONfromString<ICreateGuildRequest>(String(req.body));
 | 
					    const payload = getJSONfromString<ICreateGuildRequest>(String(req.body));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Remove pending applications for this account
 | 
				
			||||||
 | 
					    await GuildMember.deleteMany({ accountId, status: 1 });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Create guild on database
 | 
					    // Create guild on database
 | 
				
			||||||
    const guild = new Guild({
 | 
					    const guild = new Guild({
 | 
				
			||||||
        Name: await createUniqueClanName(payload.guildName)
 | 
					        Name: await createUniqueClanName(payload.guildName)
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
import { GuildMember } from "@/src/models/guildModel";
 | 
					import { GuildMember } from "@/src/models/guildModel";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "@/src/services/inventoryService";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
				
			||||||
 | 
					import { IGuildMemberClient } from "@/src/types/guildTypes";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getGuildContributionsController: RequestHandler = async (req, res) => {
 | 
					export const getGuildContributionsController: RequestHandler = async (req, res) => {
 | 
				
			||||||
@ -8,11 +9,11 @@ export const getGuildContributionsController: RequestHandler = async (req, res)
 | 
				
			|||||||
    const guildId = (await getInventory(accountId, "GuildId")).GuildId;
 | 
					    const guildId = (await getInventory(accountId, "GuildId")).GuildId;
 | 
				
			||||||
    const guildMember = (await GuildMember.findOne({ guildId, accountId: req.query.buddyId }))!;
 | 
					    const guildMember = (await GuildMember.findOne({ guildId, accountId: req.query.buddyId }))!;
 | 
				
			||||||
    res.json({
 | 
					    res.json({
 | 
				
			||||||
        _id: { $oid: req.query.buddyId },
 | 
					        _id: { $oid: req.query.buddyId as string },
 | 
				
			||||||
        RegularCreditsContributed: guildMember.RegularCreditsContributed,
 | 
					        RegularCreditsContributed: guildMember.RegularCreditsContributed,
 | 
				
			||||||
        PremiumCreditsContributed: guildMember.PremiumCreditsContributed,
 | 
					        PremiumCreditsContributed: guildMember.PremiumCreditsContributed,
 | 
				
			||||||
        MiscItemsContributed: guildMember.MiscItemsContributed,
 | 
					        MiscItemsContributed: guildMember.MiscItemsContributed,
 | 
				
			||||||
        ConsumablesContributed: [], // ???
 | 
					        ConsumablesContributed: [], // ???
 | 
				
			||||||
        ShipDecorationsContributed: guildMember.ShipDecorationsContributed
 | 
					        ShipDecorationsContributed: guildMember.ShipDecorationsContributed
 | 
				
			||||||
    });
 | 
					    } satisfies Partial<IGuildMemberClient>);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@ import { GuildMember } from "@/src/models/guildModel";
 | 
				
			|||||||
import { Inbox } from "@/src/models/inboxModel";
 | 
					import { Inbox } from "@/src/models/inboxModel";
 | 
				
			||||||
import { Account } from "@/src/models/loginModel";
 | 
					import { Account } from "@/src/models/loginModel";
 | 
				
			||||||
import { deleteGuild, getGuildForRequest, hasGuildPermission, removeDojoKeyItems } from "@/src/services/guildService";
 | 
					import { deleteGuild, getGuildForRequest, hasGuildPermission, removeDojoKeyItems } from "@/src/services/guildService";
 | 
				
			||||||
 | 
					import { createMessage } from "@/src/services/inboxService";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "@/src/services/inventoryService";
 | 
				
			||||||
import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService";
 | 
					import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService";
 | 
				
			||||||
import { GuildPermission } from "@/src/types/guildTypes";
 | 
					import { GuildPermission } from "@/src/types/guildTypes";
 | 
				
			||||||
@ -26,6 +27,26 @@ export const removeFromGuildController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            inventory.GuildId = undefined;
 | 
					            inventory.GuildId = undefined;
 | 
				
			||||||
            removeDojoKeyItems(inventory);
 | 
					            removeDojoKeyItems(inventory);
 | 
				
			||||||
            await inventory.save();
 | 
					            await inventory.save();
 | 
				
			||||||
 | 
					        } else if (guildMember.status == 1) {
 | 
				
			||||||
 | 
					            // TOVERIFY: Is this inbox message actually sent on live?
 | 
				
			||||||
 | 
					            await createMessage(guildMember.accountId, [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    sndr: "/Lotus/Language/Bosses/Ordis",
 | 
				
			||||||
 | 
					                    msg: "/Lotus/Language/Clan/RejectedFromClan",
 | 
				
			||||||
 | 
					                    sub: "/Lotus/Language/Clan/RejectedFromClanHeader",
 | 
				
			||||||
 | 
					                    arg: [
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            Key: "PLAYER_NAME",
 | 
				
			||||||
 | 
					                            Tag: (await Account.findOne({ _id: guildMember.accountId }, "DisplayName"))!.DisplayName
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            Key: "CLAN_NAME",
 | 
				
			||||||
 | 
					                            Tag: guild.Name
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    ]
 | 
				
			||||||
 | 
					                    // TOVERIFY: If this message is sent on live, is it highPriority?
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
        } else if (guildMember.status == 2) {
 | 
					        } else if (guildMember.status == 2) {
 | 
				
			||||||
            // Delete the inbox message for the invite
 | 
					            // Delete the inbox message for the invite
 | 
				
			||||||
            await Inbox.deleteOne({
 | 
					            await Inbox.deleteOne({
 | 
				
			||||||
 | 
				
			|||||||
@ -218,6 +218,8 @@ const guildMemberSchema = new Schema<IGuildMemberDatabase>({
 | 
				
			|||||||
    guildId: Types.ObjectId,
 | 
					    guildId: Types.ObjectId,
 | 
				
			||||||
    status: { type: Number, required: true },
 | 
					    status: { type: Number, required: true },
 | 
				
			||||||
    rank: { type: Number, default: 7 },
 | 
					    rank: { type: Number, default: 7 },
 | 
				
			||||||
 | 
					    RequestMsg: String,
 | 
				
			||||||
 | 
					    RequestExpiry: Date,
 | 
				
			||||||
    RegularCreditsContributed: Number,
 | 
					    RegularCreditsContributed: Number,
 | 
				
			||||||
    PremiumCreditsContributed: Number,
 | 
					    PremiumCreditsContributed: Number,
 | 
				
			||||||
    MiscItemsContributed: { type: [typeCountSchema], default: undefined },
 | 
					    MiscItemsContributed: { type: [typeCountSchema], default: undefined },
 | 
				
			||||||
@ -225,6 +227,7 @@ const guildMemberSchema = new Schema<IGuildMemberDatabase>({
 | 
				
			|||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
guildMemberSchema.index({ accountId: 1, guildId: 1 }, { unique: true });
 | 
					guildMemberSchema.index({ accountId: 1, guildId: 1 }, { unique: true });
 | 
				
			||||||
 | 
					guildMemberSchema.index({ RequestExpiry: 1 }, { expireAfterSeconds: 0 });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const GuildMember = model<IGuildMemberDatabase>("GuildMember", guildMemberSchema);
 | 
					export const GuildMember = model<IGuildMemberDatabase>("GuildMember", guildMemberSchema);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -188,6 +188,7 @@ apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController);
 | 
				
			|||||||
apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController);
 | 
					apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController);
 | 
				
			||||||
apiRouter.post("/clearNewEpisodeReward.php", clearNewEpisodeRewardController);
 | 
					apiRouter.post("/clearNewEpisodeReward.php", clearNewEpisodeRewardController);
 | 
				
			||||||
apiRouter.post("/completeRandomModChallenge.php", completeRandomModChallengeController);
 | 
					apiRouter.post("/completeRandomModChallenge.php", completeRandomModChallengeController);
 | 
				
			||||||
 | 
					apiRouter.post("/confirmGuildInvitation.php", confirmGuildInvitationController);
 | 
				
			||||||
apiRouter.post("/contributeGuildClass.php", contributeGuildClassController);
 | 
					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);
 | 
				
			||||||
 | 
				
			|||||||
@ -57,7 +57,9 @@ export const getGuildClient = async (guild: TGuildDatabaseDocument, accountId: s
 | 
				
			|||||||
        const member: IGuildMemberClient = {
 | 
					        const member: IGuildMemberClient = {
 | 
				
			||||||
            _id: toOid(guildMember.accountId),
 | 
					            _id: toOid(guildMember.accountId),
 | 
				
			||||||
            Rank: guildMember.rank,
 | 
					            Rank: guildMember.rank,
 | 
				
			||||||
            Status: guildMember.status
 | 
					            Status: guildMember.status,
 | 
				
			||||||
 | 
					            Note: guildMember.RequestMsg,
 | 
				
			||||||
 | 
					            RequestExpiry: guildMember.RequestExpiry ? toMongoDate(guildMember.RequestExpiry) : undefined
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        if (guildMember.accountId.equals(accountId)) {
 | 
					        if (guildMember.accountId.equals(accountId)) {
 | 
				
			||||||
            missingEntry = false;
 | 
					            missingEntry = false;
 | 
				
			||||||
 | 
				
			|||||||
@ -89,19 +89,39 @@ export interface IGuildMemberDatabase {
 | 
				
			|||||||
    guildId: Types.ObjectId;
 | 
					    guildId: Types.ObjectId;
 | 
				
			||||||
    status: number;
 | 
					    status: number;
 | 
				
			||||||
    rank: number;
 | 
					    rank: number;
 | 
				
			||||||
 | 
					    RequestMsg?: string;
 | 
				
			||||||
 | 
					    RequestExpiry?: Date;
 | 
				
			||||||
    RegularCreditsContributed?: number;
 | 
					    RegularCreditsContributed?: number;
 | 
				
			||||||
    PremiumCreditsContributed?: number;
 | 
					    PremiumCreditsContributed?: number;
 | 
				
			||||||
    MiscItemsContributed?: IMiscItem[];
 | 
					    MiscItemsContributed?: IMiscItem[];
 | 
				
			||||||
    ShipDecorationsContributed?: ITypeCount[];
 | 
					    ShipDecorationsContributed?: ITypeCount[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IGuildMemberClient {
 | 
					interface IFriendInfo {
 | 
				
			||||||
    _id: IOid;
 | 
					    _id: IOid;
 | 
				
			||||||
    Status: number;
 | 
					 | 
				
			||||||
    Rank: number;
 | 
					 | 
				
			||||||
    DisplayName?: string;
 | 
					    DisplayName?: string;
 | 
				
			||||||
 | 
					    PlatformNames?: string[];
 | 
				
			||||||
 | 
					    PlatformAccountId?: string;
 | 
				
			||||||
 | 
					    Status: number;
 | 
				
			||||||
    ActiveAvatarImageType?: string;
 | 
					    ActiveAvatarImageType?: string;
 | 
				
			||||||
 | 
					    LastLogin?: IMongoDate;
 | 
				
			||||||
    PlayerLevel?: number;
 | 
					    PlayerLevel?: number;
 | 
				
			||||||
 | 
					    Suffix?: number;
 | 
				
			||||||
 | 
					    Note?: string;
 | 
				
			||||||
 | 
					    Favorite?: boolean;
 | 
				
			||||||
 | 
					    NewRequest?: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GuildMemberInfo
 | 
				
			||||||
 | 
					export interface IGuildMemberClient extends IFriendInfo {
 | 
				
			||||||
 | 
					    Rank: number;
 | 
				
			||||||
 | 
					    Joined?: IMongoDate;
 | 
				
			||||||
 | 
					    RequestExpiry?: IMongoDate;
 | 
				
			||||||
 | 
					    RegularCreditsContributed?: number;
 | 
				
			||||||
 | 
					    PremiumCreditsContributed?: number;
 | 
				
			||||||
 | 
					    MiscItemsContributed?: IMiscItem[];
 | 
				
			||||||
 | 
					    ConsumablesContributed?: ITypeCount[];
 | 
				
			||||||
 | 
					    ShipDecorationsContributed?: ITypeCount[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IGuildVault {
 | 
					export interface IGuildVault {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user