From 802109e96a5cbe54620d8c544ce29207dd714109 Mon Sep 17 00:00:00 2001 From: xuans Date: Tue, 29 Sep 2026 18:09:58 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9D=83=E9=99=90=E6=95=B4=E6=94=B9=EF=BC=9A?= =?UTF-8?q?=E6=8E=A5=E5=85=A5=E9=A1=B9=E7=9B=AE=E4=BB=BB=E5=8A=A1=E8=B7=AF?= =?UTF-8?q?=E7=94=B1=E4=B8=8E=E8=AF=81=E4=B9=A6=E4=BB=BB=E5=8A=A1=E5=88=A4?= =?UTF-8?q?=E6=9D=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 提交当前任务权限开发检查点,保持总体验收位置为 P0-03 完成待复审。 --- backend/internal/httpapi/server.go | 5 +++++ backend/internal/httpapi/task_api.go | 8 +++++-- .../repository/project_task_reader.go | 21 +++++++++++-------- 3 files changed, 23 insertions(+), 11 deletions(-) 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...)