feat: create alliance #1423
50
src/controllers/api/createAllianceController.ts
Normal file
50
src/controllers/api/createAllianceController.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||
import { Alliance, AllianceMember, Guild, GuildMember } from "@/src/models/guildModel";
|
||||
import { getAllianceClient } from "@/src/services/guildService";
|
||||
import { getInventory } from "@/src/services/inventoryService";
|
||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||
import { GuildPermission } from "@/src/types/guildTypes";
|
||||
import { RequestHandler } from "express";
|
||||
|
||||
export const createAllianceController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const inventory = await getInventory(accountId, "GuildId");
|
||||
const guild = (await Guild.findById(inventory.GuildId!, "Name Tier AllianceId"))!;
|
||||
if (guild.AllianceId) {
|
||||
res.status(400).send("Guild is already in an alliance").end();
|
||||
return;
|
||||
}
|
||||
const guildMember = (await GuildMember.findOne({ guildId: guild._id, accountId }, "rank"))!;
|
||||
if (guildMember.rank > 1) {
|
||||
res.status(400).send("Invalid permission").end();
|
||||
return;
|
||||
}
|
||||
const data = getJSONfromString<ICreateAllianceRequest>(String(req.body));
|
||||
const alliance = new Alliance({ Name: data.allianceName });
|
||||
try {
|
||||
await alliance.save();
|
||||
} catch (e) {
|
||||
res.status(400).send("Alliance name already in use").end();
|
||||
return;
|
||||
}
|
||||
guild.AllianceId = alliance._id;
|
||||
await Promise.all([
|
||||
guild.save(),
|
||||
AllianceMember.insertOne({
|
||||
allianceId: alliance._id,
|
||||
guildId: guild._id,
|
||||
Pending: false,
|
||||
Permissions:
|
||||
GuildPermission.Ruler |
|
||||
GuildPermission.Promoter |
|
||||
GuildPermission.Recruiter |
|
||||
GuildPermission.Treasurer |
|
||||
GuildPermission.ChatModerator
|
||||
})
|
||||
]);
|
||||
res.json(await getAllianceClient(alliance, guild));
|
||||
};
|
||||
|
||||
interface ICreateAllianceRequest {
|
||||
allianceName: string;
|
||||
}
|
@ -1,7 +1,25 @@
|
||||
import { Alliance, Guild } from "@/src/models/guildModel";
|
||||
import { getAllianceClient } from "@/src/services/guildService";
|
||||
import { getInventory } from "@/src/services/inventoryService";
|
||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||
import { RequestHandler } from "express";
|
||||
|
||||
const getAllianceController: RequestHandler = (_req, res) => {
|
||||
res.sendStatus(200);
|
||||
export const getAllianceController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const inventory = await getInventory(accountId, "GuildId");
|
||||
if (inventory.GuildId) {
|
||||
const guild = (await Guild.findById(inventory.GuildId, "Name Tier AllianceId"))!;
|
||||
if (guild.AllianceId) {
|
||||
const alliance = (await Alliance.findById(guild.AllianceId))!;
|
||||
res.json(await getAllianceClient(alliance, guild));
|
||||
return;
|
||||
}
|
||||
}
|
||||
res.end();
|
||||
};
|
||||
|
||||
export { getAllianceController };
|
||||
/*interface IGetAllianceRequest {
|
||||
memberCount: number;
|
||||
clanLeaderName: string;
|
||||
clanLeaderId: string;
|
||||
}*/
|
||||
|
@ -5,7 +5,7 @@ import { logger } from "@/src/utils/logger";
|
||||
import { getInventory } from "@/src/services/inventoryService";
|
||||
import { createUniqueClanName, getGuildClient } from "@/src/services/guildService";
|
||||
|
||||
const getGuildController: RequestHandler = async (req, res) => {
|
||||
export const getGuildController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const inventory = await getInventory(accountId, "GuildId");
|
||||
if (inventory.GuildId) {
|
||||
@ -28,7 +28,5 @@ const getGuildController: RequestHandler = async (req, res) => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
res.sendStatus(200);
|
||||
res.end();
|
||||
};
|
||||
|
||||
export { getGuildController };
|
||||
|
@ -11,7 +11,9 @@ import {
|
||||
IGuildLogEntryRoster,
|
||||
IGuildLogEntryContributable,
|
||||
IDojoLeaderboardEntry,
|
||||
IGuildAdDatabase
|
||||
IGuildAdDatabase,
|
||||
IAllianceDatabase,
|
||||
IAllianceMemberDatabase
|
||||
} from "@/src/types/guildTypes";
|
||||
import { Document, Model, model, Schema, Types } from "mongoose";
|
||||
import { fusionTreasuresSchema, typeCountSchema } from "./inventoryModels/inventoryModel";
|
||||
@ -167,6 +169,7 @@ const guildSchema = new Schema<IGuildDatabase>(
|
||||
TradeTax: { type: Number, default: 0 },
|
||||
Tier: { type: Number, default: 1 },
|
||||
Emblem: { type: Boolean },
|
||||
AllianceId: { type: Types.ObjectId },
|
||||
DojoComponents: { type: [dojoComponentSchema], default: [] },
|
||||
DojoCapacity: { type: Number, default: 100 },
|
||||
DojoEnergy: { type: Number, default: 5 },
|
||||
@ -246,3 +249,25 @@ guildAdSchema.index({ GuildId: 1 }, { unique: true });
|
||||
guildAdSchema.index({ Expiry: 1 }, { expireAfterSeconds: 0 });
|
||||
|
||||
export const GuildAd = model<IGuildAdDatabase>("GuildAd", guildAdSchema);
|
||||
|
||||
const allianceSchema = new Schema<IAllianceDatabase>({
|
||||
Name: String,
|
||||
MOTD: longMOTDSchema,
|
||||
LongMOTD: longMOTDSchema,
|
||||
Emblem: Boolean
|
||||
});
|
||||
|
||||
allianceSchema.index({ Name: 1 }, { unique: true });
|
||||
|
||||
export const Alliance = model<IAllianceDatabase>("Alliance", allianceSchema);
|
||||
|
||||
const allianceMemberSchema = new Schema<IAllianceMemberDatabase>({
|
||||
allianceId: Schema.Types.ObjectId,
|
||||
guildId: Schema.Types.ObjectId,
|
||||
Pending: Boolean,
|
||||
Permissions: Number
|
||||
});
|
||||
|
||||
guildMemberSchema.index({ allianceId: 1, guildId: 1 }, { unique: true });
|
||||
|
||||
export const AllianceMember = model<IAllianceMemberDatabase>("AllianceMember", allianceMemberSchema);
|
||||
|
@ -22,6 +22,7 @@ import { confirmGuildInvitationController } from "@/src/controllers/api/confirmG
|
||||
import { contributeGuildClassController } from "@/src/controllers/api/contributeGuildClassController";
|
||||
import { contributeToDojoComponentController } from "@/src/controllers/api/contributeToDojoComponentController";
|
||||
import { contributeToVaultController } from "@/src/controllers/api/contributeToVaultController";
|
||||
import { createAllianceController } from "@/src/controllers/api/createAllianceController";
|
||||
import { createGuildController } from "@/src/controllers/api/createGuildController";
|
||||
import { creditsController } from "@/src/controllers/api/creditsController";
|
||||
import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
|
||||
@ -193,6 +194,7 @@ apiRouter.post("/confirmGuildInvitation.php", confirmGuildInvitationController);
|
||||
apiRouter.post("/contributeGuildClass.php", contributeGuildClassController);
|
||||
apiRouter.post("/contributeToDojoComponent.php", contributeToDojoComponentController);
|
||||
apiRouter.post("/contributeToVault.php", contributeToVaultController);
|
||||
apiRouter.post("/createAlliance.php", createAllianceController);
|
||||
apiRouter.post("/createGuild.php", createGuildController);
|
||||
apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController);
|
||||
apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController);
|
||||
|
@ -1,10 +1,13 @@
|
||||
import { Request } from "express";
|
||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||
import { getInventory } from "@/src/services/inventoryService";
|
||||
import { Guild, GuildAd, GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
|
||||
import { AllianceMember, Guild, GuildAd, GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
|
||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||
import {
|
||||
GuildPermission,
|
||||
IAllianceClient,
|
||||
IAllianceDatabase,
|
||||
IAllianceMemberClient,
|
||||
IDojoClient,
|
||||
IDojoComponentClient,
|
||||
IDojoComponentDatabase,
|
||||
@ -99,7 +102,8 @@ export const getGuildClient = async (guild: TGuildDatabaseDocument, accountId: s
|
||||
XP: guild.XP,
|
||||
IsContributor: !!guild.CeremonyContributors?.find(x => x.equals(accountId)),
|
||||
NumContributors: guild.CeremonyContributors?.length ?? 0,
|
||||
CeremonyResetDate: guild.CeremonyResetDate ? toMongoDate(guild.CeremonyResetDate) : undefined
|
||||
CeremonyResetDate: guild.CeremonyResetDate ? toMongoDate(guild.CeremonyResetDate) : undefined,
|
||||
AllianceId: guild.AllianceId ? toOid(guild.AllianceId) : undefined
|
||||
};
|
||||
};
|
||||
|
||||
@ -549,4 +553,34 @@ export const deleteGuild = async (guildId: Types.ObjectId): Promise<void> => {
|
||||
});
|
||||
|
||||
await GuildAd.deleteOne({ GuildId: guildId });
|
||||
|
||||
await AllianceMember.deleteMany({ guildId });
|
||||
|
||||
// TODO: If this guild was the founding guild of an alliance (ruler permission), that would need to be forcefully deleted now as well.
|
||||
};
|
||||
|
||||
export const getAllianceClient = async (
|
||||
alliance: IAllianceDatabase,
|
||||
guild: TGuildDatabaseDocument
|
||||
): Promise<IAllianceClient> => {
|
||||
const allianceMembers = await AllianceMember.find({ allianceId: alliance._id });
|
||||
const clans: IAllianceMemberClient[] = [];
|
||||
for (const allianceMember of allianceMembers) {
|
||||
const memberGuild = allianceMember.guildId.equals(guild._id)
|
||||
? guild
|
||||
: (await Guild.findById(allianceMember.guildId))!;
|
||||
clans.push({
|
||||
_id: toOid(allianceMember.guildId),
|
||||
Name: memberGuild.Name,
|
||||
Tier: memberGuild.Tier,
|
||||
Pending: allianceMember.Pending,
|
||||
Permissions: allianceMember.Permissions,
|
||||
MemberCount: await GuildMember.countDocuments({ guildId: memberGuild._id, status: 0 })
|
||||
});
|
||||
}
|
||||
return {
|
||||
_id: toOid(alliance._id),
|
||||
Name: alliance.Name,
|
||||
Clans: clans
|
||||
};
|
||||
};
|
||||
|
@ -18,6 +18,9 @@ export interface IGuildClient {
|
||||
IsContributor: boolean;
|
||||
NumContributors: number;
|
||||
CeremonyResetDate?: IMongoDate;
|
||||
CrossPlatformEnabled?: boolean;
|
||||
AutoContributeFromVault?: boolean;
|
||||
AllianceId?: IOid;
|
||||
}
|
||||
|
||||
export interface IGuildDatabase {
|
||||
@ -29,6 +32,7 @@ export interface IGuildDatabase {
|
||||
TradeTax: number;
|
||||
Tier: number;
|
||||
Emblem?: boolean;
|
||||
AllianceId?: Types.ObjectId;
|
||||
|
||||
DojoComponents: IDojoComponentDatabase[];
|
||||
DojoCapacity: number;
|
||||
@ -60,21 +64,21 @@ export interface IGuildDatabase {
|
||||
export interface ILongMOTD {
|
||||
message: string;
|
||||
authorName: string;
|
||||
//authorGuildName: "";
|
||||
authorGuildName?: "";
|
||||
}
|
||||
|
||||
// 32 seems to be reserved
|
||||
export enum GuildPermission {
|
||||
Ruler = 1, // Change clan hierarchy
|
||||
Ruler = 1, // Clan: Change hierarchy. Alliance: Kick clans.
|
||||
Advertiser = 8192,
|
||||
Recruiter = 2, // Invite members
|
||||
Recruiter = 2, // Send invites (Clans & Alliances)
|
||||
Regulator = 4, // Kick members
|
||||
Promoter = 8, // Promote and demote members
|
||||
Promoter = 8, // Clan: Promote and demote members. Alliance: Change clan permissions.
|
||||
Architect = 16, // Create and destroy rooms
|
||||
Decorator = 1024, // Create and destroy decos
|
||||
Treasurer = 64, // Contribute from vault and edit tax rate
|
||||
Treasurer = 64, // Clan: Contribute from vault and edit tax rate. Alliance: Divvy vault.
|
||||
Tech = 128, // Queue research
|
||||
ChatModerator = 512,
|
||||
ChatModerator = 512, // (Clans & Alliances)
|
||||
Herald = 2048, // Change MOTD
|
||||
Fabricator = 4096 // Replicate research
|
||||
}
|
||||
@ -268,3 +272,51 @@ export interface IGuildAdDatabase {
|
||||
RecruitMsg: string;
|
||||
Tier: number;
|
||||
}
|
||||
|
||||
export interface IAllianceClient {
|
||||
_id: IOid;
|
||||
Name: string;
|
||||
MOTD?: ILongMOTD;
|
||||
LongMOTD?: ILongMOTD;
|
||||
Emblem?: boolean;
|
||||
CrossPlatformEnabled?: boolean;
|
||||
Clans: IAllianceMemberClient[];
|
||||
OriginalPlatform?: number;
|
||||
}
|
||||
|
||||
export interface IAllianceDatabase {
|
||||
_id: Types.ObjectId;
|
||||
Name: string;
|
||||
MOTD?: ILongMOTD;
|
||||
LongMOTD?: ILongMOTD;
|
||||
Emblem?: boolean;
|
||||
}
|
||||
|
||||
export interface IAllianceMemberClient {
|
||||
_id: IOid;
|
||||
Name: string;
|
||||
Tier: number;
|
||||
Pending: boolean;
|
||||
Emblem?: boolean;
|
||||
Permissions: number;
|
||||
MemberCount: number;
|
||||
ClanLeader?: string;
|
||||
ClanLeaderId?: IOid;
|
||||
OriginalPlatform?: number;
|
||||
}
|
||||
|
||||
export interface IAllianceMemberDatabase {
|
||||
allianceId: Types.ObjectId;
|
||||
guildId: Types.ObjectId;
|
||||
Pending: boolean;
|
||||
Permissions: number;
|
||||
}
|
||||
|
||||
// TODO: Alliance chat permissions
|
||||
// TODO: POST /api/addToAlliance.php: {"clanName":"abc"}
|
||||
// TODO: GET /api/divvyAllianceVault.php?accountId=6633b81e9dba0b714f28ff02&nonce=5702391171614479&ct=MSI&guildId=663e9be9f741eeb5782f9df0&allianceId=000000000000000000000069&credits=1
|
||||
// TODO: GET /api/divvyAllianceVault.php?accountId=6633b81e9dba0b714f28ff02&nonce=5702391171614479&ct=MSI&guildId=663e9be9f741eeb5782f9df0&allianceId=000000000000000000000069&credits=0
|
||||
// TODO: GET /api/removeFromAlliance.php?accountId=6633b81e9dba0b714f28ff02&nonce=5702391171614479&ct=MSI&guildId=663e9be9f741eeb5782f9df0
|
||||
// TODO: GET /api/setAllianceGuildPermissions.php?accountId=6633b81e9dba0b714f28ff02&nonce=5702391171614479&ct=MSI&guildId=000000000000000000000042&perms=2
|
||||
// TODO: Handle alliance in contributeToVault
|
||||
// TODO: Handle alliance in setGuildMotd
|
||||
|
Loading…
x
Reference in New Issue
Block a user