Defer locked-period supplements to a pending ledger, route duty-holder notifications, persist stage-scoped comments, and prefer Approver for reopen.
110 lines
4.1 KiB
Go
110 lines
4.1 KiB
Go
package docnotify
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
|
|
"chat-agent-system/internal/ctxmgr"
|
|
"chat-agent-system/internal/docgov"
|
|
"chat-agent-system/internal/events"
|
|
"chat-agent-system/internal/notification"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
)
|
|
|
|
// EventConsumer is the durable notify worker. Closures remain the unique writer until live cutover.
|
|
type EventConsumer struct {
|
|
Notify *notification.Service
|
|
Docs DocumentLookup
|
|
Chat *ctxmgr.ContextManager
|
|
Env string
|
|
}
|
|
|
|
func (c *EventConsumer) HandleLease(ctx context.Context, lease events.Lease, tx pgx.Tx) error {
|
|
if c == nil || c.Notify == nil {
|
|
return events.ErrUnknownConsumer
|
|
}
|
|
principal := events.ServicePrincipal{
|
|
ID: "notify-" + c.Env, Environment: c.Env, Consumer: events.ConsumerNotify,
|
|
Actions: []string{"notify.emit"},
|
|
}
|
|
if err := events.AuthorizePrincipal(principal, lease.Environment, lease.ProjectID, "notify.emit"); err != nil {
|
|
return events.ErrQuarantine
|
|
}
|
|
kind, title, body := notifyCopy(lease.EventName)
|
|
if kind == "" {
|
|
return nil
|
|
}
|
|
docID := lease.Envelope.AggregateID
|
|
var payload map[string]any
|
|
_ = json.Unmarshal(lease.Envelope.Payload, &payload)
|
|
if payload != nil {
|
|
if id, ok := payload["doc_id"].(string); ok && id != "" {
|
|
docID = id
|
|
}
|
|
}
|
|
var recipient int64
|
|
projectID := lease.ProjectID
|
|
var doc *docgov.DocumentRecord
|
|
if c.Docs != nil && docID != "" {
|
|
d, err := c.Docs.GetDocument(ctx, docID)
|
|
if err != nil || d == nil {
|
|
return events.ErrQuarantine
|
|
}
|
|
if d.ProjectID != lease.ProjectID {
|
|
return events.ErrQuarantine
|
|
}
|
|
doc = d
|
|
projectID = d.ProjectID
|
|
}
|
|
recipient = RecipientForDocEvent(doc, lease.EventName)
|
|
if recipient <= 0 && doc != nil {
|
|
recipient = doc.AuthorID
|
|
}
|
|
if recipient <= 0 {
|
|
return events.ErrQuarantine
|
|
}
|
|
p := notification.DocumentEventPayload{ProjectID: projectID, DocID: docID}
|
|
if err := c.Notify.EmitVisibleDocumentEvent(ctx, tx, lease.EventID, kind, title, body, recipient, p); err != nil {
|
|
return err
|
|
}
|
|
if lease.EventName == events.EventDownstreamImpact && c.Chat != nil {
|
|
impacted, _ := payload["impacted_doc_id"].(string)
|
|
_ = PostProjectNotice(ctx, c.Chat, projectID, recipient, downstreamChatBody(docID, impacted), nil)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func IntendedNotifyDigest(eventID, kind string, recipient int64) string {
|
|
return events.VisibleOutcomeDigest(eventID, kind, recipient)
|
|
}
|
|
|
|
func notifyCopy(eventName string) (kind, title, body string) {
|
|
switch eventName {
|
|
case events.EventCandidateReady:
|
|
return notification.TypeDocAgentCandidateReady, "智能体变更待确认", "文档有高风险智能体候选变更,请确认后生效。"
|
|
case events.EventVersionCommitted:
|
|
return notification.TypeDocAgentVersionCommitted, "智能体版本已生效", "新的智能体文档版本已提交。"
|
|
case events.EventDownstreamImpact:
|
|
return notification.TypeDocDownstreamImpact, "下游文档受影响", "上游文档变更,请复核关联文档。"
|
|
case events.EventChangeReportDegraded:
|
|
return notification.TypeDocChangeReportDegraded, "变更报告未完整评估", "变更报告降级,受控文档暂不可送审。"
|
|
case events.EventApproved:
|
|
return notification.TypeDocApproved, "文档已批准", "文档已完成终审批准。"
|
|
case events.EventDocProposalRequired:
|
|
return notification.TypeDocProposalRequired, "文档变更待确认", "已认领文档有变更提案,请确认后由您发起修改。"
|
|
case events.EventDocUnclaimedEdit:
|
|
return notification.TypeDocUnclaimedEditApplied, "文档已更新", "未认领文档已被直接更新(无需您确认)。"
|
|
case notification.EventDocReviewRequested:
|
|
return notification.TypeDocReviewRequested, "文档待审核", "有文档已送审,请审核。"
|
|
case notification.EventDocApprovalRequested:
|
|
return notification.TypeDocApprovalRequested, "文档待批准", "审核已通过,请批准。"
|
|
case notification.EventDocRejected:
|
|
return notification.TypeDocRejected, "文档已驳回", "文档已被驳回,请查看原因并修订。"
|
|
case notification.EventDocReopened:
|
|
return notification.TypeDocReopened, "文档已重开", "文档已重开修订,请继续编制。"
|
|
default:
|
|
return "", "", ""
|
|
}
|
|
}
|