Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

150 linhas
4.0KB

  1. package draftsvc
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "qctextbuilder/internal/domain"
  11. "qctextbuilder/internal/store"
  12. )
  13. type UpsertDraftRequest struct {
  14. DraftID string `json:"draftId,omitempty"`
  15. TemplateID int64 `json:"templateId"`
  16. ManifestID string `json:"manifestId,omitempty"`
  17. Source string `json:"source,omitempty"`
  18. RequestName string `json:"requestName,omitempty"`
  19. GlobalData map[string]any `json:"globalData"`
  20. FieldValues map[string]string `json:"fieldValues"`
  21. Status string `json:"status,omitempty"`
  22. Notes string `json:"notes,omitempty"`
  23. }
  24. type Service struct {
  25. drafts store.DraftStore
  26. templates store.TemplateStore
  27. manifests store.ManifestStore
  28. }
  29. func New(draftStore store.DraftStore, templateStore store.TemplateStore, manifestStore store.ManifestStore) *Service {
  30. return &Service{
  31. drafts: draftStore,
  32. templates: templateStore,
  33. manifests: manifestStore,
  34. }
  35. }
  36. func (s *Service) SaveDraft(ctx context.Context, req UpsertDraftRequest) (*domain.BuildDraft, error) {
  37. templateID := req.TemplateID
  38. if strings.TrimSpace(req.DraftID) != "" {
  39. existing, err := s.drafts.GetDraftByID(ctx, strings.TrimSpace(req.DraftID))
  40. if err != nil {
  41. return nil, fmt.Errorf("get draft: %w", err)
  42. }
  43. if templateID == 0 {
  44. templateID = existing.TemplateID
  45. }
  46. }
  47. if templateID <= 0 {
  48. return nil, errors.New("templateId is required")
  49. }
  50. template, err := s.templates.GetTemplateByID(ctx, templateID)
  51. if err != nil {
  52. return nil, fmt.Errorf("get template: %w", err)
  53. }
  54. if !template.IsAITemplate {
  55. return nil, errors.New("only ai templates are allowed")
  56. }
  57. manifestID := strings.TrimSpace(req.ManifestID)
  58. if manifestID == "" {
  59. manifest, err := s.manifests.GetActiveManifestByTemplateID(ctx, templateID)
  60. if err != nil {
  61. return nil, fmt.Errorf("get active manifest: %w", err)
  62. }
  63. manifestID = manifest.ID
  64. }
  65. globalDataJSON, err := json.Marshal(req.GlobalData)
  66. if err != nil {
  67. return nil, errors.New("globalData is invalid JSON")
  68. }
  69. fieldValuesJSON, err := json.Marshal(req.FieldValues)
  70. if err != nil {
  71. return nil, errors.New("fieldValues is invalid JSON")
  72. }
  73. now := time.Now().UTC()
  74. source := defaultString(req.Source, "ui")
  75. status := normalizeDraftStatus(req.Status)
  76. if status == "" {
  77. status = "draft"
  78. }
  79. draft := domain.BuildDraft{
  80. ID: strings.TrimSpace(req.DraftID),
  81. TemplateID: templateID,
  82. ManifestID: manifestID,
  83. Source: source,
  84. RequestName: strings.TrimSpace(req.RequestName),
  85. GlobalDataJSON: globalDataJSON,
  86. FieldValuesJSON: fieldValuesJSON,
  87. Status: status,
  88. Notes: strings.TrimSpace(req.Notes),
  89. UpdatedAt: now,
  90. }
  91. if draft.ID == "" {
  92. draft.ID = strconv.FormatInt(time.Now().UnixNano(), 10)
  93. draft.CreatedAt = now
  94. if err := s.drafts.CreateDraft(ctx, draft); err != nil {
  95. return nil, fmt.Errorf("create draft: %w", err)
  96. }
  97. } else {
  98. existing, err := s.drafts.GetDraftByID(ctx, draft.ID)
  99. if err != nil {
  100. return nil, fmt.Errorf("get draft: %w", err)
  101. }
  102. draft.CreatedAt = existing.CreatedAt
  103. if err := s.drafts.UpdateDraft(ctx, draft); err != nil {
  104. return nil, fmt.Errorf("update draft: %w", err)
  105. }
  106. }
  107. return s.drafts.GetDraftByID(ctx, draft.ID)
  108. }
  109. func (s *Service) GetDraft(ctx context.Context, draftID string) (*domain.BuildDraft, error) {
  110. return s.drafts.GetDraftByID(ctx, strings.TrimSpace(draftID))
  111. }
  112. func (s *Service) ListDrafts(ctx context.Context, limit int) ([]domain.BuildDraft, error) {
  113. if limit <= 0 {
  114. limit = 50
  115. }
  116. return s.drafts.ListDrafts(ctx, limit)
  117. }
  118. func normalizeDraftStatus(status string) string {
  119. switch strings.ToLower(strings.TrimSpace(status)) {
  120. case "":
  121. return ""
  122. case "draft", "reviewed", "submitted":
  123. return strings.ToLower(strings.TrimSpace(status))
  124. default:
  125. return "draft"
  126. }
  127. }
  128. func defaultString(value, fallback string) string {
  129. if strings.TrimSpace(value) == "" {
  130. return fallback
  131. }
  132. return strings.TrimSpace(value)
  133. }