feat(llm,datasource): gate model/provider/oauth/datasource endpoints to admin

This commit is contained in:
matevip 2026-05-15 10:18:03 +08:00
parent 41f3408209
commit bba9975749
5 changed files with 51 additions and 0 deletions

View File

@ -10,6 +10,7 @@ import vip.mate.datasource.service.DatasourceService;
import java.util.List;
import java.util.Map;
import vip.mate.workspace.core.annotation.RequireWorkspaceRole;
/**
* 数据源管理接口
@ -26,24 +27,28 @@ public class DatasourceController {
@Operation(summary = "获取数据源列表")
@GetMapping
@RequireWorkspaceRole("admin")
public R<List<DatasourceEntity>> list() {
return R.ok(datasourceService.listAll());
}
@Operation(summary = "获取数据源详情")
@GetMapping("/{id}")
@RequireWorkspaceRole("admin")
public R<DatasourceEntity> get(@PathVariable Long id) {
return R.ok(datasourceService.getByIdMasked(id));
}
@Operation(summary = "创建数据源")
@PostMapping
@RequireWorkspaceRole("admin")
public R<DatasourceEntity> create(@RequestBody DatasourceEntity entity) {
return R.ok(datasourceService.create(entity));
}
@Operation(summary = "更新数据源")
@PutMapping("/{id}")
@RequireWorkspaceRole("admin")
public R<DatasourceEntity> update(@PathVariable Long id, @RequestBody DatasourceEntity entity) {
entity.setId(id);
return R.ok(datasourceService.update(entity));
@ -51,6 +56,7 @@ public class DatasourceController {
@Operation(summary = "删除数据源")
@DeleteMapping("/{id}")
@RequireWorkspaceRole("admin")
public R<Void> delete(@PathVariable Long id) {
datasourceService.delete(id);
return R.ok();
@ -58,6 +64,7 @@ public class DatasourceController {
@Operation(summary = "测试数据源连接")
@PostMapping("/{id}/test")
@RequireWorkspaceRole("admin")
public R<Map<String, Object>> testConnection(@PathVariable Long id) {
boolean ok = datasourceService.testConnection(id);
return R.ok(Map.of("success", ok, "message", ok ? "连接成功" : "连接失败"));
@ -65,6 +72,7 @@ public class DatasourceController {
@Operation(summary = "启用/禁用数据源")
@PutMapping("/{id}/toggle")
@RequireWorkspaceRole("admin")
public R<DatasourceEntity> toggle(@PathVariable Long id, @RequestParam boolean enabled) {
return R.ok(datasourceService.toggle(id, enabled));
}

View File

@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.RestController;
import vip.mate.common.result.R;
import vip.mate.llm.anthropic.oauth.ClaudeCodeOAuthService;
import vip.mate.llm.anthropic.oauth.ClaudeCodeOAuthService.OAuthStatus;
import vip.mate.workspace.core.annotation.RequireWorkspaceRole;
/**
* RFC-062 PR-3: management-UI surface for the Claude Code OAuth provider.
@ -45,6 +46,7 @@ public class ClaudeCodeOAuthController {
@Operation(summary = "Read current Claude Code OAuth credential status from local disk")
@GetMapping("/status")
@RequireWorkspaceRole("admin")
public R<OAuthStatus> status() {
return R.ok(oauthService.getStatus());
}
@ -60,6 +62,7 @@ public class ClaudeCodeOAuthController {
*/
@Operation(summary = "Force re-detect credentials and refresh if near expiry")
@PostMapping("/reload")
@RequireWorkspaceRole("admin")
public R<OAuthStatus> reload() {
try {
oauthService.getValidToken();

View File

@ -20,6 +20,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import vip.mate.workspace.core.annotation.RequireWorkspaceRole;
@Tag(name = "模型配置管理")
@RestController
@ -37,42 +38,49 @@ public class ModelConfigController {
@Operation(summary = "获取 Provider 列表(仅 enabled")
@GetMapping
@RequireWorkspaceRole("admin")
public R<List<ProviderInfoDTO>> list() {
return R.ok(modelProviderService.listProviders());
}
@Operation(summary = "RFC-074: 获取 Provider 全量目录(含未启用),供 Add Provider 抽屉使用")
@GetMapping("/catalog")
@RequireWorkspaceRole("admin")
public R<List<ProviderInfoDTO>> catalog() {
return R.ok(modelProviderService.listCatalog());
}
@Operation(summary = "RFC-074: 启用 Provider")
@PostMapping("/{providerId}/enable")
@RequireWorkspaceRole("admin")
public R<EnableResult> enableProvider(@PathVariable String providerId) {
return R.ok(modelProviderService.setEnabled(providerId, true));
}
@Operation(summary = "RFC-074: 禁用 Provider如其下模型为当前默认会自动切换")
@PostMapping("/{providerId}/disable")
@RequireWorkspaceRole("admin")
public R<EnableResult> disableProvider(@PathVariable String providerId) {
return R.ok(modelProviderService.setEnabled(providerId, false));
}
@Operation(summary = "获取启用模型列表")
@GetMapping("/enabled")
@RequireWorkspaceRole("admin")
public R<List<ModelConfigEntity>> listEnabled() {
return R.ok(modelConfigService.listEnabledModels());
}
@Operation(summary = "获取默认模型")
@GetMapping("/default")
@RequireWorkspaceRole("admin")
public R<ModelConfigEntity> getDefaultModel() {
return R.ok(modelConfigService.getDefaultModel());
}
@Operation(summary = "获取当前激活模型")
@GetMapping("/active")
@RequireWorkspaceRole("admin")
public R<ActiveModelsInfo> getActiveModel() {
ModelConfigEntity model = modelConfigService.getDefaultModel();
ActiveModelsInfo info = new ActiveModelsInfo();
@ -82,6 +90,7 @@ public class ModelConfigController {
@Operation(summary = "设置当前激活模型")
@PutMapping("/active")
@RequireWorkspaceRole("admin")
public R<ActiveModelsInfo> setActiveModel(@RequestBody ModelSlotRequest request) {
ModelConfigEntity model = modelConfigService.setDefaultModel(request.getProviderId(), request.getModel());
ActiveModelsInfo info = new ActiveModelsInfo();
@ -91,6 +100,7 @@ public class ModelConfigController {
@Operation(summary = "更新 Provider 配置")
@PutMapping("/{providerId}/config")
@RequireWorkspaceRole("admin")
public R<ProviderInfoDTO> updateProviderConfig(@PathVariable String providerId,
@RequestBody ProviderConfigRequest request) {
ProviderInfoDTO updated = modelProviderService.updateProviderConfig(providerId, request);
@ -101,12 +111,14 @@ public class ModelConfigController {
@Operation(summary = "创建自定义 Provider")
@PostMapping("/custom-providers")
@RequireWorkspaceRole("admin")
public R<ProviderInfoDTO> createCustomProvider(@RequestBody CreateCustomProviderRequest request) {
return R.ok(modelProviderService.createCustomProvider(request));
}
@Operation(summary = "删除自定义 Provider")
@DeleteMapping("/custom-providers/{providerId}")
@RequireWorkspaceRole("admin")
public R<Void> deleteCustomProvider(@PathVariable String providerId) {
modelProviderService.deleteCustomProvider(providerId);
return R.ok();
@ -122,6 +134,7 @@ public class ModelConfigController {
*/
@Operation(summary = "删除自定义 Provider查询参数变体兼容含特殊字符的旧 ID")
@DeleteMapping("/custom-providers")
@RequireWorkspaceRole("admin")
public R<Void> deleteCustomProviderByQuery(@RequestParam("providerId") String providerId) {
modelProviderService.deleteCustomProvider(providerId);
return R.ok();
@ -129,6 +142,7 @@ public class ModelConfigController {
@Operation(summary = "向 Provider 添加模型")
@PostMapping("/{providerId}/models")
@RequireWorkspaceRole("admin")
public R<ProviderInfoDTO> addProviderModel(@PathVariable String providerId,
@RequestBody AddProviderModelRequest request) {
return R.ok(modelProviderService.addModel(providerId, request));
@ -136,6 +150,7 @@ public class ModelConfigController {
@Operation(summary = "从 Provider 删除模型")
@DeleteMapping("/{providerId}/models/{modelId}")
@RequireWorkspaceRole("admin")
public R<ProviderInfoDTO> removeProviderModel(@PathVariable String providerId,
@PathVariable String modelId) {
return R.ok(modelProviderService.removeModel(providerId, modelId));
@ -143,18 +158,21 @@ public class ModelConfigController {
@Operation(summary = "获取模型详情")
@GetMapping("/{id}")
@RequireWorkspaceRole("admin")
public R<ModelConfigEntity> get(@PathVariable Long id) {
return R.ok(modelConfigService.getModel(id));
}
@Operation(summary = "创建模型")
@PostMapping
@RequireWorkspaceRole("admin")
public R<ModelConfigEntity> create(@RequestBody ModelConfigEntity entity) {
return R.ok(modelConfigService.createModel(entity));
}
@Operation(summary = "更新模型")
@PutMapping("/{id}")
@RequireWorkspaceRole("admin")
public R<ModelConfigEntity> update(@PathVariable Long id, @RequestBody ModelConfigEntity entity) {
entity.setId(id);
return R.ok(modelConfigService.updateModel(entity));
@ -162,6 +180,7 @@ public class ModelConfigController {
@Operation(summary = "删除模型")
@DeleteMapping("/{id}")
@RequireWorkspaceRole("admin")
public R<Void> delete(@PathVariable Long id) {
modelConfigService.deleteModel(id);
return R.ok();
@ -169,6 +188,7 @@ public class ModelConfigController {
@Operation(summary = "设置默认模型")
@PostMapping("/{id}/default")
@RequireWorkspaceRole("admin")
public R<ModelConfigEntity> setDefault(@PathVariable Long id) {
return R.ok(modelConfigService.setDefaultModel(id));
}
@ -177,12 +197,14 @@ public class ModelConfigController {
@Operation(summary = "发现远端模型")
@PostMapping("/{providerId}/discover")
@RequireWorkspaceRole("admin")
public R<DiscoverResult> discoverModels(@PathVariable String providerId) {
return R.ok(modelDiscoveryService.discoverModels(providerId));
}
@Operation(summary = "批量添加发现的模型")
@PostMapping("/{providerId}/discover/apply")
@RequireWorkspaceRole("admin")
public R<Map<String, Integer>> applyDiscoveredModels(@PathVariable String providerId,
@RequestBody ApplyDiscoveredModelsRequest request) {
int added = modelDiscoveryService.batchAddModels(providerId, request.getModelIds());
@ -191,12 +213,14 @@ public class ModelConfigController {
@Operation(summary = "测试供应商连接")
@PostMapping("/{providerId}/test-connection")
@RequireWorkspaceRole("admin")
public R<TestResult> testConnection(@PathVariable String providerId) {
return R.ok(modelDiscoveryService.testConnection(providerId));
}
@Operation(summary = "测试单个模型可用性")
@PostMapping("/{providerId}/models/{modelId}/test")
@RequireWorkspaceRole("admin")
public R<TestResult> testModel(@PathVariable String providerId,
@PathVariable String modelId) {
return R.ok(modelDiscoveryService.testModel(providerId, modelId));
@ -206,6 +230,7 @@ public class ModelConfigController {
@Operation(summary = "按类型筛选模型chat / embedding可选 modality 过滤")
@GetMapping("/by-type")
@RequireWorkspaceRole("admin")
public R<List<ModelConfigEntity>> listByType(
@RequestParam(defaultValue = "chat") String modelType,
@RequestParam(required = false) String modality) {
@ -214,6 +239,7 @@ public class ModelConfigController {
@Operation(summary = "测试 Embedding 模型连通性(嵌入一个短文本验证 API key")
@PostMapping("/embedding/{modelId}/test")
@RequireWorkspaceRole("admin")
public R<Map<String, Object>> testEmbedding(@PathVariable Long modelId) {
Map<String, Object> result = new HashMap<>();
try {
@ -241,6 +267,7 @@ public class ModelConfigController {
@Operation(summary = "获取系统默认 Embedding 模型 ID")
@GetMapping("/embedding/default")
@RequireWorkspaceRole("admin")
public R<Map<String, Object>> getDefaultEmbedding() {
SystemSettingEntity entity = systemSettingMapper.selectOne(
new LambdaQueryWrapper<SystemSettingEntity>()
@ -254,6 +281,7 @@ public class ModelConfigController {
@Operation(summary = "设置系统默认 Embedding 模型")
@PostMapping("/embedding/default")
@RequireWorkspaceRole("admin")
public R<Void> setDefaultEmbedding(@RequestBody Map<String, Object> body) {
Object v = body.get("modelId");
String value = v == null ? "" : v.toString();

View File

@ -12,6 +12,7 @@ import vip.mate.llm.oauth.OpenAIDeviceCodeService.DeviceCodeStartResult;
import vip.mate.llm.oauth.OpenAIOAuthService;
import vip.mate.llm.oauth.OpenAIOAuthService.OAuthAuthorizeResult;
import vip.mate.llm.oauth.OpenAIOAuthService.OAuthStatusResult;
import vip.mate.workspace.core.annotation.RequireWorkspaceRole;
@Tag(name = "OpenAI OAuth")
@RestController
@ -24,6 +25,7 @@ public class OAuthController {
@Operation(summary = "获取 OAuth 授权 URL自动选 LOCAL / MANUAL_PASTE 模式)")
@GetMapping("/authorize")
@RequireWorkspaceRole("admin")
public R<OAuthAuthorizeResult> authorize(HttpServletRequest request) {
// Host header 判断是否远程部署 远程则不启 localhost server MANUAL_PASTE
// 优先 X-Forwarded-Host反向代理后的实际入口fallback Host
@ -42,6 +44,7 @@ public class OAuthController {
*/
@Operation(summary = "MANUAL_PASTE 模式:用户粘贴浏览器回调 URL 完成 OAuth")
@PostMapping("/callback-paste")
@RequireWorkspaceRole("admin")
public R<Void> callbackPaste(@RequestBody PasteRequest request) {
oauthService.completeFromPastedUrl(request.callbackUrl());
return R.ok();
@ -52,18 +55,21 @@ public class OAuthController {
@Operation(summary = "Device flow: start — request user_code")
@PostMapping("/device/start")
@RequireWorkspaceRole("admin")
public R<DeviceCodeStartResult> deviceStart() {
return R.ok(deviceCodeService.start());
}
@Operation(summary = "Device flow: poll for completion")
@PostMapping("/device/poll")
@RequireWorkspaceRole("admin")
public R<DeviceCodePollResult> devicePoll(@RequestBody DeviceRequest request) {
return R.ok(deviceCodeService.poll(request.deviceAuthId()));
}
@Operation(summary = "Device flow: cancel a pending session")
@PostMapping("/device/cancel")
@RequireWorkspaceRole("admin")
public R<Void> deviceCancel(@RequestBody DeviceRequest request) {
deviceCodeService.cancel(request.deviceAuthId());
return R.ok();
@ -74,6 +80,7 @@ public class OAuthController {
@Operation(summary = "手动刷新 Token")
@PostMapping("/refresh")
@RequireWorkspaceRole("admin")
public R<Void> refresh() {
oauthService.refreshToken();
return R.ok();
@ -81,6 +88,7 @@ public class OAuthController {
@Operation(summary = "清除 OAuth 凭证")
@DeleteMapping("/revoke")
@RequireWorkspaceRole("admin")
public R<Void> revoke() {
oauthService.revokeToken();
return R.ok();
@ -88,6 +96,7 @@ public class OAuthController {
@Operation(summary = "获取 OAuth 连接状态")
@GetMapping("/status")
@RequireWorkspaceRole("admin")
public R<OAuthStatusResult> status() {
return R.ok(oauthService.getStatus());
}

View File

@ -21,6 +21,7 @@ import vip.mate.llm.service.ModelProviderService;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import vip.mate.workspace.core.annotation.RequireWorkspaceRole;
/**
* RFC-009 Phase 4 read-only diagnostic endpoint for the provider pool.
@ -49,6 +50,7 @@ public class ProviderPoolController {
@Operation(summary = "查询所有 provider 的池状态 + 冷却信息")
@GetMapping
@RequireWorkspaceRole("admin")
public R<List<ProviderPoolEntryDTO>> snapshot() {
Map<String, RemovalReason> poolView = providerPool.snapshot();
Map<String, ProviderHealthSnapshot> healthView = healthTracker.snapshot();
@ -81,6 +83,7 @@ public class ProviderPoolController {
@Operation(summary = "手动重新探测某个 provider立即更新池状态")
@PostMapping("/{providerId}/reprobe")
@RequireWorkspaceRole("admin")
public R<ReprobeResultDTO> reprobe(@PathVariable String providerId) {
ProbeResult result = initProbe.probeOne(providerId);
return R.ok(new ReprobeResultDTO(