Skip to content

Cscitech#11

Merged
CSCITech merged 6 commits into
mainfrom
cscitech
Jul 7, 2026
Merged

Cscitech#11
CSCITech merged 6 commits into
mainfrom
cscitech

Conversation

@CSCITech

@CSCITech CSCITech commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

📝 变更描述 / Description

(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

  • Closes # (如有)

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

(请在此粘贴截图、关键日志或测试报告,以证明变更生效)

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0935e42a-2a93-431d-84c5-1ee6060a9426

📥 Commits

Reviewing files that changed from the base of the PR and between fba1735 and f26d2f6.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (4)
  • dto/openai_image.go
  • dto/openai_image_test.go
  • go.mod
  • relay/helper/openai_image_request_test.go
📜 Recent review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Backend checks
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • dto/openai_image_test.go
  • dto/openai_image.go
  • relay/helper/openai_image_request_test.go
dto/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

For request structs parsed from client JSON and then re-marshaled to upstream providers, especially in relay/convert paths, optional scalar fields must use pointer types with omitempty so that absent fields stay omitted while explicit zero/false values are preserved.

Files:

  • dto/openai_image_test.go
  • dto/openai_image.go
🔇 Additional comments (5)
go.mod (2)

52-57: 🔒 Security & Privacy

golang.org/x/image bumped to v0.43.0, addressing the previously flagged vulnerabilities.

Per the earlier thread, this covers GO-2026-4961/5061/5062/5066. The golang.org/x/crypto line isn't included in this snippet to confirm v0.52.0+, but past comments indicate it was already addressed in commit 9fd1a8e.


7-8: LGTM!

dto/openai_image_test.go (1)

10-21: LGTM!

dto/openai_image.go (1)

5-5: LGTM! Error message bound now correctly reflects the accepted [0, MaxImageN] range, addressing the earlier review comment.

Also applies to: 18-26

relay/helper/openai_image_request_test.go (1)

17-82: LGTM! Expected error string updated consistently with the ValidateImageN fix.


📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added a “Billing quota” filter (all/abnormal/zero/negative) to usage logs and related task/log views, including UI dropdown support.
    • Enforced OpenAI image “n” bounds (0–128) and added clearer, localized email/password error messages.
  • Bug Fixes
    • Improved quota calculations to better handle fractional values, extreme numbers, and NaN/Inf cases.
    • Hardened SSRF-protected outbound requests and improved streaming timeout/cancellation behavior.
    • Tightened task duration validation/capping and normalized email handling to prevent duplication issues.
  • Tests
    • Expanded unit/integration coverage for quota filtering, quota math, email normalization, and request validation.

Walkthrough

This PR adds saturating quota conversion, normalized-email account handling, quota filtering for logs and tasks, SSRF-protected fetch helpers, task duration and image bounds validation, stream shutdown hardening, and option/group-ratio normalization.

Changes

Quota Rounding and Saturation

Layer / File(s) Summary
Quota conversion core
common/quota_math.go, common/quota_math_test.go, pkg/billingexpr/round.go, pkg/billingexpr/billingexpr_test.go
Adds saturating float-to-int conversion and matching quota-round tests.
Billing and token paths
relay/helper/price.go, service/task_billing.go, service/tool_billing.go, service/token_counter.go, controller/task_video.go, relay/channel/task/kling/adaptor.go, relay/relay_task.go, service/quota.go, service/text_quota.go, service/text_quota_test.go
Replaces direct integer casts with saturated quota conversion across billing, token, and task quota calculations.
Quota validation hardening
types/price_data.go, setting/task_billing_setting/rate_card.go
Rejects NaN and infinity in ratio, price, and quantity validation paths.

Estimated code review effort: 5 (Critical) | ~90 minutes

SSRF Protected Fetch Client

Layer / File(s) Summary
SSRF protection wrappers
common/ssrf_protection.go
Adds exported SSRF validation wrappers and a fetch-setting constructor.
Protected fetch dialer
service/protected_fetch_client.go, service/protected_fetch_client_test.go
Implements SSRF-aware dialing, URL validation, redirect blocking, and IP-family filtering with tests.
HTTP client delegation
service/http_client.go
Delegates dial and redirect checks to the protected fetch client and adjusts fallback client selection.

Estimated code review effort: 4 (Complex) | ~50 minutes

User Email Normalization and Auth Flows

Layer / File(s) Summary
Errors and translations
model/errors.go, i18n/keys.go, i18n/locales/*
Adds email-related errors and localized messages.
Normalized email core
model/user.go
Adds normalized email storage, locking, availability checks, binding, and update helpers.
Migration backfill
model/main.go
Backfills normalized emails during migration.
OAuth and email flows
controller/oauth.go, controller/misc.go, controller/user.go, model/topup.go
Uses normalized email checks in registration, OAuth, password reset, email verification, and top-up binding.
Tests
model/user_update_test.go, model/payment_method_guard_test.go, controller/model_list_test.go
Adds coverage for normalization, concurrency, password flows, and duplicate-email cases.

Estimated code review effort: 5 (Critical) | ~100 minutes

Log and Task Quota Filter Feature

Layer / File(s) Summary
Model query filtering
model/log.go, model/midjourney.go, model/task.go
Adds quota filter constants, query params, and filter application in log/task/midjourney queries.
Model quota filter tests
model/log_test.go, model/task_cas_test.go
Updates tests for the new quota filter behavior and indexes.
Controller wiring
controller/log.go, controller/midjourney.go, controller/task.go
Reads quota_filter in controllers and passes it into model queries.
Usage logs frontend
web/default/src/features/usage-logs/**, web/default/src/routes/_authenticated/usage-logs/$section.tsx
Adds quota filter constants, select UI, URL/search handling, API params, types, and translations.

Estimated code review effort: 4 (Complex) | ~75 minutes

Task Duration Bounds

Layer / File(s) Summary
Duration validation
relay/common/relay_info.go, relay/common/relay_utils.go, relay/common/relay_utils_test.go, relay/channel/task/ali/adaptor.go, relay/channel/task/gemini/billing.go
Adds duration-resolution helpers, request validation, and billing caps for task durations.
Adaptor duration resolution tests
relay/channel/task/ali/adaptor_kling_test.go, relay/channel/task/ali/adaptor_wan27_test.go
Adds tests for duration resolution behavior in task adaptors.

Estimated code review effort: 3 (Moderate) | ~40 minutes

Streaming and Ping Shutdown Robustness

Layer / File(s) Summary
Ping keep-alive coordination
relay/channel/api_request.go, relay/channel/api_request_test.go
Adds ping completion tracking, timeout handling, and keep-alive tests.
Stream scanner shutdown
relay/helper/stream_scanner.go, relay/helper/stream_scanner_test.go
Adds write-deadline helpers and rewrites stream-scanner cleanup and cancellation handling.
Request-context guards and chunk errors
relay/helper/common.go, relay/helper/common_test.go, relay/channel/gemini/relay_responses.go, relay/channel/openai/helper.go, relay/channel/openai/relay_image.go, relay/channel/openai/responses_via_chat.go
Adds request-context guards and propagates chunk-write errors through stream handlers.

Estimated code review effort: 4 (Complex) | ~60 minutes

Image Count and Token Bounds

Layer / File(s) Summary
Image count cap
dto/openai_image.go, dto/openai_image_test.go, relay/helper/valid_request.go, relay/channel/ali/image.go
Adds MaxImageN and validates image request n values and request-type bounds.
Shared max-token limits
relay/helper/valid_request.go, relay/helper/max_tokens_bounds_test.go
Adds shared token-bound validation and coverage for OpenAI, Claude, Gemini, and Responses requests.

Estimated code review effort: 3 (Moderate) | ~35 minutes

Option and Group Ratio Normalization

Layer / File(s) Summary
Option normalization
model/option.go, model/option_test.go
Normalizes option updates before validation and persistence.
Group ratio normalization
setting/ratio_setting/group_ratio.go, setting/ratio_setting/group_ratio_test.go
Adds reserved-name filtering and JSON normalization helpers for group ratios.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Minor Updates

Layer / File(s) Summary
Miscellaneous updates
go.mod, controller/token_test.go, web/default/src/components/model-group-selector.tsx
Updates dependencies, adjusts token denial-message expectations, and changes group-ratio display logic.
Billing label translations
web/default/src/i18n/locales/*.json
Adds billing label translations used by the quota filter UI.

Estimated code review effort: 2 (Simple) | ~15 minutes

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant UserController
    participant UserModel
    participant DB

    Client->>UserController: register / email bind / reset password
    UserController->>UserModel: NormalizeEmail(email)
    UserController->>UserModel: EnsureEmailAvailable(email)
    UserModel-->>UserController: available or ErrEmailAlreadyTaken
    alt email available
        UserController->>DB: WithNormalizedEmailWriteTx(...)
        DB-->>UserController: success
    else email taken
        UserController-->>Client: localized email-taken error
    end
Loading
sequenceDiagram
    participant HTTPClient
    participant ProtectedFetchDialer
    participant SSRFProtection
    participant Resolver

    HTTPClient->>ProtectedFetchDialer: DialContext(host, port)
    ProtectedFetchDialer->>SSRFProtection: getCachedSSRFProtection()
    SSRFProtection-->>ProtectedFetchDialer: config
    ProtectedFetchDialer->>Resolver: resolve host
    Resolver-->>ProtectedFetchDialer: candidate IPs
    ProtectedFetchDialer->>SSRFProtection: ValidateNetworkTarget / ValidateResolvedIP
    SSRFProtection-->>ProtectedFetchDialer: allow or block
    ProtectedFetchDialer-->>HTTPClient: connection or error
Loading

Possibly related PRs

  • MAX-API-Next/MAX-API#1: Both PRs modify the log query pipeline in controller/log.go and model/log.go by refactoring query parameters and filter handling.
  • MAX-API-Next/MAX-API#5: Both PRs change model/log.go quota-stat aggregation and SumUsedQuota filtering behavior.
  • MAX-API-Next/MAX-API#9: Both PRs touch task duration handling and related relay validation paths.

Poem

A rabbit hopped through quotas tall,
Clamped the floats so none would fall,
Email names grew neat and clear,
Filters bloomed from far to near,
Streams stayed calm, the guards stood true—
🥕 hop hop, the build is new!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is just "Cscitech" and does not describe the actual code changes. Use a short, specific title that summarizes the main change in the PR.
Description check ❓ Inconclusive The description is a template with placeholders and no concrete summary of the changes. Replace the template with a brief human-written summary of what changed, why, related issue, and validation.
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cscitech

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: 12

Caution

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

⚠️ Outside diff range comments (5)
web/default/src/features/usage-logs/lib/utils.ts (1)

207-235: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate quota_filter inclusion logic.

The quota_filter conditional inclusion (searchParams.quotaFilter && searchParams.quotaFilter !== QUOTA_FILTER_ALL_VALUE ? { quota_filter: ... } : {}) is duplicated verbatim in both buildBaseParams and buildApiParams. Consider extracting a small shared helper (e.g. buildQuotaFilterParam(searchParams)) to avoid drift if the exclusion logic changes later.

♻️ Proposed refactor
+function buildQuotaFilterParam(searchParams: Record<string, unknown>) {
+  return searchParams.quotaFilter &&
+    searchParams.quotaFilter !== QUOTA_FILTER_ALL_VALUE
+    ? { quota_filter: String(searchParams.quotaFilter) }
+    : {}
+}

Then use ...buildQuotaFilterParam(searchParams) in both functions.

Also applies to: 241-317

🤖 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 `@web/default/src/features/usage-logs/lib/utils.ts` around lines 207 - 235, The
quota_filter inclusion logic is duplicated in buildBaseParams and
buildApiParams, so extract the shared conditional into a small helper like
buildQuotaFilterParam(searchParams) and reuse it from both functions. Keep the
existing QUOTA_FILTER_ALL_VALUE exclusion behavior centralized in that helper,
then spread its result alongside the other params in buildBaseParams and
buildApiParams to prevent future drift.
relay/channel/openai/helper.go (1)

205-210: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Propagate ResponseChunkData failures from sendResponsesStreamData

relay/channel/openai/helper.go drops the write error, and relay/channel/openai/relay_responses.go ignores that return in both the pending-flush and live-forward paths. Return the error and stop the stream on failure so client disconnects can end the loop and record StreamEndReasonClientGone, as the other stream handlers do.

🤖 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 `@relay/channel/openai/helper.go` around lines 205 - 210, The stream write
error is being discarded in sendResponsesStreamData, which prevents
relay_responses.go from reacting to client disconnects. Update
sendResponsesStreamData to return the error from helper.ResponseChunkData
instead of ignoring it, then handle that return in both the pending-flush and
live-forward paths in relay_responses.go by breaking out of the stream loop and
recording StreamEndReasonClientGone when a write fails.
relay/channel/openai/relay_image.go (1)

128-138: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Propagate write errors from writeOpenaiImageStreamChunk

Unlike writeOpenaiImageStreamPayload, this helper drops ResponseChunkData/StringData failures, so an immediate client write error can’t stop the stream via sr.Stop(err). Thread the error back to the callback/caller if this path should abort on write failure.

🤖 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 `@relay/channel/openai/relay_image.go` around lines 128 - 138, The
writeOpenaiImageStreamChunk helper is ignoring write failures from
ResponseChunkData and StringData, so stream errors cannot be propagated back to
stop the session. Update writeOpenaiImageStreamChunk to return an error (or
otherwise surface the helper result) and have the caller/callback handle it by
stopping the stream via sr.Stop(err) when a client write fails; use the existing
writeOpenaiImageStreamPayload flow as the reference for how errors should be
threaded through.
service/tool_billing.go (1)

39-88: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Clamp TotalQuota before returning. totalQuota sums already-saturated per-item quotas, so the aggregate can still overflow before it reaches the 32-bit quota column downstream. Wrap the final total with common.QuotaFromFloat too.

🤖 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 `@service/tool_billing.go` around lines 39 - 88, `ComputeToolCallQuota`
currently returns `totalQuota` directly, which can still overflow even though
each `ToolCallItem` quota is individually clamped. Update the final
`ToolCallResult` construction to pass the accumulated total through
`common.QuotaFromFloat` before returning, using the existing `totalQuota`
calculation and `common.QuotaPerUnit`/`QuotaFromFloat` flow to keep the
aggregate within the quota column range.
model/user.go (1)

746-796: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Update()/UpdateWithTx() don't enforce email uniqueness — TOCTOU gap vs. Insert/BindEmailToUser.

Insert and BindEmailToUser wrap their check+write in WithNormalizedEmailWriteTx, serializing writers per normalized email. Update (Line 747) calls UpdateWithTx(DB, ...) directly with the plain DB handle — no lock, and buildUserUpdateValues (Line 792-796) writes email/normalized_email straight into the update map with no call to ensureEmailAvailableWithTx/EnsureEmailAvailable. The uniqueness check for this path currently lives only in the controller layer (e.g. controller/user.go calling EnsureEmailAvailable before Update), which is a separate, non-atomic query. Two concurrent profile-email updates targeting the same new address can both pass that pre-check and then both write successfully, producing duplicate normalized_email rows — undermining the uniqueness guarantee this PR is building.

Route email changes in UpdateWithTx through WithNormalizedEmailWriteTx plus an in-tx ensureEmailAvailableWithTx check, mirroring Insert/BindEmailToUser.

🤖 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 `@model/user.go` around lines 746 - 796, The email update path in
User.Update/User.UpdateWithTx is still vulnerable to a TOCTOU race because it
writes email and normalized_email from buildUserUpdateValues without any
in-transaction uniqueness check or email write lock. Update UpdateWithTx to
route email-changing updates through WithNormalizedEmailWriteTx and call
ensureEmailAvailableWithTx before persisting, mirroring Insert and
BindEmailToUser so concurrent updates cannot create duplicate normalized_email
values.
🤖 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 `@go.mod`:
- Around line 52-57: Update the dependency versions in go.mod so
golang.org/x/crypto is bumped from v0.51.0 to v0.52.0 or newer, while leaving
the unrelated golang.org/x/image entry alone. Make the change in the module
requirements list where golang.org/x/crypto is declared, and ensure the
resulting version still resolves cleanly with the rest of the golang.org/x/*
set.

In `@model/log.go`:
- Around line 113-124: `applyQuotaFilter` introduces `quota`-based predicates
that can trigger full scans on large `logs` queries used by `GetAllLogs`,
`GetUserLogs`, and `SumUsedQuota`; add an index strategy for the `logs.quota`
column, and consider a composite index with `type` and/or `created_at` if those
filters are commonly combined, so the new quota filter path stays efficient.
- Around line 639-644: `GetAllLogs`, `GetUserLogs`, and `SumUsedQuota` have
grown into long positional-parameter APIs with many same-typed string arguments,
making call sites easy to transpose silently. Refactor these entry points to
accept a request/options struct, similar to `TaskQueryParams` in
`model/midjourney.go`, and move the existing filter fields (including
`quotaFilter`) onto that struct. Update the implementations and all call sites
to use the new struct-based parameter object while preserving the current
filtering behavior in `applyLogFilter`, `applyQuotaFilter`, and related query
helpers.

In `@model/task.go`:
- Around line 408-411: Add test coverage for the new quota update path and
filter wiring. Use the existing model test patterns, especially the
`TestLogQuotaFilters` style in `model/log_test.go`, to verify `UpdateQuota`
updates the record scoped by the task primary key and that `QuotaFilter` is
applied as expected. Reference `Task.UpdateQuota` and the `QuotaFilter` setup
when adding the tests so the new behavior stays covered.

In `@model/user.go`:
- Around line 776-856: The update logic in buildUserUpdateValues is inferring
“full user” from CreatedAt, which can cause empty zero-values like Email to be
written back unintentionally and wipe existing data. Replace this heuristic with
an explicit changed-fields mechanism in buildUserUpdateValues, such as
pointer/nullable fields, a dirty-field list, or a proper struct-diff check, and
only set email/normalized_email and other fields when they were actually
intended to change.

In `@pkg/billingexpr/billingexpr_test.go`:
- Around line 295-298: Add a symmetric negative-infinity table entry to the
billing expression conversion tests so coverage matches the existing +Inf case.
Update the test table in billingexpr_test.go near the values used by the
conversion helper to include math.Inf(-1) expecting math.MinInt32, alongside the
existing math.Inf(1) case, to exercise the r <= math.MinInt32 branch
consistently.

In `@relay/channel/ali/image.go`:
- Around line 57-59: The N-bounds check and error message are duplicated between
ImageRequest handling and the request validation helper, so the logic can drift.
Extract the range check into a shared validator such as dto.ValidateImageN and
have both the image relay path and relay/helper/valid_request.go call it,
keeping the cap and message centralized in one place. Use the existing
imageRequest.Parameters.N validation in image.go as the entry point to replace
the inline bounds check with the shared helper.

In `@relay/common/relay_utils.go`:
- Around line 119-128: The duration resolution logic is duplicated in
validateTaskDurationBounds and the Ali request conversion paths, so centralize
it on TaskSubmitReq with a shared helper such as ResolvedSeconds() that applies
the existing Duration-first, Seconds-fallback, and default/clamp behavior.
Update validateTaskDurationBounds and the
convertToAliRequest/convertToAliKlingRequest flow in the Ali adaptor to call
that helper so validation and billing use the same precedence and future changes
stay consistent.
- Around line 119-128: The validation in validateTaskDurationBounds has two
correctness issues: the error text does not match the actual allowed range, and
the strconv.Atoi fallback for req.Seconds ignores conversion failures. Update
the bounds check and the returned createTaskError message so they describe the
same valid range, and change the parsing path in validateTaskDurationBounds to
detect and reject non-numeric Seconds values instead of silently treating them
as 0; use the existing TaskSubmitReq, DurationValue, and createTaskError flow to
keep the behavior consistent.

In `@relay/helper/common.go`:
- Around line 41-43: The stream helper path still assumes a valid gin context,
so ClaudeData, ClaudeChunkData, and ResponseChunkData can panic on nil context
or missing writer even though requestContextDone() treats nil as done. Update
these helpers to match StringData and PingData by returning early when c == nil
or c.Writer == nil before any c.Render or c.Request.Context() access, and keep
the existing requestContextDone() check as the next guard.

In `@setting/ratio_setting/group_ratio.go`:
- Around line 76-82: ContainsGroupRatio and GetGroupRatio are checking the
reserved-name case with a trimmed value but still using the untrimmed name for
groupRatioMap.Get, so whitespace-padded inputs miss existing entries. Update
these functions to normalize/trim the name once up front and use that trimmed
value for both the reserved-name check and the map lookup, matching the key
format produced by normalizeGroupRatioMap.

In `@web/default/src/features/usage-logs/constants.ts`:
- Around line 152-164: QUOTA_FILTER_VALUES and QUOTA_FILTER_SEARCH_VALUES are
duplicated with the same literals, which can drift and make isQuotaFilterValue
and the route zod enum in $section.tsx disagree. Refactor constants.ts so one
array is derived from the other instead of being hand-maintained separately,
keeping the shared quota filter list in sync for all usages such as
isQuotaFilterValue and z.enum(QUOTA_FILTER_SEARCH_VALUES).

---

Outside diff comments:
In `@model/user.go`:
- Around line 746-796: The email update path in User.Update/User.UpdateWithTx is
still vulnerable to a TOCTOU race because it writes email and normalized_email
from buildUserUpdateValues without any in-transaction uniqueness check or email
write lock. Update UpdateWithTx to route email-changing updates through
WithNormalizedEmailWriteTx and call ensureEmailAvailableWithTx before
persisting, mirroring Insert and BindEmailToUser so concurrent updates cannot
create duplicate normalized_email values.

In `@relay/channel/openai/helper.go`:
- Around line 205-210: The stream write error is being discarded in
sendResponsesStreamData, which prevents relay_responses.go from reacting to
client disconnects. Update sendResponsesStreamData to return the error from
helper.ResponseChunkData instead of ignoring it, then handle that return in both
the pending-flush and live-forward paths in relay_responses.go by breaking out
of the stream loop and recording StreamEndReasonClientGone when a write fails.

In `@relay/channel/openai/relay_image.go`:
- Around line 128-138: The writeOpenaiImageStreamChunk helper is ignoring write
failures from ResponseChunkData and StringData, so stream errors cannot be
propagated back to stop the session. Update writeOpenaiImageStreamChunk to
return an error (or otherwise surface the helper result) and have the
caller/callback handle it by stopping the stream via sr.Stop(err) when a client
write fails; use the existing writeOpenaiImageStreamPayload flow as the
reference for how errors should be threaded through.

In `@service/tool_billing.go`:
- Around line 39-88: `ComputeToolCallQuota` currently returns `totalQuota`
directly, which can still overflow even though each `ToolCallItem` quota is
individually clamped. Update the final `ToolCallResult` construction to pass the
accumulated total through `common.QuotaFromFloat` before returning, using the
existing `totalQuota` calculation and `common.QuotaPerUnit`/`QuotaFromFloat`
flow to keep the aggregate within the quota column range.

In `@web/default/src/features/usage-logs/lib/utils.ts`:
- Around line 207-235: The quota_filter inclusion logic is duplicated in
buildBaseParams and buildApiParams, so extract the shared conditional into a
small helper like buildQuotaFilterParam(searchParams) and reuse it from both
functions. Keep the existing QUOTA_FILTER_ALL_VALUE exclusion behavior
centralized in that helper, then spread its result alongside the other params in
buildBaseParams and buildApiParams to prevent future drift.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ba653d51-2564-4455-97e1-c478712c9d2a

📥 Commits

Reviewing files that changed from the base of the PR and between 4955d96 and 3e487b1.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (83)
  • common/quota_math.go
  • common/quota_math_test.go
  • common/ssrf_protection.go
  • controller/log.go
  • controller/midjourney.go
  • controller/misc.go
  • controller/model_list_test.go
  • controller/oauth.go
  • controller/task.go
  • controller/task_video.go
  • controller/token_test.go
  • controller/user.go
  • dto/openai_image.go
  • go.mod
  • i18n/keys.go
  • i18n/locales/en.yaml
  • i18n/locales/zh-CN.yaml
  • i18n/locales/zh-TW.yaml
  • model/errors.go
  • model/log.go
  • model/log_test.go
  • model/main.go
  • model/midjourney.go
  • model/option.go
  • model/option_test.go
  • model/payment_method_guard_test.go
  • model/task.go
  • model/topup.go
  • model/user.go
  • model/user_update_test.go
  • pkg/billingexpr/billingexpr_test.go
  • pkg/billingexpr/round.go
  • relay/channel/ali/image.go
  • relay/channel/api_request.go
  • relay/channel/api_request_test.go
  • relay/channel/gemini/relay_responses.go
  • relay/channel/openai/audio.go
  • relay/channel/openai/helper.go
  • relay/channel/openai/relay_image.go
  • relay/channel/openai/responses_via_chat.go
  • relay/channel/task/ali/adaptor.go
  • relay/channel/task/gemini/billing.go
  • relay/channel/task/kling/adaptor.go
  • relay/common/relay_utils.go
  • relay/common/relay_utils_test.go
  • relay/helper/common.go
  • relay/helper/max_tokens_bounds_test.go
  • relay/helper/openai_image_request_test.go
  • relay/helper/price.go
  • relay/helper/stream_scanner.go
  • relay/helper/stream_scanner_test.go
  • relay/helper/valid_request.go
  • relay/relay_task.go
  • service/http_client.go
  • service/protected_fetch_client.go
  • service/protected_fetch_client_test.go
  • service/quota.go
  • service/task_billing.go
  • service/text_quota.go
  • service/text_quota_test.go
  • service/token_counter.go
  • service/tool_billing.go
  • setting/ratio_setting/group_ratio.go
  • setting/ratio_setting/group_ratio_test.go
  • setting/task_billing_setting/rate_card.go
  • tools/jsonwrapcheck/allowlist.txt
  • types/price_data.go
  • web/default/src/components/model-group-selector.tsx
  • web/default/src/features/usage-logs/components/common-logs-filter-bar.tsx
  • web/default/src/features/usage-logs/components/quota-filter-select.tsx
  • web/default/src/features/usage-logs/components/task-logs-filter-bar.tsx
  • web/default/src/features/usage-logs/constants.ts
  • web/default/src/features/usage-logs/lib/filter.ts
  • web/default/src/features/usage-logs/lib/utils.test.ts
  • web/default/src/features/usage-logs/lib/utils.ts
  • web/default/src/features/usage-logs/types.ts
  • web/default/src/i18n/locales/en.json
  • web/default/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/ja.json
  • web/default/src/i18n/locales/ru.json
  • web/default/src/i18n/locales/vi.json
  • web/default/src/i18n/locales/zh.json
  • web/default/src/routes/_authenticated/usage-logs/$section.tsx
💤 Files with no reviewable changes (1)
  • tools/jsonwrapcheck/allowlist.txt
📜 Review details
🧰 Additional context used
📓 Path-based instructions (10)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • dto/openai_image.go
  • i18n/keys.go
  • controller/task_video.go
  • controller/task.go
  • relay/channel/openai/responses_via_chat.go
  • common/quota_math.go
  • controller/token_test.go
  • relay/channel/openai/helper.go
  • relay/helper/max_tokens_bounds_test.go
  • relay/channel/task/kling/adaptor.go
  • model/errors.go
  • relay/channel/gemini/relay_responses.go
  • relay/channel/ali/image.go
  • controller/midjourney.go
  • relay/common/relay_utils_test.go
  • common/quota_math_test.go
  • relay/common/relay_utils.go
  • service/tool_billing.go
  • pkg/billingexpr/billingexpr_test.go
  • pkg/billingexpr/round.go
  • common/ssrf_protection.go
  • types/price_data.go
  • relay/channel/openai/audio.go
  • controller/log.go
  • service/quota.go
  • model/midjourney.go
  • relay/helper/stream_scanner_test.go
  • relay/channel/task/gemini/billing.go
  • service/token_counter.go
  • service/task_billing.go
  • controller/model_list_test.go
  • setting/task_billing_setting/rate_card.go
  • model/main.go
  • model/task.go
  • relay/channel/task/ali/adaptor.go
  • relay/channel/openai/relay_image.go
  • relay/helper/price.go
  • service/protected_fetch_client_test.go
  • model/topup.go
  • relay/helper/openai_image_request_test.go
  • model/payment_method_guard_test.go
  • relay/relay_task.go
  • service/text_quota_test.go
  • service/text_quota.go
  • relay/helper/common.go
  • controller/oauth.go
  • setting/ratio_setting/group_ratio.go
  • relay/helper/stream_scanner.go
  • service/http_client.go
  • controller/misc.go
  • relay/channel/api_request.go
  • setting/ratio_setting/group_ratio_test.go
  • relay/helper/valid_request.go
  • model/option.go
  • relay/channel/api_request_test.go
  • model/log.go
  • service/protected_fetch_client.go
  • controller/user.go
  • model/log_test.go
  • model/user_update_test.go
  • model/user.go
  • model/option_test.go
dto/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

For request structs parsed from client JSON and then re-marshaled to upstream providers, especially in relay/convert paths, optional scalar fields must use pointer types with omitempty so that absent fields stay omitted while explicit zero/false values are preserved.

Files:

  • dto/openai_image.go
web/default/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/default/AGENTS.md)

web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用 useTranslation() 取得 t,并通过 t() 渲染用户可见文本;子组件也应自行使用 useTranslation() 保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用 if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用 any,优先使用具体类型或 unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用 import type
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用 props.xxx 以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的 types 中。
在 React 中应合理使用 useMemouseCallbackReact.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态 import
React Query 的数据获取应使用 useQuery、变更应使用 useMutation;每个查询需配置唯一 queryKey,并在成功后对相关查询执行 invalidateQueries;服务端错误应统一交给 handleServerError
Axios 请求应使用项目统一的 api 实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用 handleServerError,展示层应使用 toast.error 等统一方式;文案需走 i18n;路由级错误应由 errorComponent 承接;表单错误应通过 form.setError 等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用 cn() 合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与 dark: 处理。
应使用语义化 HTML、正确关联 label 与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用 aria-hidden="true"
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用 dangerouslySetInnerHTML;跨域与 Cookie 需配合 withCredentials 并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过 .env 读取,并使用 VITE_ 前缀;代码中不得硬编码密钥。

Files:

  • web/default/src/routes/_authenticated/usage-logs/$section.tsx
  • web/default/src/features/usage-logs/lib/filter.ts
  • web/default/src/features/usage-logs/lib/utils.test.ts
  • web/default/src/features/usage-logs/constants.ts
  • web/default/src/components/model-group-selector.tsx
  • web/default/src/features/usage-logs/components/quota-filter-select.tsx
  • web/default/src/features/usage-logs/lib/utils.ts
  • web/default/src/features/usage-logs/types.ts
  • web/default/src/features/usage-logs/components/common-logs-filter-bar.tsx
  • web/default/src/features/usage-logs/components/task-logs-filter-bar.tsx
web/default/src/routes/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/default/AGENTS.md)

路由应使用 TanStack Router,并通过 createFileRoute 定义;搜索参数应使用 Zod schema + validateSearch 校验;认证与重定向应放在 beforeLoad 中;导航应优先使用 useNavigateLink,避免直接操作 window.location

Files:

  • web/default/src/routes/_authenticated/usage-logs/$section.tsx
web/default/src/features/**/lib/**/*.ts

📄 CodeRabbit inference engine (web/default/AGENTS.md)

表单应使用 React Hook Form + Zod:在功能模块的 lib/ 下定义 schema,并用 z.infer 导出表单类型;useForm 应配合 @hookform/resolvers/zod 进行校验。

Files:

  • web/default/src/features/usage-logs/lib/filter.ts
  • web/default/src/features/usage-logs/lib/utils.test.ts
  • web/default/src/features/usage-logs/lib/utils.ts
web/default/src/features/**

📄 CodeRabbit inference engine (web/default/AGENTS.md)

功能模块应放在 src/features/<feature>/,并按需包含 components/lib/hooks/api.tstypes.tsconstants.ts 等;通用组件应放在 src/components/,通用工具与类型应放在 src/lib/

Files:

  • web/default/src/features/usage-logs/lib/filter.ts
  • web/default/src/features/usage-logs/lib/utils.test.ts
  • web/default/src/features/usage-logs/constants.ts
  • web/default/src/features/usage-logs/components/quota-filter-select.tsx
  • web/default/src/features/usage-logs/lib/utils.ts
  • web/default/src/features/usage-logs/types.ts
  • web/default/src/features/usage-logs/components/common-logs-filter-bar.tsx
  • web/default/src/features/usage-logs/components/task-logs-filter-bar.tsx
relay/channel/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

When implementing a new channel, confirm whether the provider supports StreamOptions; if it does, add the channel to streamSupportedChannels.

Files:

  • relay/channel/openai/responses_via_chat.go
  • relay/channel/openai/helper.go
  • relay/channel/task/kling/adaptor.go
  • relay/channel/gemini/relay_responses.go
  • relay/channel/ali/image.go
  • relay/channel/openai/audio.go
  • relay/channel/task/gemini/billing.go
  • relay/channel/task/ali/adaptor.go
  • relay/channel/openai/relay_image.go
  • relay/channel/api_request.go
  • relay/channel/api_request_test.go
web/default/src/**/*.test.ts

📄 CodeRabbit inference engine (web/default/AGENTS.md)

工具函数与纯逻辑应优先编写单元测试;测试文件应命名为 *.test.ts

Files:

  • web/default/src/features/usage-logs/lib/utils.test.ts
pkg/billingexpr/**/*.{go,md}

📄 CodeRabbit inference engine (AGENTS.md)

When working on tiered/dynamic billing expression pricing, first read pkg/billingexpr/expr.md and ensure all code changes in the billing expression system follow the documented design, architecture, token normalization, quota conversion, and versioning patterns.

Files:

  • pkg/billingexpr/billingexpr_test.go
  • pkg/billingexpr/round.go
web/default/src/features/**/constants.ts

📄 CodeRabbit inference engine (web/default/AGENTS.md)

各 feature 的 constants.ts 中,成功/错误/提示类消息常量应仅保存 i18n 键,展示时必须通过 t() 渲染;状态/选项的 label 应统一使用 labelKeylabel(二选一且同一 feature 内保持一致);新增此类常量时应同步登记翻译键。

Files:

  • web/default/src/features/usage-logs/constants.ts
🪛 ast-grep (0.44.1)
i18n/keys.go

[warning] 91-91: A credential is hard-coded as a string literal. Secrets stored in source code, such as passwords, API keys, and tokens, can be leaked through version control or binaries and used by internal or external malicious actors. Rotate the exposed secret and load it at runtime from a secure secret vault, a Hardware Security Module (HSM), or an environment variable if permitted by your company policy (e.g. password := os.Getenv("APP_PASSWORD")).
Context: MsgUserPasswordUnset = "user.password_unset"
Note: [CWE-798] Use of Hard-coded Credentials.

(hardcoded-credentials-string-literal-go)


[warning] 92-92: A credential is hard-coded as a string literal. Secrets stored in source code, such as passwords, API keys, and tokens, can be leaked through version control or binaries and used by internal or external malicious actors. Rotate the exposed secret and load it at runtime from a secure secret vault, a Hardware Security Module (HSM), or an environment variable if permitted by your company policy (e.g. password := os.Getenv("APP_PASSWORD")).
Context: MsgUserPasswordResetLinkInvalid = "user.password_reset_link_invalid"
Note: [CWE-798] Use of Hard-coded Credentials.

(hardcoded-credentials-string-literal-go)

🪛 OSV Scanner (2.4.0)
go.mod

[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking key constraints not enforced in golang.org/x/crypto/ssh/agent

(GO-2026-5005)


[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking agent constraints dropped when forwarding keys in golang.org/x/crypto/ssh/agent

(GO-2026-5006)


[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking byte arithmetic causes underflow and panic in golang.org/x/crypto/ssh

(GO-2026-5013)


[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking bypass of certificate restrictions in golang.org/x/crypto/ssh

(GO-2026-5014)


[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking server panic during CheckHostKey/Authenticate in golang.org/x/crypto/ssh

(GO-2026-5015)


[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking memory leak when rejecting channels can lead to DoS in golang.org/x/crypto/ssh

(GO-2026-5016)


[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking client can cause server deadlock on unexpected responses in golang.org/x/crypto/ssh

(GO-2026-5017)


[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking pathological RSA/DSA parameters may cause DoS in golang.org/x/crypto/ssh

(GO-2026-5018)


[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking bypass of FIDO/U2F security keys physical interaction in golang.org/x/crypto/ssh

(GO-2026-5019)


[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking infinite loop on large channel writes in golang.org/x/crypto/ssh

(GO-2026-5020)


[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking auth bypass via unenforced @revoked status in golang.org/x/crypto/ssh/knownhosts

(GO-2026-5021)


[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking VerifiedPublicKeyCallback permissions skip enforcement in golang.org/x/crypto/ssh

(GO-2026-5023)


[LOW] 52-52: golang.org/x/crypto 0.51.0: Invoking pathological inputs can lead to client panic in golang.org/x/crypto/ssh/agent

(GO-2026-5033)


[LOW] 53-53: golang.org/x/image 0.41.0: Panic when decoding large WEBP image on 32-bit platforms in golang.org/x/image

(GO-2026-4961)


[LOW] 53-53: golang.org/x/image 0.41.0: Panic on VP8 alpha channel size mismatch in x/image/webp in golang.org/x/image

(GO-2026-5061)


[LOW] 53-53: golang.org/x/image 0.41.0: Lack of limit on tile sizes in x/image/tiff in golang.org/x/image

(GO-2026-5062)


[LOW] 53-53: golang.org/x/image 0.41.0: Panic decoding image with out-of-bounds strip offset in x/image/tiff in golang.org/x/image

(GO-2026-5066)

🔇 Additional comments (91)
common/ssrf_protection.go (1)

282-284: LGTM!

Also applies to: 299-301, 425-428

service/protected_fetch_client.go (1)

23-115: LGTM!

service/http_client.go (1)

109-113: LGTM!

Also applies to: 126-126, 139-144

service/protected_fetch_client_test.go (1)

16-225: LGTM!

relay/common/relay_utils_test.go (1)

56-117: LGTM!

relay/channel/task/ali/adaptor.go (1)

512-526: LGTM!

Also applies to: 552-572, 779-781

relay/channel/task/gemini/billing.go (1)

53-66: LGTM!

dto/openai_image.go (1)

14-16: LGTM!

relay/helper/valid_request.go (4)

169-175: LGTM! Bounds check correctly guards both multipart and JSON n paths against dto.MaxImageN, with negative values already rejected by the *uint type in the JSON path.

Also applies to: 214-217


118-125: LGTM! exceedsMaxTokensLimit cleanly consolidates the previously ad-hoc token bound checks and is consistently applied across Responses/Claude/Text validators, matching the added test coverage.

Also applies to: 139-141, 266-268, 291-293


116-117: 🎯 Functional Correctness

No change needed
relay/helper/valid_request.go already imports math, so math.MaxInt32 compiles as written.

			> Likely an incorrect or invalid review comment.

344-346: 🩺 Stability & Availability

No issue here: GenerationConfig is a value field, so omitting generationConfig leaves the zero value and this access is safe.

			> Likely an incorrect or invalid review comment.
relay/channel/ali/image.go (1)

57-59: LGTM! Necessary check since AliImageParameters.N is a signed int sourced from arbitrary Extra["parameters"] JSON and can otherwise carry negative values that bypass the top-level *uint validation in valid_request.go.

relay/helper/max_tokens_bounds_test.go (1)

1-67: LGTM! Good coverage of exceedsMaxTokensLimit across all four request validators, with a boundary value correctly chosen just above maxTokensLimit.

relay/helper/openai_image_request_test.go (1)

1-83: LGTM! Covers both JSON and multipart n validation paths, including boundary (MaxImageN), default, and negative-value cases.

go.mod (1)

7-8: LGTM!

controller/token_test.go (1)

552-557: LGTM!

Also applies to: 633-638

web/default/src/components/model-group-selector.tsx (1)

61-65: LGTM!

controller/oauth.go (1)

4-4: LGTM!

Also applies to: 110-125, 267-273, 288-288, 314-314, 359-364

controller/misc.go (1)

4-11: LGTM!

Also applies to: 242-246, 285-287, 307-312, 323-327, 341-364

controller/user.go (1)

32-36: LGTM!

Also applies to: 192-197, 211-224, 247-250, 635-639, 812-819, 836-855, 1129-1129, 1145-1149

model/topup.go (1)

441-441: LGTM!

Also applies to: 469-472, 492-516

controller/model_list_test.go (1)

17-21: LGTM!

Also applies to: 246-285, 287-323

model/user_update_test.go (1)

6-18: LGTM!

Also applies to: 57-134, 171-204, 259-345, 375-523

model/payment_method_guard_test.go (1)

315-347: LGTM!

model/log.go (2)

94-124: LGTM!


856-862: 🎯 Functional Correctness

Confirm the retry-filter type-scoping change is intentional.

This replaces the previous else if !isRetryLogFilter(logFilter) with an unconditional else, so when logType == LogTypeUnknown the LogTypeConsume constraint is now always applied — including when a retry filter (LogFilterRetry/LogFilterErrorRetry/LogFilterEmptyRetry) is active. Previously, retry-filtered queries with LogTypeUnknown had no type constraint at all, meaning non-consume logs bearing a retry_log marker (e.g., LogTypeTopup) could leak into retry-filtered stats/logs.

The new TestSumUsedQuotaRetryFilterIgnoresNonConsumeQuota test confirms and validates this new behavior, so it appears intentional and correct. However, this control-flow change is unrelated to the quota-filter feature described for this layer and isn't called out in the AI summary or line-range description as a standalone fix — worth flagging to ensure it was a deliberate decision and not an incidental side effect of refactoring this block while adding applyQuotaFilter.

model/log_test.go (1)

27-413: LGTM!

model/midjourney.go (1)

29-35: LGTM!

Also applies to: 37-63, 65-94, 189-207, 210-225

web/default/src/features/usage-logs/types.ts (1)

71-76: LGTM!

Also applies to: 305-320, 339-352, 364-372, 378-386

web/default/src/features/usage-logs/components/quota-filter-select.tsx (1)

1-87: LGTM!

web/default/src/features/usage-logs/components/common-logs-filter-bar.tsx (1)

46-46: LGTM!

Also applies to: 58-62, 113-116, 137-137, 165-169, 180-180, 203-211, 325-334, 396-396, 406-413

web/default/src/features/usage-logs/lib/filter.ts (1)

46-46: LGTM!

model/task.go (1)

163-173: LGTM!

Also applies to: 215-296, 458-518

controller/log.go (1)

15-38: LGTM!

Also applies to: 69-91, 160-187, 189-217

controller/midjourney.go (1)

257-281: LGTM!

Also applies to: 283-307

controller/task.go (1)

22-44: LGTM!

Also applies to: 46-69

web/default/src/features/usage-logs/components/task-logs-filter-bar.tsx (1)

25-25: LGTM!

Also applies to: 35-39, 94-98, 118-118, 142-163, 180-188, 222-254

web/default/src/routes/_authenticated/usage-logs/$section.tsx (1)

22-25: LGTM!

Also applies to: 54-54

web/default/src/features/usage-logs/lib/utils.test.ts (1)

110-142: LGTM!

web/default/src/i18n/locales/en.json (1)

116-116: LGTM!

Also applies to: 319-319, 2831-2831, 5172-5172

web/default/src/i18n/locales/fr.json (1)

116-116: LGTM!

Also applies to: 319-319, 2831-2831, 5172-5172

web/default/src/i18n/locales/ja.json (1)

116-116: LGTM!

Also applies to: 319-319, 2831-2831, 5172-5172

web/default/src/i18n/locales/vi.json (1)

116-116: LGTM!

Also applies to: 319-319, 2831-2831, 5172-5172

web/default/src/i18n/locales/zh.json (1)

116-116: LGTM!

Also applies to: 319-319, 2831-2831, 5172-5172

relay/channel/api_request.go (1)

67-68: LGTM!

Also applies to: 405-461, 463-500, 518-530, 599-601

relay/channel/api_request_test.go (1)

8-13: LGTM!

Also applies to: 96-112, 253-283, 402-447

relay/helper/stream_scanner.go (1)

28-28: LGTM!

Also applies to: 44-49, 70-91, 109-143, 154-166, 191-202, 214-220, 290-290

relay/helper/stream_scanner_test.go (1)

5-5: LGTM!

Also applies to: 24-35, 59-95

relay/helper/common.go (3)

28-30: LGTM!

Also applies to: 115-117


61-75: 🩺 Stability & Availability | ⚡ Quick win

Silent context-done handling okay, but confirm this is acceptable.

ClaudeData returns nil (its declared error) and ClaudeChunkData (void) silently no-op when the context is done, whereas ResponseChunkData/StringData/PingData all surface a "request context done" error to the caller. This is asymmetric but plausibly intentional since these two functions' errors already appear to be discarded by callers. Confirm no caller relies on the error/return of ClaudeData to detect client disconnects (e.g., for StreamStatus.SetEndReason), otherwise disconnects on the Claude data path won't be recorded the way they now are on the Responses path.

Also applies to: 77-85


87-95: LGTM! ResponseChunkData correctly returns FlushWriter(c)'s error instead of discarding it, enabling callers to detect failed/short-circuited writes.

relay/channel/gemini/relay_responses.go (1)

92-95: LGTM! Correctly propagates ResponseChunkData's error and stops emitting further events.

relay/channel/openai/relay_image.go (1)

288-301: LGTM! writeOpenaiImageStreamPayload/writeOpenaiImageStreamDone correctly return the helper errors, and the unchanged caller (lines 265-277) already handles them to mark StreamEndReasonClientGone.

relay/channel/openai/responses_via_chat.go (1)

77-80: LGTM! Correctly checks ResponseChunkData's error and stops the stream via sr.Stop(streamErr) at the call site.

web/default/src/i18n/locales/ru.json (1)

116-116: LGTM!

Also applies to: 319-319, 2831-2831, 5172-5172

common/quota_math.go (1)

1-21: LGTM!

common/quota_math_test.go (1)

10-18: LGTM!

pkg/billingexpr/round.go (1)

8-23: LGTM!

service/token_counter.go (1)

199-217: LGTM!

Also applies to: 376-396

types/price_data.go (1)

33-41: LGTM!

relay/helper/price.go (2)

116-121: LGTM!


202-211: 🗄️ Data Integrity & Integration

The int32 ceiling is intentional here. Quota values are capped to match the 32-bit quota columns, so math.MaxInt32/math.MinInt32 is consistent with the persisted schema.

			> Likely an incorrect or invalid review comment.
relay/relay_task.go (3)

129-136: LGTM!


219-225: LGTM!


360-377: LGTM!

service/quota.go (1)

50-87: LGTM!

service/text_quota.go (2)

141-155: LGTM!


288-313: LGTM!

service/text_quota_test.go (2)

21-26: LGTM!


613-621: LGTM!

setting/task_billing_setting/rate_card.go (1)

80-80: LGTM!

Also applies to: 124-126, 135-137, 219-238

relay/channel/openai/audio.go (1)

106-107: LGTM!

relay/channel/task/kling/adaptor.go (1)

505-506: LGTM!

controller/task_video.go (1)

192-192: LGTM!

service/task_billing.go (2)

311-311: LGTM!


218-230: 🗄️ Data Integrity & Integration

No double-settlement path here RecalculateTaskQuota runs only after the task is moved to a terminal status under the CAS guard, and the polling scans exclude SUCCESS/FAILURE tasks. A failed UpdateQuota() can leave the persisted quota stale, but it won’t cause the same task to be settled again.

			> Likely an incorrect or invalid review comment.
model/option.go (1)

214-218: LGTM!

Also applies to: 247-261, 276-292, 332-335

setting/ratio_setting/group_ratio.go (2)

150-168: 🗄️ Data Integrity & Integration | ⚡ Quick win

Duplicate keys that collide after trimming silently overwrite each other non-deterministically.

If the input JSON has two distinct raw keys that trim to the same name (e.g. {"vip":0.5," vip ":0.9}), the loop writes both into normalized[trimmedName], and Go's randomized map iteration order means whichever key is visited last wins — non-deterministically across calls/process runs. Since this value feeds directly into billing (GetGroupRatio is multiplied into quota calculations), an ambiguous admin input could silently produce different effective ratios between the moment of validation (CheckGroupRatio) and the moment of application (UpdateGroupRatioByJSONString), or across replicas.

Consider detecting the collision and returning an error instead of silently picking one.

🛡️ Proposed fix
 	normalized := make(map[string]float64, len(checkGroupRatio))
 	for name, ratio := range checkGroupRatio {
 		trimmedName := strings.TrimSpace(name)
 		if isReservedAutoRouteGroupName(trimmedName) {
 			continue
 		}
 		if ratio < 0 {
 			return nil, errors.New("group ratio must be not less than 0: " + trimmedName)
 		}
+		if _, exists := normalized[trimmedName]; exists {
+			return nil, errors.New("duplicate group ratio name after trimming: " + trimmedName)
+		}
 		normalized[trimmedName] = ratio
 	}

84-98: LGTM!

Also applies to: 133-148, 170-183

model/option_test.go (1)

47-99: LGTM!

setting/ratio_setting/group_ratio_test.go (1)

9-48: LGTM!

i18n/keys.go (1)

91-93: 📐 Maintainability & Code Quality

Static analysis false positive.

The hardcoded-credentials-string-literal-go warnings on MsgUserPasswordUnset/MsgUserPasswordResetLinkInvalid are false positives — these are i18n message key identifiers, not credentials.

Source: Linters/SAST tools

model/errors.go (1)

12-16: LGTM!

i18n/locales/en.yaml (1)

79-81: LGTM!

i18n/locales/zh-CN.yaml (1)

43-43: LGTM!

Also applies to: 80-82

i18n/locales/zh-TW.yaml (1)

80-82: LGTM!

model/user.go (3)

219-269: LGTM!

Also applies to: 585-638, 917-1000, 1069-1127


693-713: 🎯 Functional Correctness

No issue: InsertWithTx is only invoked inside WithNormalizedEmailWriteTx, so the named lock stays on the pinned connection through commit.

			> Likely an incorrect or invalid review comment.

32-32: 🗄️ Data Integrity & Integration

Clarify whether deleted emails should stay reserved
emailQuery() uses Unscoped(), so a soft-deleted user's email still counts as taken. If re-registration after delete should be allowed, this lookup needs to exclude soft-deleted rows; otherwise the current behavior is fine.

model/main.go (1)

314-316: LGTM!

Also applies to: 392-394, 408-419

Comment thread go.mod Outdated
Comment thread model/log.go
Comment thread model/log.go Outdated
Comment thread model/task.go
Comment on lines +408 to +411
func (t *Task) UpdateQuota() error {
return DB.Model(t).Update("quota", t.Quota).Error
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

UpdateQuota correctly scopes by primary key.

DB.Model(t).Update("quota", t.Quota) relies on GORM using t's primary key to build the WHERE clause, which is standard GORM behavior. No test coverage for this new method or the QuotaFilter wiring was included in the provided files — consider adding coverage alongside the existing TestLogQuotaFilters pattern mentioned for model/log_test.go.

🤖 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 `@model/task.go` around lines 408 - 411, Add test coverage for the new quota
update path and filter wiring. Use the existing model test patterns, especially
the `TestLogQuotaFilters` style in `model/log_test.go`, to verify `UpdateQuota`
updates the record scoped by the task primary key and that `QuotaFilter` is
applied as expected. Reference `Task.UpdateQuota` and the `QuotaFilter` setup
when adding the tests so the new behavior stays covered.

Comment thread model/user.go Outdated
Comment thread relay/channel/ali/image.go Outdated
Comment thread relay/common/relay_utils.go
Comment thread relay/helper/common.go
Comment thread setting/ratio_setting/group_ratio.go
Comment thread web/default/src/features/usage-logs/constants.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

🤖 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 `@dto/openai_image.go`:
- Around line 18-26: ValidateImageN currently rejects values outside [0,
MaxImageN], but its error text in ValidateImageN says the lower bound is 1,
which conflicts with the actual accepted range and caller behavior. Update the
validation message to reflect the real bounds in ValidateImageN, keeping the
existing field handling and MaxImageN check unchanged so API consumers see the
correct valid range.

In `@go.mod`:
- Line 53: The dependency on golang.org/x/image in go.mod is still on a
vulnerable version, so update that module requirement to v0.43.0 or newer. Make
the change in the existing dependency entry for golang.org/x/image and keep the
rest of the module file unchanged.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5c4305f6-e558-49bc-b908-88a0f21cfe31

📥 Commits

Reviewing files that changed from the base of the PR and between 3e487b1 and fba1735.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (30)
  • controller/discord.go
  • controller/github.go
  • controller/linuxdo.go
  • controller/log.go
  • controller/oidc.go
  • controller/telegram.go
  • controller/user.go
  • controller/wechat.go
  • dto/openai_image.go
  • dto/openai_image_test.go
  • go.mod
  • model/log.go
  • model/log_test.go
  • model/task_cas_test.go
  • model/user.go
  • model/user_update_test.go
  • relay/channel/ali/image.go
  • relay/channel/task/ali/adaptor.go
  • relay/channel/task/ali/adaptor_kling_test.go
  • relay/channel/task/ali/adaptor_wan27_test.go
  • relay/common/relay_info.go
  • relay/common/relay_info_test.go
  • relay/common/relay_utils.go
  • relay/common/relay_utils_test.go
  • relay/helper/common.go
  • relay/helper/common_test.go
  • relay/helper/valid_request.go
  • setting/ratio_setting/group_ratio.go
  • setting/ratio_setting/group_ratio_test.go
  • web/default/src/features/usage-logs/constants.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • controller/log.go
  • relay/channel/ali/image.go
  • controller/telegram.go
  • controller/wechat.go
  • controller/discord.go
  • dto/openai_image.go
  • relay/common/relay_info.go
  • controller/oidc.go
  • relay/helper/common_test.go
  • relay/channel/task/ali/adaptor_kling_test.go
  • relay/channel/task/ali/adaptor_wan27_test.go
  • model/task_cas_test.go
  • controller/linuxdo.go
  • dto/openai_image_test.go
  • controller/github.go
  • relay/channel/task/ali/adaptor.go
  • setting/ratio_setting/group_ratio_test.go
  • relay/common/relay_utils_test.go
  • relay/helper/common.go
  • relay/helper/valid_request.go
  • relay/common/relay_info_test.go
  • relay/common/relay_utils.go
  • setting/ratio_setting/group_ratio.go
  • controller/user.go
  • model/log.go
  • model/log_test.go
  • model/user_update_test.go
  • model/user.go
relay/channel/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

When implementing a new channel, confirm whether the provider supports StreamOptions; if it does, add the channel to streamSupportedChannels.

Files:

  • relay/channel/ali/image.go
  • relay/channel/task/ali/adaptor_kling_test.go
  • relay/channel/task/ali/adaptor_wan27_test.go
  • relay/channel/task/ali/adaptor.go
dto/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

For request structs parsed from client JSON and then re-marshaled to upstream providers, especially in relay/convert paths, optional scalar fields must use pointer types with omitempty so that absent fields stay omitted while explicit zero/false values are preserved.

Files:

  • dto/openai_image.go
  • dto/openai_image_test.go
web/default/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/default/AGENTS.md)

web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用 useTranslation() 取得 t,并通过 t() 渲染用户可见文本;子组件也应自行使用 useTranslation() 保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用 if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用 any,优先使用具体类型或 unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用 import type
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用 props.xxx 以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的 types 中。
在 React 中应合理使用 useMemouseCallbackReact.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态 import
React Query 的数据获取应使用 useQuery、变更应使用 useMutation;每个查询需配置唯一 queryKey,并在成功后对相关查询执行 invalidateQueries;服务端错误应统一交给 handleServerError
Axios 请求应使用项目统一的 api 实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用 handleServerError,展示层应使用 toast.error 等统一方式;文案需走 i18n;路由级错误应由 errorComponent 承接;表单错误应通过 form.setError 等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用 cn() 合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与 dark: 处理。
应使用语义化 HTML、正确关联 label 与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用 aria-hidden="true"
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用 dangerouslySetInnerHTML;跨域与 Cookie 需配合 withCredentials 并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过 .env 读取,并使用 VITE_ 前缀;代码中不得硬编码密钥。

Files:

  • web/default/src/features/usage-logs/constants.ts
web/default/src/features/**/constants.ts

📄 CodeRabbit inference engine (web/default/AGENTS.md)

各 feature 的 constants.ts 中,成功/错误/提示类消息常量应仅保存 i18n 键,展示时必须通过 t() 渲染;状态/选项的 label 应统一使用 labelKeylabel(二选一且同一 feature 内保持一致);新增此类常量时应同步登记翻译键。

Files:

  • web/default/src/features/usage-logs/constants.ts
web/default/src/features/**

📄 CodeRabbit inference engine (web/default/AGENTS.md)

功能模块应放在 src/features/<feature>/,并按需包含 components/lib/hooks/api.tstypes.tsconstants.ts 等;通用组件应放在 src/components/,通用工具与类型应放在 src/lib/

Files:

  • web/default/src/features/usage-logs/constants.ts
🔇 Additional comments (33)
relay/channel/ali/image.go (1)

57-59: 🎯 Functional Correctness

Addressed: shared N-bounds validator extracted.

This resolves the previously raised duplication concern by centralizing the check in dto.ValidateImageN.

relay/helper/common.go (1)

61-107: 🩺 Stability & Availability

Addressed: nil/writer guards added per prior review, and flush error now propagated.

Matches the previously requested fix (nil c/c.Writer guard on ClaudeData, ClaudeChunkData, ResponseChunkData), and ResponseChunkData now returns FlushWriter(c)'s error instead of discarding it.

controller/log.go (2)

15-53: LGTM!

Also applies to: 84-120, 189-227, 229-268


28-44: 🎯 Functional Correctness

quota_filter is normalized to fixed values and applied with bound parameters, so this path is not vulnerable to SQL injection.

			> Likely an incorrect or invalid review comment.
controller/telegram.go (1)

60-61: LGTM!

controller/wechat.go (1)

171-172: LGTM!

controller/discord.go (1)

213-214: LGTM!

relay/common/relay_info.go (1)

736-749: 🎯 Functional Correctness

ResolvedSeconds is already guarded at runtime. The only production callers either use ResolvedSecondsOrDefault or run validateTaskDurationBounds, which rejects negative values before they can propagate.

			> Likely an incorrect or invalid review comment.
relay/helper/common_test.go (1)

1-22: LGTM!

relay/channel/task/ali/adaptor_kling_test.go (1)

90-141: LGTM!

relay/channel/task/ali/adaptor_wan27_test.go (1)

47-94: LGTM!

model/task_cas_test.go (1)

247-324: LGTM!

relay/common/relay_utils_test.go (1)

56-127: LGTM!

relay/common/relay_info_test.go (1)

43-84: 🎯 Functional Correctness

Explicit zero duration falls back to the default here

controller/oidc.go (1)

218-218: 🎯 Functional Correctness

No change needed UpdateFields already scopes the write by user.Id and only applies the requested field(s), so this path is fine.

			> Likely an incorrect or invalid review comment.
controller/github.go (1)

209-210: 🎯 Functional Correctness

Same UpdateFields verification as controller/linuxdo.go.

Same scoped-update pattern as LinuxDoBind; verification of UpdateFields semantics applies here too.

dto/openai_image_test.go (1)

10-21: LGTM!

web/default/src/features/usage-logs/constants.ts (1)

159-161: LGTM! Derivation from QUOTA_FILTER_VALUES resolves the previously-flagged drift risk between the filter list and the route's zod enum.

relay/channel/task/ali/adaptor.go (2)

513-517: LGTM! Consolidating duration parsing into ResolvedSecondsOrDefault removes duplicated strconv.Atoi/error-wrapping logic.


542-555: LGTM! The refactor mirrors the pattern in convertToAliRequest. The initial Duration: 5 in the struct literal (line 545) is now redundant since it's unconditionally overwritten right after, but this is harmless dead code not worth a separate fix.

go.mod (1)

52-52: LGTM! golang.org/x/crypto v0.52.0 resolves all previously-flagged OSV advisories (GO-2026-5005/5006/5013-5021/5023/5033), addressing the prior review comment.

setting/ratio_setting/group_ratio_test.go (1)

34-50: LGTM!

controller/linuxdo.go (1)

68-69: 🎯 Functional Correctness

No issue: UpdateFields uses the same updateWithTx path and cache refresh as Update, so this LinuxDO ID-only write keeps the existing behavior.

relay/helper/valid_request.go (1)

169-178: LGTM!

Also applies to: 217-221

relay/common/relay_utils.go (1)

119-128: LGTM!

Also applies to: 186-190, 209-211

setting/ratio_setting/group_ratio.go (1)

76-83: LGTM!

Also applies to: 101-113

controller/user.go (2)

391-391: LGTM!

Also applies to: 441-441, 805-833


1092-1099: 🩺 Stability & Availability

Delete does not reach the shared update path. case "delete" returns immediately after user.Delete(), so UpdateFields(false, updateFields...) only runs for enable/disable/promote/demote.

			> Likely an incorrect or invalid review comment.
model/log.go (1)

36-42: LGTM!

Also applies to: 100-116, 657-695, 746-786, 826-880

model/log_test.go (1)

27-32: LGTM!

Also applies to: 206-266

model/user_update_test.go (1)

171-204: LGTM!

Also applies to: 206-232

model/user.go (2)

21-46: LGTM!

Also applies to: 59-59, 667-717, 773-799, 910-958


801-837: 🗄️ Data Integrity & Integration

No lost-update here copyUnspecifiedUserUpdateValues does not write quota, used_quota, or request_count, so this update path does not overwrite those accounting fields.

			> Likely an incorrect or invalid review comment.

Comment thread dto/openai_image.go
Comment thread go.mod Outdated
@CSCITech
CSCITech merged commit 5dca8cf into main Jul 7, 2026
3 checks passed
This was referenced Jul 8, 2026
This was referenced Jul 15, 2026
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.

1 participant