返回提交历史
Added
src/controllers/api/createAllianceController.ts
+50
-0
Modified
src/controllers/api/getAllianceController.ts
+21
-3
Modified
src/controllers/api/getGuildController.ts
+2
-4
Modified
src/models/guildModel.ts
+26
-1
Modified
src/routes/api.ts
+2
-0
Modified
src/services/guildService.ts
+36
-2
Modified
src/types/guildTypes.ts
+58
-6
XFEstudio/SpaceNinjaServer
feat: create alliance (#1423)
Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1423 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
24ed580a
代码差异
7 个文件
+195
-16
@@ -0,0 +1,50 @@
1
import { getJSONfromString } from "@/src/helpers/stringHelpers";
2
import { Alliance, AllianceMember, Guild, GuildMember } from "@/src/models/guildModel";
3
import { getAllianceClient } from "@/src/services/guildService";
4
import { getInventory } from "@/src/services/inventoryService";
5
import { getAccountIdForRequest } from "@/src/services/loginService";
6
import { GuildPermission } from "@/src/types/guildTypes";
7
import { RequestHandler } from "express";
8
9
export const createAllianceController: RequestHandler = async (req, res) => {
10
const accountId = await getAccountIdForRequest(req);
11
const inventory = await getInventory(accountId, "GuildId");
12
const guild = (await Guild.findById(inventory.GuildId!, "Name Tier AllianceId"))!;
13
if (guild.AllianceId) {
14
res.status(400).send("Guild is already in an alliance").end();
15
return;
16
}
17
const guildMember = (await GuildMember.findOne({ guildId: guild._id, accountId }, "rank"))!;
18
if (guildMember.rank > 1) {
19
res.status(400).send("Invalid permission").end();
20
return;
21
}
22
const data = getJSONfromString<ICreateAllianceRequest>(String(req.body));
23
const alliance = new Alliance({ Name: data.allianceName });
24
try {
25
await alliance.save();
26
} catch (e) {
27
res.status(400).send("Alliance name already in use").end();
28
return;
29
}
30
guild.AllianceId = alliance._id;
31
await Promise.all([
32
guild.save(),
33
AllianceMember.insertOne({
34
allianceId: alliance._id,
35
guildId: guild._id,
36
Pending: false,
37
Permissions:
38
GuildPermission.Ruler |
39
GuildPermission.Promoter |
40
GuildPermission.Recruiter |
41
GuildPermission.Treasurer |
42
GuildPermission.ChatModerator
43
})
44
]);
45
res.json(await getAllianceClient(alliance, guild));
46
};
47
48
interface ICreateAllianceRequest {
49
allianceName: string;
50
}
@@ -1,7 +1,25 @@
1
import { Alliance, Guild } from "@/src/models/guildModel";
2
import { getAllianceClient } from "@/src/services/guildService";
3
import { getInventory } from "@/src/services/inventoryService";
4
import { getAccountIdForRequest } from "@/src/services/loginService";
1
5
import { RequestHandler } from "express";
2
6
3
const getAllianceController: RequestHandler = (_req, res) => {
4
res.sendStatus(200);
7
export const getAllianceController: RequestHandler = async (req, res) => {
8
const accountId = await getAccountIdForRequest(req);
9
const inventory = await getInventory(accountId, "GuildId");
10
if (inventory.GuildId) {
11
const guild = (await Guild.findById(inventory.GuildId, "Name Tier AllianceId"))!;
12
if (guild.AllianceId) {
13
const alliance = (await Alliance.findById(guild.AllianceId))!;
14
res.json(await getAllianceClient(alliance, guild));
15
return;
16
}
17
}
18
res.end();
5
19
};
6
20
7
export { getAllianceController };
21
/*interface IGetAllianceRequest {
22
memberCount: number;
23
clanLeaderName: string;
24
clanLeaderId: string;
25
}*/
@@ -5,7 +5,7 @@ import { logger } from "@/src/utils/logger";
5
5
import { getInventory } from "@/src/services/inventoryService";
6
6
import { createUniqueClanName, getGuildClient } from "@/src/services/guildService";
7
7
8
const getGuildController: RequestHandler = async (req, res) => {
8
export const getGuildController: RequestHandler = async (req, res) => {
9
9
const accountId = await getAccountIdForRequest(req);
10
10
const inventory = await getInventory(accountId, "GuildId");
11
11
if (inventory.GuildId) {
@@ -28,7 +28,5 @@ const getGuildController: RequestHandler = async (req, res) => {
28
28
return;
29
29
}
30
30
}
31
res.sendStatus(200);
31
res.end();
32
32
};
33
34
export { getGuildController };
@@ -11,7 +11,9 @@ import {
11
11
IGuildLogEntryRoster,
12
12
IGuildLogEntryContributable,
13
13
IDojoLeaderboardEntry,
14
IGuildAdDatabase
14
IGuildAdDatabase,
15
IAllianceDatabase,
16
IAllianceMemberDatabase
15
17
} from "@/src/types/guildTypes";
16
18
import { Document, Model, model, Schema, Types } from "mongoose";
17
19
import { fusionTreasuresSchema, typeCountSchema } from "./inventoryModels/inventoryModel";
@@ -167,6 +169,7 @@ const guildSchema = new Schema<IGuildDatabase>(
167
169
TradeTax: { type: Number, default: 0 },
168
170
Tier: { type: Number, default: 1 },
169
171
Emblem: { type: Boolean },
172
AllianceId: { type: Types.ObjectId },
170
173
DojoComponents: { type: [dojoComponentSchema], default: [] },
171
174
DojoCapacity: { type: Number, default: 100 },
172
175
DojoEnergy: { type: Number, default: 5 },
@@ -246,3 +249,25 @@ guildAdSchema.index({ GuildId: 1 }, { unique: true });
246
249
guildAdSchema.index({ Expiry: 1 }, { expireAfterSeconds: 0 });
247
250
248
251
export const GuildAd = model<IGuildAdDatabase>("GuildAd", guildAdSchema);
252
253
const allianceSchema = new Schema<IAllianceDatabase>({
254
Name: String,
255
MOTD: longMOTDSchema,
256
LongMOTD: longMOTDSchema,
257
Emblem: Boolean
258
});
259
260
allianceSchema.index({ Name: 1 }, { unique: true });
261
262
export const Alliance = model<IAllianceDatabase>("Alliance", allianceSchema);
263
264
const allianceMemberSchema = new Schema<IAllianceMemberDatabase>({
265
allianceId: Schema.Types.ObjectId,
266
guildId: Schema.Types.ObjectId,
267
Pending: Boolean,
268
Permissions: Number
269
});
270
271
guildMemberSchema.index({ allianceId: 1, guildId: 1 }, { unique: true });
272
273
export const AllianceMember = model<IAllianceMemberDatabase>("AllianceMember", allianceMemberSchema);
@@ -22,6 +22,7 @@ import { confirmGuildInvitationController } from "@/src/controllers/api/confirmG
22
22
import { contributeGuildClassController } from "@/src/controllers/api/contributeGuildClassController";
23
23
import { contributeToDojoComponentController } from "@/src/controllers/api/contributeToDojoComponentController";
24
24
import { contributeToVaultController } from "@/src/controllers/api/contributeToVaultController";
25
import { createAllianceController } from "@/src/controllers/api/createAllianceController";
25
26
import { createGuildController } from "@/src/controllers/api/createGuildController";
26
27
import { creditsController } from "@/src/controllers/api/creditsController";
27
28
import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
@@ -193,6 +194,7 @@ apiRouter.post("/confirmGuildInvitation.php", confirmGuildInvitationController);
193
194
apiRouter.post("/contributeGuildClass.php", contributeGuildClassController);
194
195
apiRouter.post("/contributeToDojoComponent.php", contributeToDojoComponentController);
195
196
apiRouter.post("/contributeToVault.php", contributeToVaultController);
197
apiRouter.post("/createAlliance.php", createAllianceController);
196
198
apiRouter.post("/createGuild.php", createGuildController);
197
199
apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController);
198
200
apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController);
@@ -1,10 +1,13 @@
1
1
import { Request } from "express";
2
2
import { getAccountIdForRequest } from "@/src/services/loginService";
3
3
import { getInventory } from "@/src/services/inventoryService";
4
import { Guild, GuildAd, GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
4
import { AllianceMember, Guild, GuildAd, GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
5
5
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
6
6
import {
7
7
GuildPermission,
8
IAllianceClient,
9
IAllianceDatabase,
10
IAllianceMemberClient,
8
11
IDojoClient,
9
12
IDojoComponentClient,
10
13
IDojoComponentDatabase,
@@ -99,7 +102,8 @@ export const getGuildClient = async (guild: TGuildDatabaseDocument, accountId: s
99
102
XP: guild.XP,
100
103
IsContributor: !!guild.CeremonyContributors?.find(x => x.equals(accountId)),
101
104
NumContributors: guild.CeremonyContributors?.length ?? 0,
102
CeremonyResetDate: guild.CeremonyResetDate ? toMongoDate(guild.CeremonyResetDate) : undefined
105
CeremonyResetDate: guild.CeremonyResetDate ? toMongoDate(guild.CeremonyResetDate) : undefined,
106
AllianceId: guild.AllianceId ? toOid(guild.AllianceId) : undefined
103
107
};
104
108
};
105
109
@@ -549,4 +553,34 @@ export const deleteGuild = async (guildId: Types.ObjectId): Promise<void> => {
549
553
});
550
554
551
555
await GuildAd.deleteOne({ GuildId: guildId });
556
557
await AllianceMember.deleteMany({ guildId });
558
559
// TODO: If this guild was the founding guild of an alliance (ruler permission), that would need to be forcefully deleted now as well.
560
};
561
562
export const getAllianceClient = async (
563
alliance: IAllianceDatabase,
564
guild: TGuildDatabaseDocument
565
): Promise<IAllianceClient> => {
566
const allianceMembers = await AllianceMember.find({ allianceId: alliance._id });
567
const clans: IAllianceMemberClient[] = [];
568
for (const allianceMember of allianceMembers) {
569
const memberGuild = allianceMember.guildId.equals(guild._id)
570
? guild
571
: (await Guild.findById(allianceMember.guildId))!;
572
clans.push({
573
_id: toOid(allianceMember.guildId),
574
Name: memberGuild.Name,
575
Tier: memberGuild.Tier,
576
Pending: allianceMember.Pending,
577
Permissions: allianceMember.Permissions,
578
MemberCount: await GuildMember.countDocuments({ guildId: memberGuild._id, status: 0 })
579
});
580
}
581
return {
582
_id: toOid(alliance._id),
583
Name: alliance.Name,
584
Clans: clans
585
};
552
586
};
@@ -18,6 +18,9 @@ export interface IGuildClient {
18
18
IsContributor: boolean;
19
19
NumContributors: number;
20
20
CeremonyResetDate?: IMongoDate;
21
CrossPlatformEnabled?: boolean;
22
AutoContributeFromVault?: boolean;
23
AllianceId?: IOid;
21
24
}
22
25
23
26
export interface IGuildDatabase {
@@ -29,6 +32,7 @@ export interface IGuildDatabase {
29
32
TradeTax: number;
30
33
Tier: number;
31
34
Emblem?: boolean;
35
AllianceId?: Types.ObjectId;
32
36
33
37
DojoComponents: IDojoComponentDatabase[];
34
38
DojoCapacity: number;
@@ -60,21 +64,21 @@ export interface IGuildDatabase {
60
64
export interface ILongMOTD {
61
65
message: string;
62
66
authorName: string;
63
//authorGuildName: "";
67
authorGuildName?: "";
64
68
}
65
69
66
70
// 32 seems to be reserved
67
71
export enum GuildPermission {
68
Ruler = 1, // Change clan hierarchy
72
Ruler = 1, // Clan: Change hierarchy. Alliance: Kick clans.
69
73
Advertiser = 8192,
70
Recruiter = 2, // Invite members
74
Recruiter = 2, // Send invites (Clans & Alliances)
71
75
Regulator = 4, // Kick members
72
Promoter = 8, // Promote and demote members
76
Promoter = 8, // Clan: Promote and demote members. Alliance: Change clan permissions.
73
77
Architect = 16, // Create and destroy rooms
74
78
Decorator = 1024, // Create and destroy decos
75
Treasurer = 64, // Contribute from vault and edit tax rate
79
Treasurer = 64, // Clan: Contribute from vault and edit tax rate. Alliance: Divvy vault.
76
80
Tech = 128, // Queue research
77
ChatModerator = 512,
81
ChatModerator = 512, // (Clans & Alliances)
78
82
Herald = 2048, // Change MOTD
79
83
Fabricator = 4096 // Replicate research
80
84
}
@@ -268,3 +272,51 @@ export interface IGuildAdDatabase {
268
272
RecruitMsg: string;
269
273
Tier: number;
270
274
}
275
276
export interface IAllianceClient {
277
_id: IOid;
278
Name: string;
279
MOTD?: ILongMOTD;
280
LongMOTD?: ILongMOTD;
281
Emblem?: boolean;
282
CrossPlatformEnabled?: boolean;
283
Clans: IAllianceMemberClient[];
284
OriginalPlatform?: number;
285
}
286
287
export interface IAllianceDatabase {
288
_id: Types.ObjectId;
289
Name: string;
290
MOTD?: ILongMOTD;
291
LongMOTD?: ILongMOTD;
292
Emblem?: boolean;
293
}
294
295
export interface IAllianceMemberClient {
296
_id: IOid;
297
Name: string;
298
Tier: number;
299
Pending: boolean;
300
Emblem?: boolean;
301
Permissions: number;
302
MemberCount: number;
303
ClanLeader?: string;
304
ClanLeaderId?: IOid;
305
OriginalPlatform?: number;
306
}
307
308
export interface IAllianceMemberDatabase {
309
allianceId: Types.ObjectId;
310
guildId: Types.ObjectId;
311
Pending: boolean;
312
Permissions: number;
313
}
314
315
// TODO: Alliance chat permissions
316
// TODO: POST /api/addToAlliance.php: {"clanName":"abc"}
317
// TODO: GET /api/divvyAllianceVault.php?accountId=6633b81e9dba0b714f28ff02&nonce=5702391171614479&ct=MSI&guildId=663e9be9f741eeb5782f9df0&allianceId=000000000000000000000069&credits=1
318
// TODO: GET /api/divvyAllianceVault.php?accountId=6633b81e9dba0b714f28ff02&nonce=5702391171614479&ct=MSI&guildId=663e9be9f741eeb5782f9df0&allianceId=000000000000000000000069&credits=0
319
// TODO: GET /api/removeFromAlliance.php?accountId=6633b81e9dba0b714f28ff02&nonce=5702391171614479&ct=MSI&guildId=663e9be9f741eeb5782f9df0
320
// TODO: GET /api/setAllianceGuildPermissions.php?accountId=6633b81e9dba0b714f28ff02&nonce=5702391171614479&ct=MSI&guildId=000000000000000000000042&perms=2
321
// TODO: Handle alliance in contributeToVault
322
// TODO: Handle alliance in setGuildMotd