XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESpaceNinjaServer

A simple server for a small space ninja game

公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/XFESpaceNinjaServer

feat: alliance invites (#1452)

Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1452 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>

92e8ffd7
Sainan <63328889+Sainan@users.noreply.github.com>
提交于

代码差异

8 个文件 +200 -7
Added src/controllers/api/addToAllianceController.ts +117 -0
@@ -0,0 +1,117 @@
1 import { getJSONfromString, regexEscape } from "@/src/helpers/stringHelpers";
2 import { Alliance, AllianceMember, Guild, GuildMember } from "@/src/models/guildModel";
3 import { createMessage } from "@/src/services/inboxService";
4 import { getInventory } from "@/src/services/inventoryService";
5 import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService";
6 import { GuildPermission } from "@/src/types/guildTypes";
7 import { logger } from "@/src/utils/logger";
8 import { RequestHandler } from "express";
9 import { ExportFlavour } from "warframe-public-export-plus";
10
11 export const addToAllianceController: RequestHandler = async (req, res) => {
12 // Check requester is a warlord in their guild
13 const account = await getAccountForRequest(req);
14 const guildMember = (await GuildMember.findOne({ accountId: account._id, status: 0 }))!;
15 if (guildMember.rank > 1) {
16 res.status(400).json({ Error: 104 });
17 return;
18 }
19
20 // Check guild has invite permissions in the alliance
21 const allianceMember = (await AllianceMember.findOne({
22 allianceId: req.query.allianceId,
23 guildId: guildMember.guildId
24 }))!;
25 if (!(allianceMember.Permissions & GuildPermission.Recruiter)) {
26 res.status(400).json({ Error: 104 });
27 return;
28 }
29
30 // Find clan to invite
31 const payload = getJSONfromString<IAddToAllianceRequest>(String(req.body));
32 const guilds = await Guild.find(
33 {
34 Name:
35 payload.clanName.indexOf("#") == -1
36 ? new RegExp("^" + regexEscape(payload.clanName) + "#...$")
37 : payload.clanName
38 },
39 "Name"
40 );
41 if (guilds.length == 0) {
42 res.status(400).json({ Error: 101 });
43 return;
44 }
45 if (guilds.length > 1) {
46 const choices: IGuildChoice[] = [];
47 for (const guild of guilds) {
48 choices.push({
49 OriginalPlatform: 0,
50 Name: guild.Name
51 });
52 }
53 res.json(choices);
54 return;
55 }
56
57 // Add clan as a pending alliance member
58 try {
59 await AllianceMember.insertOne({
60 allianceId: req.query.allianceId,
61 guildId: guilds[0]._id,
62 Pending: true,
63 Permissions: 0
64 });
65 } catch (e) {
66 logger.debug(`alliance invite failed due to ${String(e)}`);
67 res.status(400).json({ Error: 102 });
68 return;
69 }
70
71 // Send inbox message to founding warlord
72 // TOVERIFY: Should other warlords get this as well?
73 // TOVERIFY: Who/what should the sender be?
74 // TOVERIFY: Should this message be highPriority?
75 const invitedClanOwnerMember = (await GuildMember.findOne({ guildId: guilds[0]._id, rank: 0 }))!;
76 const senderInventory = await getInventory(account._id.toString(), "ActiveAvatarImageType");
77 const senderGuild = (await Guild.findById(allianceMember.guildId, "Name"))!;
78 const alliance = (await Alliance.findById(req.query.allianceId, "Name"))!;
79 await createMessage(invitedClanOwnerMember.accountId, [
80 {
81 sndr: getSuffixedName(account),
82 msg: "/Lotus/Language/Menu/Mailbox_AllianceInvite_Body",
83 arg: [
84 {
85 Key: "THEIR_CLAN",
86 Tag: senderGuild.Name
87 },
88 {
89 Key: "CLAN",
90 Tag: guilds[0].Name
91 },
92 {
93 Key: "ALLIANCE",
94 Tag: alliance.Name
95 }
96 ],
97 sub: "/Lotus/Language/Menu/Mailbox_AllianceInvite_Title",
98 icon: ExportFlavour[senderInventory.ActiveAvatarImageType].icon,
99 contextInfo: alliance._id.toString(),
100 highPriority: true,
101 acceptAction: "ALLIANCE_INVITE",
102 declineAction: "ALLIANCE_INVITE",
103 hasAccountAction: true
104 }
105 ]);
106
107 res.end();
108 };
109
110 interface IAddToAllianceRequest {
111 clanName: string;
112 }
113
114 interface IGuildChoice {
115 OriginalPlatform: number;
116 Name: string;
117 }
Modified src/controllers/api/addToGuildController.ts +1 -1
@@ -88,7 +88,7 @@ export const addToGuildController: RequestHandler = async (req, res) => {
88 88 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.
89 89 });
90 90 } catch (e) {
91 logger.debug(`alliance invite failed due to ${String(e)}`);
91 logger.debug(`guild invite failed due to ${String(e)}`);
92 92 res.status(400).send("Already requested");
93 93 }
94 94 res.end();
Added src/controllers/api/confirmAllianceInvitationController.ts +37 -0
@@ -0,0 +1,37 @@
1 import { Alliance, AllianceMember, Guild, GuildMember } from "@/src/models/guildModel";
2 import { getAllianceClient } from "@/src/services/guildService";
3 import { getAccountIdForRequest } from "@/src/services/loginService";
4 import { RequestHandler } from "express";
5
6 export const confirmAllianceInvitationController: RequestHandler = async (req, res) => {
7 // Check requester is a warlord in their guild
8 const accountId = await getAccountIdForRequest(req);
9 const guildMember = (await GuildMember.findOne({ accountId, status: 0 }))!;
10 if (guildMember.rank > 1) {
11 res.status(400).json({ Error: 104 });
12 return;
13 }
14
15 const allianceMember = await AllianceMember.findOne({
16 allianceId: req.query.allianceId,
17 guildId: guildMember.guildId
18 });
19 if (!allianceMember || !allianceMember.Pending) {
20 res.status(400);
21 return;
22 }
23 allianceMember.Pending = false;
24
25 const guild = (await Guild.findById(guildMember.guildId))!;
26 guild.AllianceId = allianceMember.allianceId;
27
28 await Promise.all([allianceMember.save(), guild.save()]);
29
30 // Give client the new alliance data which uses "AllianceId" instead of "_id" in this response
31 const alliance = (await Alliance.findById(allianceMember.allianceId))!;
32 const { _id, ...rest } = await getAllianceClient(alliance, guild);
33 res.json({
34 AllianceId: _id,
35 ...rest
36 });
37 };
Added src/controllers/api/declineAllianceInviteController.ts +17 -0
@@ -0,0 +1,17 @@
1 import { AllianceMember, GuildMember } from "@/src/models/guildModel";
2 import { getAccountIdForRequest } from "@/src/services/loginService";
3 import { RequestHandler } from "express";
4
5 export const declineAllianceInviteController: RequestHandler = async (req, res) => {
6 // Check requester is a warlord in their guild
7 const accountId = await getAccountIdForRequest(req);
8 const guildMember = (await GuildMember.findOne({ accountId, status: 0 }))!;
9 if (guildMember.rank > 1) {
10 res.status(400).json({ Error: 104 });
11 return;
12 }
13
14 await AllianceMember.deleteOne({ allianceId: req.query.allianceId, guildId: guildMember.guildId });
15
16 res.end();
17 };
Modified src/helpers/stringHelpers.ts +18 -0
@@ -26,3 +26,21 @@ export const getIndexAfter = (str: string, searchWord: string): number => {
26 26 }
27 27 return index + searchWord.length;
28 28 };
29
30 export const regexEscape = (str: string): string => {
31 str = str.split(".").join("\\.");
32 str = str.split("\\").join("\\\\");
33 str = str.split("[").join("\\[");
34 str = str.split("]").join("\\]");
35 str = str.split("+").join("\\+");
36 str = str.split("*").join("\\*");
37 str = str.split("$").join("\\$");
38 str = str.split("^").join("\\^");
39 str = str.split("?").join("\\?");
40 str = str.split("|").join("\\|");
41 str = str.split("(").join("\\(");
42 str = str.split(")").join("\\)");
43 str = str.split("{").join("\\{");
44 str = str.split("}").join("\\}");
45 return str;
46 };
Modified src/models/guildModel.ts +4 -4
@@ -265,10 +265,10 @@ allianceSchema.index({ Name: 1 }, { unique: true });
265 265 export const Alliance = model<IAllianceDatabase>("Alliance", allianceSchema);
266 266
267 267 const allianceMemberSchema = new Schema<IAllianceMemberDatabase>({
268 allianceId: Schema.Types.ObjectId,
269 guildId: Schema.Types.ObjectId,
270 Pending: Boolean,
271 Permissions: Number
268 allianceId: { type: Schema.Types.ObjectId, required: true },
269 guildId: { type: Schema.Types.ObjectId, required: true },
270 Pending: { type: Boolean, required: true },
271 Permissions: { type: Number, required: true }
272 272 });
273 273
274 274 allianceMemberSchema.index({ allianceId: 1, guildId: 1 }, { unique: true });
Modified src/routes/api.ts +6 -0
@@ -4,6 +4,7 @@ import { abortDojoComponentController } from "@/src/controllers/api/abortDojoCom
4 4 import { abortDojoComponentDestructionController } from "@/src/controllers/api/abortDojoComponentDestructionController";
5 5 import { activateRandomModController } from "@/src/controllers/api/activateRandomModController";
6 6 import { addFriendImageController } from "@/src/controllers/api/addFriendImageController";
7 import { addToAllianceController } from "@/src/controllers/api/addToAllianceController";
7 8 import { addToGuildController } from "@/src/controllers/api/addToGuildController";
8 9 import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController";
9 10 import { archonFusionController } from "@/src/controllers/api/archonFusionController";
@@ -18,6 +19,7 @@ import { claimLibraryDailyTaskRewardController } from "@/src/controllers/api/cla
18 19 import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController";
19 20 import { clearNewEpisodeRewardController } from "@/src/controllers/api/clearNewEpisodeRewardController";
20 21 import { completeRandomModChallengeController } from "@/src/controllers/api/completeRandomModChallengeController";
22 import { confirmAllianceInvitationController } from "@/src/controllers/api/confirmAllianceInvitationController";
21 23 import { confirmGuildInvitationController } from "@/src/controllers/api/confirmGuildInvitationController";
22 24 import { contributeGuildClassController } from "@/src/controllers/api/contributeGuildClassController";
23 25 import { contributeToDojoComponentController } from "@/src/controllers/api/contributeToDojoComponentController";
@@ -27,6 +29,7 @@ import { createGuildController } from "@/src/controllers/api/createGuildControll
27 29 import { creditsController } from "@/src/controllers/api/creditsController";
28 30 import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
29 31 import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController";
32 import { declineAllianceInviteController } from "@/src/controllers/api/declineAllianceInviteController";
30 33 import { declineGuildInviteController } from "@/src/controllers/api/declineGuildInviteController";
31 34 import { deleteSessionController } from "@/src/controllers/api/deleteSessionController";
32 35 import { destroyDojoDecoController } from "@/src/controllers/api/destroyDojoDecoController";
@@ -140,8 +143,10 @@ apiRouter.get("/cancelGuildAdvertisement.php", cancelGuildAdvertisementControlle
140 143 apiRouter.get("/changeGuildRank.php", changeGuildRankController);
141 144 apiRouter.get("/checkDailyMissionBonus.php", checkDailyMissionBonusController);
142 145 apiRouter.get("/claimLibraryDailyTaskReward.php", claimLibraryDailyTaskRewardController);
146 apiRouter.get("/confirmAllianceInvitation.php", confirmAllianceInvitationController);
143 147 apiRouter.get("/confirmGuildInvitation.php", confirmGuildInvitationController);
144 148 apiRouter.get("/credits.php", creditsController);
149 apiRouter.get("/declineAllianceInvite.php", declineAllianceInviteController);
145 150 apiRouter.get("/declineGuildInvite.php", declineGuildInviteController);
146 151 apiRouter.get("/deleteSession.php", deleteSessionController);
147 152 apiRouter.get("/dojo", dojoController);
@@ -181,6 +186,7 @@ apiRouter.get("/updateSession.php", updateSessionGetController);
181 186 apiRouter.post("/abortDojoComponent.php", abortDojoComponentController);
182 187 apiRouter.post("/activateRandomMod.php", activateRandomModController);
183 188 apiRouter.post("/addFriendImage.php", addFriendImageController);
189 apiRouter.post("/addToAlliance.php", addToAllianceController);
184 190 apiRouter.post("/addToGuild.php", addToGuildController);
185 191 apiRouter.post("/arcaneCommon.php", arcaneCommonController);
186 192 apiRouter.post("/archonFusion.php", archonFusionController);
Modified src/types/guildTypes.ts +0 -2
@@ -315,8 +315,6 @@ export interface IAllianceMemberDatabase {
315 315 Permissions: number;
316 316 }
317 317
318 // TODO: Alliance chat permissions
319 // TODO: POST /api/addToAlliance.php: {"clanName":"abc"}
320 318 // TODO: GET /api/divvyAllianceVault.php?accountId=6633b81e9dba0b714f28ff02&nonce=5702391171614479&ct=MSI&guildId=663e9be9f741eeb5782f9df0&allianceId=000000000000000000000069&credits=1
321 319 // TODO: GET /api/divvyAllianceVault.php?accountId=6633b81e9dba0b714f28ff02&nonce=5702391171614479&ct=MSI&guildId=663e9be9f741eeb5782f9df0&allianceId=000000000000000000000069&credits=0
322 320 // TODO: GET /api/removeFromAlliance.php?accountId=6633b81e9dba0b714f28ff02&nonce=5702391171614479&ct=MSI&guildId=663e9be9f741eeb5782f9df0