feat(ECR-048): ReportTemplate 写面闭环并 Closed
growth.write POST/PUT · migration 000057 · 无新 C 端 · Loop STOP Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
|
||||
"github.com/yuxingu/digital-psychology/apps/api/internal/repository"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidReportTemplate = errors.New("invalid report template")
|
||||
ErrReportTemplateConflict = errors.New("report template code conflict")
|
||||
reportTemplateCodeRe = regexp.MustCompile(`^[a-z][a-z0-9_]{1,62}$`)
|
||||
reportTemplateSceneRe = regexp.MustCompile(`^[a-z][a-z0-9_]{0,30}$`)
|
||||
)
|
||||
|
||||
// ReportTemplateWriteBody is JSON for create/update.
|
||||
type ReportTemplateWriteBody struct {
|
||||
Code string `json:"code"`
|
||||
Title string `json:"title"`
|
||||
Scene string `json:"scene"`
|
||||
Active bool `json:"active"`
|
||||
}
|
||||
|
||||
// CreateReportTemplate validates, inserts, audits.
|
||||
func (s *Service) CreateReportTemplate(ctx context.Context, adminID uuid.UUID, body ReportTemplateWriteBody) (*repository.ReportTemplateRow, error) {
|
||||
in, err := normalizeReportTemplateWrite(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
meta, _ := json.Marshal(map[string]any{"code": in.Code, "scene": in.Scene, "active": in.Active})
|
||||
row, err := s.Repo.CreateReportTemplateWithAudit(ctx, adminID, in, meta)
|
||||
if repository.ReportTemplateCodeConflict(err) {
|
||||
return nil, ErrReportTemplateConflict
|
||||
}
|
||||
return row, err
|
||||
}
|
||||
|
||||
// UpdateReportTemplate validates, updates, audits.
|
||||
func (s *Service) UpdateReportTemplate(ctx context.Context, adminID, id uuid.UUID, body ReportTemplateWriteBody) (*repository.ReportTemplateRow, error) {
|
||||
in, err := normalizeReportTemplateWrite(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
meta, _ := json.Marshal(map[string]any{"code": in.Code, "scene": in.Scene, "active": in.Active})
|
||||
row, err := s.Repo.UpdateReportTemplateWithAudit(ctx, adminID, id, in, meta)
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return nil, ErrReportTemplateNotFound
|
||||
}
|
||||
if repository.ReportTemplateCodeConflict(err) {
|
||||
return nil, ErrReportTemplateConflict
|
||||
}
|
||||
return row, err
|
||||
}
|
||||
|
||||
func normalizeReportTemplateWrite(body ReportTemplateWriteBody) (repository.ReportTemplateWriteInput, error) {
|
||||
code := strings.TrimSpace(body.Code)
|
||||
title := strings.TrimSpace(body.Title)
|
||||
scene := strings.TrimSpace(body.Scene)
|
||||
if !reportTemplateCodeRe.MatchString(code) {
|
||||
return repository.ReportTemplateWriteInput{}, ErrInvalidReportTemplate
|
||||
}
|
||||
if !reportTemplateSceneRe.MatchString(scene) {
|
||||
return repository.ReportTemplateWriteInput{}, ErrInvalidReportTemplate
|
||||
}
|
||||
if title == "" || utf8.RuneCountInString(title) > 128 {
|
||||
return repository.ReportTemplateWriteInput{}, ErrInvalidReportTemplate
|
||||
}
|
||||
return repository.ReportTemplateWriteInput{Code: code, Title: title, Scene: scene, Active: body.Active}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user