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.List;
import java.util.Map; import java.util.Map;
import vip.mate.workspace.core.annotation.RequireWorkspaceRole;
/** /**
* 数据源管理接口 * 数据源管理接口
@ -26,24 +27,28 @@ public class DatasourceController {
@Operation(summary = "获取数据源列表") @Operation(summary = "获取数据源列表")
@GetMapping @GetMapping
@RequireWorkspaceRole("admin")
public R<List<DatasourceEntity>> list() { public R<List<DatasourceEntity>> list() {
return R.ok(datasourceService.listAll()); return R.ok(datasourceService.listAll());
} }
@Operation(summary = "获取数据源详情") @Operation(summary = "获取数据源详情")
@GetMapping("/{id}") @GetMapping("/{id}")
@RequireWorkspaceRole("admin")
public R<DatasourceEntity> get(@PathVariable Long id) { public R<DatasourceEntity> get(@PathVariable Long id) {
return R.ok(datasourceService.getByIdMasked(id)); return R.ok(datasourceService.getByIdMasked(id));
} }
@Operation(summary = "创建数据源") @Operation(summary = "创建数据源")
@PostMapping @PostMapping
@RequireWorkspaceRole("admin")
public R<DatasourceEntity> create(@RequestBody DatasourceEntity entity) { public R<DatasourceEntity> create(@RequestBody DatasourceEntity entity) {
return R.ok(datasourceService.create(entity)); return R.ok(datasourceService.create(entity));
} }
@Operation(summary = "更新数据源") @Operation(summary = "更新数据源")
@PutMapping("/{id}") @PutMapping("/{id}")
@RequireWorkspaceRole("admin")
public R<DatasourceEntity> update(@PathVariable Long id, @RequestBody DatasourceEntity entity) { public R<DatasourceEntity> update(@PathVariable Long id, @RequestBody DatasourceEntity entity) {
entity.setId(id); entity.setId(id);
return R.ok(datasourceService.update(entity)); return R.ok(datasourceService.update(entity));
@ -51,6 +56,7 @@ public class DatasourceController {
@Operation(summary = "删除数据源") @Operation(summary = "删除数据源")
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
@RequireWorkspaceRole("admin")
public R<Void> delete(@PathVariable Long id) { public R<Void> delete(@PathVariable Long id) {
datasourceService.delete(id); datasourceService.delete(id);
return R.ok(); return R.ok();
@ -58,6 +64,7 @@ public class DatasourceController {
@Operation(summary = "测试数据源连接") @Operation(summary = "测试数据源连接")
@PostMapping("/{id}/test") @PostMapping("/{id}/test")
@RequireWorkspaceRole("admin")
public R<Map<String, Object>> testConnection(@PathVariable Long id) { public R<Map<String, Object>> testConnection(@PathVariable Long id) {
boolean ok = datasourceService.testConnection(id); boolean ok = datasourceService.testConnection(id);
return R.ok(Map.of("success", ok, "message", ok ? "连接成功" : "连接失败")); return R.ok(Map.of("success", ok, "message", ok ? "连接成功" : "连接失败"));
@ -65,6 +72,7 @@ public class DatasourceController {
@Operation(summary = "启用/禁用数据源") @Operation(summary = "启用/禁用数据源")
@PutMapping("/{id}/toggle") @PutMapping("/{id}/toggle")
@RequireWorkspaceRole("admin")
public R<DatasourceEntity> toggle(@PathVariable Long id, @RequestParam boolean enabled) { public R<DatasourceEntity> toggle(@PathVariable Long id, @RequestParam boolean enabled) {
return R.ok(datasourceService.toggle(id, 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.common.result.R;
import vip.mate.llm.anthropic.oauth.ClaudeCodeOAuthService; import vip.mate.llm.anthropic.oauth.ClaudeCodeOAuthService;
import vip.mate.llm.anthropic.oauth.ClaudeCodeOAuthService.OAuthStatus; 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. * 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") @Operation(summary = "Read current Claude Code OAuth credential status from local disk")
@GetMapping("/status") @GetMapping("/status")
@RequireWorkspaceRole("admin")
public R<OAuthStatus> status() { public R<OAuthStatus> status() {
return R.ok(oauthService.getStatus()); return R.ok(oauthService.getStatus());
} }
@ -60,6 +62,7 @@ public class ClaudeCodeOAuthController {
*/ */
@Operation(summary = "Force re-detect credentials and refresh if near expiry") @Operation(summary = "Force re-detect credentials and refresh if near expiry")
@PostMapping("/reload") @PostMapping("/reload")
@RequireWorkspaceRole("admin")
public R<OAuthStatus> reload() { public R<OAuthStatus> reload() {
try { try {
oauthService.getValidToken(); oauthService.getValidToken();

View File

@ -20,6 +20,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import vip.mate.workspace.core.annotation.RequireWorkspaceRole;
@Tag(name = "模型配置管理") @Tag(name = "模型配置管理")
@RestController @RestController
@ -37,42 +38,49 @@ public class ModelConfigController {
@Operation(summary = "获取 Provider 列表(仅 enabled") @Operation(summary = "获取 Provider 列表(仅 enabled")
@GetMapping @GetMapping
@RequireWorkspaceRole("admin")
public R<List<ProviderInfoDTO>> list() { public R<List<ProviderInfoDTO>> list() {
return R.ok(modelProviderService.listProviders()); return R.ok(modelProviderService.listProviders());
} }
@Operation(summary = "RFC-074: 获取 Provider 全量目录(含未启用),供 Add Provider 抽屉使用") @Operation(summary = "RFC-074: 获取 Provider 全量目录(含未启用),供 Add Provider 抽屉使用")
@GetMapping("/catalog") @GetMapping("/catalog")
@RequireWorkspaceRole("admin")
public R<List<ProviderInfoDTO>> catalog() { public R<List<ProviderInfoDTO>> catalog() {
return R.ok(modelProviderService.listCatalog()); return R.ok(modelProviderService.listCatalog());
} }
@Operation(summary = "RFC-074: 启用 Provider") @Operation(summary = "RFC-074: 启用 Provider")
@PostMapping("/{providerId}/enable") @PostMapping("/{providerId}/enable")
@RequireWorkspaceRole("admin")
public R<EnableResult> enableProvider(@PathVariable String providerId) { public R<EnableResult> enableProvider(@PathVariable String providerId) {
return R.ok(modelProviderService.setEnabled(providerId, true)); return R.ok(modelProviderService.setEnabled(providerId, true));
} }
@Operation(summary = "RFC-074: 禁用 Provider如其下模型为当前默认会自动切换") @Operation(summary = "RFC-074: 禁用 Provider如其下模型为当前默认会自动切换")
@PostMapping("/{providerId}/disable") @PostMapping("/{providerId}/disable")
@RequireWorkspaceRole("admin")
public R<EnableResult> disableProvider(@PathVariable String providerId) { public R<EnableResult> disableProvider(@PathVariable String providerId) {
return R.ok(modelProviderService.setEnabled(providerId, false)); return R.ok(modelProviderService.setEnabled(providerId, false));
} }
@Operation(summary = "获取启用模型列表") @Operation(summary = "获取启用模型列表")
@GetMapping("/enabled") @GetMapping("/enabled")
@RequireWorkspaceRole("admin")
public R<List<ModelConfigEntity>> listEnabled() { public R<List<ModelConfigEntity>> listEnabled() {
return R.ok(modelConfigService.listEnabledModels()); return R.ok(modelConfigService.listEnabledModels());
} }
@Operation(summary = "获取默认模型") @Operation(summary = "获取默认模型")
@GetMapping("/default") @GetMapping("/default")
@RequireWorkspaceRole("admin")
public R<ModelConfigEntity> getDefaultModel() { public R<ModelConfigEntity> getDefaultModel() {
return R.ok(modelConfigService.getDefaultModel()); return R.ok(modelConfigService.getDefaultModel());
} }
@Operation(summary = "获取当前激活模型") @Operation(summary = "获取当前激活模型")
@GetMapping("/active") @GetMapping("/active")
@RequireWorkspaceRole("admin")
public R<ActiveModelsInfo> getActiveModel() { public R<ActiveModelsInfo> getActiveModel() {
ModelConfigEntity model = modelConfigService.getDefaultModel(); ModelConfigEntity model = modelConfigService.getDefaultModel();
ActiveModelsInfo info = new ActiveModelsInfo(); ActiveModelsInfo info = new ActiveModelsInfo();
@ -82,6 +90,7 @@ public class ModelConfigController {
@Operation(summary = "设置当前激活模型") @Operation(summary = "设置当前激活模型")
@PutMapping("/active") @PutMapping("/active")
@RequireWorkspaceRole("admin")
public R<ActiveModelsInfo> setActiveModel(@RequestBody ModelSlotRequest request) { public R<ActiveModelsInfo> setActiveModel(@RequestBody ModelSlotRequest request) {
ModelConfigEntity model = modelConfigService.setDefaultModel(request.getProviderId(), request.getModel()); ModelConfigEntity model = modelConfigService.setDefaultModel(request.getProviderId(), request.getModel());
ActiveModelsInfo info = new ActiveModelsInfo(); ActiveModelsInfo info = new ActiveModelsInfo();
@ -91,6 +100,7 @@ public class ModelConfigController {
@Operation(summary = "更新 Provider 配置") @Operation(summary = "更新 Provider 配置")
@PutMapping("/{providerId}/config") @PutMapping("/{providerId}/config")
@RequireWorkspaceRole("admin")
public R<ProviderInfoDTO> updateProviderConfig(@PathVariable String providerId, public R<ProviderInfoDTO> updateProviderConfig(@PathVariable String providerId,
@RequestBody ProviderConfigRequest request) { @RequestBody ProviderConfigRequest request) {
ProviderInfoDTO updated = modelProviderService.updateProviderConfig(providerId, request); ProviderInfoDTO updated = modelProviderService.updateProviderConfig(providerId, request);
@ -101,12 +111,14 @@ public class ModelConfigController {
@Operation(summary = "创建自定义 Provider") @Operation(summary = "创建自定义 Provider")
@PostMapping("/custom-providers") @PostMapping("/custom-providers")
@RequireWorkspaceRole("admin")
public R<ProviderInfoDTO> createCustomProvider(@RequestBody CreateCustomProviderRequest request) { public R<ProviderInfoDTO> createCustomProvider(@RequestBody CreateCustomProviderRequest request) {
return R.ok(modelProviderService.createCustomProvider(request)); return R.ok(modelProviderService.createCustomProvider(request));
} }
@Operation(summary = "删除自定义 Provider") @Operation(summary = "删除自定义 Provider")
@DeleteMapping("/custom-providers/{providerId}") @DeleteMapping("/custom-providers/{providerId}")
@RequireWorkspaceRole("admin")
public R<Void> deleteCustomProvider(@PathVariable String providerId) { public R<Void> deleteCustomProvider(@PathVariable String providerId) {
modelProviderService.deleteCustomProvider(providerId); modelProviderService.deleteCustomProvider(providerId);
return R.ok(); return R.ok();
@ -122,6 +134,7 @@ public class ModelConfigController {
*/ */
@Operation(summary = "删除自定义 Provider查询参数变体兼容含特殊字符的旧 ID") @Operation(summary = "删除自定义 Provider查询参数变体兼容含特殊字符的旧 ID")
@DeleteMapping("/custom-providers") @DeleteMapping("/custom-providers")
@RequireWorkspaceRole("admin")
public R<Void> deleteCustomProviderByQuery(@RequestParam("providerId") String providerId) { public R<Void> deleteCustomProviderByQuery(@RequestParam("providerId") String providerId) {
modelProviderService.deleteCustomProvider(providerId); modelProviderService.deleteCustomProvider(providerId);
return R.ok(); return R.ok();
@ -129,6 +142,7 @@ public class ModelConfigController {
@Operation(summary = "向 Provider 添加模型") @Operation(summary = "向 Provider 添加模型")
@PostMapping("/{providerId}/models") @PostMapping("/{providerId}/models")
@RequireWorkspaceRole("admin")
public R<ProviderInfoDTO> addProviderModel(@PathVariable String providerId, public R<ProviderInfoDTO> addProviderModel(@PathVariable String providerId,
@RequestBody AddProviderModelRequest request) { @RequestBody AddProviderModelRequest request) {
return R.ok(modelProviderService.addModel(providerId, request)); return R.ok(modelProviderService.addModel(providerId, request));
@ -136,6 +150,7 @@ public class ModelConfigController {
@Operation(summary = "从 Provider 删除模型") @Operation(summary = "从 Provider 删除模型")
@DeleteMapping("/{providerId}/models/{modelId}") @DeleteMapping("/{providerId}/models/{modelId}")
@RequireWorkspaceRole("admin")
public R<ProviderInfoDTO> removeProviderModel(@PathVariable String providerId, public R<ProviderInfoDTO> removeProviderModel(@PathVariable String providerId,
@PathVariable String modelId) { @PathVariable String modelId) {
return R.ok(modelProviderService.removeModel(providerId, modelId)); return R.ok(modelProviderService.removeModel(providerId, modelId));
@ -143,18 +158,21 @@ public class ModelConfigController {
@Operation(summary = "获取模型详情") @Operation(summary = "获取模型详情")
@GetMapping("/{id}") @GetMapping("/{id}")
@RequireWorkspaceRole("admin")
public R<ModelConfigEntity> get(@PathVariable Long id) { public R<ModelConfigEntity> get(@PathVariable Long id) {
return R.ok(modelConfigService.getModel(id)); return R.ok(modelConfigService.getModel(id));
} }
@Operation(summary = "创建模型") @Operation(summary = "创建模型")
@PostMapping @PostMapping
@RequireWorkspaceRole("admin")
public R<ModelConfigEntity> create(@RequestBody ModelConfigEntity entity) { public R<ModelConfigEntity> create(@RequestBody ModelConfigEntity entity) {
return R.ok(modelConfigService.createModel(entity)); return R.ok(modelConfigService.createModel(entity));
} }
@Operation(summary = "更新模型") @Operation(summary = "更新模型")
@PutMapping("/{id}") @PutMapping("/{id}")
@RequireWorkspaceRole("admin")
public R<ModelConfigEntity> update(@PathVariable Long id, @RequestBody ModelConfigEntity entity) { public R<ModelConfigEntity> update(@PathVariable Long id, @RequestBody ModelConfigEntity entity) {
entity.setId(id); entity.setId(id);
return R.ok(modelConfigService.updateModel(entity)); return R.ok(modelConfigService.updateModel(entity));
@ -162,6 +180,7 @@ public class ModelConfigController {
@Operation(summary = "删除模型") @Operation(summary = "删除模型")
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
@RequireWorkspaceRole("admin")
public R<Void> delete(@PathVariable Long id) { public R<Void> delete(@PathVariable Long id) {
modelConfigService.deleteModel(id); modelConfigService.deleteModel(id);
return R.ok(); return R.ok();
@ -169,6 +188,7 @@ public class ModelConfigController {
@Operation(summary = "设置默认模型") @Operation(summary = "设置默认模型")
@PostMapping("/{id}/default") @PostMapping("/{id}/default")
@RequireWorkspaceRole("admin")
public R<ModelConfigEntity> setDefault(@PathVariable Long id) { public R<ModelConfigEntity> setDefault(@PathVariable Long id) {
return R.ok(modelConfigService.setDefaultModel(id)); return R.ok(modelConfigService.setDefaultModel(id));
} }
@ -177,12 +197,14 @@ public class ModelConfigController {
@Operation(summary = "发现远端模型") @Operation(summary = "发现远端模型")
@PostMapping("/{providerId}/discover") @PostMapping("/{providerId}/discover")
@RequireWorkspaceRole("admin")
public R<DiscoverResult> discoverModels(@PathVariable String providerId) { public R<DiscoverResult> discoverModels(@PathVariable String providerId) {
return R.ok(modelDiscoveryService.discoverModels(providerId)); return R.ok(modelDiscoveryService.discoverModels(providerId));
} }
@Operation(summary = "批量添加发现的模型") @Operation(summary = "批量添加发现的模型")
@PostMapping("/{providerId}/discover/apply") @PostMapping("/{providerId}/discover/apply")
@RequireWorkspaceRole("admin")
public R<Map<String, Integer>> applyDiscoveredModels(@PathVariable String providerId, public R<Map<String, Integer>> applyDiscoveredModels(@PathVariable String providerId,
@RequestBody ApplyDiscoveredModelsRequest request) { @RequestBody ApplyDiscoveredModelsRequest request) {
int added = modelDiscoveryService.batchAddModels(providerId, request.getModelIds()); int added = modelDiscoveryService.batchAddModels(providerId, request.getModelIds());
@ -191,12 +213,14 @@ public class ModelConfigController {
@Operation(summary = "测试供应商连接") @Operation(summary = "测试供应商连接")
@PostMapping("/{providerId}/test-connection") @PostMapping("/{providerId}/test-connection")
@RequireWorkspaceRole("admin")
public R<TestResult> testConnection(@PathVariable String providerId) { public R<TestResult> testConnection(@PathVariable String providerId) {
return R.ok(modelDiscoveryService.testConnection(providerId)); return R.ok(modelDiscoveryService.testConnection(providerId));
} }
@Operation(summary = "测试单个模型可用性") @Operation(summary = "测试单个模型可用性")
@PostMapping("/{providerId}/models/{modelId}/test") @PostMapping("/{providerId}/models/{modelId}/test")
@RequireWorkspaceRole("admin")
public R<TestResult> testModel(@PathVariable String providerId, public R<TestResult> testModel(@PathVariable String providerId,
@PathVariable String modelId) { @PathVariable String modelId) {
return R.ok(modelDiscoveryService.testModel(providerId, modelId)); return R.ok(modelDiscoveryService.testModel(providerId, modelId));
@ -206,6 +230,7 @@ public class ModelConfigController {
@Operation(summary = "按类型筛选模型chat / embedding可选 modality 过滤") @Operation(summary = "按类型筛选模型chat / embedding可选 modality 过滤")
@GetMapping("/by-type") @GetMapping("/by-type")
@RequireWorkspaceRole("admin")
public R<List<ModelConfigEntity>> listByType( public R<List<ModelConfigEntity>> listByType(
@RequestParam(defaultValue = "chat") String modelType, @RequestParam(defaultValue = "chat") String modelType,
@RequestParam(required = false) String modality) { @RequestParam(required = false) String modality) {
@ -214,6 +239,7 @@ public class ModelConfigController {
@Operation(summary = "测试 Embedding 模型连通性(嵌入一个短文本验证 API key") @Operation(summary = "测试 Embedding 模型连通性(嵌入一个短文本验证 API key")
@PostMapping("/embedding/{modelId}/test") @PostMapping("/embedding/{modelId}/test")
@RequireWorkspaceRole("admin")
public R<Map<String, Object>> testEmbedding(@PathVariable Long modelId) { public R<Map<String, Object>> testEmbedding(@PathVariable Long modelId) {
Map<String, Object> result = new HashMap<>(); Map<String, Object> result = new HashMap<>();
try { try {
@ -241,6 +267,7 @@ public class ModelConfigController {
@Operation(summary = "获取系统默认 Embedding 模型 ID") @Operation(summary = "获取系统默认 Embedding 模型 ID")
@GetMapping("/embedding/default") @GetMapping("/embedding/default")
@RequireWorkspaceRole("admin")
public R<Map<String, Object>> getDefaultEmbedding() { public R<Map<String, Object>> getDefaultEmbedding() {
SystemSettingEntity entity = systemSettingMapper.selectOne( SystemSettingEntity entity = systemSettingMapper.selectOne(
new LambdaQueryWrapper<SystemSettingEntity>() new LambdaQueryWrapper<SystemSettingEntity>()
@ -254,6 +281,7 @@ public class ModelConfigController {
@Operation(summary = "设置系统默认 Embedding 模型") @Operation(summary = "设置系统默认 Embedding 模型")
@PostMapping("/embedding/default") @PostMapping("/embedding/default")
@RequireWorkspaceRole("admin")
public R<Void> setDefaultEmbedding(@RequestBody Map<String, Object> body) { public R<Void> setDefaultEmbedding(@RequestBody Map<String, Object> body) {
Object v = body.get("modelId"); Object v = body.get("modelId");
String value = v == null ? "" : v.toString(); 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;
import vip.mate.llm.oauth.OpenAIOAuthService.OAuthAuthorizeResult; import vip.mate.llm.oauth.OpenAIOAuthService.OAuthAuthorizeResult;
import vip.mate.llm.oauth.OpenAIOAuthService.OAuthStatusResult; import vip.mate.llm.oauth.OpenAIOAuthService.OAuthStatusResult;
import vip.mate.workspace.core.annotation.RequireWorkspaceRole;
@Tag(name = "OpenAI OAuth") @Tag(name = "OpenAI OAuth")
@RestController @RestController
@ -24,6 +25,7 @@ public class OAuthController {
@Operation(summary = "获取 OAuth 授权 URL自动选 LOCAL / MANUAL_PASTE 模式)") @Operation(summary = "获取 OAuth 授权 URL自动选 LOCAL / MANUAL_PASTE 模式)")
@GetMapping("/authorize") @GetMapping("/authorize")
@RequireWorkspaceRole("admin")
public R<OAuthAuthorizeResult> authorize(HttpServletRequest request) { public R<OAuthAuthorizeResult> authorize(HttpServletRequest request) {
// Host header 判断是否远程部署 远程则不启 localhost server MANUAL_PASTE // Host header 判断是否远程部署 远程则不启 localhost server MANUAL_PASTE
// 优先 X-Forwarded-Host反向代理后的实际入口fallback Host // 优先 X-Forwarded-Host反向代理后的实际入口fallback Host
@ -42,6 +44,7 @@ public class OAuthController {
*/ */
@Operation(summary = "MANUAL_PASTE 模式:用户粘贴浏览器回调 URL 完成 OAuth") @Operation(summary = "MANUAL_PASTE 模式:用户粘贴浏览器回调 URL 完成 OAuth")
@PostMapping("/callback-paste") @PostMapping("/callback-paste")
@RequireWorkspaceRole("admin")
public R<Void> callbackPaste(@RequestBody PasteRequest request) { public R<Void> callbackPaste(@RequestBody PasteRequest request) {
oauthService.completeFromPastedUrl(request.callbackUrl()); oauthService.completeFromPastedUrl(request.callbackUrl());
return R.ok(); return R.ok();
@ -52,18 +55,21 @@ public class OAuthController {
@Operation(summary = "Device flow: start — request user_code") @Operation(summary = "Device flow: start — request user_code")
@PostMapping("/device/start") @PostMapping("/device/start")
@RequireWorkspaceRole("admin")
public R<DeviceCodeStartResult> deviceStart() { public R<DeviceCodeStartResult> deviceStart() {
return R.ok(deviceCodeService.start()); return R.ok(deviceCodeService.start());
} }
@Operation(summary = "Device flow: poll for completion") @Operation(summary = "Device flow: poll for completion")
@PostMapping("/device/poll") @PostMapping("/device/poll")
@RequireWorkspaceRole("admin")
public R<DeviceCodePollResult> devicePoll(@RequestBody DeviceRequest request) { public R<DeviceCodePollResult> devicePoll(@RequestBody DeviceRequest request) {
return R.ok(deviceCodeService.poll(request.deviceAuthId())); return R.ok(deviceCodeService.poll(request.deviceAuthId()));
} }
@Operation(summary = "Device flow: cancel a pending session") @Operation(summary = "Device flow: cancel a pending session")
@PostMapping("/device/cancel") @PostMapping("/device/cancel")
@RequireWorkspaceRole("admin")
public R<Void> deviceCancel(@RequestBody DeviceRequest request) { public R<Void> deviceCancel(@RequestBody DeviceRequest request) {
deviceCodeService.cancel(request.deviceAuthId()); deviceCodeService.cancel(request.deviceAuthId());
return R.ok(); return R.ok();
@ -74,6 +80,7 @@ public class OAuthController {
@Operation(summary = "手动刷新 Token") @Operation(summary = "手动刷新 Token")
@PostMapping("/refresh") @PostMapping("/refresh")
@RequireWorkspaceRole("admin")
public R<Void> refresh() { public R<Void> refresh() {
oauthService.refreshToken(); oauthService.refreshToken();
return R.ok(); return R.ok();
@ -81,6 +88,7 @@ public class OAuthController {
@Operation(summary = "清除 OAuth 凭证") @Operation(summary = "清除 OAuth 凭证")
@DeleteMapping("/revoke") @DeleteMapping("/revoke")
@RequireWorkspaceRole("admin")
public R<Void> revoke() { public R<Void> revoke() {
oauthService.revokeToken(); oauthService.revokeToken();
return R.ok(); return R.ok();
@ -88,6 +96,7 @@ public class OAuthController {
@Operation(summary = "获取 OAuth 连接状态") @Operation(summary = "获取 OAuth 连接状态")
@GetMapping("/status") @GetMapping("/status")
@RequireWorkspaceRole("admin")
public R<OAuthStatusResult> status() { public R<OAuthStatusResult> status() {
return R.ok(oauthService.getStatus()); return R.ok(oauthService.getStatus());
} }

View File

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