forked from OpenWF/SpaceNinjaServer
		
	feat: alliance invites (#1452)
Reviewed-on: OpenWF/SpaceNinjaServer#1452 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
							
								
									0b18932dd8
								
							
						
					
					
						commit
						92e8ffd709
					
				
							
								
								
									
										117
									
								
								src/controllers/api/addToAllianceController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								src/controllers/api/addToAllianceController.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,117 @@
 | 
			
		||||
import { getJSONfromString, regexEscape } from "@/src/helpers/stringHelpers";
 | 
			
		||||
import { Alliance, AllianceMember, Guild, GuildMember } from "@/src/models/guildModel";
 | 
			
		||||
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";
 | 
			
		||||
import { logger } from "@/src/utils/logger";
 | 
			
		||||
import { RequestHandler } from "express";
 | 
			
		||||
import { ExportFlavour } from "warframe-public-export-plus";
 | 
			
		||||
 | 
			
		||||
export const addToAllianceController: RequestHandler = async (req, res) => {
 | 
			
		||||
    // Check requester is a warlord in their guild
 | 
			
		||||
    const account = await getAccountForRequest(req);
 | 
			
		||||
    const guildMember = (await GuildMember.findOne({ accountId: account._id, status: 0 }))!;
 | 
			
		||||
    if (guildMember.rank > 1) {
 | 
			
		||||
        res.status(400).json({ Error: 104 });
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check guild has invite permissions in the alliance
 | 
			
		||||
    const allianceMember = (await AllianceMember.findOne({
 | 
			
		||||
        allianceId: req.query.allianceId,
 | 
			
		||||
        guildId: guildMember.guildId
 | 
			
		||||
    }))!;
 | 
			
		||||
    if (!(allianceMember.Permissions & GuildPermission.Recruiter)) {
 | 
			
		||||
        res.status(400).json({ Error: 104 });
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Find clan to invite
 | 
			
		||||
    const payload = getJSONfromString<IAddToAllianceRequest>(String(req.body));
 | 
			
		||||
    const guilds = await Guild.find(
 | 
			
		||||
        {
 | 
			
		||||
            Name:
 | 
			
		||||
                payload.clanName.indexOf("#") == -1
 | 
			
		||||
                    ? new RegExp("^" + regexEscape(payload.clanName) + "#...$")
 | 
			
		||||
                    : payload.clanName
 | 
			
		||||
        },
 | 
			
		||||
        "Name"
 | 
			
		||||
    );
 | 
			
		||||
    if (guilds.length == 0) {
 | 
			
		||||
        res.status(400).json({ Error: 101 });
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (guilds.length > 1) {
 | 
			
		||||
        const choices: IGuildChoice[] = [];
 | 
			
		||||
        for (const guild of guilds) {
 | 
			
		||||
            choices.push({
 | 
			
		||||
                OriginalPlatform: 0,
 | 
			
		||||
                Name: guild.Name
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        res.json(choices);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Add clan as a pending alliance member
 | 
			
		||||
    try {
 | 
			
		||||
        await AllianceMember.insertOne({
 | 
			
		||||
            allianceId: req.query.allianceId,
 | 
			
		||||
            guildId: guilds[0]._id,
 | 
			
		||||
            Pending: true,
 | 
			
		||||
            Permissions: 0
 | 
			
		||||
        });
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        logger.debug(`alliance invite failed due to ${String(e)}`);
 | 
			
		||||
        res.status(400).json({ Error: 102 });
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Send inbox message to founding warlord
 | 
			
		||||
    // TOVERIFY: Should other warlords get this as well?
 | 
			
		||||
    // TOVERIFY: Who/what should the sender be?
 | 
			
		||||
    // TOVERIFY: Should this message be highPriority?
 | 
			
		||||
    const invitedClanOwnerMember = (await GuildMember.findOne({ guildId: guilds[0]._id, rank: 0 }))!;
 | 
			
		||||
    const senderInventory = await getInventory(account._id.toString(), "ActiveAvatarImageType");
 | 
			
		||||
    const senderGuild = (await Guild.findById(allianceMember.guildId, "Name"))!;
 | 
			
		||||
    const alliance = (await Alliance.findById(req.query.allianceId, "Name"))!;
 | 
			
		||||
    await createMessage(invitedClanOwnerMember.accountId, [
 | 
			
		||||
        {
 | 
			
		||||
            sndr: getSuffixedName(account),
 | 
			
		||||
            msg: "/Lotus/Language/Menu/Mailbox_AllianceInvite_Body",
 | 
			
		||||
            arg: [
 | 
			
		||||
                {
 | 
			
		||||
                    Key: "THEIR_CLAN",
 | 
			
		||||
                    Tag: senderGuild.Name
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    Key: "CLAN",
 | 
			
		||||
                    Tag: guilds[0].Name
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    Key: "ALLIANCE",
 | 
			
		||||
                    Tag: alliance.Name
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            sub: "/Lotus/Language/Menu/Mailbox_AllianceInvite_Title",
 | 
			
		||||
            icon: ExportFlavour[senderInventory.ActiveAvatarImageType].icon,
 | 
			
		||||
            contextInfo: alliance._id.toString(),
 | 
			
		||||
            highPriority: true,
 | 
			
		||||
            acceptAction: "ALLIANCE_INVITE",
 | 
			
		||||
            declineAction: "ALLIANCE_INVITE",
 | 
			
		||||
            hasAccountAction: true
 | 
			
		||||
        }
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    res.end();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
interface IAddToAllianceRequest {
 | 
			
		||||
    clanName: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IGuildChoice {
 | 
			
		||||
    OriginalPlatform: number;
 | 
			
		||||
    Name: string;
 | 
			
		||||
}
 | 
			
		||||
@ -88,7 +88,7 @@ export const addToGuildController: RequestHandler = async (req, res) => {
 | 
			
		||||
                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) {
 | 
			
		||||
            logger.debug(`alliance invite failed due to ${String(e)}`);
 | 
			
		||||
            logger.debug(`guild invite failed due to ${String(e)}`);
 | 
			
		||||
            res.status(400).send("Already requested");
 | 
			
		||||
        }
 | 
			
		||||
        res.end();
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										37
									
								
								src/controllers/api/confirmAllianceInvitationController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/controllers/api/confirmAllianceInvitationController.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
			
		||||
import { Alliance, AllianceMember, Guild, GuildMember } from "@/src/models/guildModel";
 | 
			
		||||
import { getAllianceClient } from "@/src/services/guildService";
 | 
			
		||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
			
		||||
import { RequestHandler } from "express";
 | 
			
		||||
 | 
			
		||||
export const confirmAllianceInvitationController: RequestHandler = async (req, res) => {
 | 
			
		||||
    // Check requester is a warlord in their guild
 | 
			
		||||
    const accountId = await getAccountIdForRequest(req);
 | 
			
		||||
    const guildMember = (await GuildMember.findOne({ accountId, status: 0 }))!;
 | 
			
		||||
    if (guildMember.rank > 1) {
 | 
			
		||||
        res.status(400).json({ Error: 104 });
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const allianceMember = await AllianceMember.findOne({
 | 
			
		||||
        allianceId: req.query.allianceId,
 | 
			
		||||
        guildId: guildMember.guildId
 | 
			
		||||
    });
 | 
			
		||||
    if (!allianceMember || !allianceMember.Pending) {
 | 
			
		||||
        res.status(400);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    allianceMember.Pending = false;
 | 
			
		||||
 | 
			
		||||
    const guild = (await Guild.findById(guildMember.guildId))!;
 | 
			
		||||
    guild.AllianceId = allianceMember.allianceId;
 | 
			
		||||
 | 
			
		||||
    await Promise.all([allianceMember.save(), guild.save()]);
 | 
			
		||||
 | 
			
		||||
    // Give client the new alliance data which uses "AllianceId" instead of "_id" in this response
 | 
			
		||||
    const alliance = (await Alliance.findById(allianceMember.allianceId))!;
 | 
			
		||||
    const { _id, ...rest } = await getAllianceClient(alliance, guild);
 | 
			
		||||
    res.json({
 | 
			
		||||
        AllianceId: _id,
 | 
			
		||||
        ...rest
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										17
									
								
								src/controllers/api/declineAllianceInviteController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/controllers/api/declineAllianceInviteController.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
import { AllianceMember, GuildMember } from "@/src/models/guildModel";
 | 
			
		||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
			
		||||
import { RequestHandler } from "express";
 | 
			
		||||
 | 
			
		||||
export const declineAllianceInviteController: RequestHandler = async (req, res) => {
 | 
			
		||||
    // Check requester is a warlord in their guild
 | 
			
		||||
    const accountId = await getAccountIdForRequest(req);
 | 
			
		||||
    const guildMember = (await GuildMember.findOne({ accountId, status: 0 }))!;
 | 
			
		||||
    if (guildMember.rank > 1) {
 | 
			
		||||
        res.status(400).json({ Error: 104 });
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    await AllianceMember.deleteOne({ allianceId: req.query.allianceId, guildId: guildMember.guildId });
 | 
			
		||||
 | 
			
		||||
    res.end();
 | 
			
		||||
};
 | 
			
		||||
@ -26,3 +26,21 @@ export const getIndexAfter = (str: string, searchWord: string): number => {
 | 
			
		||||
    }
 | 
			
		||||
    return index + searchWord.length;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const regexEscape = (str: string): string => {
 | 
			
		||||
    str = str.split(".").join("\\.");
 | 
			
		||||
    str = str.split("\\").join("\\\\");
 | 
			
		||||
    str = str.split("[").join("\\[");
 | 
			
		||||
    str = str.split("]").join("\\]");
 | 
			
		||||
    str = str.split("+").join("\\+");
 | 
			
		||||
    str = str.split("*").join("\\*");
 | 
			
		||||
    str = str.split("$").join("\\$");
 | 
			
		||||
    str = str.split("^").join("\\^");
 | 
			
		||||
    str = str.split("?").join("\\?");
 | 
			
		||||
    str = str.split("|").join("\\|");
 | 
			
		||||
    str = str.split("(").join("\\(");
 | 
			
		||||
    str = str.split(")").join("\\)");
 | 
			
		||||
    str = str.split("{").join("\\{");
 | 
			
		||||
    str = str.split("}").join("\\}");
 | 
			
		||||
    return str;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -265,10 +265,10 @@ allianceSchema.index({ Name: 1 }, { unique: true });
 | 
			
		||||
export const Alliance = model<IAllianceDatabase>("Alliance", allianceSchema);
 | 
			
		||||
 | 
			
		||||
const allianceMemberSchema = new Schema<IAllianceMemberDatabase>({
 | 
			
		||||
    allianceId: Schema.Types.ObjectId,
 | 
			
		||||
    guildId: Schema.Types.ObjectId,
 | 
			
		||||
    Pending: Boolean,
 | 
			
		||||
    Permissions: Number
 | 
			
		||||
    allianceId: { type: Schema.Types.ObjectId, required: true },
 | 
			
		||||
    guildId: { type: Schema.Types.ObjectId, required: true },
 | 
			
		||||
    Pending: { type: Boolean, required: true },
 | 
			
		||||
    Permissions: { type: Number, required: true }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
allianceMemberSchema.index({ allianceId: 1, guildId: 1 }, { unique: true });
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ import { abortDojoComponentController } from "@/src/controllers/api/abortDojoCom
 | 
			
		||||
import { abortDojoComponentDestructionController } from "@/src/controllers/api/abortDojoComponentDestructionController";
 | 
			
		||||
import { activateRandomModController } from "@/src/controllers/api/activateRandomModController";
 | 
			
		||||
import { addFriendImageController } from "@/src/controllers/api/addFriendImageController";
 | 
			
		||||
import { addToAllianceController } from "@/src/controllers/api/addToAllianceController";
 | 
			
		||||
import { addToGuildController } from "@/src/controllers/api/addToGuildController";
 | 
			
		||||
import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController";
 | 
			
		||||
import { archonFusionController } from "@/src/controllers/api/archonFusionController";
 | 
			
		||||
@ -18,6 +19,7 @@ import { claimLibraryDailyTaskRewardController } from "@/src/controllers/api/cla
 | 
			
		||||
import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController";
 | 
			
		||||
import { clearNewEpisodeRewardController } from "@/src/controllers/api/clearNewEpisodeRewardController";
 | 
			
		||||
import { completeRandomModChallengeController } from "@/src/controllers/api/completeRandomModChallengeController";
 | 
			
		||||
import { confirmAllianceInvitationController } from "@/src/controllers/api/confirmAllianceInvitationController";
 | 
			
		||||
import { confirmGuildInvitationController } from "@/src/controllers/api/confirmGuildInvitationController";
 | 
			
		||||
import { contributeGuildClassController } from "@/src/controllers/api/contributeGuildClassController";
 | 
			
		||||
import { contributeToDojoComponentController } from "@/src/controllers/api/contributeToDojoComponentController";
 | 
			
		||||
@ -27,6 +29,7 @@ import { createGuildController } from "@/src/controllers/api/createGuildControll
 | 
			
		||||
import { creditsController } from "@/src/controllers/api/creditsController";
 | 
			
		||||
import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
 | 
			
		||||
import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController";
 | 
			
		||||
import { declineAllianceInviteController } from "@/src/controllers/api/declineAllianceInviteController";
 | 
			
		||||
import { declineGuildInviteController } from "@/src/controllers/api/declineGuildInviteController";
 | 
			
		||||
import { deleteSessionController } from "@/src/controllers/api/deleteSessionController";
 | 
			
		||||
import { destroyDojoDecoController } from "@/src/controllers/api/destroyDojoDecoController";
 | 
			
		||||
@ -140,8 +143,10 @@ apiRouter.get("/cancelGuildAdvertisement.php", cancelGuildAdvertisementControlle
 | 
			
		||||
apiRouter.get("/changeGuildRank.php", changeGuildRankController);
 | 
			
		||||
apiRouter.get("/checkDailyMissionBonus.php", checkDailyMissionBonusController);
 | 
			
		||||
apiRouter.get("/claimLibraryDailyTaskReward.php", claimLibraryDailyTaskRewardController);
 | 
			
		||||
apiRouter.get("/confirmAllianceInvitation.php", confirmAllianceInvitationController);
 | 
			
		||||
apiRouter.get("/confirmGuildInvitation.php", confirmGuildInvitationController);
 | 
			
		||||
apiRouter.get("/credits.php", creditsController);
 | 
			
		||||
apiRouter.get("/declineAllianceInvite.php", declineAllianceInviteController);
 | 
			
		||||
apiRouter.get("/declineGuildInvite.php", declineGuildInviteController);
 | 
			
		||||
apiRouter.get("/deleteSession.php", deleteSessionController);
 | 
			
		||||
apiRouter.get("/dojo", dojoController);
 | 
			
		||||
@ -181,6 +186,7 @@ apiRouter.get("/updateSession.php", updateSessionGetController);
 | 
			
		||||
apiRouter.post("/abortDojoComponent.php", abortDojoComponentController);
 | 
			
		||||
apiRouter.post("/activateRandomMod.php", activateRandomModController);
 | 
			
		||||
apiRouter.post("/addFriendImage.php", addFriendImageController);
 | 
			
		||||
apiRouter.post("/addToAlliance.php", addToAllianceController);
 | 
			
		||||
apiRouter.post("/addToGuild.php", addToGuildController);
 | 
			
		||||
apiRouter.post("/arcaneCommon.php", arcaneCommonController);
 | 
			
		||||
apiRouter.post("/archonFusion.php", archonFusionController);
 | 
			
		||||
 | 
			
		||||
@ -315,8 +315,6 @@ export interface IAllianceMemberDatabase {
 | 
			
		||||
    Permissions: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: Alliance chat permissions
 | 
			
		||||
// TODO: POST /api/addToAlliance.php: {"clanName":"abc"}
 | 
			
		||||
// TODO: GET /api/divvyAllianceVault.php?accountId=6633b81e9dba0b714f28ff02&nonce=5702391171614479&ct=MSI&guildId=663e9be9f741eeb5782f9df0&allianceId=000000000000000000000069&credits=1
 | 
			
		||||
// TODO: GET /api/divvyAllianceVault.php?accountId=6633b81e9dba0b714f28ff02&nonce=5702391171614479&ct=MSI&guildId=663e9be9f741eeb5782f9df0&allianceId=000000000000000000000069&credits=0
 | 
			
		||||
// TODO: GET /api/removeFromAlliance.php?accountId=6633b81e9dba0b714f28ff02&nonce=5702391171614479&ct=MSI&guildId=663e9be9f741eeb5782f9df0
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user