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: 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
Sainan <63328889+Sainan@users.noreply.github.com>
提交于

代码差异

7 个文件 +195 -16
Added src/controllers/api/createAllianceController.ts +50 -0
@@ -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 }
Modified src/controllers/api/getAllianceController.ts +21 -3
@@ -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 }*/
Modified src/controllers/api/getGuildController.ts +2 -4
@@ -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 };
Modified src/models/guildModel.ts +26 -1
@@ -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);
Modified src/routes/api.ts +2 -0
@@ -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);
Modified src/services/guildService.ts +36 -2
@@ -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 };
Modified src/types/guildTypes.ts +58 -6
@@ -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