feat(server/devices): users.max_devices_override 单用户设备上限覆盖(NULL走套餐默认)+ 迁移000025
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 23s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 16s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 39s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 19s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 36s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 3s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 4s
ci-pangolin / Go — build + test (pull_request) Failing after 13s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 10s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 5m8s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 19s
ci-pangolin / Lint — shellcheck (pull_request) Failing after 13m37s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 23s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 16s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 39s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 19s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 36s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 3s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 4s
ci-pangolin / Go — build + test (pull_request) Failing after 13s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 10s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 5m8s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 19s
ci-pangolin / Lint — shellcheck (pull_request) Failing after 13m37s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
This commit is contained in:
@@ -450,7 +450,21 @@ func (svc *Service) ResolvePlan(ctx context.Context, userID int64) (Plan, *apier
|
||||
if err != nil {
|
||||
return Plan{}, apierr.ErrInternal
|
||||
}
|
||||
return resolveEffectivePlan(time.Now().UTC(), status, subs, free)
|
||||
plan, apiErr := resolveEffectivePlan(time.Now().UTC(), status, subs, free)
|
||||
if apiErr != nil {
|
||||
return Plan{}, apiErr
|
||||
}
|
||||
// Per-user device-cap override (migration 000025, users.max_devices_override):
|
||||
// NULL/0 = no override, keep the plan-derived cap resolved above. Applied
|
||||
// once here — the single funnel both the subscription path and the free
|
||||
// fallback flow through — so every consumer (subscription middleware,
|
||||
// /v1/me, CheckDeviceLimit) sees it uniformly.
|
||||
if override, ok, err := svc.store.GetMaxDevicesOverride(ctx, userID); err != nil {
|
||||
return Plan{}, apierr.ErrInternal
|
||||
} else if ok {
|
||||
plan.MaxDevices = override
|
||||
}
|
||||
return plan, nil
|
||||
}
|
||||
|
||||
// CheckDeviceLimit prunes stale devices (best-effort churn cleanup), resolves the
|
||||
|
||||
Reference in New Issue
Block a user