Files
agentic-coding-workflow/internal/chat/service_template.go
T

108 lines
3.0 KiB
Go

package chat
import (
"context"
"log/slog"
"github.com/google/uuid"
"github.com/yan1h/agent-coding-workflow/internal/audit"
"github.com/yan1h/agent-coding-workflow/internal/infra/errs"
)
type templateService struct {
repo Repository
auditor audit.Recorder
log *slog.Logger
}
var _ TemplateService = (*templateService)(nil)
// NewTemplateService 构造 prompt_templates CRUD 服务。
func NewTemplateService(repo Repository, a audit.Recorder, log *slog.Logger) TemplateService {
return &templateService{repo: repo, auditor: a, log: log}
}
func (s *templateService) List(ctx context.Context, userID uuid.UUID) ([]PromptTemplate, error) {
return s.repo.ListPromptTemplatesForUser(ctx, userID)
}
func (s *templateService) Create(ctx context.Context, userID uuid.UUID, name, content string, scope TemplateScope) (*PromptTemplate, error) {
if scope != TemplateScopeSystem && scope != TemplateScopeUser {
return nil, errs.New(errs.CodeInvalidInput, "invalid scope")
}
params := InsertTemplateParams{
ID: uuid.Must(uuid.NewV7()),
Name: name,
Content: content,
Scope: scope,
}
if scope == TemplateScopeUser {
uid := userID
params.OwnerID = &uid
}
t, err := s.repo.InsertPromptTemplate(ctx, params)
if err != nil {
return nil, err
}
if scope == TemplateScopeSystem {
s.tryAudit(ctx, audit.Entry{
UserID: &userID, Action: "prompt_template.created",
TargetType: "prompt_template", TargetID: t.ID.String(),
})
}
return t, nil
}
func (s *templateService) Update(ctx context.Context, userID, id uuid.UUID, name, content string) error {
t, err := s.repo.GetPromptTemplate(ctx, id)
if err != nil {
return err
}
if t == nil {
return errs.New(errs.CodeChatTemplateNotFound, "template not found")
}
if t.Scope == TemplateScopeUser && (t.OwnerID == nil || *t.OwnerID != userID) {
return errs.New(errs.CodeForbidden, "not template owner")
}
if err := s.repo.UpdatePromptTemplate(ctx, id, name, content); err != nil {
return err
}
if t.Scope == TemplateScopeSystem {
s.tryAudit(ctx, audit.Entry{
UserID: &userID, Action: "prompt_template.updated",
TargetType: "prompt_template", TargetID: id.String(),
})
}
return nil
}
func (s *templateService) Delete(ctx context.Context, userID, id uuid.UUID) error {
t, err := s.repo.GetPromptTemplate(ctx, id)
if err != nil {
return err
}
if t == nil {
return errs.New(errs.CodeChatTemplateNotFound, "template not found")
}
if t.Scope == TemplateScopeUser && (t.OwnerID == nil || *t.OwnerID != userID) {
return errs.New(errs.CodeForbidden, "not template owner")
}
if err := s.repo.DeletePromptTemplate(ctx, id); err != nil {
return err
}
if t.Scope == TemplateScopeSystem {
s.tryAudit(ctx, audit.Entry{
UserID: &userID, Action: "prompt_template.deleted",
TargetType: "prompt_template", TargetID: id.String(),
})
}
return nil
}
func (s *templateService) tryAudit(ctx context.Context, e audit.Entry) {
if err := s.auditor.Record(ctx, e); err != nil {
s.log.Warn("audit record failed", "action", e.Action, "err", err)
}
}