feat: trade fish for standing #681

Merged
Sainan merged 2 commits from fish-standing into main 2025-01-02 15:10:18 -08:00
3 changed files with 33 additions and 15 deletions

8
package-lock.json generated
View File

@ -12,7 +12,7 @@
"copyfiles": "^2.4.1", "copyfiles": "^2.4.1",
"express": "^5", "express": "^5",
"mongoose": "^8.9.2", "mongoose": "^8.9.2",
"warframe-public-export-plus": "^0.5.17", "warframe-public-export-plus": "^0.5.18",
"warframe-riven-info": "^0.1.2", "warframe-riven-info": "^0.1.2",
"winston": "^3.17.0", "winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0" "winston-daily-rotate-file": "^5.0.0"
@ -3778,9 +3778,9 @@
} }
}, },
"node_modules/warframe-public-export-plus": { "node_modules/warframe-public-export-plus": {
"version": "0.5.17", "version": "0.5.18",
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.17.tgz", "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.18.tgz",
"integrity": "sha512-AWOfUxDHz+UmpbA9ZUGLIrP+3eQOiVq9tw1FXgx7ySkJLEnZUsoi3wn0IFiavSy2iE6JQIyCiSIZCJQTaCV6kA==" "integrity": "sha512-wUaW5Ua5tXHOYkKJxbealdCcTnRLUN7UCkvYOJEwlB/H14EBzDaqxg4engGqzbq4H8fmttyp3EUo4vazSaxZWg=="
}, },
"node_modules/warframe-riven-info": { "node_modules/warframe-riven-info": {
"version": "0.1.2", "version": "0.1.2",

View File

@ -16,7 +16,7 @@
"copyfiles": "^2.4.1", "copyfiles": "^2.4.1",
"express": "^5", "express": "^5",
"mongoose": "^8.9.2", "mongoose": "^8.9.2",
"warframe-public-export-plus": "^0.5.17", "warframe-public-export-plus": "^0.5.18",
"warframe-riven-info": "^0.1.2", "warframe-riven-info": "^0.1.2",
"winston": "^3.17.0", "winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0" "winston-daily-rotate-file": "^5.0.0"

View File

@ -6,30 +6,48 @@ import { RequestHandler } from "express";
import { ExportResources } from "warframe-public-export-plus"; import { ExportResources } from "warframe-public-export-plus";
export const fishmongerController: RequestHandler = async (req, res) => { export const fishmongerController: RequestHandler = async (req, res) => {
if (!req.query.dissect) {
throw new Error("expected fishmonger request to be for dissection");
}
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
const body = getJSONfromString(String(req.body)) as IFishmongerRequest; const body = getJSONfromString(String(req.body)) as IFishmongerRequest;
const miscItemChanges: IMiscItem[] = []; const miscItemChanges: IMiscItem[] = [];
let syndicateTag: string | undefined;
let standingChange = 0;
for (const fish of body.Fish) { for (const fish of body.Fish) {
for (const part of ExportResources[fish.ItemType].dissectionParts!) { const fishData = ExportResources[fish.ItemType];
if (req.query.dissect == "1") {
for (const part of fishData.dissectionParts!) {
const partItem = miscItemChanges.find(x => x.ItemType == part.ItemType); const partItem = miscItemChanges.find(x => x.ItemType == part.ItemType);
if (partItem) { if (partItem) {
partItem.ItemCount += part.ItemCount; partItem.ItemCount += part.ItemCount * fish.ItemCount;
} else { } else {
miscItemChanges.push(part); miscItemChanges.push({ ItemType: part.ItemType, ItemCount: part.ItemCount * fish.ItemCount });
} }
} }
coderabbitai[bot] commented 2025-01-01 21:54:43 -08:00 (Migrated from github.com)
Review

💡 Codebase verification

Based on the code analysis, I can now provide a final response:

Validation needed for fishData access

The code immediately uses fishData.dissectionParts without checking if fishData exists, which could cause runtime errors. The validation is particularly important because:

  1. ExportResources is accessed with a dynamic key fish.ItemType
  2. The value is immediately used to access dissectionParts property
  3. Other services like purchaseService and inventoryService implement existence checks with in operator before accessing ExportResources
  • src/controllers/api/fishmongerController.ts:16: Add null check before accessing fishData
🔗 Analysis chain

Verify existence of fishData
Accessing ExportResources[fish.ItemType] without any check can cause errors if fish.ItemType is missing from the export or is undefined. Consider adding a validation step or fallback logic.

+ if (!fishData) {
+   throw new Error(\`Missing fish data for type: \${fish.ItemType}\`);
+ }

Let me gather information about the ExportResources and its usage to verify this concern.


Let me analyze the usage of ExportResources to understand if we need validation. I'll search for its usage patterns and error handling.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Find the definition and structure of ExportResources
ast-grep --pattern 'const ExportResources = $_'

# Also search for any type definitions or interfaces related to it
rg "ExportResources" -A 5 -B 5

# Look for ItemType usage in the codebase
rg "ItemType" -A 2 -B 2

Length of output: 87233


Script:

#!/bin/bash
# Look for ExportResources usage patterns and error handling
ast-grep --pattern 'ExportResources[$_]'

# Look for any error handling around ExportResources
rg "ExportResources.*\{" -A 3 -B 3

# Look for the specific fishmonger controller implementation
rg -A 10 -B 10 "fishmongerController"

Length of output: 11028

_:bulb: Codebase verification_ Based on the code analysis, I can now provide a final response: **Validation needed for `fishData` access** The code immediately uses `fishData.dissectionParts` without checking if `fishData` exists, which could cause runtime errors. The validation is particularly important because: 1. `ExportResources` is accessed with a dynamic key `fish.ItemType` 2. The value is immediately used to access `dissectionParts` property 3. Other services like `purchaseService` and `inventoryService` implement existence checks with `in` operator before accessing `ExportResources` - `src/controllers/api/fishmongerController.ts:16`: Add null check before accessing `fishData` <details> <summary>🔗 Analysis chain</summary> **Verify existence of `fishData`** Accessing `ExportResources[fish.ItemType]` without any check can cause errors if `fish.ItemType` is missing from the export or is undefined. Consider adding a validation step or fallback logic. ```diff + if (!fishData) { + throw new Error(\`Missing fish data for type: \${fish.ItemType}\`); + } ``` --- Let me gather information about the `ExportResources` and its usage to verify this concern. --- Let me analyze the usage of `ExportResources` to understand if we need validation. I'll search for its usage patterns and error handling. </details> <details> <summary>🏁 Scripts executed</summary> The following scripts were executed for the analysis: Error: No shell scripts found --- Script: ```shell #!/bin/bash # Find the definition and structure of ExportResources ast-grep --pattern 'const ExportResources = $_' # Also search for any type definitions or interfaces related to it rg "ExportResources" -A 5 -B 5 # Look for ItemType usage in the codebase rg "ItemType" -A 2 -B 2 ``` Length of output: 87233 --- Script: ```shell #!/bin/bash # Look for ExportResources usage patterns and error handling ast-grep --pattern 'ExportResources[$_]' # Look for any error handling around ExportResources rg "ExportResources.*\{" -A 3 -B 3 # Look for the specific fishmonger controller implementation rg -A 10 -B 10 "fishmongerController" ``` Length of output: 11028 </details> <!-- This is an auto-generated comment by CodeRabbit -->
} else {
syndicateTag = fishData.syndicateTag!;
standingChange += fishData.standingBonus! * fish.ItemCount;
}
miscItemChanges.push({ ItemType: fish.ItemType, ItemCount: fish.ItemCount * -1 }); miscItemChanges.push({ ItemType: fish.ItemType, ItemCount: fish.ItemCount * -1 });
} }
addMiscItems(inventory, miscItemChanges); addMiscItems(inventory, miscItemChanges);
if (standingChange && syndicateTag) {
coderabbitai[bot] commented 2025-01-01 21:54:44 -08:00 (Migrated from github.com)
Review

💡 Codebase verification

Based on the code analysis, I can now provide the final response:

The non-null assertion on dissectionParts is potentially unsafe

The code shows that fishData comes from ExportResources[fish.ItemType] which is imported from warframe-public-export-plus. The non-null assertion (!) on dissectionParts is risky because:

  • There's no type checking or null check before accessing dissectionParts
  • The property is only accessed when dissect === "1", suggesting it's an optional operation
  • The same pattern of using non-null assertions on optional properties is seen with syndicateTag! and standingBonus! in the else branch

Recommend implementing the suggested null-safe approach:

if (req.query.dissect === "1") {
    const parts = fishData.dissectionParts || [];
    for (const part of parts) {
        // ...
    }
}
🔗 Analysis chain

Ensure safe usage of optional dissectionParts
The non-null assertion fishData.dissectionParts! assumes that dissectionParts is always defined. If there's a possibility of missing or empty dissection parts for new fish types, handle it gracefully to avoid runtime errors.

 if (req.query.dissect === "1") {
-   for (const part of fishData.dissectionParts!) {
+   const parts = fishData.dissectionParts || [];
+   for (const part of parts) {
       ...
   }
 }

Let me verify the safety concerns around the dissectionParts usage by examining the codebase.


Let me search for more context about the ExportResources type and its usage.


Let me check for the actual data structure and initialization of ExportResources.


Let me check the complete fishmongerController for more context about how dissectionParts is used.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Find the type definition or interface for fishData to understand the dissectionParts property
ast-grep --pattern 'interface $_ {
  $$$
  dissectionParts$_
  $$$
}'

# Also search for type declarations
ast-grep --pattern 'type $_ = {
  $$$
  dissectionParts$_
  $$$
}'

# Look for other usages of dissectionParts to understand the pattern
rg "dissectionParts" -A 2 -B 2

Length of output: 669


Script:

#!/bin/bash
# Find the ExportResources type/interface definition
ast-grep --pattern 'type ExportResources = {
  $$$
}'

ast-grep --pattern 'interface ExportResources {
  $$$
}'

# Look for the ExportResources declaration/initialization
rg "ExportResources.*=" -A 5

# Look for any fish-related types or interfaces
ast-grep --pattern 'interface $Fish {
  $$$
}'

ast-grep --pattern 'type $Fish = {
  $$$
}'

Length of output: 1806


Script:

#!/bin/bash
# Look for files that might contain ExportResources data
fd "resources|exports" --type f

# Look for dissectionParts initialization or usage in resource files
rg -l "dissectionParts.*[=:]" 

# Check for any fish or dissection related constants or configurations
rg -l "fish.*dissect|dissect.*fish" -i

Length of output: 150


Script:

#!/bin/bash
# Get the full content of fishmongerController
cat src/controllers/api/fishmongerController.ts

# Look for any test files related to fishmonger
fd "fishmonger.*test" --type f

# Look for any resource files with .json extension that might contain fish data
fd "\.(json|ts)$" --type f | rg -i "fish|resource"

Length of output: 2748

_:bulb: Codebase verification_ Based on the code analysis, I can now provide the final response: **The non-null assertion on `dissectionParts` is potentially unsafe** The code shows that `fishData` comes from `ExportResources[fish.ItemType]` which is imported from `warframe-public-export-plus`. The non-null assertion (`!`) on `dissectionParts` is risky because: - There's no type checking or null check before accessing `dissectionParts` - The property is only accessed when `dissect === "1"`, suggesting it's an optional operation - The same pattern of using non-null assertions on optional properties is seen with `syndicateTag!` and `standingBonus!` in the else branch Recommend implementing the suggested null-safe approach: ```typescript if (req.query.dissect === "1") { const parts = fishData.dissectionParts || []; for (const part of parts) { // ... } } ``` <details> <summary>🔗 Analysis chain</summary> **Ensure safe usage of optional `dissectionParts`** The non-null assertion `fishData.dissectionParts!` assumes that `dissectionParts` is always defined. If there's a possibility of missing or empty dissection parts for new fish types, handle it gracefully to avoid runtime errors. ```diff if (req.query.dissect === "1") { - for (const part of fishData.dissectionParts!) { + const parts = fishData.dissectionParts || []; + for (const part of parts) { ... } } ``` --- Let me verify the safety concerns around the `dissectionParts` usage by examining the codebase. --- Let me search for more context about the `ExportResources` type and its usage. --- Let me check for the actual data structure and initialization of `ExportResources`. --- Let me check the complete fishmongerController for more context about how dissectionParts is used. </details> <details> <summary>🏁 Scripts executed</summary> The following scripts were executed for the analysis: Error: No shell scripts found --- Script: ```shell #!/bin/bash # Find the type definition or interface for fishData to understand the dissectionParts property ast-grep --pattern 'interface $_ { $$$ dissectionParts$_ $$$ }' # Also search for type declarations ast-grep --pattern 'type $_ = { $$$ dissectionParts$_ $$$ }' # Look for other usages of dissectionParts to understand the pattern rg "dissectionParts" -A 2 -B 2 ``` Length of output: 669 --- Script: ```shell #!/bin/bash # Find the ExportResources type/interface definition ast-grep --pattern 'type ExportResources = { $$$ }' ast-grep --pattern 'interface ExportResources { $$$ }' # Look for the ExportResources declaration/initialization rg "ExportResources.*=" -A 5 # Look for any fish-related types or interfaces ast-grep --pattern 'interface $Fish { $$$ }' ast-grep --pattern 'type $Fish = { $$$ }' ``` Length of output: 1806 --- Script: ```shell #!/bin/bash # Look for files that might contain ExportResources data fd "resources|exports" --type f # Look for dissectionParts initialization or usage in resource files rg -l "dissectionParts.*[=:]" # Check for any fish or dissection related constants or configurations rg -l "fish.*dissect|dissect.*fish" -i ``` Length of output: 150 --- Script: ```shell #!/bin/bash # Get the full content of fishmongerController cat src/controllers/api/fishmongerController.ts # Look for any test files related to fishmonger fd "fishmonger.*test" --type f # Look for any resource files with .json extension that might contain fish data fd "\.(json|ts)$" --type f | rg -i "fish|resource" ``` Length of output: 2748 </details> <!-- This is an auto-generated comment by CodeRabbit -->
const syndicate = inventory.Affiliations.find(x => x.Tag == syndicateTag);
if (syndicate !== undefined) {
syndicate.Standing += standingChange;
} else {
inventory.Affiliations.push({
Tag: syndicateTag,
Standing: standingChange
});
}
}
await inventory.save(); await inventory.save();
res.json({ res.json({
InventoryChanges: { InventoryChanges: {
MiscItems: miscItemChanges MiscItems: miscItemChanges
} },
SyndicateTag: syndicateTag,
StandingChange: standingChange
}); });
}; };