feat: guild ads
All checks were successful
Build / build (20) (push) Successful in 39s
Build / build (22) (push) Successful in 1m17s
Build / build (18) (push) Successful in 1m19s
Build / build (18) (pull_request) Successful in 41s
Build / build (20) (pull_request) Successful in 1m16s
Build / build (22) (pull_request) Successful in 1m25s
All checks were successful
Build / build (20) (push) Successful in 39s
Build / build (22) (push) Successful in 1m17s
Build / build (18) (push) Successful in 1m19s
Build / build (18) (pull_request) Successful in 41s
Build / build (20) (pull_request) Successful in 1m16s
Build / build (22) (pull_request) Successful in 1m25s
This commit is contained in:
parent
516f822e43
commit
e8211a3881
20
src/controllers/api/cancelGuildAdvertisementController.ts
Normal file
20
src/controllers/api/cancelGuildAdvertisementController.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { GuildAd } from "@/src/models/guildModel";
|
||||
import { getGuildForRequestEx, hasGuildPermission } 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 cancelGuildAdvertisementController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const inventory = await getInventory(accountId, "GuildId");
|
||||
const guild = await getGuildForRequestEx(req, inventory);
|
||||
if (!(await hasGuildPermission(guild, accountId, GuildPermission.Advertiser))) {
|
||||
res.status(400).end();
|
||||
return;
|
||||
}
|
||||
|
||||
await GuildAd.deleteOne({ GuildId: guild._id });
|
||||
|
||||
res.end();
|
||||
};
|
@ -1,6 +1,7 @@
|
||||
import { GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
|
||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||
import {
|
||||
addGuildMemberMiscItemContribution,
|
||||
getDojoClient,
|
||||
getGuildForRequestEx,
|
||||
hasAccessToDojo,
|
||||
@ -143,8 +144,7 @@ const processContribution = (
|
||||
ItemCount: ingredientContribution.ItemCount * -1
|
||||
});
|
||||
|
||||
guildMember.MiscItemsContributed ??= [];
|
||||
guildMember.MiscItemsContributed.push(ingredientContribution);
|
||||
addGuildMemberMiscItemContribution(guildMember, ingredientContribution);
|
||||
}
|
||||
addMiscItems(inventory, miscItemChanges);
|
||||
inventoryChanges.MiscItems = miscItemChanges;
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { GuildMember } from "@/src/models/guildModel";
|
||||
import { addVaultMiscItems, getGuildForRequestEx } from "@/src/services/guildService";
|
||||
import {
|
||||
addGuildMemberMiscItemContribution,
|
||||
addVaultMiscItems,
|
||||
getGuildForRequestEx
|
||||
} from "@/src/services/guildService";
|
||||
import { addFusionTreasures, addMiscItems, addShipDecorations, getInventory } from "@/src/services/inventoryService";
|
||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||
import { IFusionTreasure, IMiscItem, ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||
@ -25,14 +29,8 @@ export const contributeToVaultController: RequestHandler = async (req, res) => {
|
||||
if (request.MiscItems.length) {
|
||||
addVaultMiscItems(guild, request.MiscItems);
|
||||
|
||||
guildMember.MiscItemsContributed ??= [];
|
||||
for (const item of request.MiscItems) {
|
||||
const miscItemContribution = guildMember.MiscItemsContributed.find(x => x.ItemType == item.ItemType);
|
||||
if (miscItemContribution) {
|
||||
miscItemContribution.ItemCount += item.ItemCount;
|
||||
} else {
|
||||
guildMember.MiscItemsContributed.push(item);
|
||||
}
|
||||
addGuildMemberMiscItemContribution(guildMember, item);
|
||||
|
||||
addMiscItems(inventory, [{ ...item, ItemCount: item.ItemCount * -1 }]);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { RequestHandler } from "express";
|
||||
import {
|
||||
addGuildMemberMiscItemContribution,
|
||||
getGuildForRequestEx,
|
||||
getGuildVault,
|
||||
hasAccessToDojo,
|
||||
@ -146,8 +147,7 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
||||
ItemCount: miscItem.ItemCount * -1
|
||||
});
|
||||
|
||||
guildMember.MiscItemsContributed ??= [];
|
||||
guildMember.MiscItemsContributed.push(miscItem);
|
||||
addGuildMemberMiscItemContribution(guildMember, miscItem);
|
||||
}
|
||||
}
|
||||
addMiscItems(inventory, miscItemChanges);
|
||||
|
75
src/controllers/api/postGuildAdvertisementController.ts
Normal file
75
src/controllers/api/postGuildAdvertisementController.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||
import { GuildAd, GuildMember } from "@/src/models/guildModel";
|
||||
import {
|
||||
addGuildMemberMiscItemContribution,
|
||||
addVaultMiscItems,
|
||||
getGuildForRequestEx,
|
||||
getVaultMiscItemCount,
|
||||
hasGuildPermissionEx
|
||||
} from "@/src/services/guildService";
|
||||
import { getInventory } from "@/src/services/inventoryService";
|
||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||
import { getVendorManifestByTypeName, preprocessVendorManifest } from "@/src/services/serversideVendorsService";
|
||||
import { GuildPermission } from "@/src/types/guildTypes";
|
||||
import { IPurchaseParams } from "@/src/types/purchaseTypes";
|
||||
import { RequestHandler } from "express";
|
||||
|
||||
export const postGuildAdvertisementController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const inventory = await getInventory(accountId, "GuildId MiscItems");
|
||||
const guild = await getGuildForRequestEx(req, inventory);
|
||||
const guildMember = (await GuildMember.findOne({ accountId, guildId: guild._id }))!;
|
||||
if (!hasGuildPermissionEx(guild, guildMember, GuildPermission.Advertiser)) {
|
||||
res.status(400).end();
|
||||
return;
|
||||
}
|
||||
const payload = getJSONfromString<IPostGuildAdvertisementRequest>(String(req.body));
|
||||
|
||||
// Handle resource cost
|
||||
const vendor = preprocessVendorManifest(
|
||||
getVendorManifestByTypeName("/Lotus/Types/Game/VendorManifests/Hubs/GuildAdvertisementVendorManifest")!
|
||||
);
|
||||
const offer = vendor.VendorInfo.ItemManifest.find(x => x.StoreItem == payload.PurchaseParams.StoreItem)!;
|
||||
if (getVaultMiscItemCount(guild, offer.ItemPrices![0].ItemType) >= offer.ItemPrices![0].ItemCount) {
|
||||
addVaultMiscItems(guild, [
|
||||
{
|
||||
ItemType: offer.ItemPrices![0].ItemType,
|
||||
ItemCount: offer.ItemPrices![0].ItemCount * -1
|
||||
}
|
||||
]);
|
||||
} else {
|
||||
const miscItem = inventory.MiscItems.find(x => x.ItemType == offer.ItemPrices![0].ItemType);
|
||||
if (!miscItem || miscItem.ItemCount < offer.ItemPrices![0].ItemCount) {
|
||||
res.status(400).json("Insufficient funds");
|
||||
return;
|
||||
}
|
||||
miscItem.ItemCount -= offer.ItemPrices![0].ItemCount;
|
||||
addGuildMemberMiscItemContribution(guildMember, offer.ItemPrices![0]);
|
||||
await guildMember.save();
|
||||
await inventory.save();
|
||||
}
|
||||
|
||||
// Create or update ad
|
||||
await GuildAd.findOneAndUpdate(
|
||||
{ GuildId: guild._id },
|
||||
{
|
||||
Emblem: guild.Emblem,
|
||||
Expiry: new Date(Date.now() + 12 * 3600 * 1000),
|
||||
Features: payload.Features,
|
||||
GuildName: guild.Name,
|
||||
MemberCount: await GuildMember.countDocuments({ guildId: guild._id, status: 0 }),
|
||||
RecruitMsg: payload.RecruitMsg,
|
||||
Tier: guild.Tier
|
||||
},
|
||||
{ upsert: true }
|
||||
);
|
||||
|
||||
res.end();
|
||||
};
|
||||
|
||||
interface IPostGuildAdvertisementRequest {
|
||||
Features: number;
|
||||
RecruitMsg: string;
|
||||
Languages: string[];
|
||||
PurchaseParams: IPurchaseParams;
|
||||
}
|
26
src/controllers/dynamic/getGuildAdsController.ts
Normal file
26
src/controllers/dynamic/getGuildAdsController.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
|
||||
import { GuildAd } from "@/src/models/guildModel";
|
||||
import { IGuildAdInfoClient } from "@/src/types/guildTypes";
|
||||
import { RequestHandler } from "express";
|
||||
|
||||
export const getGuildAdsController: RequestHandler = async (req, res) => {
|
||||
const ads = await GuildAd.find(req.query.tier ? { Tier: req.query.tier } : {});
|
||||
const guildAdInfos: IGuildAdInfoClient[] = [];
|
||||
for (const ad of ads) {
|
||||
guildAdInfos.push({
|
||||
_id: toOid(ad.GuildId),
|
||||
CrossPlatformEnabled: true,
|
||||
Emblem: ad.Emblem,
|
||||
Expiry: toMongoDate(ad.Expiry),
|
||||
Features: ad.Features,
|
||||
GuildName: ad.GuildName,
|
||||
MemberCount: ad.MemberCount,
|
||||
OriginalPlatform: 0,
|
||||
RecruitMsg: ad.RecruitMsg,
|
||||
Tier: ad.Tier
|
||||
});
|
||||
}
|
||||
res.json({
|
||||
GuildAdInfos: guildAdInfos
|
||||
});
|
||||
};
|
@ -10,7 +10,8 @@ import {
|
||||
IGuildLogRoomChange,
|
||||
IGuildLogEntryRoster,
|
||||
IGuildLogEntryContributable,
|
||||
IDojoLeaderboardEntry
|
||||
IDojoLeaderboardEntry,
|
||||
IGuildAdDatabase
|
||||
} from "@/src/types/guildTypes";
|
||||
import { Document, Model, model, Schema, Types } from "mongoose";
|
||||
import { fusionTreasuresSchema, typeCountSchema } from "./inventoryModels/inventoryModel";
|
||||
@ -165,6 +166,7 @@ const guildSchema = new Schema<IGuildDatabase>(
|
||||
Ranks: { type: [guildRankSchema], default: defaultRanks },
|
||||
TradeTax: { type: Number, default: 0 },
|
||||
Tier: { type: Number, default: 1 },
|
||||
Emblem: { type: Boolean },
|
||||
DojoComponents: { type: [dojoComponentSchema], default: [] },
|
||||
DojoCapacity: { type: Number, default: 100 },
|
||||
DojoEnergy: { type: Number, default: 5 },
|
||||
@ -225,3 +227,19 @@ const guildMemberSchema = new Schema<IGuildMemberDatabase>({
|
||||
guildMemberSchema.index({ accountId: 1, guildId: 1 }, { unique: true });
|
||||
|
||||
export const GuildMember = model<IGuildMemberDatabase>("GuildMember", guildMemberSchema);
|
||||
|
||||
const guildAdSchema = new Schema<IGuildAdDatabase>({
|
||||
GuildId: { type: Schema.Types.ObjectId, required: true },
|
||||
Emblem: Boolean,
|
||||
Expiry: { type: Date, required: true },
|
||||
Features: { type: Number, required: true },
|
||||
GuildName: { type: String, required: true },
|
||||
MemberCount: { type: Number, required: true },
|
||||
RecruitMsg: { type: String, required: true },
|
||||
Tier: { type: Number, required: true }
|
||||
});
|
||||
|
||||
guildAdSchema.index({ guildId: 1 }, { unique: true });
|
||||
guildAdSchema.index({ Expiry: 1 }, { expireAfterSeconds: 0 });
|
||||
|
||||
export const GuildAd = model<IGuildAdDatabase>("GuildAd", guildAdSchema);
|
||||
|
@ -9,6 +9,7 @@ import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonContro
|
||||
import { archonFusionController } from "@/src/controllers/api/archonFusionController";
|
||||
import { artifactsController } from "@/src/controllers/api/artifactsController";
|
||||
import { artifactTransmutationController } from "@/src/controllers/api/artifactTransmutationController";
|
||||
import { cancelGuildAdvertisementController } from "@/src/controllers/api/cancelGuildAdvertisementController";
|
||||
import { changeDojoRootController } from "@/src/controllers/api/changeDojoRootController";
|
||||
import { changeGuildRankController } from "@/src/controllers/api/changeGuildRankController";
|
||||
import { checkDailyMissionBonusController } from "@/src/controllers/api/checkDailyMissionBonusController";
|
||||
@ -80,6 +81,7 @@ import { nameWeaponController } from "@/src/controllers/api/nameWeaponController
|
||||
import { nemesisController } from "@/src/controllers/api/nemesisController";
|
||||
import { placeDecoInComponentController } from "@/src/controllers/api/placeDecoInComponentController";
|
||||
import { playerSkillsController } from "@/src/controllers/api/playerSkillsController";
|
||||
import { postGuildAdvertisementController } from "@/src/controllers/api/postGuildAdvertisementController";
|
||||
import { projectionManagerController } from "@/src/controllers/api/projectionManagerController";
|
||||
import { purchaseController } from "@/src/controllers/api/purchaseController";
|
||||
import { queueDojoComponentDestructionController } from "@/src/controllers/api/queueDojoComponentDestructionController";
|
||||
@ -131,6 +133,7 @@ const apiRouter = express.Router();
|
||||
// get
|
||||
apiRouter.get("/abandonLibraryDailyTask.php", abandonLibraryDailyTaskController);
|
||||
apiRouter.get("/abortDojoComponentDestruction.php", abortDojoComponentDestructionController);
|
||||
apiRouter.get("/cancelGuildAdvertisement.php", cancelGuildAdvertisementController);
|
||||
apiRouter.get("/changeGuildRank.php", changeGuildRankController);
|
||||
apiRouter.get("/checkDailyMissionBonus.php", checkDailyMissionBonusController);
|
||||
apiRouter.get("/claimLibraryDailyTaskReward.php", claimLibraryDailyTaskRewardController);
|
||||
@ -228,6 +231,7 @@ apiRouter.post("/nameWeapon.php", nameWeaponController);
|
||||
apiRouter.post("/nemesis.php", nemesisController);
|
||||
apiRouter.post("/placeDecoInComponent.php", placeDecoInComponentController);
|
||||
apiRouter.post("/playerSkills.php", playerSkillsController);
|
||||
apiRouter.post("/postGuildAdvertisement.php", postGuildAdvertisementController);
|
||||
apiRouter.post("/projectionManager.php", projectionManagerController);
|
||||
apiRouter.post("/purchase.php", purchaseController);
|
||||
apiRouter.post("/redeemPromoCode.php", redeemPromoCodeController);
|
||||
|
@ -1,11 +1,13 @@
|
||||
import express from "express";
|
||||
import { aggregateSessionsController } from "@/src/controllers/dynamic/aggregateSessionsController";
|
||||
import { getGuildAdsController } from "@/src/controllers/dynamic/getGuildAdsController";
|
||||
import { getProfileViewingDataController } from "@/src/controllers/dynamic/getProfileViewingDataController";
|
||||
import { worldStateController } from "@/src/controllers/dynamic/worldStateController";
|
||||
|
||||
const dynamicController = express.Router();
|
||||
|
||||
dynamicController.get("/aggregateSessions.php", aggregateSessionsController);
|
||||
dynamicController.get("/getGuildAds.php", getGuildAdsController);
|
||||
dynamicController.get("/getProfileViewingData.php", getProfileViewingDataController);
|
||||
dynamicController.get("/worldState.php", worldStateController);
|
||||
|
||||
|
@ -298,6 +298,10 @@ const moveResourcesToVault = (guild: TGuildDatabaseDocument, component: IDojoCon
|
||||
}
|
||||
};
|
||||
|
||||
export const getVaultMiscItemCount = (guild: TGuildDatabaseDocument, itemType: string): number => {
|
||||
return guild.VaultMiscItems?.find(x => x.ItemType == itemType)?.ItemCount ?? 0;
|
||||
};
|
||||
|
||||
export const addVaultMiscItems = (guild: TGuildDatabaseDocument, miscItems: ITypeCount[]): void => {
|
||||
guild.VaultMiscItems ??= [];
|
||||
for (const miscItem of miscItems) {
|
||||
@ -310,6 +314,16 @@ export const addVaultMiscItems = (guild: TGuildDatabaseDocument, miscItems: ITyp
|
||||
}
|
||||
};
|
||||
|
||||
export const addGuildMemberMiscItemContribution = (guildMember: IGuildMemberDatabase, item: ITypeCount): void => {
|
||||
guildMember.MiscItemsContributed ??= [];
|
||||
const miscItemContribution = guildMember.MiscItemsContributed.find(x => x.ItemType == item.ItemType);
|
||||
if (miscItemContribution) {
|
||||
miscItemContribution.ItemCount += item.ItemCount;
|
||||
} else {
|
||||
guildMember.MiscItemsContributed.push(item);
|
||||
}
|
||||
};
|
||||
|
||||
export const processDojoBuildMaterialsGathered = (guild: TGuildDatabaseDocument, build: IDojoBuild): void => {
|
||||
if (build.guildXpValue) {
|
||||
guild.ClaimedXP ??= [];
|
||||
|
@ -28,6 +28,7 @@ export interface IGuildDatabase {
|
||||
Ranks: IGuildRank[];
|
||||
TradeTax: number;
|
||||
Tier: number;
|
||||
Emblem?: boolean;
|
||||
|
||||
DojoComponents: IDojoComponentDatabase[];
|
||||
DojoCapacity: number;
|
||||
@ -223,3 +224,27 @@ export interface IDojoLeaderboardEntry {
|
||||
r: number; // rank
|
||||
n: string; // displayName
|
||||
}
|
||||
|
||||
export interface IGuildAdInfoClient {
|
||||
_id: IOid; // Guild ID
|
||||
CrossPlatformEnabled: boolean;
|
||||
Emblem?: boolean;
|
||||
Expiry: IMongoDate;
|
||||
Features: number;
|
||||
GuildName: string;
|
||||
MemberCount: number;
|
||||
OriginalPlatform: number;
|
||||
RecruitMsg: string;
|
||||
Tier: number;
|
||||
}
|
||||
|
||||
export interface IGuildAdDatabase {
|
||||
GuildId: Types.ObjectId;
|
||||
Emblem?: boolean;
|
||||
Expiry: Date;
|
||||
Features: number;
|
||||
GuildName: string;
|
||||
MemberCount: number;
|
||||
RecruitMsg: string;
|
||||
Tier: number;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user