diff --git a/backend/internal/httpapi/server.go b/backend/internal/httpapi/server.go index 7958b13..78e50bf 100644 --- a/backend/internal/httpapi/server.go +++ b/backend/internal/httpapi/server.go @@ -213,6 +213,11 @@ func (s *Server) registerRoutes() { domainAPI.PUT("/domains/:id", s.dnsOperation, s.updateDomain) domainAPI.DELETE("/domains/:id", s.deleteDomain) domainAPI.POST("/domains/:id/issue", s.longOperation(certificateTaskTimeout), s.issueDomain) + api := s.router.Group("/api/v1", privateProjectResponse, s.requireAuthenticated) + api.GET("/tasks", s.listTasks) + api.GET("/tasks/:id", s.getTask) + api.DELETE("/tasks/:id", s.cancelTask) + api.GET("/tasks/:id/attempts", s.listTaskAttempts) adminAPI.GET("/settings", s.getSettings) adminAPI.PUT("/settings", s.updateSettings) diff --git a/backend/internal/httpapi/task_api.go b/backend/internal/httpapi/task_api.go index 036135e..325c928 100644 --- a/backend/internal/httpapi/task_api.go +++ b/backend/internal/httpapi/task_api.go @@ -20,8 +20,12 @@ func (s *Server) issueDomainAsTask(c *gin.Context) { s.writeError(c, http.StatusNotImplemented, "证书申请接口尚未配置", errors.New("证书申请工作流未配置")) return } - if s.tasks == nil || s.projectResources == nil || s.projectMembers == nil { - s.writeError(c, http.StatusServiceUnavailable, "证书任务权限服务尚未就绪", errors.New("任务、项目资源或项目权限服务未配置")) + if s.tasks == nil { + s.writeError(c, http.StatusNotImplemented, "证书任务接口尚未配置", errors.New("任务仓储未配置")) + return + } + if s.projectResources == nil || s.projectMembers == nil { + s.writeError(c, http.StatusServiceUnavailable, "证书任务权限服务尚未就绪", errors.New("项目资源或项目权限服务未配置")) return } domainID := strings.TrimSpace(c.Param("id")) diff --git a/backend/internal/repository/project_task_reader.go b/backend/internal/repository/project_task_reader.go index ca2a756..67a9c0a 100644 --- a/backend/internal/repository/project_task_reader.go +++ b/backend/internal/repository/project_task_reader.go @@ -21,11 +21,14 @@ type ProjectTaskReader interface { var _ ProjectTaskReader = (*SQLTaskRepository)(nil) -func taskVisibilityPredicate(alias string) (string, []any) { - roles := []domain.ProjectRole{ - domain.ProjectRoleAdmin, - domain.ProjectRoleAuditViewer, - domain.ProjectRoleReadOnly, +func taskVisibilityPredicate(alias string, permission domain.ProjectPermission) (string, []any) { + roles := []domain.ProjectRole{domain.ProjectRoleAdmin} + if permission == domain.PermissionTaskRead { + roles = []domain.ProjectRole{ + domain.ProjectRoleAdmin, + domain.ProjectRoleAuditViewer, + domain.ProjectRoleReadOnly, + } } placeholders := make([]string, 0, len(roles)) args := []any{""} @@ -55,7 +58,7 @@ func (r *SQLTaskRepository) ListVisibleTasks(ctx context.Context, actorID, domai if limit <= 0 || limit > 200 { limit = 50 } - predicate, args := taskVisibilityPredicate("tasks") + predicate, args := taskVisibilityPredicate("tasks", domain.PermissionTaskRead) args[0] = strings.TrimSpace(actorID) query := taskSelect + ` WHERE ` + predicate if domainID = strings.TrimSpace(domainID); domainID != "" { @@ -86,7 +89,7 @@ func (r *SQLTaskRepository) GetVisibleTask(ctx context.Context, actorID, taskID if r == nil || r.db == nil { return Task{}, errors.New("数据库连接不能为空") } - predicate, args := taskVisibilityPredicate("tasks") + predicate, args := taskVisibilityPredicate("tasks", domain.PermissionTaskRead) args[0] = strings.TrimSpace(actorID) args = append(args, strings.TrimSpace(taskID)) return scanTask(r.db.QueryRowContext(ctx, r.query(taskSelect+` WHERE `+predicate+` AND tasks.id = ?`), args...)) @@ -96,7 +99,7 @@ func (r *SQLTaskRepository) ListVisibleTaskAttempts(ctx context.Context, actorID if r == nil || r.db == nil { return nil, errors.New("数据库连接不能为空") } - predicate, args := taskVisibilityPredicate("tasks") + 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 attempts.id, attempts.task_id, attempts.attempt_number, @@ -131,7 +134,7 @@ func (r *SQLTaskRepository) CancelVisibleTask(ctx context.Context, actorID, task return fmt.Errorf("开始取消任务事务失败:%w", err) } rollback := func() { _ = tx.Rollback() } - predicate, predicateArgs := taskVisibilityPredicate("tasks") + predicate, predicateArgs := taskVisibilityPredicate("tasks", domain.PermissionTaskCancel) predicateArgs[0] = strings.TrimSpace(actorID) args := []any{message, nullableTime(finishedAt), time.Now().UTC(), strings.TrimSpace(taskID)} args = append(args, predicateArgs...)