返回提交历史
Added
src/controllers/api/addToAllianceController.ts
+117
-0
Modified
src/controllers/api/addToGuildController.ts
+1
-1
Added
src/controllers/api/confirmAllianceInvitationController.ts
+37
-0
Added
src/controllers/api/declineAllianceInviteController.ts
+17
-0
Modified
src/helpers/stringHelpers.ts
+18
-0
Modified
src/models/guildModel.ts
+4
-4
Modified
src/routes/api.ts
+6
-0
Modified
src/types/guildTypes.ts
+0
-2
XFEstudio/SpaceNinjaServer
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
代码差异
8 个文件
+200
-7
@@ -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
}
@@ -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();
@@ -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
};
@@ -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
};
@@ -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
};
@@ -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 });
@@ -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);
@@ -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