87 lines
3.5 KiB
Go
87 lines
3.5 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.pcux.cn/xuans/Scert/backend/internal/certificate"
|
|
"git.pcux.cn/xuans/Scert/backend/internal/domain"
|
|
)
|
|
|
|
// TaskValidationResult 仅保存已校验的公开元数据,不包含证书路径和私钥。
|
|
type TaskValidationResult struct {
|
|
TaskID string `json:"task_id"`
|
|
AttemptID string `json:"attempt_id"`
|
|
AttemptNumber int `json:"attempt_number"`
|
|
Validation certificate.ValidationResult `json:"validation"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
type TaskValidationReader interface {
|
|
ListVisibleTaskValidations(context.Context, string, string) ([]TaskValidationResult, error)
|
|
}
|
|
|
|
func (r *SQLTaskRepository) recordCompletionValidation(ctx context.Context, tx *sql.Tx, completion TaskCompletion) error {
|
|
if completion.Report != nil || completion.Status != "success" || completion.Retry {
|
|
return errors.New("校验元数据只能随独立校验任务成功提交")
|
|
}
|
|
var attemptNumber int
|
|
var taskType string
|
|
if err := tx.QueryRowContext(ctx, r.query(`SELECT attempts.attempt_number, tasks.task_type
|
|
FROM task_attempts attempts JOIN tasks ON tasks.id = attempts.task_id
|
|
WHERE attempts.id = ? AND tasks.id = ?`), completion.AttemptID, completion.TaskID).Scan(&attemptNumber, &taskType); err != nil {
|
|
return fmt.Errorf("读取校验结果所属任务失败:%w", err)
|
|
}
|
|
if taskType != "certificate_validate" {
|
|
return errors.New("校验结果不能保存到其他类型任务")
|
|
}
|
|
content, err := json.Marshal(completion.Validation)
|
|
if err != nil {
|
|
return fmt.Errorf("序列化校验结果失败:%w", err)
|
|
}
|
|
if _, err := tx.ExecContext(ctx, r.query(`INSERT INTO task_validation_results
|
|
(task_id, attempt_id, attempt_number, validation_json, created_at) VALUES (?, ?, ?, ?, ?)`),
|
|
completion.TaskID, completion.AttemptID, attemptNumber, string(content), completion.FinishedAt.UTC()); err != nil {
|
|
return fmt.Errorf("保存校验结果失败:%w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *SQLTaskRepository) ListVisibleTaskValidations(ctx context.Context, actorID, taskID string) ([]TaskValidationResult, error) {
|
|
if r == nil || r.db == nil {
|
|
return nil, errors.New("数据库连接不能为空")
|
|
}
|
|
predicate, args := taskVisibilityPredicate("tasks", domain.PermissionTaskRead)
|
|
args[0] = strings.TrimSpace(actorID)
|
|
args = append(args, strings.TrimSpace(taskID))
|
|
rows, err := r.db.QueryContext(ctx, r.query(`SELECT results.task_id, results.attempt_id, results.attempt_number,
|
|
results.validation_json, results.created_at FROM task_validation_results results
|
|
JOIN tasks ON tasks.id = results.task_id WHERE `+predicate+` AND results.task_id = ? ORDER BY results.attempt_number`), args...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("查询任务校验结果失败:%w", err)
|
|
}
|
|
defer rows.Close()
|
|
items := make([]TaskValidationResult, 0)
|
|
for rows.Next() {
|
|
var item TaskValidationResult
|
|
var content string
|
|
if err := rows.Scan(&item.TaskID, &item.AttemptID, &item.AttemptNumber, &content, &item.CreatedAt); err != nil {
|
|
return nil, fmt.Errorf("读取任务校验结果失败:%w", err)
|
|
}
|
|
if err := json.Unmarshal([]byte(content), &item.Validation); err != nil {
|
|
return nil, fmt.Errorf("解析任务校验结果失败:%w", err)
|
|
}
|
|
item.CreatedAt = item.CreatedAt.UTC()
|
|
items = append(items, item)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, fmt.Errorf("读取任务校验结果列表失败:%w", err)
|
|
}
|
|
return items, nil
|
|
}
|