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

SpaceNinjaServer

A simple server for a small space ninja game

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

XFEstudio/SpaceNinjaServer

feat: clan members (#1143)

Now you can add/remove members and accept/decline invites. Closes #1110 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1143 Co-authored-by: Sainan <sainan@calamity.inc> Co-committed-by: Sainan <sainan@calamity.inc>

fae6615d
Sainan <sainan@calamity.inc>
提交于

代码差异

13 个文件 +375 -87
Added src/controllers/api/addToGuildController.ts +75 -0
@@ -0,0 +1,75 @@
1 import { Guild, GuildMember } from "@/src/models/guildModel";
2 import { Account } from "@/src/models/loginModel";
3 import { fillInInventoryDataForGuildMember } from "@/src/services/guildService";
4 import { createMessage } from "@/src/services/inboxService";
5 import { getInventory } from "@/src/services/inventoryService";
6 import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService";
7 import { IOid } from "@/src/types/commonTypes";
8 import { IGuildMemberClient } from "@/src/types/guildTypes";
9 import { RequestHandler } from "express";
10 import { ExportFlavour } from "warframe-public-export-plus";
11
12 export const addToGuildController: RequestHandler = async (req, res) => {
13 const payload = JSON.parse(String(req.body)) as IAddToGuildRequest;
14
15 const account = await Account.findOne({ DisplayName: payload.UserName });
16 if (!account) {
17 res.status(400).json("Username does not exist");
18 return;
19 }
20
21 const guild = (await Guild.findOne({ _id: payload.GuildId.$oid }, "Name"))!;
22 // TODO: Check sender is allowed to send invites for this guild.
23
24 if (
25 await GuildMember.exists({
26 accountId: account._id,
27 guildId: payload.GuildId.$oid
28 })
29 ) {
30 res.status(400).json("User already invited to clan");
31 return;
32 }
33
34 await GuildMember.insertOne({
35 accountId: account._id,
36 guildId: payload.GuildId.$oid,
37 status: 2 // outgoing invite
38 });
39
40 const senderAccount = await getAccountForRequest(req);
41 const senderInventory = await getInventory(senderAccount._id.toString(), "ActiveAvatarImageType");
42 await createMessage(account._id.toString(), [
43 {
44 sndr: getSuffixedName(senderAccount),
45 msg: "/Lotus/Language/Menu/Mailbox_ClanInvite_Body",
46 arg: [
47 {
48 Key: "clan",
49 Tag: guild.Name + "#000"
50 }
51 ],
52 sub: "/Lotus/Language/Menu/Mailbox_ClanInvite_Title",
53 icon: ExportFlavour[senderInventory.ActiveAvatarImageType].icon,
54 contextInfo: payload.GuildId.$oid,
55 highPriority: true,
56 acceptAction: "GUILD_INVITE",
57 declineAction: "GUILD_INVITE",
58 hasAccountAction: true
59 }
60 ]);
61
62 const member: IGuildMemberClient = {
63 _id: { $oid: account._id.toString() },
64 DisplayName: account.DisplayName,
65 Rank: 7,
66 Status: 2
67 };
68 await fillInInventoryDataForGuildMember(member);
69 res.json({ NewMember: member });
70 };
71
72 interface IAddToGuildRequest {
73 UserName: string;
74 GuildId: IOid;
75 }
Added src/controllers/api/confirmGuildInvitationController.ts +32 -0
@@ -0,0 +1,32 @@
1 import { Guild, GuildMember } from "@/src/models/guildModel";
2 import { getGuildClient, updateInventoryForConfirmedGuildJoin } from "@/src/services/guildService";
3 import { getAccountIdForRequest } from "@/src/services/loginService";
4 import { RequestHandler } from "express";
5 import { Types } from "mongoose";
6
7 export const confirmGuildInvitationController: RequestHandler = async (req, res) => {
8 const accountId = await getAccountIdForRequest(req);
9 const guildMember = await GuildMember.findOne({
10 accountId: accountId,
11 guildId: req.query.clanId as string
12 });
13 if (guildMember) {
14 guildMember.status = 0;
15 await guildMember.save();
16 await updateInventoryForConfirmedGuildJoin(accountId, new Types.ObjectId(req.query.clanId as string));
17 const guild = (await Guild.findOne({ _id: req.query.clanId as string }))!;
18 res.json({
19 ...(await getGuildClient(guild, accountId)),
20 InventoryChanges: {
21 Recipes: [
22 {
23 ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
24 ItemCount: 1
25 }
26 ]
27 }
28 });
29 } else {
30 res.end();
31 }
32 };
Modified src/controllers/api/createGuildController.ts +10 -15
@@ -1,8 +1,8 @@
1 1 import { RequestHandler } from "express";
2 2 import { getAccountIdForRequest } from "@/src/services/loginService";
3 3 import { getJSONfromString } from "@/src/helpers/stringHelpers";
4 import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
5 import { Guild } from "@/src/models/guildModel";
4 import { Guild, GuildMember } from "@/src/models/guildModel";
5 import { updateInventoryForConfirmedGuildJoin } from "@/src/services/guildService";
6 6
7 7 export const createGuildController: RequestHandler = async (req, res) => {
8 8 const accountId = await getAccountIdForRequest(req);
@@ -14,20 +14,15 @@ export const createGuildController: RequestHandler = async (req, res) => {
14 14 });
15 15 await guild.save();
16 16
17 // Update inventory
18 const inventory = await Inventory.findOne({ accountOwnerId: accountId });
19 if (inventory) {
20 // Set GuildId
21 inventory.GuildId = guild._id;
22
23 // Give clan key (TODO: This should only be a blueprint)
24 inventory.LevelKeys.push({
25 ItemType: "/Lotus/Types/Keys/DojoKey",
26 ItemCount: 1
27 });
17 // Create guild member on database
18 await GuildMember.insertOne({
19 accountId: accountId,
20 guildId: guild._id,
21 status: 0,
22 rank: 0
23 });
28 24
29 await inventory.save();
30 }
25 await updateInventoryForConfirmedGuildJoin(accountId, guild._id);
31 26
32 27 res.json(guild);
33 28 };
Added src/controllers/api/declineGuildInviteController.ts +14 -0
@@ -0,0 +1,14 @@
1 import { GuildMember } from "@/src/models/guildModel";
2 import { getAccountForRequest } from "@/src/services/loginService";
3 import { RequestHandler } from "express";
4
5 export const declineGuildInviteController: RequestHandler = async (req, res) => {
6 const accountId = await getAccountForRequest(req);
7
8 await GuildMember.deleteOne({
9 accountId: accountId,
10 guildId: req.query.clanId as string
11 });
12
13 res.end();
14 };
Modified src/controllers/api/getGuildController.ts +4 -66
@@ -1,18 +1,13 @@
1 1 import { RequestHandler } from "express";
2 import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
3 2 import { Guild } from "@/src/models/guildModel";
4 3 import { getAccountIdForRequest } from "@/src/services/loginService";
5 import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
6 import { getGuildVault } from "@/src/services/guildService";
7 4 import { logger } from "@/src/utils/logger";
5 import { getInventory } from "@/src/services/inventoryService";
6 import { getGuildClient } from "@/src/services/guildService";
8 7
9 8 const getGuildController: RequestHandler = async (req, res) => {
10 9 const accountId = await getAccountIdForRequest(req);
11 const inventory = await Inventory.findOne({ accountOwnerId: accountId });
12 if (!inventory) {
13 res.status(400).json({ error: "inventory was undefined" });
14 return;
15 }
10 const inventory = await getInventory(accountId);
16 11 if (inventory.GuildId) {
17 12 const guild = await Guild.findOne({ _id: inventory.GuildId });
18 13 if (guild) {
@@ -23,64 +18,7 @@ const getGuildController: RequestHandler = async (req, res) => {
23 18 guild.CeremonyResetDate = undefined;
24 19 await guild.save();
25 20 }
26 res.json({
27 _id: toOid(guild._id),
28 Name: guild.Name,
29 MOTD: guild.MOTD,
30 LongMOTD: guild.LongMOTD,
31 Members: [
32 {
33 _id: { $oid: req.query.accountId },
34 Rank: 0,
35 Status: 0
36 }
37 ],
38 Ranks: [
39 {
40 Name: "/Lotus/Language/Game/Rank_Creator",
41 Permissions: 16351
42 },
43 {
44 Name: "/Lotus/Language/Game/Rank_Warlord",
45 Permissions: 14303
46 },
47 {
48 Name: "/Lotus/Language/Game/Rank_General",
49 Permissions: 4318
50 },
51 {
52 Name: "/Lotus/Language/Game/Rank_Officer",
53 Permissions: 4314
54 },
55 {
56 Name: "/Lotus/Language/Game/Rank_Leader",
57 Permissions: 4106
58 },
59 {
60 Name: "/Lotus/Language/Game/Rank_Sage",
61 Permissions: 4304
62 },
63 {
64 Name: "/Lotus/Language/Game/Rank_Soldier",
65 Permissions: 4098
66 },
67 {
68 Name: "/Lotus/Language/Game/Rank_Initiate",
69 Permissions: 4096
70 },
71 {
72 Name: "/Lotus/Language/Game/Rank_Utility",
73 Permissions: 4096
74 }
75 ],
76 Tier: 1,
77 Vault: getGuildVault(guild),
78 Class: guild.Class,
79 XP: guild.XP,
80 IsContributor: !!guild.CeremonyContributors?.find(x => x.equals(accountId)),
81 NumContributors: guild.CeremonyContributors?.length ?? 0,
82 CeremonyResetDate: guild.CeremonyResetDate ? toMongoDate(guild.CeremonyResetDate) : undefined
83 });
21 res.json(await getGuildClient(guild, accountId));
84 22 return;
85 23 }
86 24 }
Added src/controllers/api/removeFromGuildController.ts +45 -0
@@ -0,0 +1,45 @@
1 import { GuildMember } from "@/src/models/guildModel";
2 import { getGuildForRequest } from "@/src/services/guildService";
3 import { getInventory } from "@/src/services/inventoryService";
4 import { RequestHandler } from "express";
5
6 export const removeFromGuildController: RequestHandler = async (req, res) => {
7 const guild = await getGuildForRequest(req);
8 // TODO: Check permissions
9 const payload = JSON.parse(String(req.body)) as IRemoveFromGuildRequest;
10
11 const guildMember = (await GuildMember.findOne({ accountId: payload.userId, guildId: guild._id }))!;
12 if (guildMember.status == 0) {
13 const inventory = await getInventory(payload.userId);
14 inventory.GuildId = undefined;
15
16 // Remove clan key or blueprint from kicked member
17 const itemIndex = inventory.MiscItems.findIndex(x => x.ItemType == "/Lotus/Types/Keys/DojoKey");
18 if (itemIndex != -1) {
19 inventory.MiscItems.splice(itemIndex, 1);
20 } else {
21 const recipeIndex = inventory.Recipes.findIndex(x => x.ItemType == "/Lotus/Types/Keys/DojoKeyBlueprint");
22 if (recipeIndex != -1) {
23 inventory.Recipes.splice(itemIndex, 1);
24 }
25 }
26
27 await inventory.save();
28
29 // TODO: Handle clan leader kicking themselves (guild should be deleted in this case, I think)
30 } else if (guildMember.status == 2) {
31 // TODO: Maybe the inbox message for the sent invite should be deleted?
32 }
33 await GuildMember.deleteOne({ _id: guildMember._id });
34
35 res.json({
36 _id: payload.userId,
37 ItemToRemove: "/Lotus/Types/Keys/DojoKey",
38 RecipeToRemove: "/Lotus/Types/Keys/DojoKeyBlueprint"
39 });
40 };
41
42 interface IRemoveFromGuildRequest {
43 userId: string;
44 kicker?: string;
45 }
Modified src/controllers/custom/deleteAccountController.ts +3 -0
@@ -7,11 +7,14 @@ import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
7 7 import { PersonalRooms } from "@/src/models/personalRoomsModel";
8 8 import { Ship } from "@/src/models/shipModel";
9 9 import { Stats } from "@/src/models/statsModel";
10 import { GuildMember } from "@/src/models/guildModel";
10 11
11 12 export const deleteAccountController: RequestHandler = async (req, res) => {
12 13 const accountId = await getAccountIdForRequest(req);
14 // TODO: Handle the account being the creator of a guild
13 15 await Promise.all([
14 16 Account.deleteOne({ _id: accountId }),
17 GuildMember.deleteOne({ accountId: accountId }),
15 18 Inbox.deleteMany({ ownerId: accountId }),
16 19 Inventory.deleteOne({ accountOwnerId: accountId }),
17 20 Loadout.deleteOne({ loadoutOwnerId: accountId }),
Modified src/models/guildModel.ts +14 -2
@@ -4,7 +4,8 @@ import {
4 4 ITechProjectDatabase,
5 5 ITechProjectClient,
6 6 IDojoDecoDatabase,
7 ILongMOTD
7 ILongMOTD,
8 IGuildMemberDatabase
8 9 } from "@/src/types/guildTypes";
9 10 import { Document, Model, model, Schema, Types } from "mongoose";
10 11 import { fusionTreasuresSchema, typeCountSchema } from "./inventoryModels/inventoryModel";
@@ -70,7 +71,7 @@ const longMOTDSchema = new Schema<ILongMOTD>(
70 71
71 72 const guildSchema = new Schema<IGuildDatabase>(
72 73 {
73 Name: { type: String, required: true },
74 Name: { type: String, required: true, unique: true },
74 75 MOTD: { type: String, default: "" },
75 76 LongMOTD: { type: longMOTDSchema, default: undefined },
76 77 DojoComponents: { type: [dojoComponentSchema], default: [] },
@@ -113,3 +114,14 @@ export type TGuildDatabaseDocument = Document<unknown, {}, IGuildDatabase> &
113 114 keyof GuildDocumentProps
114 115 > &
115 116 GuildDocumentProps;
117
118 const guildMemberSchema = new Schema<IGuildMemberDatabase>({
119 accountId: Types.ObjectId,
120 guildId: Types.ObjectId,
121 status: { type: Number, required: true },
122 rank: { type: Number, default: 7 }
123 });
124
125 guildMemberSchema.index({ accountId: 1, guildId: 1 }, { unique: true });
126
127 export const GuildMember = model<IGuildMemberDatabase>("GuildMember", guildMemberSchema);
Modified src/models/inboxModel.ts +9 -1
@@ -32,6 +32,10 @@ export interface IMessage {
32 32 transmission?: string;
33 33 arg?: Arg[];
34 34 r?: boolean;
35 contextInfo?: string;
36 acceptAction?: string;
37 declineAction?: string;
38 hasAccountAction?: boolean;
35 39 }
36 40
37 41 export interface Arg {
@@ -100,7 +104,11 @@ const messageSchema = new Schema<IMessageDatabase>(
100 104 }
101 105 ],
102 106 default: undefined
103 }
107 },
108 contextInfo: String,
109 acceptAction: String,
110 declineAction: String,
111 hasAccountAction: Boolean
104 112 },
105 113 { timestamps: { createdAt: "date", updatedAt: false }, id: false }
106 114 );
Modified src/models/inventoryModels/inventoryModel.ts +1 -1
@@ -1249,7 +1249,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
1249 1249 Drones: [droneSchema],
1250 1250
1251 1251 //Active profile ico
1252 ActiveAvatarImageType: String,
1252 ActiveAvatarImageType: { type: String, default: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageDefault" },
1253 1253
1254 1254 // open location store like EidolonPlainsDiscoverable or OrbVallisCaveDiscoverable
1255 1255 DiscoveredMarkers: [Schema.Types.Mixed],
Modified src/routes/api.ts +8 -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 { addToGuildController } from "@/src/controllers/api/addToGuildController";
7 8 import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController";
8 9 import { archonFusionController } from "@/src/controllers/api/archonFusionController";
9 10 import { artifactsController } from "@/src/controllers/api/artifactsController";
@@ -14,11 +15,13 @@ import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompl
14 15 import { claimLibraryDailyTaskRewardController } from "@/src/controllers/api/claimLibraryDailyTaskRewardController";
15 16 import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController";
16 17 import { completeRandomModChallengeController } from "@/src/controllers/api/completeRandomModChallengeController";
18 import { confirmGuildInvitationController } from "@/src/controllers/api/confirmGuildInvitationController";
17 19 import { contributeGuildClassController } from "@/src/controllers/api/contributeGuildClassController";
18 20 import { contributeToDojoComponentController } from "@/src/controllers/api/contributeToDojoComponentController";
19 21 import { contributeToVaultController } from "@/src/controllers/api/contributeToVaultController";
20 22 import { createGuildController } from "@/src/controllers/api/createGuildController";
21 23 import { creditsController } from "@/src/controllers/api/creditsController";
24 import { declineGuildInviteController } from "@/src/controllers/api/declineGuildInviteController";
22 25 import { deleteSessionController } from "@/src/controllers/api/deleteSessionController";
23 26 import { destroyDojoDecoController } from "@/src/controllers/api/destroyDojoDecoController";
24 27 import { dojoComponentRushController } from "@/src/controllers/api/dojoComponentRushController";
@@ -69,6 +72,7 @@ import { playerSkillsController } from "@/src/controllers/api/playerSkillsContro
69 72 import { projectionManagerController } from "@/src/controllers/api/projectionManagerController";
70 73 import { purchaseController } from "@/src/controllers/api/purchaseController";
71 74 import { queueDojoComponentDestructionController } from "@/src/controllers/api/queueDojoComponentDestructionController";
75 import { removeFromGuildController } from "@/src/controllers/api/removeFromGuildController";
72 76 import { rerollRandomModController } from "@/src/controllers/api/rerollRandomModController";
73 77 import { saveDialogueController } from "@/src/controllers/api/saveDialogueController";
74 78 import { saveLoadoutController } from "@/src/controllers/api/saveLoadout";
@@ -113,7 +117,9 @@ apiRouter.get("/abandonLibraryDailyTask.php", abandonLibraryDailyTaskController)
113 117 apiRouter.get("/abortDojoComponentDestruction.php", abortDojoComponentDestructionController);
114 118 apiRouter.get("/checkDailyMissionBonus.php", checkDailyMissionBonusController);
115 119 apiRouter.get("/claimLibraryDailyTaskReward.php", claimLibraryDailyTaskRewardController);
120 apiRouter.get("/confirmGuildInvitation.php", confirmGuildInvitationController);
116 121 apiRouter.get("/credits.php", creditsController);
122 apiRouter.get("/declineGuildInvite.php", declineGuildInviteController);
117 123 apiRouter.get("/deleteSession.php", deleteSessionController);
118 124 apiRouter.get("/dojo", dojoController);
119 125 apiRouter.get("/drones.php", dronesController);
@@ -150,6 +156,7 @@ apiRouter.get("/updateSession.php", updateSessionGetController);
150 156 apiRouter.post("/abortDojoComponent.php", abortDojoComponentController);
151 157 apiRouter.post("/activateRandomMod.php", activateRandomModController);
152 158 apiRouter.post("/addFriendImage.php", addFriendImageController);
159 apiRouter.post("/addToGuild.php", addToGuildController);
153 160 apiRouter.post("/arcaneCommon.php", arcaneCommonController);
154 161 apiRouter.post("/archonFusion.php", archonFusionController);
155 162 apiRouter.post("/artifacts.php", artifactsController);
@@ -193,6 +200,7 @@ apiRouter.post("/placeDecoInComponent.php", placeDecoInComponentController);
193 200 apiRouter.post("/playerSkills.php", playerSkillsController);
194 201 apiRouter.post("/projectionManager.php", projectionManagerController);
195 202 apiRouter.post("/purchase.php", purchaseController);
203 apiRouter.post("/removeFromGuild.php", removeFromGuildController);
196 204 apiRouter.post("/rerollRandomMod.php", rerollRandomModController);
197 205 apiRouter.post("/saveDialogue.php", saveDialogueController);
198 206 apiRouter.post("/saveLoadout.php", saveLoadoutController);
Modified src/services/guildService.ts +125 -2
@@ -1,19 +1,23 @@
1 1 import { Request } from "express";
2 2 import { getAccountIdForRequest } from "@/src/services/loginService";
3 import { getInventory } from "@/src/services/inventoryService";
4 import { Guild, TGuildDatabaseDocument } from "@/src/models/guildModel";
3 import { addRecipes, getInventory } from "@/src/services/inventoryService";
4 import { Guild, GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
5 5 import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
6 6 import {
7 7 IDojoClient,
8 8 IDojoComponentClient,
9 9 IDojoContributable,
10 10 IDojoDecoClient,
11 IGuildClient,
12 IGuildMemberClient,
11 13 IGuildVault
12 14 } from "@/src/types/guildTypes";
13 15 import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
14 16 import { Types } from "mongoose";
15 17 import { ExportDojoRecipes, IDojoBuild } from "warframe-public-export-plus";
16 18 import { logger } from "../utils/logger";
19 import { config } from "./configService";
20 import { Account } from "../models/loginModel";
17 21
18 22 export const getGuildForRequest = async (req: Request): Promise<TGuildDatabaseDocument> => {
19 23 const accountId = await getAccountIdForRequest(req);
@@ -36,6 +40,99 @@ export const getGuildForRequestEx = async (
36 40 return guild;
37 41 };
38 42
43 export const getGuildClient = async (guild: TGuildDatabaseDocument, accountId: string): Promise<IGuildClient> => {
44 const guildMembers = await GuildMember.find({ guildId: guild._id });
45
46 const members: IGuildMemberClient[] = [];
47 let missingEntry = true;
48 for (const guildMember of guildMembers) {
49 const member: IGuildMemberClient = {
50 _id: toOid(guildMember.accountId),
51 Rank: guildMember.rank,
52 Status: guildMember.status
53 };
54 if (guildMember.accountId.equals(accountId)) {
55 missingEntry = false;
56 } else {
57 member.DisplayName = (await Account.findOne(
58 {
59 _id: guildMember.accountId
60 },
61 "DisplayName"
62 ))!.DisplayName;
63 await fillInInventoryDataForGuildMember(member);
64 }
65 members.push(member);
66 }
67 if (missingEntry) {
68 // Handle clans created prior to creation of the GuildMember model.
69 await GuildMember.insertOne({
70 accountId: accountId,
71 guildId: guild._id,
72 status: 0,
73 rank: 0
74 });
75 members.push({
76 _id: { $oid: accountId },
77 Status: 0,
78 Rank: 0
79 });
80 }
81
82 return {
83 _id: toOid(guild._id),
84 Name: guild.Name,
85 MOTD: guild.MOTD,
86 LongMOTD: guild.LongMOTD,
87 Members: members,
88 Ranks: [
89 {
90 Name: "/Lotus/Language/Game/Rank_Creator",
91 Permissions: 16351
92 },
93 {
94 Name: "/Lotus/Language/Game/Rank_Warlord",
95 Permissions: 14303
96 },
97 {
98 Name: "/Lotus/Language/Game/Rank_General",
99 Permissions: 4318
100 },
101 {
102 Name: "/Lotus/Language/Game/Rank_Officer",
103 Permissions: 4314
104 },
105 {
106 Name: "/Lotus/Language/Game/Rank_Leader",
107 Permissions: 4106
108 },
109 {
110 Name: "/Lotus/Language/Game/Rank_Sage",
111 Permissions: 4304
112 },
113 {
114 Name: "/Lotus/Language/Game/Rank_Soldier",
115 Permissions: 4098
116 },
117 {
118 Name: "/Lotus/Language/Game/Rank_Initiate",
119 Permissions: 4096
120 },
121 {
122 Name: "/Lotus/Language/Game/Rank_Utility",
123 Permissions: 4096
124 }
125 ],
126 Tier: 1,
127 Vault: getGuildVault(guild),
128 Class: guild.Class,
129 XP: guild.XP,
130 IsContributor: !!guild.CeremonyContributors?.find(x => x.equals(accountId)),
131 NumContributors: guild.CeremonyContributors?.length ?? 0,
132 CeremonyResetDate: guild.CeremonyResetDate ? toMongoDate(guild.CeremonyResetDate) : undefined
133 };
134 };
135
39 136 export const getGuildVault = (guild: TGuildDatabaseDocument): IGuildVault => {
40 137 return {
41 138 DojoRefundRegularCredits: guild.VaultRegularCredits,
@@ -192,3 +289,29 @@ export const processDojoBuildMaterialsGathered = (guild: TGuildDatabaseDocument,
192 289 }
193 290 }
194 291 };
292
293 export const fillInInventoryDataForGuildMember = async (member: IGuildMemberClient): Promise<void> => {
294 const inventory = await getInventory(member._id.$oid, "PlayerLevel ActiveAvatarImageType");
295 member.PlayerLevel = config.spoofMasteryRank == -1 ? inventory.PlayerLevel : config.spoofMasteryRank;
296 member.ActiveAvatarImageType = inventory.ActiveAvatarImageType;
297 };
298
299 export const updateInventoryForConfirmedGuildJoin = async (
300 accountId: string,
301 guildId: Types.ObjectId
302 ): Promise<void> => {
303 const inventory = await getInventory(accountId);
304
305 // Set GuildId
306 inventory.GuildId = guildId;
307
308 // Give clan key blueprint
309 addRecipes(inventory, [
310 {
311 ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
312 ItemCount: 1
313 }
314 ]);
315
316 await inventory.save();
317 };
Modified src/types/guildTypes.ts +35 -0