mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 09:38:02 +00:00
feat: 实现 API Keys 批量删除后端功能
- 新增 DELETE /admin/api-keys/batch 端点
- 支持批量删除最多100个API Keys
- 完整的请求参数验证(数组格式、数量限制、ID有效性)
- 逐个删除并记录成功/失败状态
- 详细的错误信息和日志记录
- 返回成功/失败统计结果
请求格式: { "keyIds": ["key1", "key2", ...] }
响应格式: { "success": true, "data": { "successCount": 2, "failedCount": 0, "errors": [] } }
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
14
.mcp.json
Normal file
14
.mcp.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"spec-workflow": {
|
||||||
|
"type": "stdio",
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"@pimzino/spec-workflow-mcp@latest",
|
||||||
|
"/Users/weidian/project/claude-relay-service"
|
||||||
|
],
|
||||||
|
"env": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -814,6 +814,95 @@ router.delete('/api-keys/:keyId', authenticateAdmin, async (req, res) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 批量删除API Keys
|
||||||
|
router.delete('/api-keys/batch', authenticateAdmin, async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { keyIds } = req.body
|
||||||
|
|
||||||
|
// 参数验证
|
||||||
|
if (!keyIds || !Array.isArray(keyIds) || keyIds.length === 0) {
|
||||||
|
return res.status(400).json({
|
||||||
|
error: 'Invalid request',
|
||||||
|
message: 'keyIds 必须是一个非空数组'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyIds.length > 100) {
|
||||||
|
return res.status(400).json({
|
||||||
|
error: 'Too many keys',
|
||||||
|
message: '每次最多只能删除100个API Keys'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证keyIds格式
|
||||||
|
const invalidKeys = keyIds.filter((id) => !id || typeof id !== 'string')
|
||||||
|
if (invalidKeys.length > 0) {
|
||||||
|
return res.status(400).json({
|
||||||
|
error: 'Invalid key IDs',
|
||||||
|
message: '包含无效的API Key ID'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(`🗑️ Admin attempting batch delete of ${keyIds.length} API keys`)
|
||||||
|
|
||||||
|
const results = {
|
||||||
|
successCount: 0,
|
||||||
|
failedCount: 0,
|
||||||
|
errors: []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 逐个删除,记录成功和失败情况
|
||||||
|
for (const keyId of keyIds) {
|
||||||
|
try {
|
||||||
|
// 检查API Key是否存在
|
||||||
|
const apiKey = await apiKeyService.getApiKey(keyId)
|
||||||
|
if (!apiKey) {
|
||||||
|
results.failedCount++
|
||||||
|
results.errors.push({ keyId, error: 'API Key 不存在' })
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行删除
|
||||||
|
await apiKeyService.deleteApiKey(keyId)
|
||||||
|
results.successCount++
|
||||||
|
|
||||||
|
logger.success(`✅ Batch delete: API key ${keyId} deleted successfully`)
|
||||||
|
} catch (error) {
|
||||||
|
results.failedCount++
|
||||||
|
results.errors.push({
|
||||||
|
keyId,
|
||||||
|
error: error.message || '删除失败'
|
||||||
|
})
|
||||||
|
|
||||||
|
logger.error(`❌ Batch delete failed for key ${keyId}:`, error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录批量删除结果
|
||||||
|
if (results.successCount > 0) {
|
||||||
|
logger.success(
|
||||||
|
`🎉 Batch delete completed: ${results.successCount} successful, ${results.failedCount} failed`
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
logger.warn(
|
||||||
|
`⚠️ Batch delete completed with no successful deletions: ${results.failedCount} failed`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
success: true,
|
||||||
|
message: `批量删除完成`,
|
||||||
|
data: results
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('❌ Failed to batch delete API keys:', error)
|
||||||
|
return res.status(500).json({
|
||||||
|
error: 'Batch delete failed',
|
||||||
|
message: error.message
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 👥 账户分组管理
|
// 👥 账户分组管理
|
||||||
|
|
||||||
// 创建账户分组
|
// 创建账户分组
|
||||||
|
|||||||
Reference in New Issue
Block a user