508 Commits

Author SHA1 Message Date
lyen1688
f597c1581b feat(group): 支持自定义 /v1/models 模型列表 2026-05-27 18:00:45 +08:00
DaydreamCoding
11fe7de926 fix(account): 重新授权不再清空 Extra 配置
Claude / OpenAI 账号重新授权走通用 PUT /accounts/:id 时,后端
UpdateAccount 会全量覆盖 account.Extra(仅保留 5 个 quota 用量键),
导致 base_rpm / window_cost_limit / window_cost_sticky_reserve /
max_sessions / quota_* / privacy_mode 等持久化配置全部丢失。

新增专用接口 POST /accounts/:id/apply-oauth-credentials,沿用
现有 /refresh 路径模式:Credentials-only update + Extra JSONB
key 级合并(UpdateAccountExtra) + ClearError + InvalidateToken。

作用域:Claude OAuth / Claude Cookie auth / OpenAI OAuth 三个
调用点。Gemini / Antigravity 现有路径本就不传 extra,保持不变。

顺带修复:旧重新授权路径未调用 InvalidateToken,导致重新授权后
首请求可能仍用缓存中的旧 token 而立即 401。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 19:46:08 +08:00
Wesley Liddick
bebc082306
Merge pull request #2766 from DaydreamCoding/feat/user-platform-quota
feat(quota): 用户 × 平台 USD 配额
2026-05-26 14:13:18 +08:00
lyen1688
23f3d426c6 feat: 支持内容审计风险阈值配置 2026-05-26 13:58:02 +08:00
DaydreamCoding
6b39b344d8 feat(quota): 用户 × 平台 USD 配额
为用户在 anthropic/openai/gemini/antigravity 四个平台上提供日/周/月
三个窗口的 USD 配额管控。配额语义:未设置=不限制,0=禁用,>0=美元上限。

两层模型:
- 配置层:系统默认配额,以及 email/linuxdo/oidc/wechat/github/google/
  dingtalk 七个鉴权来源的默认配额,存于 settings,以嵌套 JSON 整体读写
  (系统 1 个 key + 每个来源 1 个 key),整体替换语义。
- 运行时层:user_platform_quota 表按用户记录实际配额,与配置层解耦。

后端:新增 ent schema 与 140_user_platform_quotas.sql 迁移、repository
与 service 端口、计费链路集成、管理端与用户端读写接口。
前端:管理端设置页配额编辑、用户配额管理 Modal、用户 Dashboard 展示、
中英文案。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 10:49:20 +08:00
wucm667
0d5c6f7cc7 feat(risk-control): 内容审计支持按模型生效 2026-05-21 21:18:43 +08:00
shaw
a613a587ba feat: add subscription expiry email toggle 2026-05-21 14:27:50 +08:00
Wesley Liddick
eda04c6129
Merge pull request #2615 from wucm667/feat/redeem-code-batch-update
feat(redeem): 兑换码支持批量修改
2026-05-21 10:39:46 +08:00
lyen1688
08c8c67df7 为 API Key ACL 增加反代真实 IP 开关 2026-05-20 22:51:46 +08:00
wucm667
3263ca63c7 feat(redeem): add redeem code batch update 2026-05-20 16:08:41 +08:00
Wesley Liddick
378a0a6a61
Merge pull request #2599 from Arron196/feature/email-template-editor
feat: 添加邮件模板编辑器与通知邮件模板化
2026-05-20 15:12:57 +08:00
shaw
878ad3b569 feat(openai-gateway): Codex OAuth 账号浏览器 UA 自动改写规避 Cloudflare
质询
2026-05-20 14:33:51 +08:00
shaw
91da815993 feat(risk-control): 内容审计新增关键词拦截 2026-05-20 11:13:53 +08:00
benjamin
88346b4d53 feat(admin): 添加邮件模板管理接口
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-20 11:09:18 +08:00
Wesley Liddick
03730fbcf3
Merge pull request #2585 from Arron196/feature/channel-monitor-openai-detection
优化渠道监控 OpenAI 检测协议与内置模板
2026-05-20 08:50:44 +08:00
Wesley Liddick
74e35a0150
Merge pull request #2582 from wucm667/feat/channel-pricing-sync-models
feat(channels): 模型定价支持一键同步最新模型
2026-05-20 08:43:10 +08:00
Wesley Liddick
44c13e7a73
Merge pull request #2578 from wucm667/feat/payment-force-qrcode
feat(payment): 支持强制移动端统一使用二维码支付
2026-05-20 08:41:29 +08:00
benjamin
917bd877ae feat(channel-monitor): 暴露 API 模式接口字段
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-19 22:05:43 +08:00
wucm667
92ad68a314 feat(channels): 模型定价支持一键同步最新模型
从 LiteLLM 定价目录中读取指定平台的最新模型列表,
将尚未录入的模型以新定价条目(价格留空)的形式追加,
管理员只需点击同步最新模型按钮即可完成操作。

- backend/service: PricingService 新增 ListModelNamesByProvider
- backend/handler: ChannelHandler 新增 SyncPricingModels (GET /api/v1/admin/channels/pricing/sync-models)
- backend/routes: 注册新路由(在 /:id 通配符之前)
- backend/wire_gen: 手动更新 NewChannelHandler 调用
- frontend/api: channels.ts 新增 syncPricingModels
- frontend/i18n: zh.ts / en.ts 新增 5 个 key
- frontend/view: ChannelsView 定价区域标题行新增「同步最新模型」按钮
- tests: pricing_service_test + channel_handler_test 新增单元测试
2026-05-19 20:32:32 +08:00
name
2eb622f2f6 Remove ops retry replay storage 2026-05-19 19:37:41 +08:00
wucm667
e4c7927eff feat(payment): 支持强制移动端统一使用二维码支付 2026-05-19 18:22:12 +08:00
Wesley Liddick
21ae52c01f
Merge pull request #2571 from sherlockwhite/fix/openai-account-email-and-usage-refresh
fix(accounts): show email and fix usage refresh for OpenAI OAuth accounts
2026-05-19 16:56:26 +08:00
Wesley Liddick
2a242aec0f
Merge pull request #2573 from wucm667/feat/redeem-code-expiry
feat(redeem): 兑换码支持设置使用有效期
2026-05-19 16:25:12 +08:00
Wesley Liddick
a929e285ce
Merge pull request #2271 from StarryKira/fix/redact-account-credentials
fix(security): 屏蔽 admin 账号接口返回的敏感凭证字段
2026-05-19 16:15:36 +08:00
wucm667
e4aaf0af29 feat(redeem): 兑换码支持设置使用有效期 2026-05-19 15:53:28 +08:00
chenjian
41e7ae534c fix(accounts): fix OpenAI OAuth usage quota never refreshing on manual refresh
The refresh button had no effect because two independent gates blocked
the Codex probe:

1. isOpenAICodexSnapshotStale returned false for non-WS-v2 accounts even
   when data was stale — this is correct for background auto-refresh (Codex
   quota is only auto-tracked for Codex CLI / WS v2 accounts), so this
   behavior is preserved.

2. shouldProbeOpenAICodexSnapshot had a 10-min in-memory rate limit with
   no bypass for explicit user requests.

Fix: add a force parameter threaded from handler → GetUsage → getOpenAIUsage
→ shouldProbeOpenAICodexSnapshot. When force=true (manual refresh button),
both gates are bypassed and the probe always runs. Background auto-loads
continue to respect the original WS v2 logic and 10-min rate limit.
2026-05-19 15:43:21 +08:00
Wesley Liddick
1b6ed24c33
Merge pull request #2492 from DaydreamCoding/feat/dingtalk-login
feat(dingtalk): 钉钉 OAuth 登录接入 + internal_only 用户属性同步
2026-05-19 15:36:13 +08:00
DaydreamCoding
b19da9c7fe feat(dingtalk): 钉钉 OAuth 登录接入与 internal_only 用户属性同步
⚠️ 应用类型约束:当前实现仅支持「钉钉登录-企业内部应用」(DingTalk 开放平台
internal_app 类型)。第三方个人应用、第三方企业应用类型暂不支持——OAuth 流程
相同但 corp 校验、跨企业行为不同。backend 通过 DingTalkAppKind 校验对非
internal_app 类型 fail-closed(硬约束)。

钉钉 OAuth 登录主链
- 4 步 OAuth 链:ExchangeCodeForUserToken / GetUnionIdByUserToken /
  GetUserIdByUnionId / GetStaffInfoByUserId;app token 缓存
- pending session 机制持久化 OAuth 中间态;cookie-only token 持久化
- 三种分流:bind_login_required / email_completion / choose_account_action
- corp_restriction_policy 支持 none + internal_only;stale "whitelist" 在
  加载层与写入层均静默 coerce 为 none + slog.Warn
- bypass_registration 开关:企业内部模式豁免全局 REGISTRATION_DISABLED
- isReservedEmail / signup_source / canUnbindProvider / OAuth pending flow
  等横切点支持 dingtalk provider
- migration 136:4 表 CHECK 约束加入 'dingtalk' provider 值

internal_only 模式同步企业邮箱/姓名/部门到用户属性
- SyncCorpEmail / SyncDisplayName / SyncDept 三个独立开关 + 对应
  SyncXxxAttrKey 目标属性 key(默认 dingtalk_email / dingtalk_name /
  dingtalk_department);非 internal_only policy 在写入层与加载层均
  coerce 为 false,admin handler 与 setting_service 双层兜底
- 同步语义:首次注册写 users.username(昵称优先 → 企业姓名 fallback),
  之后每次登录刷新 3 个属性;空值也写入以覆盖旧值
- 邮箱三级 fallback:org_email > email > extension["企业邮箱"]
  (钉钉自定义字段 JSON)
- 部门路径递归向上拼接,跳过 dept_id=1 选首个真实子部门,剥离根组织名
- GetUnionIdByUserToken 同时返回 OIDC /contact/users/me 的 nick 字段;
  新增 GetDeptInfo 调用 OAPI /topapi/v2/department/get
- AuthHandler 注入 UserAttributeService;OAuth pending flow 在
  createPendingOAuthAccount / bindPendingOAuthLogin 分别派发到
  AfterRegistration(syncUsername=true)/ AfterLogin
- migration 137 seed dingtalk_email/name/department 三个用户属性定义

附带修复(同集成路径暴露的两个 OAuth 注册回归)
- LoginOrRegisterOAuthWithTokenPair 新建用户分支用 inferLegacySignupSource
  覆写 caller 显式传入的 signupSource,导致 dingtalk/linuxdo/oidc/wechat
  渠道授权按 email 渠道读取;改为只在 caller 未显式传入时回退邮箱推断
- mergeProviderDefaultGrantSettings 把 parse fallback 默认值
  (Concurrency=5 / Balance=0) 当作"未配置"哨兵,admin 显式设 5 时被误判
  退回全局默认(复现:全局默认 1 + 渠道默认并发 5 + grant_on_signup → 新
  用户实际 concurrency=1);去掉哨兵,admin 任何 >=0 值都覆盖 globalDefaults

前端
- DingTalk Login / Callback / EmailCompletion / ChoiceAccount / Error
  视图;router + auth API client
- admin SettingsView:corp policy radio(none / internal_only)+ bypass
  注册开关 + i18n;internal_only 下展示三同步开关 + 目标 attr key 下拉
  (拉取 user attribute definitions),展示 fieldEmail /
  qyapi_get_department_list 钉钉权限申请提示
- Profile:S1 主动绑定 / S5 解绑钉钉按钮 + 合成邮箱防自锁

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 15:27:47 +08:00
DaydreamCoding
664e9fdcd4 feat(usage): 用户用量按平台拆分 + UsersView 列设置可配置 + 用量列排序
后端
- BatchUserUsageStats / UserDashboardStats 新增 ByPlatform 字段
  复用 ops 路径 COALESCE(g.platform, a.platform) 语义,不冗余 DB 字段
- 抽出 usageLogEffectivePlatformExpr 常量供管理员与用户两路径共用
- GetBatchUsersUsage cacheKey 加 v=2 + 当日日期,修复跨午夜旧缓存兼容新字段

前端
- 新建 PlatformUsageBreakdown:管理员用量列 hover tooltip 展示各平台 today/total
- 新建 PlatformCostCell:单平台 today/total 紧凑单元格
- UsersView 列设置新增 Claude/OpenAI/Gemini/Antigravity 四个平台子列,默认隐藏可手动启用
- 普通用户 Dashboard 新增 Row 3 平台拆分卡片,受 isSimple 控制
- 平台之和 < 总值时显式展示"其他"行,避免数字对不齐
- last_active_at 从 FORCED_VISIBLE_COLUMNS 移除,允许用户隐藏并持久化
- 列设置加 schema 版本号 + 迁移机制,老用户升级时新增默认隐藏列自动应用
- UsersView 用量列(汇总 + 4 平台子列)加入前端单页排序:列头单按钮 + 弹出菜单
  切换"今日 / 近30天",三态循环 desc → asc → off;菜单底部备注"仅对本页数据排序"
- sortedUsers computed 在 server-side-sort 结果之上叠加本地排序,缺失值按 0 处理;
  usageSort 状态独立 localStorage 持久化,互不干扰后端 sort_by
- i18n 新增 admin.users.sortBy / sortCurrentPageOnly

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 15:25:34 +08:00
benjamin
36c00374d3 feat: expose upstream model sync admin API
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-18 19:01:33 +08:00
shaw
a07a0dac63 feat: add configurable Antigravity user agent version 2026-05-11 22:25:20 +08:00
shaw
9377c96746 fix: 让消息 cache_control 改写默认关闭 2026-05-11 21:26:41 +08:00
ZeroDeng
f788e6bdba fix(service): handle unexpected default transport type, simplify warning append 2026-05-11 11:43:44 +08:00
shaw
fda1ed459d feat: 优化 OAuth 账号导入流程 2026-05-08 11:36:09 +08:00
haruka
0f8e2d0934 fix(security): 屏蔽 admin 账号接口返回的敏感凭证字段
Account.Credentials 是 JSONB map,混合存放可编辑的非敏感配置(base_url、
model_mapping、project_id 等)与敏感秘钥(OAuth access/refresh/id token、
API key、AWS secret、Vertex private key 等)。当前所有 admin 账号接口直接
透传该 map,token 经由浏览器 DevTools、抓包、日志等途径泄漏。

- service 包新增 SensitiveCredentialKeys 清单与 MergePreservingSensitiveCreds
  作为单一权威定义。
- dto 层 RedactCredentials 在响应里剥离敏感子键,输出 credentials_status
  (has_<key> 布尔标识)告知前端存在性,不暴露原值。
- AccountFromServiceShallow 接入脱敏,覆盖 list、get、create、update、
  refresh、batch、bulk-update、OAuth 创建等 9 个 handler。
- service.UpdateAccount 改为合并语义:incoming 没传敏感键则保留 existing,
  让前端"全对象 PUT"流程在脱敏后无感工作;显式提供新 token 仍会覆盖。
- 前端 EditAccountModal 修复脱敏后会崩的两处兜底:apikey 必填检查和
  Vertex SA JSON 存在性校验改读 credentials_status.has_*。
- 导出端点 /admin/accounts/data 走独立的 DataAccount 结构,按设计保留
  完整 credentials 作为管理员备份路径。

测试:RedactCredentials 单元测试、mapper 端到端 JSON 断言(确认序列化
后无 token 子串)、UpdateAccount 合并语义三种场景(保留 / 覆盖 / 空 map 跳过)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 03:44:04 +08:00
shaw
e872cbec0b feat: 添加登录注册条款确认 2026-05-07 17:35:05 +08:00
shaw
0eca600ffa fix moderation key handling and key UI 2026-05-07 14:31:19 +08:00
Wesley Liddick
e69319e747
Merge pull request #2224 from lyen1688/feat-email-oauth-github-google
feat: 增加 GitHub 和 Google 邮箱快捷登录
2026-05-07 10:07:28 +08:00
Wesley Liddick
d52da45363
Merge pull request #2202 from Michael-Jetson/main
新增三大功能:兑换码邀请返利、批量修改用户并发数、Markdown页面渲染
2026-05-07 09:35:14 +08:00
shaw
fff4a300c6 feat(risk-control): add content moderation audit 2026-05-07 09:14:47 +08:00
lyen1688
af550fa64e feat: 增加 GitHub 和 Google 邮箱快捷登录 2026-05-06 16:06:11 +08:00
Michael-Jetson
4cbd4932a0 feat: add redeem code affiliate rebate, batch concurrency API, and markdown page rendering
1. Redeem code affiliate rebate: balance-type redeem codes now trigger
   invite rebate for the inviter. Payment fulfillment uses context key
   to prevent double-rebate.

2. Batch concurrency update: new POST /admin/users/batch-concurrency
   endpoint supporting mode=set/add with all=true for all users.

3. Markdown page rendering: new GET /api/v1/pages/:slug API serves local
   .md files. Custom menu items with url="md:slug" render markdown with
   collapsible TOC sidebar, scroll spy, and copy buttons on code blocks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-05 06:44:37 -07:00
Wesley Liddick
37f7c7128c
Merge pull request #2120 from gaoren002/fix/rate-limit-429-cooldown-config
fix(rate-limit): make 429 fallback cooldown configurable
2026-05-05 19:46:11 +08:00
2ue
6faa344916 feat: add OpenAI image generation controls 2026-05-05 03:26:54 +08:00
Wesley Liddick
dc09b367dc
Merge pull request #2143 from alfadb/fix/openai-apikey-cc-default-routing
修复:APIKey 账户上游不支持 OpenAI Responses API 时的 Chat Completions 路由回退
2026-05-03 22:58:26 +08:00
lyen1688
3ab40269b4 完善返利转入余额历史显示 2026-05-03 20:33:14 +08:00
lyen1688
6a41cf6a51 feat: add admin affiliate record pages 2026-05-03 20:33:13 +08:00
alfadb
adf01ac880 fix(openai-gateway): address PR review — probe URL /v1 prefix, Create trigger, tests
Fix four issues flagged by copilot-pull-request-reviewer on PR #2143:

1. Probe URL missing /v1 prefix (openai_apikey_responses_probe.go)
   Replaced bare TrimSuffix + "/responses" with buildOpenAIResponsesURL(),
   which handles bare domain → /v1/responses correctly. Affected:
   - ProbeOpenAIAPIKeyResponsesSupport (probe URL)
   - TestAccount endpoint (apiURL for APIKey accounts)

2. Create endpoint not triggering probe (account_handler.go)
   Capture created account from idempotent closure and call
   scheduleOpenAIResponsesProbe after success, same pattern as
   BatchCreate and Update.

3. Tests (openai_gateway_chat_completions_raw_test.go)
   Added TestBuildOpenAIChatCompletionsURL (7 cases covering
   bare domain, /v1 suffix, trailing slash, third-party domains,
   whitespace) and TestBuildOpenAIResponsesURL_ProbeURL (6 cases
   locking the probe URL construction for bare-domain inputs).

All unit tests pass; go build ./cmd/server/ clean.
2026-04-30 21:46:46 +08:00
alfadb-bot
4e4cc80971 fix(openai-gateway): route APIKey accounts to /v1/chat/completions when upstream lacks Responses API
OpenAI APIKey accounts with base_url pointing to third-party OpenAI-compatible
upstreams (DeepSeek, Kimi, GLM, Qwen, etc.) were failing because the gateway
unconditionally converted Chat Completions requests to Responses format and
forwarded to {base_url}/v1/responses, which only exists on OpenAI's official
endpoint.

Detection-based routing:
- Probe upstream capability on account create/update via a minimal POST to
  /v1/responses; HTTP 404/405 means 'unsupported', any other response means
  'supported'.
- Persist result as accounts.extra.openai_responses_supported (bool).
- ForwardAsChatCompletions branches at function entry: APIKey accounts with
  explicit support=false go through new forwardAsRawChatCompletions which
  passthrough-forwards CC body to /v1/chat/completions without protocol
  conversion.

Default behavior for accounts without the marker preserves the legacy
'always Responses' path — existing OpenAI APIKey accounts that were working
before this change continue to work without modification (the 'reality is
evidence' principle: an account that has been running implies upstream
capability).

Probe is fired async after Create / Update / BatchCreate; failures only log,
never block the admin flow. BulkUpdate omitted (low signal of base_url
changes; can be added if needed).

Implementation:
- New pkg internal/pkg/openai_compat: marker key + ShouldUseResponsesAPI
- New service file openai_apikey_responses_probe.go: probe + persist
- New service file openai_gateway_chat_completions_raw.go: CC pass-through
- Account test endpoint short-circuits with explicit message for
  probed-unsupported accounts (full CC test path is a TODO)

Zero schema changes, zero migrations, zero frontend changes, zero wire
modifications — all wired through existing AccountTestService injection.

Closes: DeepSeek-OpenAI account (id=128) production failure
2026-04-30 19:25:45 +08:00
shaw
73b872998e feat: 添加 Anthropic 缓存 TTL 注入开关 2026-04-30 13:38:22 +08:00