Foundry 1 - Preliminary (#127)
This commit is contained in:
		
							parent
							
								
									4a102b9d3b
								
							
						
					
					
						commit
						8b50189fcf
					
				@ -3,11 +3,13 @@ const secondsPerMinute = 60;
 | 
				
			|||||||
const minutesPerHour = 60;
 | 
					const minutesPerHour = 60;
 | 
				
			||||||
const hoursPerDay = 24;
 | 
					const hoursPerDay = 24;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const unixSecond = millisecondsPerSecond;
 | 
				
			||||||
const unixMinute = secondsPerMinute * millisecondsPerSecond;
 | 
					const unixMinute = secondsPerMinute * millisecondsPerSecond;
 | 
				
			||||||
const unixHour = unixMinute * minutesPerHour;
 | 
					const unixHour = unixMinute * minutesPerHour;
 | 
				
			||||||
const unixDay = hoursPerDay * unixHour;
 | 
					const unixDay = hoursPerDay * unixHour;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const unixTimesInMs = {
 | 
					export const unixTimesInMs = {
 | 
				
			||||||
 | 
					    second: unixSecond,
 | 
				
			||||||
    minute: unixMinute,
 | 
					    minute: unixMinute,
 | 
				
			||||||
    hour: unixHour,
 | 
					    hour: unixHour,
 | 
				
			||||||
    day: unixDay
 | 
					    day: unixDay
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										64
									
								
								src/controllers/api/claimCompletedRecipeController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/controllers/api/claimCompletedRecipeController.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					//this is a controller for the claimCompletedRecipe route
 | 
				
			||||||
 | 
					//it will claim a recipe for the user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { Request, RequestHandler, Response } from "express";
 | 
				
			||||||
 | 
					import { logger } from "@/src/utils/logger";
 | 
				
			||||||
 | 
					import { getItemByBlueprint, getItemCategoryByUniqueName } from "@/src/services/itemDataService";
 | 
				
			||||||
 | 
					import { IOid } from "@/src/types/commonTypes";
 | 
				
			||||||
 | 
					import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
				
			||||||
 | 
					import { getInventory } from "@/src/services/inventoryService";
 | 
				
			||||||
 | 
					import { IInventoryDatabase } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface IClaimCompletedRecipeRequest {
 | 
				
			||||||
 | 
					    RecipeIds: IOid[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// eslint-disable-next-line @typescript-eslint/no-misused-promises
 | 
				
			||||||
 | 
					export const claimCompletedRecipeController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
					    const claimCompletedRecipeRequest = getJSONfromString(req.body.toString()) as IClaimCompletedRecipeRequest;
 | 
				
			||||||
 | 
					    const accountId = req.query.accountId as string;
 | 
				
			||||||
 | 
					    if (!accountId) throw new Error("no account id");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    console.log(claimCompletedRecipeRequest);
 | 
				
			||||||
 | 
					    const inventory = await getInventory(accountId);
 | 
				
			||||||
 | 
					    const pendingRecipe = inventory.PendingRecipes.find(
 | 
				
			||||||
 | 
					        recipe => recipe._id?.toString() === claimCompletedRecipeRequest.RecipeIds[0].$oid
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    console.log(pendingRecipe);
 | 
				
			||||||
 | 
					    if (!pendingRecipe) {
 | 
				
			||||||
 | 
					        logger.error(`no pending recipe found with id ${claimCompletedRecipeRequest.RecipeIds[0].$oid}`);
 | 
				
			||||||
 | 
					        throw new Error(`no pending recipe found with id ${claimCompletedRecipeRequest.RecipeIds[0].$oid}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //check recipe is indeed ready to be completed
 | 
				
			||||||
 | 
					    // if (pendingRecipe.CompletionDate > new Date()) {
 | 
				
			||||||
 | 
					    //     logger.error(`recipe ${pendingRecipe._id} is not ready to be completed`);
 | 
				
			||||||
 | 
					    //     throw new Error(`recipe ${pendingRecipe._id} is not ready to be completed`);
 | 
				
			||||||
 | 
					    // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //get completed Items
 | 
				
			||||||
 | 
					    const completedItemName = getItemByBlueprint(pendingRecipe.ItemType)?.uniqueName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!completedItemName) {
 | 
				
			||||||
 | 
					        logger.error(`no completed item found for recipe ${pendingRecipe._id}`);
 | 
				
			||||||
 | 
					        throw new Error(`no completed item found for recipe ${pendingRecipe._id}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const itemCategory = getItemCategoryByUniqueName(completedItemName) as keyof typeof inventory;
 | 
				
			||||||
 | 
					    console.log(itemCategory);
 | 
				
			||||||
 | 
					    //TODO: remove all Schema.Mixed for inventory[itemCategory] not to be any
 | 
				
			||||||
 | 
					    //add item
 | 
				
			||||||
 | 
					    //inventory[itemCategory].
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //add additional item components like mods or weapons for a sentinel.
 | 
				
			||||||
 | 
					    //const additionalItemComponents = itemComponents[uniqueName]
 | 
				
			||||||
 | 
					    //add these items to inventory
 | 
				
			||||||
 | 
					    //return changes as InventoryChanges
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //remove pending recipe
 | 
				
			||||||
 | 
					    inventory.PendingRecipes.pull(pendingRecipe._id);
 | 
				
			||||||
 | 
					    // await inventory.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    logger.debug("Claiming Completed Recipe", { completedItemName });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    res.json({ InventoryChanges: {} });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -24,6 +24,7 @@ const inventoryController: RequestHandler = async (request: Request, response: R
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //TODO: make a function that converts from database representation to client
 | 
				
			||||||
    const inventoryJSON = inventory.toJSON();
 | 
					    const inventoryJSON = inventory.toJSON();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const inventoryResponse = toInventoryResponse(inventoryJSON);
 | 
					    const inventoryResponse = toInventoryResponse(inventoryJSON);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										21
									
								
								src/controllers/api/startRecipeController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/controllers/api/startRecipeController.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					import { parseString } from "@/src/helpers/general";
 | 
				
			||||||
 | 
					import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
				
			||||||
 | 
					import { startRecipe } from "@/src/services/recipeService";
 | 
				
			||||||
 | 
					import { logger } from "@/src/utils/logger";
 | 
				
			||||||
 | 
					import { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IStartRecipeRequest {
 | 
				
			||||||
 | 
					    RecipeName: string;
 | 
				
			||||||
 | 
					    Ids: string[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// eslint-disable-next-line @typescript-eslint/no-misused-promises
 | 
				
			||||||
 | 
					export const startRecipeController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
					    const startRecipeRequest = getJSONfromString(req.body.toString()) as IStartRecipeRequest;
 | 
				
			||||||
 | 
					    logger.debug("StartRecipe Request", { startRecipeRequest });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const accountId = parseString(req.query.accountId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const newRecipeId = await startRecipe(startRecipeRequest.RecipeName, accountId);
 | 
				
			||||||
 | 
					    res.json(newRecipeId);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
import { ItemType, toAddItemRequest } from "@/src/helpers/customHelpers/addItemHelpers";
 | 
					import { ItemType, toAddItemRequest } from "@/src/helpers/customHelpers/addItemHelpers";
 | 
				
			||||||
import { getWeaponType } from "@/src/helpers/purchaseHelpers";
 | 
					import { getWeaponType } from "@/src/services/itemDataService";
 | 
				
			||||||
import { addPowerSuit, addWeapon } from "@/src/services/inventoryService";
 | 
					import { addPowerSuit, addWeapon } from "@/src/services/inventoryService";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
import { isString, parseString } from "@/src/helpers/general";
 | 
					import { isString, parseString } from "@/src/helpers/general";
 | 
				
			||||||
import { items } from "@/static/data/items";
 | 
					import { items } from "@/src/services/itemDataService";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export enum ItemType {
 | 
					export enum ItemType {
 | 
				
			||||||
    Powersuit = "Powersuit",
 | 
					    Powersuit = "Powersuit",
 | 
				
			||||||
@ -23,20 +23,20 @@ interface IAddItemRequest {
 | 
				
			|||||||
    InternalName: string;
 | 
					    InternalName: string;
 | 
				
			||||||
    accountId: string;
 | 
					    accountId: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
export const isInternalName = (internalName: string): boolean => {
 | 
					export const isInternalItemName = (internalName: string): boolean => {
 | 
				
			||||||
    const item = items.find(i => i.uniqueName === internalName);
 | 
					    const item = items.find(i => i.uniqueName === internalName);
 | 
				
			||||||
    return Boolean(item);
 | 
					    return Boolean(item);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const parseInternalName = (internalName: unknown): string => {
 | 
					const parseInternalItemName = (internalName: unknown): string => {
 | 
				
			||||||
    if (!isString(internalName) || !isInternalName(internalName)) {
 | 
					    if (!isString(internalName) || !isInternalItemName(internalName)) {
 | 
				
			||||||
        throw new Error("incorrect internal name");
 | 
					        throw new Error("incorrect internal name");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return internalName;
 | 
					    return internalName;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const toAddItemRequest = (body: unknown): IAddItemRequest => {
 | 
					export const toAddItemRequest = (body: unknown): IAddItemRequest => {
 | 
				
			||||||
    if (!body || typeof body !== "object") {
 | 
					    if (!body || typeof body !== "object") {
 | 
				
			||||||
        throw new Error("incorrect or missing add item request data");
 | 
					        throw new Error("incorrect or missing add item request data");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -44,12 +44,10 @@ const toAddItemRequest = (body: unknown): IAddItemRequest => {
 | 
				
			|||||||
    if ("type" in body && "internalName" in body && "accountId" in body) {
 | 
					    if ("type" in body && "internalName" in body && "accountId" in body) {
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
            type: parseItemType(body.type),
 | 
					            type: parseItemType(body.type),
 | 
				
			||||||
            InternalName: parseInternalName(body.internalName),
 | 
					            InternalName: parseInternalItemName(body.internalName),
 | 
				
			||||||
            accountId: parseString(body.accountId)
 | 
					            accountId: parseString(body.accountId)
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    throw new Error("malformed add item request");
 | 
					    throw new Error("malformed add item request");
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
export { toAddItemRequest };
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,7 @@
 | 
				
			|||||||
import { parseBoolean, parseNumber, parseString } from "@/src/helpers/general";
 | 
					import { parseBoolean, parseNumber, parseString } from "@/src/helpers/general";
 | 
				
			||||||
import { WeaponTypeInternal } from "@/src/services/inventoryService";
 | 
					import { weapons } from "@/src/services/itemDataService";
 | 
				
			||||||
import { slotPurchaseNameToSlotName } from "@/src/services/purchaseService";
 | 
					import { slotPurchaseNameToSlotName } from "@/src/services/purchaseService";
 | 
				
			||||||
import { IPurchaseRequest, SlotPurchaseName } from "@/src/types/purchaseTypes";
 | 
					import { IPurchaseRequest, SlotPurchaseName } from "@/src/types/purchaseTypes";
 | 
				
			||||||
import { weapons } from "@/static/data/items";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const toPurchaseRequest = (purchaseRequest: unknown): IPurchaseRequest => {
 | 
					export const toPurchaseRequest = (purchaseRequest: unknown): IPurchaseRequest => {
 | 
				
			||||||
    if (!purchaseRequest || typeof purchaseRequest !== "object") {
 | 
					    if (!purchaseRequest || typeof purchaseRequest !== "object") {
 | 
				
			||||||
@ -41,22 +40,6 @@ export const toPurchaseRequest = (purchaseRequest: unknown): IPurchaseRequest =>
 | 
				
			|||||||
    throw new Error("invalid purchaseRequest");
 | 
					    throw new Error("invalid purchaseRequest");
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getWeaponType = (weaponName: string) => {
 | 
					 | 
				
			||||||
    const weaponInfo = weapons.find(i => i.uniqueName === weaponName);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!weaponInfo) {
 | 
					 | 
				
			||||||
        throw new Error(`unknown weapon ${weaponName}`);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const weaponType = weaponInfo.productCategory as WeaponTypeInternal;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!weaponType) {
 | 
					 | 
				
			||||||
        throw new Error(`unknown weapon category for item ${weaponName}`);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return weaponType;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const isSlotPurchaseName = (slotPurchaseName: string): slotPurchaseName is SlotPurchaseName => {
 | 
					export const isSlotPurchaseName = (slotPurchaseName: string): slotPurchaseName is SlotPurchaseName => {
 | 
				
			||||||
    return slotPurchaseName in slotPurchaseNameToSlotName;
 | 
					    return slotPurchaseName in slotPurchaseNameToSlotName;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
export const getJSONfromString = (str: string): any => {
 | 
					export const getJSONfromString = (str: string) => {
 | 
				
			||||||
    const jsonSubstring = str.substring(0, str.lastIndexOf("}") + 1);
 | 
					    const jsonSubstring = str.substring(0, str.lastIndexOf("}") + 1);
 | 
				
			||||||
    return JSON.parse(jsonSubstring);
 | 
					    return JSON.parse(jsonSubstring);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -16,3 +16,11 @@ export const getSubstringFromKeywordToKeyword = (str: string, keywordBegin: stri
 | 
				
			|||||||
    const endIndex = str.indexOf(keywordEnd);
 | 
					    const endIndex = str.indexOf(keywordEnd);
 | 
				
			||||||
    return str.substring(beginIndex, endIndex + 1);
 | 
					    return str.substring(beginIndex, endIndex + 1);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getIndexAfter = (str: string, searchWord: string) => {
 | 
				
			||||||
 | 
					    const index = str.indexOf(searchWord);
 | 
				
			||||||
 | 
					    if (index === -1) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return index + searchWord.length;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
import { Model, Schema, Types, model } from "mongoose";
 | 
					import { HydratedDocument, Model, Schema, Types, model } from "mongoose";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    IFlavourItem,
 | 
					    IFlavourItem,
 | 
				
			||||||
    IRawUpgrade,
 | 
					    IRawUpgrade,
 | 
				
			||||||
@ -10,7 +10,9 @@ import {
 | 
				
			|||||||
    ISlots,
 | 
					    ISlots,
 | 
				
			||||||
    IGenericItem,
 | 
					    IGenericItem,
 | 
				
			||||||
    IMailbox,
 | 
					    IMailbox,
 | 
				
			||||||
    IDuviriInfo
 | 
					    IDuviriInfo,
 | 
				
			||||||
 | 
					    IPendingRecipe as IPendingRecipeDatabase,
 | 
				
			||||||
 | 
					    IPendingRecipeResponse
 | 
				
			||||||
} from "../../types/inventoryTypes/inventoryTypes";
 | 
					} from "../../types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
import { IMongoDate, IOid } from "../../types/commonTypes";
 | 
					import { IMongoDate, IOid } from "../../types/commonTypes";
 | 
				
			||||||
import { ISuitDatabase } from "@/src/types/inventoryTypes/SuitTypes";
 | 
					import { ISuitDatabase } from "@/src/types/inventoryTypes/SuitTypes";
 | 
				
			||||||
@ -25,6 +27,29 @@ import {
 | 
				
			|||||||
} from "@/src/types/inventoryTypes/commonInventoryTypes";
 | 
					} from "@/src/types/inventoryTypes/commonInventoryTypes";
 | 
				
			||||||
import { toOid } from "@/src/helpers/inventoryHelpers";
 | 
					import { toOid } from "@/src/helpers/inventoryHelpers";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const pendingRecipeSchema = new Schema<IPendingRecipeDatabase>(
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ItemType: String,
 | 
				
			||||||
 | 
					        CompletionDate: Date
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { id: false }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pendingRecipeSchema.virtual("ItemId").get(function () {
 | 
				
			||||||
 | 
					    return { $oid: this._id.toString() };
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pendingRecipeSchema.set("toJSON", {
 | 
				
			||||||
 | 
					    virtuals: true,
 | 
				
			||||||
 | 
					    transform(_document, returnedObject) {
 | 
				
			||||||
 | 
					        delete returnedObject._id;
 | 
				
			||||||
 | 
					        delete returnedObject.__v;
 | 
				
			||||||
 | 
					        (returnedObject as IPendingRecipeResponse).CompletionDate = {
 | 
				
			||||||
 | 
					            $date: { $numberLong: (returnedObject as IPendingRecipeDatabase).CompletionDate.getTime().toString() }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const polaritySchema = new Schema<IPolarity>({
 | 
					const polaritySchema = new Schema<IPolarity>({
 | 
				
			||||||
    Slot: Number,
 | 
					    Slot: Number,
 | 
				
			||||||
    Value: String
 | 
					    Value: String
 | 
				
			||||||
@ -296,7 +321,6 @@ DuviriInfoSchema.set("toJSON", {
 | 
				
			|||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
 | 
					const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
 | 
				
			||||||
 | 
					 | 
				
			||||||
    accountOwnerId: Schema.Types.ObjectId,
 | 
					    accountOwnerId: Schema.Types.ObjectId,
 | 
				
			||||||
    SubscribedToEmails: Number,
 | 
					    SubscribedToEmails: Number,
 | 
				
			||||||
    Created: Schema.Types.Mixed,
 | 
					    Created: Schema.Types.Mixed,
 | 
				
			||||||
@ -325,7 +349,6 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
 | 
				
			|||||||
    MechBin: slotsBinSchema,
 | 
					    MechBin: slotsBinSchema,
 | 
				
			||||||
    CrewMemberBin: slotsBinSchema,
 | 
					    CrewMemberBin: slotsBinSchema,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    //How many trades do you have left
 | 
					    //How many trades do you have left
 | 
				
			||||||
    TradesRemaining: Number,
 | 
					    TradesRemaining: Number,
 | 
				
			||||||
    //How many Gift do you have left*(gift spends the trade)
 | 
					    //How many Gift do you have left*(gift spends the trade)
 | 
				
			||||||
@ -351,10 +374,9 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
 | 
				
			|||||||
    DailyAffiliationZariman: Number,
 | 
					    DailyAffiliationZariman: Number,
 | 
				
			||||||
    DailyAffiliationKahl: Number,
 | 
					    DailyAffiliationKahl: Number,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    //Daily Focus limit
 | 
					    //Daily Focus limit
 | 
				
			||||||
    DailyFocus: Number,
 | 
					    DailyFocus: Number,
 | 
				
			||||||
    //you not used Focus 
 | 
					    //you not used Focus
 | 
				
			||||||
    FocusXP: Schema.Types.Mixed,
 | 
					    FocusXP: Schema.Types.Mixed,
 | 
				
			||||||
    //Curent active like Active school focuses is = "Zenurik"
 | 
					    //Curent active like Active school focuses is = "Zenurik"
 | 
				
			||||||
    FocusAbility: String,
 | 
					    FocusAbility: String,
 | 
				
			||||||
@ -441,24 +463,21 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
 | 
				
			|||||||
    //Railjack/Components(https://warframe.fandom.com/wiki/Railjack/Components)
 | 
					    //Railjack/Components(https://warframe.fandom.com/wiki/Railjack/Components)
 | 
				
			||||||
    CrewShipRawSalvage: [Schema.Types.Mixed],
 | 
					    CrewShipRawSalvage: [Schema.Types.Mixed],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    //Default RailJack
 | 
					    //Default RailJack
 | 
				
			||||||
    CrewShips: [Schema.Types.Mixed],
 | 
					    CrewShips: [Schema.Types.Mixed],
 | 
				
			||||||
    CrewShipAmmo: [Schema.Types.Mixed],
 | 
					    CrewShipAmmo: [Schema.Types.Mixed],
 | 
				
			||||||
    CrewShipWeapons: [Schema.Types.Mixed],
 | 
					    CrewShipWeapons: [Schema.Types.Mixed],
 | 
				
			||||||
    CrewShipWeaponSkins: [Schema.Types.Mixed],
 | 
					    CrewShipWeaponSkins: [Schema.Types.Mixed],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    //NPC Crew and weapon
 | 
					    //NPC Crew and weapon
 | 
				
			||||||
    CrewMembers: [Schema.Types.Mixed],
 | 
					    CrewMembers: [Schema.Types.Mixed],
 | 
				
			||||||
    CrewShipSalvagedWeaponSkins: [Schema.Types.Mixed],
 | 
					    CrewShipSalvagedWeaponSkins: [Schema.Types.Mixed],
 | 
				
			||||||
    CrewShipSalvagedWeapons: [Schema.Types.Mixed],
 | 
					    CrewShipSalvagedWeapons: [Schema.Types.Mixed],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    //Complete Mission\Quests
 | 
					    //Complete Mission\Quests
 | 
				
			||||||
    Missions: [Schema.Types.Mixed],
 | 
					    Missions: [Schema.Types.Mixed],
 | 
				
			||||||
    QuestKeys: [Schema.Types.Mixed],
 | 
					    QuestKeys: [Schema.Types.Mixed],
 | 
				
			||||||
    //item like DojoKey or Boss missions key 
 | 
					    //item like DojoKey or Boss missions key
 | 
				
			||||||
    LevelKeys: [Schema.Types.Mixed],
 | 
					    LevelKeys: [Schema.Types.Mixed],
 | 
				
			||||||
    //Active quests
 | 
					    //Active quests
 | 
				
			||||||
    Quests: [Schema.Types.Mixed],
 | 
					    Quests: [Schema.Types.Mixed],
 | 
				
			||||||
@ -478,25 +497,22 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
 | 
				
			|||||||
    //Retries rank up(3 time)
 | 
					    //Retries rank up(3 time)
 | 
				
			||||||
    TrainingRetriesLeft: Number,
 | 
					    TrainingRetriesLeft: Number,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    //you saw last played Region when you opened the star map
 | 
					    //you saw last played Region when you opened the star map
 | 
				
			||||||
    LastRegionPlayed: String,
 | 
					    LastRegionPlayed: String,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //Blueprint
 | 
					    //Blueprint
 | 
				
			||||||
    Recipes: [Schema.Types.Mixed],
 | 
					    Recipes: [Schema.Types.Mixed],
 | 
				
			||||||
    //Crafting Blueprint(Item Name + CompletionDate)
 | 
					    //Crafting Blueprint(Item Name + CompletionDate)
 | 
				
			||||||
    PendingRecipes: [Schema.Types.Mixed],
 | 
					    PendingRecipes: [pendingRecipeSchema],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //warframe\Weapon skins
 | 
					    //warframe\Weapon skins
 | 
				
			||||||
    WeaponSkins: [Schema.Types.Mixed],
 | 
					    WeaponSkins: [Schema.Types.Mixed],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    //Ayatan Item
 | 
					    //Ayatan Item
 | 
				
			||||||
    FusionTreasures: [Schema.Types.Mixed],
 | 
					    FusionTreasures: [Schema.Types.Mixed],
 | 
				
			||||||
    //"node": "TreasureTutorial", "state": "TS_COMPLETED"
 | 
					    //"node": "TreasureTutorial", "state": "TS_COMPLETED"
 | 
				
			||||||
    TauntHistory: [Schema.Types.Mixed],
 | 
					    TauntHistory: [Schema.Types.Mixed],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    //noShow2FA,VisitPrimeVault etc
 | 
					    //noShow2FA,VisitPrimeVault etc
 | 
				
			||||||
    WebFlags: Schema.Types.Mixed,
 | 
					    WebFlags: Schema.Types.Mixed,
 | 
				
			||||||
    //Id CompletedAlerts
 | 
					    //Id CompletedAlerts
 | 
				
			||||||
@ -508,7 +524,6 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
 | 
				
			|||||||
    //Alert->Kuva Siphon
 | 
					    //Alert->Kuva Siphon
 | 
				
			||||||
    PeriodicMissionCompletions: [Schema.Types.Mixed],
 | 
					    PeriodicMissionCompletions: [Schema.Types.Mixed],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    //Codex->LoreFragment
 | 
					    //Codex->LoreFragment
 | 
				
			||||||
    LoreFragmentScans: [Schema.Types.Mixed],
 | 
					    LoreFragmentScans: [Schema.Types.Mixed],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -520,7 +535,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
 | 
				
			|||||||
    ActiveDojoColorResearch: String,
 | 
					    ActiveDojoColorResearch: String,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SentientSpawnChanceBoosters: Schema.Types.Mixed,
 | 
					    SentientSpawnChanceBoosters: Schema.Types.Mixed,
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    QualifyingInvasions: [Schema.Types.Mixed],
 | 
					    QualifyingInvasions: [Schema.Types.Mixed],
 | 
				
			||||||
    FactionScores: [Number],
 | 
					    FactionScores: [Number],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -530,11 +545,9 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
 | 
				
			|||||||
    //If you want change Spectre Gear id
 | 
					    //If you want change Spectre Gear id
 | 
				
			||||||
    PendingSpectreLoadouts: [Schema.Types.Mixed],
 | 
					    PendingSpectreLoadouts: [Schema.Types.Mixed],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    //New quest Email spam
 | 
					    //New quest Email spam
 | 
				
			||||||
    //example:"ItemType": "/Lotus/Types/Keys/RailJackBuildQuest/RailjackBuildQuestEmailItem",
 | 
					    //example:"ItemType": "/Lotus/Types/Keys/RailJackBuildQuest/RailjackBuildQuestEmailItem",
 | 
				
			||||||
    EmailItems: [Schema.Types.Mixed],
 | 
					    EmailItems: [Schema.Types.Mixed],
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //Profile->Wishlist
 | 
					    //Profile->Wishlist
 | 
				
			||||||
    Wishlist: [String],
 | 
					    Wishlist: [String],
 | 
				
			||||||
@ -561,7 +574,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    //Game mission\ivent score example  "Tag": "WaterFight", "Best": 170, "Count": 1258,
 | 
					    //Game mission\ivent score example  "Tag": "WaterFight", "Best": 170, "Count": 1258,
 | 
				
			||||||
    PersonalGoalProgress: [Schema.Types.Mixed],
 | 
					    PersonalGoalProgress: [Schema.Types.Mixed],
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    //Setting interface Style
 | 
					    //Setting interface Style
 | 
				
			||||||
    ThemeStyle: String,
 | 
					    ThemeStyle: String,
 | 
				
			||||||
    ThemeBackground: String,
 | 
					    ThemeBackground: String,
 | 
				
			||||||
@ -579,7 +592,6 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
 | 
				
			|||||||
    //Night Wave Challenge
 | 
					    //Night Wave Challenge
 | 
				
			||||||
    SeasonChallengeHistory: [Schema.Types.Mixed],
 | 
					    SeasonChallengeHistory: [Schema.Types.Mixed],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    //Cephalon Simaris Entries Example:"TargetType"+"Scans"(1-10)+"Completed": true|false
 | 
					    //Cephalon Simaris Entries Example:"TargetType"+"Scans"(1-10)+"Completed": true|false
 | 
				
			||||||
    LibraryPersonalProgress: [Schema.Types.Mixed],
 | 
					    LibraryPersonalProgress: [Schema.Types.Mixed],
 | 
				
			||||||
    //Cephalon Simaris Daily Task
 | 
					    //Cephalon Simaris Daily Task
 | 
				
			||||||
@ -587,23 +599,23 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    //https://warframe.fandom.com/wiki/Invasion
 | 
					    //https://warframe.fandom.com/wiki/Invasion
 | 
				
			||||||
    InvasionChainProgress: [Schema.Types.Mixed],
 | 
					    InvasionChainProgress: [Schema.Types.Mixed],
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    //https://warframe.fandom.com/wiki/Parazon
 | 
					    //https://warframe.fandom.com/wiki/Parazon
 | 
				
			||||||
    DataKnives: [GenericItemSchema],
 | 
					    DataKnives: [GenericItemSchema],
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    //CorpusLich or GrineerLich
 | 
					    //CorpusLich or GrineerLich
 | 
				
			||||||
    NemesisAbandonedRewards: [String],
 | 
					    NemesisAbandonedRewards: [String],
 | 
				
			||||||
    //CorpusLich\KuvaLich 
 | 
					    //CorpusLich\KuvaLich
 | 
				
			||||||
    NemesisHistory: [Schema.Types.Mixed],
 | 
					    NemesisHistory: [Schema.Types.Mixed],
 | 
				
			||||||
    LastNemesisAllySpawnTime: Schema.Types.Mixed,
 | 
					    LastNemesisAllySpawnTime: Schema.Types.Mixed,
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    //TradingRulesConfirmed,ShowFriendInvNotifications(Option->Social)
 | 
					    //TradingRulesConfirmed,ShowFriendInvNotifications(Option->Social)
 | 
				
			||||||
    Settings: Schema.Types.Mixed,
 | 
					    Settings: Schema.Types.Mixed,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //Railjack craft 
 | 
					    //Railjack craft
 | 
				
			||||||
    //https://warframe.fandom.com/wiki/Rising_Tide
 | 
					    //https://warframe.fandom.com/wiki/Rising_Tide
 | 
				
			||||||
    PersonalTechProjects: [Schema.Types.Mixed],
 | 
					    PersonalTechProjects: [Schema.Types.Mixed],
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    //Modulars lvl and exp(Railjack|Duviri)
 | 
					    //Modulars lvl and exp(Railjack|Duviri)
 | 
				
			||||||
    //https://warframe.fandom.com/wiki/Intrinsics
 | 
					    //https://warframe.fandom.com/wiki/Intrinsics
 | 
				
			||||||
    PlayerSkills: Schema.Types.Mixed,
 | 
					    PlayerSkills: Schema.Types.Mixed,
 | 
				
			||||||
@ -611,7 +623,6 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
 | 
				
			|||||||
    //TradeBannedUntil data
 | 
					    //TradeBannedUntil data
 | 
				
			||||||
    TradeBannedUntil: Schema.Types.Mixed,
 | 
					    TradeBannedUntil: Schema.Types.Mixed,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    //https://warframe.fandom.com/wiki/Helminth
 | 
					    //https://warframe.fandom.com/wiki/Helminth
 | 
				
			||||||
    InfestedFoundry: Schema.Types.Mixed,
 | 
					    InfestedFoundry: Schema.Types.Mixed,
 | 
				
			||||||
    NextRefill: Schema.Types.Mixed,
 | 
					    NextRefill: Schema.Types.Mixed,
 | 
				
			||||||
@ -624,7 +635,6 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
 | 
				
			|||||||
    //https://warframe.fandom.com/wiki/Incarnon
 | 
					    //https://warframe.fandom.com/wiki/Incarnon
 | 
				
			||||||
    EvolutionProgress: [Schema.Types.Mixed],
 | 
					    EvolutionProgress: [Schema.Types.Mixed],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    //Unknown and system
 | 
					    //Unknown and system
 | 
				
			||||||
    DuviriInfo: DuviriInfoSchema,
 | 
					    DuviriInfo: DuviriInfoSchema,
 | 
				
			||||||
    Mailbox: MailboxSchema,
 | 
					    Mailbox: MailboxSchema,
 | 
				
			||||||
@ -650,7 +660,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
 | 
				
			|||||||
    CollectibleSeries: [Schema.Types.Mixed],
 | 
					    CollectibleSeries: [Schema.Types.Mixed],
 | 
				
			||||||
    HasResetAccount: Boolean,
 | 
					    HasResetAccount: Boolean,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //Discount Coupon 
 | 
					    //Discount Coupon
 | 
				
			||||||
    PendingCoupon: Schema.Types.Mixed,
 | 
					    PendingCoupon: Schema.Types.Mixed,
 | 
				
			||||||
    //Like BossAladV,BossCaptainVor come for you on missions % chance
 | 
					    //Like BossAladV,BossCaptainVor come for you on missions % chance
 | 
				
			||||||
    DeathMarks: [String],
 | 
					    DeathMarks: [String],
 | 
				
			||||||
@ -685,13 +695,14 @@ type InventoryDocumentProps = {
 | 
				
			|||||||
    MiscItems: Types.DocumentArray<IMiscItem>;
 | 
					    MiscItems: Types.DocumentArray<IMiscItem>;
 | 
				
			||||||
    Boosters: Types.DocumentArray<IBooster>;
 | 
					    Boosters: Types.DocumentArray<IBooster>;
 | 
				
			||||||
    OperatorLoadOuts: Types.DocumentArray<IOperatorConfigClient>;
 | 
					    OperatorLoadOuts: Types.DocumentArray<IOperatorConfigClient>;
 | 
				
			||||||
    AdultOperatorLoadOuts: Types.DocumentArray<IOperatorConfigClient>;
 | 
					    AdultOperatorLoadOuts: Types.DocumentArray<IOperatorConfigClient>; //TODO: this should still contain _id
 | 
				
			||||||
    MechSuits: Types.DocumentArray<ISuitDatabase>;
 | 
					    MechSuits: Types.DocumentArray<ISuitDatabase>;
 | 
				
			||||||
    Scoops: Types.DocumentArray<IGenericItem>;
 | 
					    Scoops: Types.DocumentArray<IGenericItem>;
 | 
				
			||||||
    DataKnives: Types.DocumentArray<IGenericItem>;
 | 
					    DataKnives: Types.DocumentArray<IGenericItem>;
 | 
				
			||||||
    DrifterMelee: Types.DocumentArray<IGenericItem>;
 | 
					    DrifterMelee: Types.DocumentArray<IGenericItem>;
 | 
				
			||||||
    Sentinels: Types.DocumentArray<IWeaponDatabase>;
 | 
					    Sentinels: Types.DocumentArray<IWeaponDatabase>;
 | 
				
			||||||
    Horses: Types.DocumentArray<IGenericItem>;
 | 
					    Horses: Types.DocumentArray<IGenericItem>;
 | 
				
			||||||
 | 
					    PendingRecipes: Types.DocumentArray<IPendingRecipeDatabase>;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type InventoryModelType = Model<IInventoryDatabase, {}, InventoryDocumentProps>;
 | 
					type InventoryModelType = Model<IInventoryDatabase, {}, InventoryDocumentProps>;
 | 
				
			||||||
 | 
				
			|||||||
@ -35,6 +35,8 @@ import express from "express";
 | 
				
			|||||||
import { setBootLocationController } from "@/src/controllers/api/setBootLocationController";
 | 
					import { setBootLocationController } from "@/src/controllers/api/setBootLocationController";
 | 
				
			||||||
import { focusController } from "@/src/controllers/api/focusController";
 | 
					import { focusController } from "@/src/controllers/api/focusController";
 | 
				
			||||||
import { inventorySlotsController } from "@/src/controllers/api/inventorySlotsController";
 | 
					import { inventorySlotsController } from "@/src/controllers/api/inventorySlotsController";
 | 
				
			||||||
 | 
					import { startRecipeController } from "@/src/controllers/api/startRecipeController";
 | 
				
			||||||
 | 
					import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompletedRecipeController";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const apiRouter = express.Router();
 | 
					const apiRouter = express.Router();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -62,6 +64,9 @@ apiRouter.get("/logout.php", logoutController);
 | 
				
			|||||||
apiRouter.get("/setBootLocation.php", setBootLocationController);
 | 
					apiRouter.get("/setBootLocation.php", setBootLocationController);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// post
 | 
					// post
 | 
				
			||||||
 | 
					// eslint-disable-next-line @typescript-eslint/no-misused-promises
 | 
				
			||||||
 | 
					apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController);
 | 
				
			||||||
 | 
					apiRouter.post("/startRecipe.php", startRecipeController);
 | 
				
			||||||
apiRouter.post("/inventorySlots.php", inventorySlotsController);
 | 
					apiRouter.post("/inventorySlots.php", inventorySlotsController);
 | 
				
			||||||
apiRouter.post("/focus.php", focusController);
 | 
					apiRouter.post("/focus.php", focusController);
 | 
				
			||||||
apiRouter.post("/artifacts.php", artifactsController);
 | 
					apiRouter.post("/artifacts.php", artifactsController);
 | 
				
			||||||
 | 
				
			|||||||
@ -17,6 +17,7 @@ import {
 | 
				
			|||||||
import { IGenericUpdate } from "../types/genericUpdate";
 | 
					import { IGenericUpdate } from "../types/genericUpdate";
 | 
				
			||||||
import { IArtifactsRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
 | 
					import { IArtifactsRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { logger } from "@/src/utils/logger";
 | 
				
			||||||
 | 
					import { WeaponTypeInternal } from "@/src/services/itemDataService";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const createInventory = async (accountOwnerId: Types.ObjectId, loadOutPresetId: Types.ObjectId) => {
 | 
					export const createInventory = async (accountOwnerId: Types.ObjectId, loadOutPresetId: Types.ObjectId) => {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
@ -145,8 +146,6 @@ export const updateGeneric = async (data: IGenericUpdate, accountId: string) =>
 | 
				
			|||||||
    return data;
 | 
					    return data;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type WeaponTypeInternal = "LongGuns" | "Pistols" | "Melee";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const addWeapon = async (
 | 
					export const addWeapon = async (
 | 
				
			||||||
    weaponType: WeaponTypeInternal,
 | 
					    weaponType: WeaponTypeInternal,
 | 
				
			||||||
    weaponName: string,
 | 
					    weaponName: string,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										117
									
								
								src/services/itemDataService.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								src/services/itemDataService.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,117 @@
 | 
				
			|||||||
 | 
					import { getIndexAfter } from "@/src/helpers/stringHelpers";
 | 
				
			||||||
 | 
					import { logger } from "@/src/utils/logger";
 | 
				
			||||||
 | 
					import Items, { Buildable, Category, Item, Warframe, Weapon } from "warframe-items";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MinWeapon = Omit<Weapon, "patchlogs">;
 | 
				
			||||||
 | 
					type MinItem = Omit<Item, "patchlogs">;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const weapons: MinWeapon[] = (new Items({ category: ["Primary", "Secondary", "Melee"] }) as Weapon[]).map(
 | 
				
			||||||
 | 
					    item => {
 | 
				
			||||||
 | 
					        const next = { ...item };
 | 
				
			||||||
 | 
					        delete next.patchlogs;
 | 
				
			||||||
 | 
					        return next;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type WeaponTypeInternal = "LongGuns" | "Pistols" | "Melee";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const items: MinItem[] = new Items({ category: ["All"] }).map(item => {
 | 
				
			||||||
 | 
					    const next = { ...item };
 | 
				
			||||||
 | 
					    delete next.patchlogs;
 | 
				
			||||||
 | 
					    return next;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getWeaponType = (weaponName: string) => {
 | 
				
			||||||
 | 
					    const weaponInfo = weapons.find(i => i.uniqueName === weaponName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!weaponInfo) {
 | 
				
			||||||
 | 
					        throw new Error(`unknown weapon ${weaponName}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const weaponType = weaponInfo.productCategory as WeaponTypeInternal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!weaponType) {
 | 
				
			||||||
 | 
					        logger.error(`unknown weapon category for item ${weaponName}`);
 | 
				
			||||||
 | 
					        throw new Error(`unknown weapon category for item ${weaponName}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return weaponType;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getNamesObj = (category: Category) =>
 | 
				
			||||||
 | 
					    new Items({ category: [category] }).reduce<{ [index: string]: string }>((acc, item) => {
 | 
				
			||||||
 | 
					        acc[item.name!.replace("'S", "'s")] = item.uniqueName!;
 | 
				
			||||||
 | 
					        return acc;
 | 
				
			||||||
 | 
					    }, {});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const modNames = getNamesObj("Mods");
 | 
				
			||||||
 | 
					export const resourceNames = getNamesObj("Resources");
 | 
				
			||||||
 | 
					export const miscNames = getNamesObj("Misc");
 | 
				
			||||||
 | 
					export const relicNames = getNamesObj("Relics");
 | 
				
			||||||
 | 
					export const skinNames = getNamesObj("Skins");
 | 
				
			||||||
 | 
					export const arcaneNames = getNamesObj("Arcanes");
 | 
				
			||||||
 | 
					export const gearNames = getNamesObj("Gear");
 | 
				
			||||||
 | 
					//logger.debug(`gear names`, { gearNames });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const craftNames = Object.fromEntries(
 | 
				
			||||||
 | 
					    (
 | 
				
			||||||
 | 
					        new Items({
 | 
				
			||||||
 | 
					            category: [
 | 
				
			||||||
 | 
					                "Warframes",
 | 
				
			||||||
 | 
					                "Gear",
 | 
				
			||||||
 | 
					                "Melee",
 | 
				
			||||||
 | 
					                "Primary",
 | 
				
			||||||
 | 
					                "Secondary",
 | 
				
			||||||
 | 
					                "Sentinels",
 | 
				
			||||||
 | 
					                "Misc",
 | 
				
			||||||
 | 
					                "Arch-Gun",
 | 
				
			||||||
 | 
					                "Arch-Melee"
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        }) as Warframe[]
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					        .flatMap(item => item.components || [])
 | 
				
			||||||
 | 
					        .filter(item => item.drops && item.drops[0])
 | 
				
			||||||
 | 
					        .map(item => [item.drops![0].type, item.uniqueName])
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const blueprintNames = Object.fromEntries(
 | 
				
			||||||
 | 
					    Object.keys(craftNames)
 | 
				
			||||||
 | 
					        .filter(name => name.includes("Blueprint"))
 | 
				
			||||||
 | 
					        .map(name => [name, craftNames[name]])
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const buildables = items.filter(item => !!(item as Buildable).components);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getItemByBlueprint = (uniqueName: string): (MinItem & Buildable) | undefined => {
 | 
				
			||||||
 | 
					    const item = buildables.find(
 | 
				
			||||||
 | 
					        item => (item as Buildable).components?.find(component => component.uniqueName === uniqueName)
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    return item;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getItemCategoryByUniqueName = (uniqueName: string) => {
 | 
				
			||||||
 | 
					    //Lotus/Types/Items/MiscItems/PolymerBundle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let splitWord = "Items/";
 | 
				
			||||||
 | 
					    if (!uniqueName.includes("/Items/")) {
 | 
				
			||||||
 | 
					        splitWord = "/Types/";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const index = getIndexAfter(uniqueName, splitWord);
 | 
				
			||||||
 | 
					    if (index === -1) {
 | 
				
			||||||
 | 
					        logger.error(`error parsing item category ${uniqueName}`);
 | 
				
			||||||
 | 
					        throw new Error(`error parsing item category ${uniqueName}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const category = uniqueName.substring(index).split("/")[0];
 | 
				
			||||||
 | 
					    return category;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getItemByUniqueName = (uniqueName: string) => {
 | 
				
			||||||
 | 
					    const item = items.find(item => item.uniqueName === uniqueName);
 | 
				
			||||||
 | 
					    return item;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getItemByName = (name: string) => {
 | 
				
			||||||
 | 
					    const item = items.find(item => item.name === name);
 | 
				
			||||||
 | 
					    return item;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -1,7 +1,14 @@
 | 
				
			|||||||
import { IMissionRewardResponse, IReward, IInventoryFieldType, inventoryFields } from "@/src/types/missionTypes";
 | 
					import { IMissionRewardResponse, IReward, IInventoryFieldType, inventoryFields } from "@/src/types/missionTypes";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import missionsDropTable from "@/static/json/missions-drop-table.json";
 | 
					import missionsDropTable from "@/static/json/missions-drop-table.json";
 | 
				
			||||||
import { modNames, relicNames, miscNames, resourceNames, gearNames, blueprintNames } from "@/static/data/items";
 | 
					import {
 | 
				
			||||||
 | 
					    modNames,
 | 
				
			||||||
 | 
					    relicNames,
 | 
				
			||||||
 | 
					    miscNames,
 | 
				
			||||||
 | 
					    resourceNames,
 | 
				
			||||||
 | 
					    gearNames,
 | 
				
			||||||
 | 
					    blueprintNames
 | 
				
			||||||
 | 
					} from "@/src/services/itemDataService";
 | 
				
			||||||
import { IMissionInventoryUpdateRequest } from "../types/requestTypes";
 | 
					import { IMissionInventoryUpdateRequest } from "../types/requestTypes";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { logger } from "@/src/utils/logger";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
import { getWeaponType, parseSlotPurchaseName } from "@/src/helpers/purchaseHelpers";
 | 
					import { parseSlotPurchaseName } from "@/src/helpers/purchaseHelpers";
 | 
				
			||||||
 | 
					import { getWeaponType } from "@/src/services/itemDataService";
 | 
				
			||||||
import { getSubstringFromKeyword } from "@/src/helpers/stringHelpers";
 | 
					import { getSubstringFromKeyword } from "@/src/helpers/stringHelpers";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    addBooster,
 | 
					    addBooster,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										74
									
								
								src/services/recipeService.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/services/recipeService.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					import { unixTimesInMs } from "@/src/constants/timeConstants";
 | 
				
			||||||
 | 
					import { getInventory } from "@/src/services/inventoryService";
 | 
				
			||||||
 | 
					import { getItemByBlueprint, getItemCategoryByUniqueName } from "@/src/services/itemDataService";
 | 
				
			||||||
 | 
					import { logger } from "@/src/utils/logger";
 | 
				
			||||||
 | 
					import { Types } from "mongoose";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface IResource {
 | 
				
			||||||
 | 
					    uniqueName: string;
 | 
				
			||||||
 | 
					    count: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// export const updateResources = async (accountId: string, components: IResource[]) => {
 | 
				
			||||||
 | 
					//     const inventory = await getInventory(accountId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//     for (const component of components) {
 | 
				
			||||||
 | 
					//         const category = getItemCategoryByUniqueName(component.uniqueName) as keyof typeof inventory;
 | 
				
			||||||
 | 
					//         //validate category
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//         console.log(component.uniqueName);
 | 
				
			||||||
 | 
					//         console.log("cate", category);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//         const invItem = inventory[category];
 | 
				
			||||||
 | 
					//         console.log("invItem", invItem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//         inventory["MiscItems"];
 | 
				
			||||||
 | 
					//     }
 | 
				
			||||||
 | 
					// };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const startRecipe = async (recipeName: string, accountId: string) => {
 | 
				
			||||||
 | 
					    const recipe = getItemByBlueprint(recipeName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!recipe) {
 | 
				
			||||||
 | 
					        logger.error(`unknown recipe ${recipeName}`);
 | 
				
			||||||
 | 
					        throw new Error(`unknown recipe ${recipeName}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const componentsNeeded = recipe.components?.map(component => ({
 | 
				
			||||||
 | 
					        uniqueName: component.uniqueName,
 | 
				
			||||||
 | 
					        count: component.itemCount
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!componentsNeeded) {
 | 
				
			||||||
 | 
					        logger.error(`recipe ${recipeName} has no components`);
 | 
				
			||||||
 | 
					        throw new Error(`recipe ${recipeName} has no components`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //TODO: consume components used
 | 
				
			||||||
 | 
					    //await updateResources(accountId, componentsNeeded);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //might be redundant
 | 
				
			||||||
 | 
					    if (recipe.consumeOnBuild) {
 | 
				
			||||||
 | 
					        //consume
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!recipe.buildTime) {
 | 
				
			||||||
 | 
					        logger.error(`recipe ${recipeName} has no build time`);
 | 
				
			||||||
 | 
					        throw new Error(`recipe ${recipeName} has no build time`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    //buildtime is in seconds
 | 
				
			||||||
 | 
					    const completionDate = new Date(Date.now() + recipe.buildTime * unixTimesInMs.second);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const inventory = await getInventory(accountId);
 | 
				
			||||||
 | 
					    inventory.PendingRecipes.push({
 | 
				
			||||||
 | 
					        ItemType: recipeName,
 | 
				
			||||||
 | 
					        CompletionDate: completionDate,
 | 
				
			||||||
 | 
					        _id: new Types.ObjectId()
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const newInventory = await inventory.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        RecipeId: { $oid: newInventory.PendingRecipes[newInventory.PendingRecipes.length - 1]._id?.toString() }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -14,11 +14,13 @@ import { IOperatorLoadOutSigcol, IWeaponDatabase } from "@/src/types/inventoryTy
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
//Document extends will be deleted soon. TODO: delete and migrate uses to ...
 | 
					//Document extends will be deleted soon. TODO: delete and migrate uses to ...
 | 
				
			||||||
export interface IInventoryDatabaseDocument extends IInventoryDatabase, Document {}
 | 
					export interface IInventoryDatabaseDocument extends IInventoryDatabase, Document {}
 | 
				
			||||||
export interface IInventoryDatabase extends Omit<IInventoryResponse, "TrainingDate" | "LoadOutPresets" | "Mailbox"> {
 | 
					export interface IInventoryDatabase
 | 
				
			||||||
 | 
					    extends Omit<IInventoryResponse, "TrainingDate" | "LoadOutPresets" | "Mailbox" | "PendingRecipes"> {
 | 
				
			||||||
    accountOwnerId: Types.ObjectId;
 | 
					    accountOwnerId: Types.ObjectId;
 | 
				
			||||||
    TrainingDate: Date; // TrainingDate changed from IMongoDate to Date
 | 
					    TrainingDate: Date; // TrainingDate changed from IMongoDate to Date
 | 
				
			||||||
    LoadOutPresets: Types.ObjectId; // LoadOutPresets changed from ILoadOutPresets to Types.ObjectId for population
 | 
					    LoadOutPresets: Types.ObjectId; // LoadOutPresets changed from ILoadOutPresets to Types.ObjectId for population
 | 
				
			||||||
    Mailbox: Types.ObjectId; // Mailbox changed from IMailbox to Types.ObjectId
 | 
					    Mailbox: Types.ObjectId; // Mailbox changed from IMailbox to Types.ObjectId
 | 
				
			||||||
 | 
					    PendingRecipes: IPendingRecipe[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IInventoryResponseDocument extends IInventoryResponse, Document {}
 | 
					export interface IInventoryResponseDocument extends IInventoryResponse, Document {}
 | 
				
			||||||
@ -41,6 +43,11 @@ export interface IMailbox {
 | 
				
			|||||||
    LastInboxId: IOid;
 | 
					    LastInboxId: IOid;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//TODO: perhaps split response and database into their own files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface IPendingRecipeResponse extends Omit<IPendingRecipe, "CompletionDate"> {
 | 
				
			||||||
 | 
					    CompletionDate: IMongoDate;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
export interface IInventoryResponse {
 | 
					export interface IInventoryResponse {
 | 
				
			||||||
    Horses: IGenericItem[];
 | 
					    Horses: IGenericItem[];
 | 
				
			||||||
    DrifterMelee: IGenericItem[];
 | 
					    DrifterMelee: IGenericItem[];
 | 
				
			||||||
@ -96,7 +103,7 @@ export interface IInventoryResponse {
 | 
				
			|||||||
    XPInfo: IEmailItem[];
 | 
					    XPInfo: IEmailItem[];
 | 
				
			||||||
    Recipes: IConsumable[];
 | 
					    Recipes: IConsumable[];
 | 
				
			||||||
    WeaponSkins: IWeaponSkin[];
 | 
					    WeaponSkins: IWeaponSkin[];
 | 
				
			||||||
    PendingRecipes: IPendingRecipe[];
 | 
					    PendingRecipes: IPendingRecipeResponse[];
 | 
				
			||||||
    TrainingDate: IMongoDate;
 | 
					    TrainingDate: IMongoDate;
 | 
				
			||||||
    PlayerLevel: number;
 | 
					    PlayerLevel: number;
 | 
				
			||||||
    Upgrades: ICrewShipSalvagedWeaponSkin[];
 | 
					    Upgrades: ICrewShipSalvagedWeaponSkin[];
 | 
				
			||||||
@ -816,7 +823,7 @@ export interface IPendingCoupon {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export interface IPendingRecipe {
 | 
					export interface IPendingRecipe {
 | 
				
			||||||
    ItemType: string;
 | 
					    ItemType: string;
 | 
				
			||||||
    CompletionDate: IMongoDate;
 | 
					    CompletionDate: Date;
 | 
				
			||||||
    ItemId: IOid;
 | 
					    ItemId: IOid;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,60 +0,0 @@
 | 
				
			|||||||
import Items, { Category, Item, Warframe, Weapon } from "warframe-items";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type MinWeapon = Omit<Weapon, "patchlogs">;
 | 
					 | 
				
			||||||
type MinItem = Omit<Item, "patchlogs">;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const weapons: MinWeapon[] = (new Items({ category: ["Primary", "Secondary", "Melee"] }) as Weapon[]).map(
 | 
					 | 
				
			||||||
    item => {
 | 
					 | 
				
			||||||
        const next = { ...item };
 | 
					 | 
				
			||||||
        delete next.patchlogs;
 | 
					 | 
				
			||||||
        return next;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const items: MinItem[] = new Items({ category: ["All"] }).map(item => {
 | 
					 | 
				
			||||||
    const next = { ...item };
 | 
					 | 
				
			||||||
    delete next.patchlogs;
 | 
					 | 
				
			||||||
    return next;
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const getNamesObj = (category: Category) =>
 | 
					 | 
				
			||||||
    new Items({ category: [category] }).reduce((acc, item) => {
 | 
					 | 
				
			||||||
        acc[item.name!.replace("'S", "'s")] = item.uniqueName!;
 | 
					 | 
				
			||||||
        return acc;
 | 
					 | 
				
			||||||
    }, {} as ImportAssertions);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const modNames = getNamesObj("Mods");
 | 
					 | 
				
			||||||
export const resourceNames = getNamesObj("Resources");
 | 
					 | 
				
			||||||
export const miscNames = getNamesObj("Misc");
 | 
					 | 
				
			||||||
export const relicNames = getNamesObj("Relics");
 | 
					 | 
				
			||||||
export const skinNames = getNamesObj("Skins");
 | 
					 | 
				
			||||||
export const arcaneNames = getNamesObj("Arcanes");
 | 
					 | 
				
			||||||
export const gearNames = getNamesObj("Gear");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const craftNames: ImportAssertions = Object.fromEntries(
 | 
					 | 
				
			||||||
    (
 | 
					 | 
				
			||||||
        new Items({
 | 
					 | 
				
			||||||
            category: [
 | 
					 | 
				
			||||||
                "Warframes",
 | 
					 | 
				
			||||||
                "Gear",
 | 
					 | 
				
			||||||
                "Melee",
 | 
					 | 
				
			||||||
                "Primary",
 | 
					 | 
				
			||||||
                "Secondary",
 | 
					 | 
				
			||||||
                "Sentinels",
 | 
					 | 
				
			||||||
                "Misc",
 | 
					 | 
				
			||||||
                "Arch-Gun",
 | 
					 | 
				
			||||||
                "Arch-Melee"
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
        }) as Warframe[]
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
        .flatMap(item => item.components || [])
 | 
					 | 
				
			||||||
        .filter(item => item.drops && item.drops[0])
 | 
					 | 
				
			||||||
        .map(item => [item.drops![0].type, item.uniqueName])
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
craftNames["Forma Blueprint"] = "/Lotus/Types/Recipes/Components/FormaBlueprint";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const blueprintNames: ImportAssertions = Object.fromEntries(
 | 
					 | 
				
			||||||
    Object.keys(craftNames)
 | 
					 | 
				
			||||||
        .filter(name => name.includes("Blueprint"))
 | 
					 | 
				
			||||||
        .map(name => [name, craftNames[name]])
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user