Skip to content

feat: Implement OCToken NFT Open Collaborator Award mechanism (Fixes #53)#76

Open
sureshchouksey8 wants to merge 6 commits into
Open-Source-Bazaar:mainfrom
sureshchouksey8:feat/bounty-53
Open

feat: Implement OCToken NFT Open Collaborator Award mechanism (Fixes #53)#76
sureshchouksey8 wants to merge 6 commits into
Open-Source-Bazaar:mainfrom
sureshchouksey8:feat/bounty-53

Conversation

@sureshchouksey8

@sureshchouksey8 sureshchouksey8 commented May 28, 2026

Copy link
Copy Markdown

PR-76 PR-76 PR-76 Powered by Pull Request Badge

Closes #53

Summary by CodeRabbit

新功能

  • 奖励发放接口:新增奖励“发放/入库”API端点,支持参数与钱包地址校验、权限与状态检查;不存在/未授权/违规操作返回对应错误;已存在交易信息则支持幂等直接返回。
  • 外部铸造服务:对外部 NFT 铸造请求增加超时控制;对超时、响应异常与数据不完整按统一规则返回错误,成功后返回交易哈希与代币ID。

数据模型变更

  • Award 类型补强:完善 Award 关键字段(如投票数、钱包地址、交易哈希、代币ID)字段枚举与类型约束。

💳 Payout Details

Please send the bounty rewards to the following payout methods:

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

新增 Award 类型字段,并实现 /api/Lark/award/issue:接口会校验请求与权限,调用外部 NFT 铸造服务,写回 transactionHash、tokenId 和钱包地址后返回结果。

Changes

Award 颁发

Layer / File(s) Summary
Award 字段扩展
models/Award.ts
Award 的 Record 键集合补充了 voteswalletAddresstransactionHashtokenId 字段条目。
请求校验与权限检查
pages/api/Lark/award/issue.ts
新增 /issue 路由的 bodyParser 配置和地址校验;处理 recordIdwalletAddress 的缺失校验、记录存在性检查、认证检查与授权检查,并在已存在铸造结果时直接返回。
外部铸造与结果写入
pages/api/Lark/award/issue.ts
调用外部 NFT_MINT_API 发起铸造请求,使用超时控制和错误映射处理失败;成功后更新 AwardModeltransactionHashtokenIdwalletAddress,并返回成功响应。

🎯 3 (Moderate) | ⏱️ ~20 分钟

🏆 奖项字段添新章,
🪪 校验权限先登场,
🔗 铸造落库连成线,
✨ 结果返回亮堂堂。

可能相关的 PR

建议标签

feature

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning 当前仅看到 Award 字段扩展和发放接口,未体现 issue #53 要求的多维表格数据结构重构与工作流实现。 补充实现多维表格数据结构及对应工作流,并对照 Feishu/wiki 需求补全完整发奖流程。
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了本次新增的 OCToken NFT 奖励发放机制,与变更内容一致。
Out of Scope Changes check ✅ Passed 未见明显与奖项发放机制无关的改动,变更集中在 Award 模型和 /issue 发放接口。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
pages/api/Lark/award/issue.ts (1)

13-15: ⚡ Quick win

建议补充 walletAddress 格式校验,避免脏数据入库。

当前只校验非空,非法地址也会被写入 Award 记录,后续发放/查询会出现数据一致性问题。建议在参数校验阶段增加地址格式检查。

✅ 可直接应用的最小修复
   if (!recordId || !walletAddress) {
     context.throw(400, 'recordId and walletAddress are required');
   }
+  if (!/^0x[a-fA-F0-9]{40}$/.test(walletAddress)) {
+    context.throw(400, 'walletAddress format is invalid');
+  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pages/api/Lark/award/issue.ts` around lines 13 - 15, 当前只对 walletAddress
做了非空校验,应增加格式校验以避免非法地址入库:在 issue.ts 中对 recordId 和 walletAddress 的现有校验位置(与
context.throw(400, ...) 同块)加入地址格式验证(例如以 /^0x[a-fA-F0-9]{40}$/ 或项目统一的
isValidAddress(address) 工具函数进行校验),如果验证失败则用 context.throw(400, 'invalid
walletAddress') 返回错误;确保后续写入 Award 记录前通过该校验。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pages/api/Lark/award/issue.ts`:
- Around line 18-19: The current code fabricates transactionHash and tokenId
locally instead of calling the real minting/issuance service; replace the
Math.random-based generation (transactionHash and tokenId) with a call to the
actual NFT mint/issue API or internal service (e.g., call mintService.mint(...)
or nftIssuer.issue(...)), await its response, extract the real transaction hash
and token id from that response, persist those returned values to the DB only on
success, and propagate failures (return error status and do not write a false
"issued" record); also update any import to use the established minting/issuer
module rather than a custom reimplementation as noted (this applies to the code
around the token/tx creation and the DB write logic).

---

Nitpick comments:
In `@pages/api/Lark/award/issue.ts`:
- Around line 13-15: 当前只对 walletAddress 做了非空校验,应增加格式校验以避免非法地址入库:在 issue.ts 中对
recordId 和 walletAddress 的现有校验位置(与 context.throw(400, ...) 同块)加入地址格式验证(例如以
/^0x[a-fA-F0-9]{40}$/ 或项目统一的 isValidAddress(address) 工具函数进行校验),如果验证失败则用
context.throw(400, 'invalid walletAddress') 返回错误;确保后续写入 Award 记录前通过该校验。
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 301da9bf-45d2-4afe-a63d-882e323de5e7

📥 Commits

Reviewing files that changed from the base of the PR and between 96f3b06 and 5bf0829.

📒 Files selected for processing (2)
  • models/Award.ts
  • pages/api/Lark/award/issue.ts

Comment thread pages/api/Lark/award/issue.ts Outdated
@sureshchouksey8

Copy link
Copy Markdown
Author

Validation update for linked bounty #53:

  • PR implements the OCToken NFT-style open collaborator award issuance flow by adding award token fields and a protected award issue endpoint.
  • Pushed a formatting follow-up in 5407ceb after rechecking the touched API route.
  • Local validation passed:
    • pnpm exec prettier --check models/Award.ts pages/api/Lark/award/issue.ts
    • pnpm exec tsc --noEmit
    • git diff --check
  • CodeRabbit status is green on the current head.

Current PR head is 5407ceb0bafb16b1ad7af875c934eb08b8bb40bf; GitHub reports the PR as open, non-draft, and mergeable. Ready for maintainer review/merge for the 90 TQT $ reward issue.

@sureshchouksey8

Copy link
Copy Markdown
Author

Addressed the remaining CodeRabbit wallet validation nit in 695db1f.

What changed:

  • Added an Ethereum-style 0x + 40 hex character validation guard for walletAddress before updating the award record.
  • Invalid or non-string wallet addresses now return 400 instead of being stored as award issuance data.

Validation rerun locally:

  • pnpm exec prettier --check pages/api/Lark/award/issue.ts
  • pnpm exec tsc --noEmit
  • git diff --check

This keeps PR #76 aligned with issue #53 while preventing malformed wallet data from entering the award table.

@sureshchouksey8

Copy link
Copy Markdown
Author

Scope clarification for review on #53:

While rechecking CodeRabbit's note about the generated transactionHash / tokenId, I found no existing OCToken minting/issuer module or web3 dependency in this repo to call from pages/api/Lark/award/issue.ts.

So the current PR should be reviewed as the Lark/Bitable award issuance data-flow slice:

  • extends the Award Bitable record with walletAddress, transactionHash, and tokenId fields;
  • adds the authenticated /api/Lark/award/issue endpoint;
  • validates recordId and Ethereum-style wallet addresses before updating the award record;
  • persists issuance metadata back through AwardModel.updateOne().

I do not want to overclaim this as a real on-chain mint without an existing OCToken service contract/API in the project. If the intended acceptance criterion is real chain minting, please point me to the issuer API/contract/module to integrate; otherwise this is ready for review as the award-table issuance workflow for the 90 TQT $ issue.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
pages/api/Lark/award/issue.ts (1)

13-40: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

避免使用 any,请补充强类型以符合 TypeScript 规范。

(context.request as any).bodyawait response.json()data 为隐式 any)绕过了类型检查,data.transactionHash/data.tokenId 缺乏校验保障。建议为请求体与铸造响应定义接口类型。

🔧 示意:为请求体与响应定义类型
-  const { recordId, walletAddress } = (context.request as any).body;
+  const { recordId, walletAddress } = context.request.body as {
+    recordId?: string;
+    walletAddress?: string;
+  };
@@
-    const data = await response.json();
-    transactionHash = data.transactionHash;
-    tokenId = data.tokenId;
+    const data = (await response.json()) as {
+      transactionHash?: string;
+      tokenId?: string;
+    };
+    transactionHash = data.transactionHash;
+    tokenId = data.tokenId;

如代码规范 **/*.{ts,tsx} 所述:“Let TypeScript infer types when possible to avoid verbose annotations”,应避免使用 any 削弱类型安全。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pages/api/Lark/award/issue.ts` around lines 13 - 40, The issue is that
`issue.ts` uses `any` for both the incoming request body and the mint API
response, which bypasses TypeScript safety. Update the handler around
`context.request` and the `fetch`/`response.json()` flow by introducing explicit
interfaces for the request payload and the mint response, then use those types
instead of `(context.request as any).body` and untyped `data` in the
`walletAddress`, `recordId`, `transactionHash`, and `tokenId` assignments. Keep
the validation in `issue`/`mint` flow intact, but ensure the parsed JSON is
checked against the typed response shape before reading its fields.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pages/api/Lark/award/issue.ts`:
- Around line 26-47: 外部铸造调用缺少超时控制,`issue.ts` 中的 `fetch(mintApiUrl, ...)` 可能因
`NFT_MINT_API` 慢响应而一直挂起;请在该铸造请求里加入 `AbortController` 或等效超时机制,并让超时时间与默认
`mintApiUrl` 一样可通过配置覆盖。更新 `context.throw` 处理路径,确保超时被明确转换为 502/可读错误,并保留
`transactionHash`、`tokenId` 的现有校验逻辑不变。
- Line 12: The issue is that the /issue endpoint in router.post currently only
authenticates with verifyJWT and lacks authorization checks for the specific
resource being awarded. Add a permission check inside the award handler to
verify the authenticated user is allowed to operate on the targeted
walletAddress or recordId, such as confirming ownership or requiring admin
privileges, and reject unauthorized requests before proceeding with the issue
flow.
- Around line 12-57: Add an idempotency check to the award issuance flow in the
router.post('/issue') handler before calling the Mint API. Use AwardModel to
query whether the incoming recordId already has an existing issuance record, and
if it does, either return the existing transaction/token data or throw a 409
conflict instead of minting again. Keep the check close to the existing fetch
logic so the repeated-submit path is handled before any external side effects.

---

Nitpick comments:
In `@pages/api/Lark/award/issue.ts`:
- Around line 13-40: The issue is that `issue.ts` uses `any` for both the
incoming request body and the mint API response, which bypasses TypeScript
safety. Update the handler around `context.request` and the
`fetch`/`response.json()` flow by introducing explicit interfaces for the
request payload and the mint response, then use those types instead of
`(context.request as any).body` and untyped `data` in the `walletAddress`,
`recordId`, `transactionHash`, and `tokenId` assignments. Keep the validation in
`issue`/`mint` flow intact, but ensure the parsed JSON is checked against the
typed response shape before reading its fields.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 99777876-4de5-4f5f-8732-247dd4c540f4

📥 Commits

Reviewing files that changed from the base of the PR and between 5bf0829 and e3ea704.

📒 Files selected for processing (1)
  • pages/api/Lark/award/issue.ts

Comment thread pages/api/Lark/award/issue.ts
Comment thread pages/api/Lark/award/issue.ts
Comment thread pages/api/Lark/award/issue.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
pages/api/Lark/award/issue.ts (2)

13-25: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

先校验 recordId 类型再访问 Lark 与铸造服务。

当前只做 truthy 检查,数组或对象会继续进入 getOne()、mint 请求体和 updateOne()。请收窄为非空字符串并复用规范化后的值。

建议修复
-  const { recordId, walletAddress } = (context.request as any).body;
+  const { recordId, walletAddress } = (context.request.body ?? {}) as {
+    recordId?: unknown;
+    walletAddress?: unknown;
+  };

-  if (!recordId || !walletAddress) {
+  if (typeof recordId !== 'string' || !recordId.trim() || !walletAddress) {
     context.throw(400, 'recordId and walletAddress are required');
   }
+
+  const awardRecordId = recordId.trim();

-  const award = await awardModel.getOne(recordId);
+  const award = await awardModel.getOne(awardRecordId);

并在 mint 请求与 updateOne() 中使用 awardRecordId

Also applies to: 63-67, 89-96

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pages/api/Lark/award/issue.ts` around lines 13 - 25, The current `recordId`
validation in `issue` only checks truthiness, so non-string values can flow into
`AwardModel.getOne()`, the Lark mint request, and `updateOne()`. Tighten the
input check to require a non-empty string, normalize it once into a canonical
variable such as `awardRecordId`, and then use that normalized value everywhere
the record ID is passed, including the mint request body and `updateOne()`.

74-80: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

校验 mint 响应 schema 后再写回。

response.json() 是不可信边界;仅做 truthy 检查会让对象、错误格式哈希等值进入持久化。至少校验 transactionHash 为字符串且符合交易哈希格式,并把 tokenId 规范化为非空字符串。

建议修复
-    const data = await response.json();
-    transactionHash = data.transactionHash;
-    tokenId = data.tokenId;
+    const data = (await response.json()) as {
+      transactionHash?: unknown;
+      tokenId?: unknown;
+    };
+
+    if (
+      typeof data.transactionHash !== 'string' ||
+      !/^0x[a-fA-F0-9]{64}$/.test(data.transactionHash) ||
+      (typeof data.tokenId !== 'string' && typeof data.tokenId !== 'number') ||
+      `${data.tokenId}`.trim() === ''
+    ) {
+      throw new Error('Invalid response from minting service');
+    }
+
+    transactionHash = data.transactionHash;
+    tokenId = `${data.tokenId}`;

-    if (!transactionHash || !tokenId) {
-      throw new Error('Invalid response from minting service');
-    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pages/api/Lark/award/issue.ts` around lines 74 - 80, The mint response
handling in issueToken should validate the parsed JSON before assigning
transactionHash and tokenId. In the response.json() flow, replace the simple
truthy check with explicit schema validation: ensure transactionHash is a string
matching the expected transaction-hash format and tokenId is normalized to a
non-empty string before any write-back or downstream use. If validation fails,
keep throwing the invalid response error from issueToken.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pages/api/Lark/award/issue.ts`:
- Around line 44-52: The current idempotency check in issue flow returns an
existing award purely from transactionHash/tokenId and does not bind the result
to walletAddress, so concurrent requests can still double-mint and later
overwrite each other via updateOne. Update the award issuance path in issue.ts
to make minting idempotent by recordId or by reserving an “issuing” lock/status
before calling the external mint service, then finalize the record after
success; also verify the incoming walletAddress matches the stored wallet and
return 409 on mismatch. Apply the same fix to the duplicated logic around the
referenced issue-processing block so both paths use the same wallet-bound
concurrency guard.
- Around line 36-40: 当前发放授权逻辑在 issueAward 相关校验里使用了 currentUser.name 与 “Robot”
展示名以及 award.nominator/award.nomineeName 做比较,存在重名和篡改风险。请改为基于 JWT 负载中的稳定字段
currentUser.id 做权限判断,并把奖项记录中参与比对的字段切换为内部 ID(包括 Robot 的 ID 0)。确保 issue.ts
中这段授权分支只依赖 ID 级别的身份校验,避免继续使用文本身份。

---

Outside diff comments:
In `@pages/api/Lark/award/issue.ts`:
- Around line 13-25: The current `recordId` validation in `issue` only checks
truthiness, so non-string values can flow into `AwardModel.getOne()`, the Lark
mint request, and `updateOne()`. Tighten the input check to require a non-empty
string, normalize it once into a canonical variable such as `awardRecordId`, and
then use that normalized value everywhere the record ID is passed, including the
mint request body and `updateOne()`.
- Around line 74-80: The mint response handling in issueToken should validate
the parsed JSON before assigning transactionHash and tokenId. In the
response.json() flow, replace the simple truthy check with explicit schema
validation: ensure transactionHash is a string matching the expected
transaction-hash format and tokenId is normalized to a non-empty string before
any write-back or downstream use. If validation fails, keep throwing the invalid
response error from issueToken.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ac4efecc-2cb5-4b9a-b13e-5faaebc537c2

📥 Commits

Reviewing files that changed from the base of the PR and between e3ea704 and 179196a.

📒 Files selected for processing (1)
  • pages/api/Lark/award/issue.ts

Comment on lines +36 to +40
if (
currentUser.name !== 'Robot' &&
currentUser.name !== award.nominator &&
currentUser.name !== award.nomineeName
) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 验证 verifyJWT 写入 context.state.user 的字段,以及是否已有稳定 role/id 可复用。
rg -nP -C4 '\bverifyJWT\b|context\.state\.user|state\.user|isAdmin|role|userId|email|name' pages models --type=ts

Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io

Length of output: 47055


不要用展示名和 Robot 字符串做发放授权。

currentUser.name 是文本身份,存在重名或篡改风险。验证确认 JWT 负载中包含稳定字段 id(其中 Robot 的 ID 为 0)。请改用 currentUser.id 进行权限校验,并将奖项记录中的比对字段对应为内部 ID,确保认证逻辑的稳定性与安全性。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pages/api/Lark/award/issue.ts` around lines 36 - 40, 当前发放授权逻辑在 issueAward
相关校验里使用了 currentUser.name 与 “Robot” 展示名以及 award.nominator/award.nomineeName
做比较,存在重名和篡改风险。请改为基于 JWT 负载中的稳定字段 currentUser.id 做权限判断,并把奖项记录中参与比对的字段切换为内部 ID(包括
Robot 的 ID 0)。确保 issue.ts 中这段授权分支只依赖 ID 级别的身份校验,避免继续使用文本身份。

Comment thread pages/api/Lark/award/issue.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
pages/api/Lark/award/issue.ts (4)

43-45: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

先规范化钱包地址再做幂等绑定。

正则允许 checksum / mixed-case 地址,但 Line 83 是原始字符串比较;同一个 Ethereum 地址只要大小写不同就会被误判为不同钱包并返回 409。

建议修复
   if (typeof walletAddress !== 'string' || !EthereumAddressPattern.test(walletAddress)) {
     context.throw(400, 'walletAddress must be a valid Ethereum address');
   }
+  const normalizedWalletAddress = walletAddress.toLowerCase();
-    if (award.walletAddress && award.walletAddress !== walletAddress) {
+    if (
+      award.walletAddress &&
+      String(award.walletAddress).toLowerCase() !== normalizedWalletAddress
+    ) {
-      walletAddress,
+      walletAddress: normalizedWalletAddress,
-      body: JSON.stringify({ walletAddress, recordId }),
+      body: JSON.stringify({ walletAddress: normalizedWalletAddress, recordId }),

Also applies to: 83-84, 95-99, 112-116, 149-154

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pages/api/Lark/award/issue.ts` around lines 43 - 45, Normalize walletAddress
to a canonical form before any idempotency or duplicate-binding checks, because
the current raw-string comparisons in the issue flow can treat the same Ethereum
address with different casing as different wallets. Update the validation and
comparison logic in the award issue handler so the value is normalized once
after the EthereumAddressPattern check, then reuse that normalized value in the
existing binding/409 paths and any subsequent comparisons in the issue flow.

37-40: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

校验 recordId 必须是非空字符串。

当前只做 truthy 检查,数组/对象等请求体也会进入 getOne() / updateOne(),把非法 ID 传到模型层。

建议修复
   const { recordId, walletAddress } = (context.request as any).body;
 
-  if (!recordId || !walletAddress) {
+  if (typeof recordId !== 'string' || !recordId.trim() || !walletAddress) {
     context.throw(400, 'recordId and walletAddress are required');
   }
+
+  const normalizedRecordId = recordId.trim();

同时把后续 recordId 参数替换为 normalizedRecordId

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pages/api/Lark/award/issue.ts` around lines 37 - 40, The recordId validation
in the award issue API only checks truthiness, so non-string values like arrays
or objects can still flow into getOne() and updateOne(). Update the handler in
issue() to validate recordId as a non-empty string, normalize it into a
normalizedRecordId value, and use that normalized variable for the subsequent
model calls and any related checks.

108-110: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

NFT_MINT_TIMEOUT 做正数兜底。

parseInt 对非法、0、负数配置不会回退默认值,可能导致立即 abort 或异常超时配置,进而让发放流程整体失败。

建议修复
-    const timeoutVal = parseInt(process.env.NFT_MINT_TIMEOUT || '10000', 10);
+    const parsedTimeout = Number(process.env.NFT_MINT_TIMEOUT);
+    const timeoutVal =
+      Number.isFinite(parsedTimeout) && parsedTimeout > 0 ? parsedTimeout : 10_000;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pages/api/Lark/award/issue.ts` around lines 108 - 110, `NFT_MINT_TIMEOUT`
的解析缺少正数兜底,非法值、0 或负数会被直接用于 `setTimeout` 导致异常超时行为。请在 `issue.ts` 中围绕 `timeoutVal` 和
`AbortController` 增加校验:先解析环境变量,再在 `timeoutVal` 非法或小于等于 0 时回退到默认值 10000,确保
`setTimeout(() => controller.abort(), timeoutVal)` 只使用有效正数超时。

123-129: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

不要把 mint 响应的任意 truthy 值写成凭证。

当前只检查非空;如果 mint 服务返回对象、错误格式哈希或空白 tokenId,记录会被标记为已颁发但凭证不可用。

建议修复
     const data = await response.json();
-    transactionHash = data.transactionHash;
-    tokenId = data.tokenId;
 
-    if (!transactionHash || !tokenId) {
+    if (
+      typeof data.transactionHash !== 'string' ||
+      !/^0x[a-fA-F0-9]{64}$/.test(data.transactionHash) ||
+      typeof data.tokenId !== 'string' ||
+      !data.tokenId.trim()
+    ) {
       throw new Error('Invalid response from minting service');
     }
+
+    transactionHash = data.transactionHash;
+    tokenId = data.tokenId.trim();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pages/api/Lark/award/issue.ts` around lines 123 - 129, The mint response
handling in the issue flow is too permissive and can persist non-usable values
as credentials. In the award issuance logic around the response.json parsing,
tighten validation before assigning transactionHash and tokenId: verify both
fields are the expected primitive string values, reject objects/other truthy
shapes, and treat blank or whitespace-only tokenId as invalid. Keep the existing
invalid-response error path in the issue handler so only a real transaction hash
and usable token ID are written.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pages/api/Lark/award/issue.ts`:
- Around line 12-20: getUserIds currently does not fully normalize IDs to
strings, and its Boolean filtering can drop valid values like 0, which can break
the later includes-based authorization check in the award issue flow. Update
getUserIds in issue.ts so every branch returns stringified IDs consistently, and
replace the truthy filter with an explicit non-null/non-undefined check; make
sure the downstream logic around the includes check and display-name fallback
continues to work with the normalized string IDs.

---

Outside diff comments:
In `@pages/api/Lark/award/issue.ts`:
- Around line 43-45: Normalize walletAddress to a canonical form before any
idempotency or duplicate-binding checks, because the current raw-string
comparisons in the issue flow can treat the same Ethereum address with different
casing as different wallets. Update the validation and comparison logic in the
award issue handler so the value is normalized once after the
EthereumAddressPattern check, then reuse that normalized value in the existing
binding/409 paths and any subsequent comparisons in the issue flow.
- Around line 37-40: The recordId validation in the award issue API only checks
truthiness, so non-string values like arrays or objects can still flow into
getOne() and updateOne(). Update the handler in issue() to validate recordId as
a non-empty string, normalize it into a normalizedRecordId value, and use that
normalized variable for the subsequent model calls and any related checks.
- Around line 108-110: `NFT_MINT_TIMEOUT` 的解析缺少正数兜底,非法值、0 或负数会被直接用于 `setTimeout`
导致异常超时行为。请在 `issue.ts` 中围绕 `timeoutVal` 和 `AbortController` 增加校验:先解析环境变量,再在
`timeoutVal` 非法或小于等于 0 时回退到默认值 10000,确保 `setTimeout(() => controller.abort(),
timeoutVal)` 只使用有效正数超时。
- Around line 123-129: The mint response handling in the issue flow is too
permissive and can persist non-usable values as credentials. In the award
issuance logic around the response.json parsing, tighten validation before
assigning transactionHash and tokenId: verify both fields are the expected
primitive string values, reject objects/other truthy shapes, and treat blank or
whitespace-only tokenId as invalid. Keep the existing invalid-response error
path in the issue handler so only a real transaction hash and usable token ID
are written.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9d8b1b81-0c61-4f2c-b1f9-b0eb8119344f

📥 Commits

Reviewing files that changed from the base of the PR and between 179196a and d893ec6.

📒 Files selected for processing (1)
  • pages/api/Lark/award/issue.ts

Comment on lines +12 to +20
const getUserIds = (field: any): string[] => {
if (!field) return [];
if (Array.isArray(field)) {
return field.map(u => (typeof u === 'object' && u ? u.id : String(u))).filter(Boolean);
}
if (typeof field === 'object' && field) {
return [field.id].filter(Boolean);
}
return [String(field)];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

getUserIds 的返回值真正归一化为字符串。

当前对象分支会返回原始 id,且 .filter(Boolean) 会丢掉数值 0;但 Line 64 后续用字符串 ID 做 includes,这会导致 ID 授权误判并落到展示名兜底。

建议修复
 const getUserIds = (field: any): string[] => {
   if (!field) return [];
   if (Array.isArray(field)) {
-    return field.map(u => (typeof u === 'object' && u ? u.id : String(u))).filter(Boolean);
+    return field
+      .map(u => (typeof u === 'object' && u ? u.id : u))
+      .filter(id => id !== undefined && id !== null && id !== '')
+      .map(String);
   }
   if (typeof field === 'object' && field) {
-    return [field.id].filter(Boolean);
+    return field.id === undefined || field.id === null || field.id === ''
+      ? []
+      : [String(field.id)];
   }
   return [String(field)];
 };

Also applies to: 64-69

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pages/api/Lark/award/issue.ts` around lines 12 - 20, getUserIds currently
does not fully normalize IDs to strings, and its Boolean filtering can drop
valid values like 0, which can break the later includes-based authorization
check in the award issue flow. Update getUserIds in issue.ts so every branch
returns stringified IDs consistently, and replace the truthy filter with an
explicit non-null/non-undefined check; make sure the downstream logic around the
includes check and display-name fallback continues to work with the normalized
string IDs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

基于 OCToken NFT 机制实现【开放协作人奖】颁发程序

1 participant