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 { createMessage } from "@/src/services/inboxService";
 | 
			
		||||
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 { GuildPermission, IGuildMemberClient } from "@/src/types/guildTypes";
 | 
			
		||||
import { logger } from "@/src/utils/logger";
 | 
			
		||||
import { RequestHandler } from "express";
 | 
			
		||||
import { ExportFlavour } from "warframe-public-export-plus";
 | 
			
		||||
 | 
			
		||||
export const addToGuildController: RequestHandler = async (req, res) => {
 | 
			
		||||
    const payload = JSON.parse(String(req.body)) as IAddToGuildRequest;
 | 
			
		||||
 | 
			
		||||
    const account = await Account.findOne({ DisplayName: payload.UserName });
 | 
			
		||||
    if (!account) {
 | 
			
		||||
        res.status(400).json("Username does not exist");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if ("UserName" in payload) {
 | 
			
		||||
        // Clan recruiter sending an invite
 | 
			
		||||
 | 
			
		||||
    const inventory = await getInventory(account._id.toString(), "Settings");
 | 
			
		||||
    // TODO: Also consider GIFT_MODE_FRIENDS once friends are implemented
 | 
			
		||||
    if (inventory.Settings?.GuildInvRestriction == "GIFT_MODE_NONE") {
 | 
			
		||||
        res.status(400).json("Invite restricted");
 | 
			
		||||
        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 account = await Account.findOne({ DisplayName: payload.UserName });
 | 
			
		||||
        if (!account) {
 | 
			
		||||
            res.status(400).json("Username does not exist");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    const member: IGuildMemberClient = {
 | 
			
		||||
        _id: { $oid: account._id.toString() },
 | 
			
		||||
        DisplayName: account.DisplayName,
 | 
			
		||||
        Rank: 7,
 | 
			
		||||
        Status: 2
 | 
			
		||||
    };
 | 
			
		||||
    await fillInInventoryDataForGuildMember(member);
 | 
			
		||||
    res.json({ NewMember: member });
 | 
			
		||||
        const inventory = await getInventory(account._id.toString(), "Settings");
 | 
			
		||||
        // TODO: Also consider GIFT_MODE_FRIENDS once friends are implemented
 | 
			
		||||
        if (inventory.Settings?.GuildInvRestriction == "GIFT_MODE_NONE") {
 | 
			
		||||
            res.status(400).json("Invite restricted");
 | 
			
		||||
            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, [
 | 
			
		||||
            {
 | 
			
		||||
                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 {
 | 
			
		||||
    UserName: string;
 | 
			
		||||
    UserName?: string;
 | 
			
		||||
    GuildId: IOid;
 | 
			
		||||
    RequestMsg?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,18 +1,76 @@
 | 
			
		||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
			
		||||
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 { 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 { RequestHandler } from "express";
 | 
			
		||||
import { Types } from "mongoose";
 | 
			
		||||
 | 
			
		||||
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 invitedGuildMember = await GuildMember.findOne({
 | 
			
		||||
        accountId: account._id,
 | 
			
		||||
        guildId: req.query.clanId as string
 | 
			
		||||
    });
 | 
			
		||||
    if (invitedGuildMember) {
 | 
			
		||||
    if (invitedGuildMember && invitedGuildMember.status == 2) {
 | 
			
		||||
        let inventoryChanges: IInventoryChanges = {};
 | 
			
		||||
 | 
			
		||||
        // 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;
 | 
			
		||||
        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");
 | 
			
		||||
        inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
 | 
			
		||||
        const recipeChanges = [
 | 
			
		||||
@ -45,6 +107,7 @@ export const confirmGuildInvitationController: RequestHandler = async (req, res)
 | 
			
		||||
 | 
			
		||||
        const guild = (await Guild.findById(req.query.clanId as string))!;
 | 
			
		||||
 | 
			
		||||
        // Add join to clan log
 | 
			
		||||
        guild.RosterActivity ??= [];
 | 
			
		||||
        guild.RosterActivity.push({
 | 
			
		||||
            dateTime: new Date(),
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,9 @@ export const createGuildController: RequestHandler = async (req, res) => {
 | 
			
		||||
    const accountId = await getAccountIdForRequest(req);
 | 
			
		||||
    const payload = getJSONfromString<ICreateGuildRequest>(String(req.body));
 | 
			
		||||
 | 
			
		||||
    // Remove pending applications for this account
 | 
			
		||||
    await GuildMember.deleteMany({ accountId, status: 1 });
 | 
			
		||||
 | 
			
		||||
    // Create guild on database
 | 
			
		||||
    const guild = new Guild({
 | 
			
		||||
        Name: await createUniqueClanName(payload.guildName)
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
import { GuildMember } from "@/src/models/guildModel";
 | 
			
		||||
import { getInventory } from "@/src/services/inventoryService";
 | 
			
		||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
			
		||||
import { IGuildMemberClient } from "@/src/types/guildTypes";
 | 
			
		||||
import { RequestHandler } from "express";
 | 
			
		||||
 | 
			
		||||
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 guildMember = (await GuildMember.findOne({ guildId, accountId: req.query.buddyId }))!;
 | 
			
		||||
    res.json({
 | 
			
		||||
        _id: { $oid: req.query.buddyId },
 | 
			
		||||
        _id: { $oid: req.query.buddyId as string },
 | 
			
		||||
        RegularCreditsContributed: guildMember.RegularCreditsContributed,
 | 
			
		||||
        PremiumCreditsContributed: guildMember.PremiumCreditsContributed,
 | 
			
		||||
        MiscItemsContributed: guildMember.MiscItemsContributed,
 | 
			
		||||
        ConsumablesContributed: [], // ???
 | 
			
		||||
        ShipDecorationsContributed: guildMember.ShipDecorationsContributed
 | 
			
		||||
    });
 | 
			
		||||
    } satisfies Partial<IGuildMemberClient>);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@ import { GuildMember } from "@/src/models/guildModel";
 | 
			
		||||
import { Inbox } from "@/src/models/inboxModel";
 | 
			
		||||
import { Account } from "@/src/models/loginModel";
 | 
			
		||||
import { deleteGuild, getGuildForRequest, hasGuildPermission, removeDojoKeyItems } from "@/src/services/guildService";
 | 
			
		||||
import { createMessage } from "@/src/services/inboxService";
 | 
			
		||||
import { getInventory } from "@/src/services/inventoryService";
 | 
			
		||||
import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService";
 | 
			
		||||
import { GuildPermission } from "@/src/types/guildTypes";
 | 
			
		||||
@ -26,6 +27,26 @@ export const removeFromGuildController: RequestHandler = async (req, res) => {
 | 
			
		||||
            inventory.GuildId = undefined;
 | 
			
		||||
            removeDojoKeyItems(inventory);
 | 
			
		||||
            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) {
 | 
			
		||||
            // Delete the inbox message for the invite
 | 
			
		||||
            await Inbox.deleteOne({
 | 
			
		||||
 | 
			
		||||
@ -218,6 +218,8 @@ const guildMemberSchema = new Schema<IGuildMemberDatabase>({
 | 
			
		||||
    guildId: Types.ObjectId,
 | 
			
		||||
    status: { type: Number, required: true },
 | 
			
		||||
    rank: { type: Number, default: 7 },
 | 
			
		||||
    RequestMsg: String,
 | 
			
		||||
    RequestExpiry: Date,
 | 
			
		||||
    RegularCreditsContributed: Number,
 | 
			
		||||
    PremiumCreditsContributed: Number,
 | 
			
		||||
    MiscItemsContributed: { type: [typeCountSchema], default: undefined },
 | 
			
		||||
@ -225,6 +227,7 @@ const guildMemberSchema = new Schema<IGuildMemberDatabase>({
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
guildMemberSchema.index({ accountId: 1, guildId: 1 }, { unique: true });
 | 
			
		||||
guildMemberSchema.index({ RequestExpiry: 1 }, { expireAfterSeconds: 0 });
 | 
			
		||||
 | 
			
		||||
export const GuildMember = model<IGuildMemberDatabase>("GuildMember", guildMemberSchema);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -188,6 +188,7 @@ apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController);
 | 
			
		||||
apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController);
 | 
			
		||||
apiRouter.post("/clearNewEpisodeReward.php", clearNewEpisodeRewardController);
 | 
			
		||||
apiRouter.post("/completeRandomModChallenge.php", completeRandomModChallengeController);
 | 
			
		||||
apiRouter.post("/confirmGuildInvitation.php", confirmGuildInvitationController);
 | 
			
		||||
apiRouter.post("/contributeGuildClass.php", contributeGuildClassController);
 | 
			
		||||
apiRouter.post("/contributeToDojoComponent.php", contributeToDojoComponentController);
 | 
			
		||||
apiRouter.post("/contributeToVault.php", contributeToVaultController);
 | 
			
		||||
 | 
			
		||||
@ -57,7 +57,9 @@ export const getGuildClient = async (guild: TGuildDatabaseDocument, accountId: s
 | 
			
		||||
        const member: IGuildMemberClient = {
 | 
			
		||||
            _id: toOid(guildMember.accountId),
 | 
			
		||||
            Rank: guildMember.rank,
 | 
			
		||||
            Status: guildMember.status
 | 
			
		||||
            Status: guildMember.status,
 | 
			
		||||
            Note: guildMember.RequestMsg,
 | 
			
		||||
            RequestExpiry: guildMember.RequestExpiry ? toMongoDate(guildMember.RequestExpiry) : undefined
 | 
			
		||||
        };
 | 
			
		||||
        if (guildMember.accountId.equals(accountId)) {
 | 
			
		||||
            missingEntry = false;
 | 
			
		||||
 | 
			
		||||
@ -89,19 +89,39 @@ export interface IGuildMemberDatabase {
 | 
			
		||||
    guildId: Types.ObjectId;
 | 
			
		||||
    status: number;
 | 
			
		||||
    rank: number;
 | 
			
		||||
    RequestMsg?: string;
 | 
			
		||||
    RequestExpiry?: Date;
 | 
			
		||||
    RegularCreditsContributed?: number;
 | 
			
		||||
    PremiumCreditsContributed?: number;
 | 
			
		||||
    MiscItemsContributed?: IMiscItem[];
 | 
			
		||||
    ShipDecorationsContributed?: ITypeCount[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IGuildMemberClient {
 | 
			
		||||
interface IFriendInfo {
 | 
			
		||||
    _id: IOid;
 | 
			
		||||
    Status: number;
 | 
			
		||||
    Rank: number;
 | 
			
		||||
    DisplayName?: string;
 | 
			
		||||
    PlatformNames?: string[];
 | 
			
		||||
    PlatformAccountId?: string;
 | 
			
		||||
    Status: number;
 | 
			
		||||
    ActiveAvatarImageType?: string;
 | 
			
		||||
    LastLogin?: IMongoDate;
 | 
			
		||||
    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 {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user