feat: 分组密钥检查增加状态选项 (#86)

This commit is contained in:
tbphp
2025-08-01 10:01:49 +08:00
committed by GitHub
parent 1c658fad56
commit d4dd5eab67
5 changed files with 60 additions and 15 deletions

View File

@@ -62,6 +62,12 @@ type GroupIDRequest struct {
GroupID uint `json:"group_id" binding:"required"` GroupID uint `json:"group_id" binding:"required"`
} }
// ValidateGroupKeysRequest defines the payload for validating keys in a group.
type ValidateGroupKeysRequest struct {
GroupID uint `json:"group_id" binding:"required"`
Status string `json:"status,omitempty"`
}
// AddMultipleKeys handles creating new keys from a text block within a specific group. // AddMultipleKeys handles creating new keys from a text block within a specific group.
func (s *Server) AddMultipleKeys(c *gin.Context) { func (s *Server) AddMultipleKeys(c *gin.Context) {
var req KeyTextRequest var req KeyTextRequest
@@ -258,12 +264,18 @@ func (s *Server) TestMultipleKeys(c *gin.Context) {
// ValidateGroupKeys initiates a manual validation task for all keys in a group. // ValidateGroupKeys initiates a manual validation task for all keys in a group.
func (s *Server) ValidateGroupKeys(c *gin.Context) { func (s *Server) ValidateGroupKeys(c *gin.Context) {
var req GroupIDRequest var req ValidateGroupKeysRequest
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
response.Error(c, app_errors.NewAPIError(app_errors.ErrInvalidJSON, err.Error())) response.Error(c, app_errors.NewAPIError(app_errors.ErrInvalidJSON, err.Error()))
return return
} }
// Validate status if provided
if req.Status != "" && req.Status != models.KeyStatusActive && req.Status != models.KeyStatusInvalid {
response.Error(c, app_errors.NewAPIError(app_errors.ErrValidation, "Invalid status value"))
return
}
groupDB, ok := s.findGroupByID(c, req.GroupID) groupDB, ok := s.findGroupByID(c, req.GroupID)
if !ok { if !ok {
return return
@@ -275,7 +287,7 @@ func (s *Server) ValidateGroupKeys(c *gin.Context) {
return return
} }
taskStatus, err := s.KeyManualValidationService.StartValidationTask(group) taskStatus, err := s.KeyManualValidationService.StartValidationTask(group, req.Status)
if err != nil { if err != nil {
response.Error(c, app_errors.NewAPIError(app_errors.ErrTaskInProgress, err.Error())) response.Error(c, app_errors.NewAPIError(app_errors.ErrTaskInProgress, err.Error()))
return return

View File

@@ -41,10 +41,14 @@ func NewKeyManualValidationService(db *gorm.DB, validator *keypool.KeyValidator,
} }
// StartValidationTask starts a new manual validation task for a given group. // StartValidationTask starts a new manual validation task for a given group.
func (s *KeyManualValidationService) StartValidationTask(group *models.Group) (*TaskStatus, error) { func (s *KeyManualValidationService) StartValidationTask(group *models.Group, status string) (*TaskStatus, error) {
var keys []models.APIKey var keys []models.APIKey
if err := s.DB.Where("group_id = ?", group.ID).Find(&keys).Error; err != nil { query := s.DB.Where("group_id = ?", group.ID)
return nil, fmt.Errorf("failed to get keys for group %s: %w", group.Name, err) if status != "" {
query = query.Where("status = ?", status)
}
if err := query.Find(&keys).Error; err != nil {
return nil, fmt.Errorf("failed to get keys for group %s with status '%s': %w", group.Name, status, err)
} }
if len(keys) == 0 { if len(keys) == 0 {
@@ -59,13 +63,20 @@ func (s *KeyManualValidationService) StartValidationTask(group *models.Group) (*
} }
// Run the validation in a separate goroutine // Run the validation in a separate goroutine
go s.runValidation(group, keys) go s.runValidation(group, keys, status)
return taskStatus, nil return taskStatus, nil
} }
func (s *KeyManualValidationService) runValidation(group *models.Group, keys []models.APIKey) { func (s *KeyManualValidationService) runValidation(group *models.Group, keys []models.APIKey, status string) {
logrus.Infof("Starting manual validation for group %s", group.Name) logFields := logrus.Fields{
"group": group.Name,
"status": status,
}
if status == "" {
logFields["status"] = "all"
}
logrus.WithFields(logFields).Info("Starting manual validation")
jobs := make(chan models.APIKey, len(keys)) jobs := make(chan models.APIKey, len(keys))
results := make(chan bool, len(keys)) results := make(chan bool, len(keys))

View File

@@ -175,14 +175,21 @@ export const keysApi = {
}, },
// 验证分组密钥 // 验证分组密钥
async validateGroupKeys(groupId: number): Promise<{ async validateGroupKeys(
groupId: number,
status?: "active" | "invalid"
): Promise<{
is_running: boolean; is_running: boolean;
group_name: string; group_name: string;
processed: number; processed: number;
total: number; total: number;
started_at: string; started_at: string;
}> { }> {
const res = await http.post("/keys/validate-group", { group_id: groupId }); const payload: { group_id: number; status?: string } = { group_id: groupId };
if (status) {
payload.status = status;
}
const res = await http.post("/keys/validate-group", payload);
return res.data; return res.data;
}, },

View File

@@ -49,7 +49,7 @@ async function pollOnce() {
let msg = "任务已完成。"; let msg = "任务已完成。";
if (task.task_type === "KEY_VALIDATION") { if (task.task_type === "KEY_VALIDATION") {
const result = task.result as import("@/types/models").KeyValidationResult; const result = task.result as import("@/types/models").KeyValidationResult;
msg = `密钥验证完成,处理了 ${result.total_keys} 个密钥,其中 ${result.valid_keys}有效${result.invalid_keys}无效`; msg = `密钥验证完成,处理了 ${result.total_keys} 个密钥,其中 ${result.valid_keys}成功${result.invalid_keys}失败。请注意:验证失败并不一定拉黑该密钥,需要失败次数达到阈值才会拉黑`;
} else if (task.task_type === "KEY_IMPORT") { } else if (task.task_type === "KEY_IMPORT") {
const result = task.result as import("@/types/models").KeyImportResult; const result = task.result as import("@/types/models").KeyImportResult;
msg = `密钥导入完成,成功添加 ${result.added_count} 个密钥,忽略了 ${result.ignored_count} 个。`; msg = `密钥导入完成,成功添加 ${result.added_count} 个密钥,忽略了 ${result.ignored_count} 个。`;

View File

@@ -67,6 +67,8 @@ const moreOptions = [
{ label: "清空所有无效密钥", key: "clearInvalid", props: { style: { color: "#d03050" } } }, { label: "清空所有无效密钥", key: "clearInvalid", props: { style: { color: "#d03050" } } },
{ type: "divider" }, { type: "divider" },
{ label: "验证所有密钥", key: "validateAll" }, { label: "验证所有密钥", key: "validateAll" },
{ label: "验证有效密钥", key: "validateActive" },
{ label: "验证无效密钥", key: "validateInvalid" },
]; ];
let testingMsg: MessageReactive | null = null; let testingMsg: MessageReactive | null = null;
@@ -150,7 +152,13 @@ function handleMoreAction(key: string) {
restoreAllInvalid(); restoreAllInvalid();
break; break;
case "validateAll": case "validateAll":
validateAllKeys(); validateKeys("all");
break;
case "validateActive":
validateKeys("active");
break;
case "validateInvalid":
validateKeys("invalid");
break; break;
case "clearInvalid": case "clearInvalid":
clearAllInvalid(); clearAllInvalid();
@@ -395,17 +403,24 @@ async function restoreAllInvalid() {
}); });
} }
async function validateAllKeys() { async function validateKeys(status: "all" | "active" | "invalid") {
if (!props.selectedGroup?.id || testingMsg) { if (!props.selectedGroup?.id || testingMsg) {
return; return;
} }
testingMsg = window.$message.info("正在验证密钥...", { let statusText = "所有";
if (status === "active") {
statusText = "有效";
} else if (status === "invalid") {
statusText = "无效";
}
testingMsg = window.$message.info(`正在验证${statusText}密钥...`, {
duration: 0, duration: 0,
}); });
try { try {
await keysApi.validateGroupKeys(props.selectedGroup.id); await keysApi.validateGroupKeys(props.selectedGroup.id, status === "all" ? undefined : status);
localStorage.removeItem("last_closed_task"); localStorage.removeItem("last_closed_task");
appState.taskPollingTrigger++; appState.taskPollingTrigger++;
} catch (_error) { } catch (_error) {