feat(api): wire document approval hook and project notifications API.
Register workflow approval callback on server start and expose GET /projects/{id}/notifications.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
committed by
weichen
co-authored by
Cursor
parent
32b88beee0
commit
4bfe1cb5ad
@@ -0,0 +1,35 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (s *Server) handleListProjectNotifications(w http.ResponseWriter, r *http.Request) {
|
||||
user, ok := s.requireAuthenticatedUser(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if s.notifySvc == nil || !s.notifySvc.Available() {
|
||||
http.Error(w, "notification service unavailable", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
|
||||
projectID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err != nil || projectID <= 0 {
|
||||
http.Error(w, "invalid project id", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
sinceID, _ := strconv.ParseInt(r.URL.Query().Get("since_id"), 10, 64)
|
||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||
|
||||
items, err := s.notifySvc.ListProjectNotifications(r.Context(), user.ID, projectID, sinceID, limit)
|
||||
if err != nil {
|
||||
http.Error(w, "list notifications failed: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
writeJSONResponse(w, http.StatusOK, map[string]any{
|
||||
"items": items,
|
||||
})
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"chat-agent-system/internal/coordinator"
|
||||
"chat-agent-system/internal/ctxmgr"
|
||||
"chat-agent-system/internal/intent"
|
||||
"chat-agent-system/internal/notification"
|
||||
"chat-agent-system/internal/observability"
|
||||
"chat-agent-system/internal/projectinstance"
|
||||
"chat-agent-system/internal/projectworkflow"
|
||||
@@ -42,6 +43,7 @@ type Server struct {
|
||||
authzSvc *authz.Service
|
||||
wfDefSvc *workflowdef.Service
|
||||
instSvc *projectinstance.Service
|
||||
notifySvc *notification.Service
|
||||
resolver *workspace.Resolver
|
||||
httpServer *http.Server
|
||||
}
|
||||
@@ -97,8 +99,10 @@ func NewServer(cfg *config.Config, svc *bizdev.Service) *Server {
|
||||
authzSvc: authzSvc,
|
||||
wfDefSvc: wfDefSvc,
|
||||
instSvc: instSvc,
|
||||
notifySvc: notification.NewService(pool),
|
||||
resolver: workspace.NewResolver(cfg.DataDir, pool),
|
||||
}
|
||||
s.registerWorkflowApprovalHook()
|
||||
s.initTaskRunExecutors()
|
||||
return s
|
||||
}
|
||||
@@ -149,6 +153,7 @@ func (s *Server) Routes() http.Handler {
|
||||
mux.HandleFunc("GET /api/v1/projects/{id}/workflows/{workflow_key}/runs", s.handleListProjectWorkflowRuns)
|
||||
mux.HandleFunc("GET /api/v1/projects/{id}/lineage", s.handleGetProjectLineage)
|
||||
mux.HandleFunc("GET /api/v1/projects/{id}/documents", s.handleListProjectWorkflowDocuments)
|
||||
mux.HandleFunc("GET /api/v1/projects/{id}/notifications", s.handleListProjectNotifications)
|
||||
|
||||
// 3. 对话协同服务 (标准 JSON 阻塞)
|
||||
mux.HandleFunc("POST /api/v1/chat", s.handleChat)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"chat-agent-system/internal/docgov"
|
||||
"chat-agent-system/internal/notification"
|
||||
)
|
||||
|
||||
func (s *Server) registerWorkflowApprovalHook() {
|
||||
if s == nil || s.svc == nil || s.svc.DocGov() == nil || s.instSvc == nil || !s.instSvc.Available() {
|
||||
return
|
||||
}
|
||||
s.svc.DocGov().AddOnApprovedHook(s.onWorkflowDocumentApproved)
|
||||
}
|
||||
|
||||
func (s *Server) onWorkflowDocumentApproved(ctx context.Context, doc *docgov.DocumentRecord) {
|
||||
if doc == nil || doc.TaskKey == "" || doc.ProjectID <= 0 || s.instSvc == nil {
|
||||
return
|
||||
}
|
||||
|
||||
result, err := s.instSvc.HandleDocumentApproved(ctx, doc.ProjectID, doc.TaskKey)
|
||||
if err != nil || result == nil || !result.StageReady {
|
||||
return
|
||||
}
|
||||
if s.notifySvc == nil || !s.notifySvc.Available() {
|
||||
return
|
||||
}
|
||||
|
||||
project, err := s.pwSvc.GetProject(ctx, doc.ProjectID, 0)
|
||||
if err != nil || project == nil || project.CreatorUserID <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
_, _ = s.notifySvc.EmitStageReadyToAdvance(ctx, project.CreatorUserID, notification.StageReadyPayload{
|
||||
ProjectID: doc.ProjectID,
|
||||
WorkflowInstanceID: result.InstanceID,
|
||||
StageInstanceID: result.StageInstanceID,
|
||||
StageKey: result.StageKey,
|
||||
StageName: result.StageName,
|
||||
ConfigRevision: result.ConfigRevision,
|
||||
RequiredDocCount: result.RequiredDocCount,
|
||||
ApprovedDocCount: result.ApprovedDocCount,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user