feat: getProfileViewingData for clans (#1412)
Reviewed-on: #1412 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
This commit is contained in:
parent
1a4ad8b7a5
commit
404c747642
@ -1,5 +1,5 @@
|
|||||||
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
|
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
import { Guild } from "@/src/models/guildModel";
|
import { Guild, GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
|
||||||
import { Inventory, TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
import { Inventory, TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
||||||
import { Account } from "@/src/models/loginModel";
|
import { Account } from "@/src/models/loginModel";
|
||||||
@ -19,20 +19,18 @@ import {
|
|||||||
} from "@/src/types/inventoryTypes/inventoryTypes";
|
} from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { catBreadHash } from "../api/inventoryController";
|
import { catBreadHash } from "../api/inventoryController";
|
||||||
import { ExportCustoms } from "warframe-public-export-plus";
|
import { ExportCustoms, ExportDojoRecipes } from "warframe-public-export-plus";
|
||||||
|
import { IStatsClient } from "@/src/types/statTypes";
|
||||||
|
import { toStoreItem } from "@/src/services/itemDataService";
|
||||||
|
|
||||||
export const getProfileViewingDataController: RequestHandler = async (req, res) => {
|
export const getProfileViewingDataController: RequestHandler = async (req, res) => {
|
||||||
if (!req.query.playerId) {
|
if (req.query.playerId) {
|
||||||
res.status(400).end();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const account = await Account.findById(req.query.playerId as string, "DisplayName");
|
const account = await Account.findById(req.query.playerId as string, "DisplayName");
|
||||||
if (!account) {
|
if (!account) {
|
||||||
res.status(400).send("No account or guild ID specified");
|
res.status(409).send("Could not find requested account");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const inventory = (await Inventory.findOne({ accountOwnerId: account._id }))!;
|
const inventory = (await Inventory.findOne({ accountOwnerId: account._id }))!;
|
||||||
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "NORMAL"))!;
|
|
||||||
|
|
||||||
const result: IPlayerProfileViewingDataResult = {
|
const result: IPlayerProfileViewingDataResult = {
|
||||||
AccountId: toOid(account._id),
|
AccountId: toOid(account._id),
|
||||||
@ -55,46 +53,10 @@ export const getProfileViewingDataController: RequestHandler = async (req, res)
|
|||||||
Wishlist: inventory.Wishlist,
|
Wishlist: inventory.Wishlist,
|
||||||
Alignment: inventory.Alignment
|
Alignment: inventory.Alignment
|
||||||
};
|
};
|
||||||
if (inventory.CurrentLoadOutIds.length) {
|
await populateLoadout(inventory, result);
|
||||||
result.LoadOutPreset = loadout.NORMAL.id(inventory.CurrentLoadOutIds[0].$oid)!.toJSON<ILoadoutConfigClient>();
|
|
||||||
result.LoadOutPreset.ItemId = undefined;
|
|
||||||
const skins = new Set<string>();
|
|
||||||
if (result.LoadOutPreset.s) {
|
|
||||||
result.LoadOutInventory.Suits = [
|
|
||||||
inventory.Suits.id(result.LoadOutPreset.s.ItemId.$oid)!.toJSON<IEquipmentClient>()
|
|
||||||
];
|
|
||||||
resolveAndCollectSkins(inventory, skins, result.LoadOutInventory.Suits[0]);
|
|
||||||
}
|
|
||||||
if (result.LoadOutPreset.p) {
|
|
||||||
result.LoadOutInventory.Pistols = [
|
|
||||||
inventory.Pistols.id(result.LoadOutPreset.p.ItemId.$oid)!.toJSON<IEquipmentClient>()
|
|
||||||
];
|
|
||||||
resolveAndCollectSkins(inventory, skins, result.LoadOutInventory.Pistols[0]);
|
|
||||||
}
|
|
||||||
if (result.LoadOutPreset.l) {
|
|
||||||
result.LoadOutInventory.LongGuns = [
|
|
||||||
inventory.LongGuns.id(result.LoadOutPreset.l.ItemId.$oid)!.toJSON<IEquipmentClient>()
|
|
||||||
];
|
|
||||||
resolveAndCollectSkins(inventory, skins, result.LoadOutInventory.LongGuns[0]);
|
|
||||||
}
|
|
||||||
if (result.LoadOutPreset.m) {
|
|
||||||
result.LoadOutInventory.Melee = [
|
|
||||||
inventory.Melee.id(result.LoadOutPreset.m.ItemId.$oid)!.toJSON<IEquipmentClient>()
|
|
||||||
];
|
|
||||||
resolveAndCollectSkins(inventory, skins, result.LoadOutInventory.Melee[0]);
|
|
||||||
}
|
|
||||||
for (const skin of skins) {
|
|
||||||
result.LoadOutInventory.WeaponSkins.push({ ItemType: skin });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (inventory.GuildId) {
|
if (inventory.GuildId) {
|
||||||
const guild = (await Guild.findById(inventory.GuildId, "Name Tier XP Class"))!;
|
const guild = (await Guild.findById(inventory.GuildId, "Name Tier XP Class Emblem"))!;
|
||||||
result.GuildId = toOid(inventory.GuildId);
|
populateGuild(guild, result);
|
||||||
result.GuildName = guild.Name;
|
|
||||||
result.GuildTier = guild.Tier;
|
|
||||||
result.GuildXp = guild.XP;
|
|
||||||
result.GuildClass = guild.Class;
|
|
||||||
result.GuildEmblem = false;
|
|
||||||
}
|
}
|
||||||
for (const key of allDailyAffiliationKeys) {
|
for (const key of allDailyAffiliationKeys) {
|
||||||
result[key] = inventory[key];
|
result[key] = inventory[key];
|
||||||
@ -112,6 +74,100 @@ export const getProfileViewingDataController: RequestHandler = async (req, res)
|
|||||||
//XpCacheExpiryDate, some IMongoDate in the future, no clue what it's for
|
//XpCacheExpiryDate, some IMongoDate in the future, no clue what it's for
|
||||||
Stats: stats
|
Stats: stats
|
||||||
});
|
});
|
||||||
|
} else if (req.query.guildId) {
|
||||||
|
const guild = await Guild.findById(req.query.guildId, "Name Tier XP Class Emblem TechProjects ClaimedXP");
|
||||||
|
if (!guild) {
|
||||||
|
res.status(409).send("Could not find guild");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const members = await GuildMember.find({ guildId: guild._id, status: 0 });
|
||||||
|
const results: IPlayerProfileViewingDataResult[] = [];
|
||||||
|
for (let i = 0; i != Math.min(4, members.length); ++i) {
|
||||||
|
const member = members[i];
|
||||||
|
const [account, inventory] = await Promise.all([
|
||||||
|
Account.findById(member.accountId, "DisplayName"),
|
||||||
|
Inventory.findOne(
|
||||||
|
{ accountOwnerId: member.accountId },
|
||||||
|
"DisplayName PlayerLevel XPInfo LoadOutPresets CurrentLoadOutIds WeaponSkins Suits Pistols LongGuns Melee"
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
const result: IPlayerProfileViewingDataResult = {
|
||||||
|
AccountId: toOid(account!._id),
|
||||||
|
DisplayName: account!.DisplayName,
|
||||||
|
PlayerLevel: inventory!.PlayerLevel,
|
||||||
|
LoadOutInventory: {
|
||||||
|
WeaponSkins: [],
|
||||||
|
XPInfo: inventory!.XPInfo
|
||||||
|
}
|
||||||
|
};
|
||||||
|
await populateLoadout(inventory!, result);
|
||||||
|
results.push(result);
|
||||||
|
}
|
||||||
|
populateGuild(guild, results[0]);
|
||||||
|
|
||||||
|
const combinedStats: IStatsClient = {};
|
||||||
|
const statsArr = await Stats.find({ accountOwnerId: { $in: members.map(x => x.accountId) } }).lean(); // need this as POJO so Object.entries works as expected
|
||||||
|
for (const stats of statsArr) {
|
||||||
|
for (const [key, value] of Object.entries(stats)) {
|
||||||
|
if (typeof value == "number" && key != "__v") {
|
||||||
|
(combinedStats[key as keyof IStatsClient] as number | undefined) ??= 0;
|
||||||
|
(combinedStats[key as keyof IStatsClient] as number) += value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const arrayName of ["Weapons", "Enemies", "Scans", "Missions", "PVP"] as const) {
|
||||||
|
if (stats[arrayName]) {
|
||||||
|
combinedStats[arrayName] ??= [];
|
||||||
|
for (const entry of stats[arrayName]) {
|
||||||
|
const combinedEntry = combinedStats[arrayName].find(x => x.type == entry.type);
|
||||||
|
if (combinedEntry) {
|
||||||
|
for (const [key, value] of Object.entries(entry)) {
|
||||||
|
if (typeof value == "number") {
|
||||||
|
(combinedEntry[key as keyof typeof combinedEntry] as unknown as
|
||||||
|
| number
|
||||||
|
| undefined) ??= 0;
|
||||||
|
(combinedEntry[key as keyof typeof combinedEntry] as unknown as number) += value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
|
||||||
|
combinedStats[arrayName].push(entry as any);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const xpComponents: IXPComponentClient[] = [];
|
||||||
|
if (guild.ClaimedXP) {
|
||||||
|
for (const componentName of guild.ClaimedXP) {
|
||||||
|
if (componentName.endsWith(".level")) {
|
||||||
|
const [key] = Object.entries(ExportDojoRecipes.rooms).find(
|
||||||
|
([_key, value]) => value.resultType == componentName
|
||||||
|
)!;
|
||||||
|
xpComponents.push({
|
||||||
|
StoreTypeName: toStoreItem(key)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const [key] = Object.entries(ExportDojoRecipes.decos).find(
|
||||||
|
([_key, value]) => value.resultType == componentName
|
||||||
|
)!;
|
||||||
|
xpComponents.push({
|
||||||
|
StoreTypeName: toStoreItem(key)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
Results: results,
|
||||||
|
TechProjects: guild.TechProjects,
|
||||||
|
XpComponents: xpComponents,
|
||||||
|
//XpCacheExpiryDate, some IMongoDate in the future, no clue what it's for
|
||||||
|
Stats: combinedStats
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.sendStatus(400);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IPlayerProfileViewingDataResult extends Partial<IDailyAffiliations> {
|
interface IPlayerProfileViewingDataResult extends Partial<IDailyAffiliations> {
|
||||||
@ -133,20 +189,40 @@ interface IPlayerProfileViewingDataResult extends Partial<IDailyAffiliations> {
|
|||||||
GuildXp?: number;
|
GuildXp?: number;
|
||||||
GuildClass?: number;
|
GuildClass?: number;
|
||||||
GuildEmblem?: boolean;
|
GuildEmblem?: boolean;
|
||||||
PlayerSkills: IPlayerSkills;
|
PlayerSkills?: IPlayerSkills;
|
||||||
ChallengeProgress: IChallengeProgress[];
|
ChallengeProgress?: IChallengeProgress[];
|
||||||
DeathMarks: string[];
|
DeathMarks?: string[];
|
||||||
Harvestable: boolean;
|
Harvestable?: boolean;
|
||||||
DeathSquadable: boolean;
|
DeathSquadable?: boolean;
|
||||||
Created: IMongoDate;
|
Created?: IMongoDate;
|
||||||
MigratedToConsole: boolean;
|
MigratedToConsole?: boolean;
|
||||||
Missions: IMission[];
|
Missions?: IMission[];
|
||||||
Affiliations: IAffiliation[];
|
Affiliations?: IAffiliation[];
|
||||||
DailyFocus: number;
|
DailyFocus?: number;
|
||||||
Wishlist: string[];
|
Wishlist?: string[];
|
||||||
Alignment?: IAlignment;
|
Alignment?: IAlignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IXPComponentClient {
|
||||||
|
_id?: IOid;
|
||||||
|
StoreTypeName: string;
|
||||||
|
TypeName?: string;
|
||||||
|
PurchaseQuantity?: number;
|
||||||
|
ProductCategory?: "Recipes";
|
||||||
|
Rarity?: "COMMON";
|
||||||
|
RegularPrice?: number;
|
||||||
|
PremiumPrice?: number;
|
||||||
|
SellingPrice?: number;
|
||||||
|
DateAddedToManifest?: number;
|
||||||
|
PrimeSellingPrice?: number;
|
||||||
|
GuildXp?: number;
|
||||||
|
ResultPrefab?: string;
|
||||||
|
ResultDecoration?: string;
|
||||||
|
ShowInMarket?: boolean;
|
||||||
|
ShowInInventory?: boolean;
|
||||||
|
locTags?: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
let skinLookupTable: Record<number, string> | undefined;
|
let skinLookupTable: Record<number, string> | undefined;
|
||||||
|
|
||||||
const resolveAndCollectSkins = (
|
const resolveAndCollectSkins = (
|
||||||
@ -181,3 +257,51 @@ const resolveAndCollectSkins = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const populateLoadout = async (
|
||||||
|
inventory: TInventoryDatabaseDocument,
|
||||||
|
result: IPlayerProfileViewingDataResult
|
||||||
|
): Promise<void> => {
|
||||||
|
if (inventory.CurrentLoadOutIds.length) {
|
||||||
|
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "NORMAL"))!;
|
||||||
|
result.LoadOutPreset = loadout.NORMAL.id(inventory.CurrentLoadOutIds[0].$oid)!.toJSON<ILoadoutConfigClient>();
|
||||||
|
result.LoadOutPreset.ItemId = undefined;
|
||||||
|
const skins = new Set<string>();
|
||||||
|
if (result.LoadOutPreset.s) {
|
||||||
|
result.LoadOutInventory.Suits = [
|
||||||
|
inventory.Suits.id(result.LoadOutPreset.s.ItemId.$oid)!.toJSON<IEquipmentClient>()
|
||||||
|
];
|
||||||
|
resolveAndCollectSkins(inventory, skins, result.LoadOutInventory.Suits[0]);
|
||||||
|
}
|
||||||
|
if (result.LoadOutPreset.p) {
|
||||||
|
result.LoadOutInventory.Pistols = [
|
||||||
|
inventory.Pistols.id(result.LoadOutPreset.p.ItemId.$oid)!.toJSON<IEquipmentClient>()
|
||||||
|
];
|
||||||
|
resolveAndCollectSkins(inventory, skins, result.LoadOutInventory.Pistols[0]);
|
||||||
|
}
|
||||||
|
if (result.LoadOutPreset.l) {
|
||||||
|
result.LoadOutInventory.LongGuns = [
|
||||||
|
inventory.LongGuns.id(result.LoadOutPreset.l.ItemId.$oid)!.toJSON<IEquipmentClient>()
|
||||||
|
];
|
||||||
|
resolveAndCollectSkins(inventory, skins, result.LoadOutInventory.LongGuns[0]);
|
||||||
|
}
|
||||||
|
if (result.LoadOutPreset.m) {
|
||||||
|
result.LoadOutInventory.Melee = [
|
||||||
|
inventory.Melee.id(result.LoadOutPreset.m.ItemId.$oid)!.toJSON<IEquipmentClient>()
|
||||||
|
];
|
||||||
|
resolveAndCollectSkins(inventory, skins, result.LoadOutInventory.Melee[0]);
|
||||||
|
}
|
||||||
|
for (const skin of skins) {
|
||||||
|
result.LoadOutInventory.WeaponSkins.push({ ItemType: skin });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const populateGuild = (guild: TGuildDatabaseDocument, result: IPlayerProfileViewingDataResult): void => {
|
||||||
|
result.GuildId = toOid(guild._id);
|
||||||
|
result.GuildName = guild.Name;
|
||||||
|
result.GuildTier = guild.Tier;
|
||||||
|
result.GuildXp = guild.XP;
|
||||||
|
result.GuildClass = guild.Class;
|
||||||
|
result.GuildEmblem = guild.Emblem;
|
||||||
|
};
|
||||||
|
@ -31,6 +31,14 @@ export interface IStatsClient {
|
|||||||
CaliberChicksScore?: number;
|
CaliberChicksScore?: number;
|
||||||
OlliesCrashCourseScore?: number;
|
OlliesCrashCourseScore?: number;
|
||||||
DojoObstacleScore?: number;
|
DojoObstacleScore?: number;
|
||||||
|
|
||||||
|
// not in schema
|
||||||
|
PVP?: {
|
||||||
|
suitDeaths?: number;
|
||||||
|
suitKills?: number;
|
||||||
|
weaponKills?: number;
|
||||||
|
type: string;
|
||||||
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IStatsDatabase extends IStatsClient {
|
export interface IStatsDatabase extends IStatsClient {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user