Files
digital-psychology/apps/api/internal/repository/report_template_write.go
T
jackyu66gitandCursor e0f605558b feat(ECR-048): ReportTemplate 写面闭环并 Closed
growth.write POST/PUT · migration 000057 · 无新 C 端 · Loop STOP

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-13 22:51:42 +08:00

118 lines
3.2 KiB
Go

package repository
import (
"context"
"encoding/json"
"errors"
"strings"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
)
// ReportTemplateWriteInput is create/update payload.
type ReportTemplateWriteInput struct {
Code string
Title string
Scene string
Active bool
}
// CreateReportTemplateWithAudit inserts and audits.
func (r *AdminRepo) CreateReportTemplateWithAudit(
ctx context.Context, adminID uuid.UUID, in ReportTemplateWriteInput, meta json.RawMessage,
) (*ReportTemplateRow, error) {
tx, err := r.Pool.Begin(ctx)
if err != nil {
return nil, err
}
defer tx.Rollback(ctx)
var row ReportTemplateRow
err = tx.QueryRow(ctx, `
INSERT INTO report_templates(code, title, scene, active, system)
VALUES ($1,$2,$3,$4,false)
RETURNING id, code, title, scene, active, system, updated_at`,
in.Code, in.Title, in.Scene, in.Active,
).Scan(&row.ID, &row.Code, &row.Title, &row.Scene, &row.Active, &row.System, &row.UpdatedAt)
if err != nil {
return nil, mapReportTemplateWriteErr(err)
}
if meta == nil {
meta = json.RawMessage(`{}`)
}
if _, err := tx.Exec(ctx, `
INSERT INTO admin_audit_logs(admin_id, action, target_type, target_id, meta)
VALUES ($1,'growth.report_template.create','report_template',$2,$3)`,
adminID, row.ID.String(), meta,
); err != nil {
return nil, err
}
if err := tx.Commit(ctx); err != nil {
return nil, err
}
return &row, nil
}
// UpdateReportTemplateWithAudit updates and audits.
func (r *AdminRepo) UpdateReportTemplateWithAudit(
ctx context.Context, adminID, id uuid.UUID, in ReportTemplateWriteInput, meta json.RawMessage,
) (*ReportTemplateRow, error) {
tx, err := r.Pool.Begin(ctx)
if err != nil {
return nil, err
}
defer tx.Rollback(ctx)
var system bool
var oldCode string
err = tx.QueryRow(ctx, `SELECT system, code FROM report_templates WHERE id=$1`, id).Scan(&system, &oldCode)
if errors.Is(err, pgx.ErrNoRows) {
return nil, pgx.ErrNoRows
}
if err != nil {
return nil, err
}
code := in.Code
if system {
code = oldCode
}
var row ReportTemplateRow
err = tx.QueryRow(ctx, `
UPDATE report_templates
SET code=$2, title=$3, scene=$4, active=$5, updated_at=now()
WHERE id=$1
RETURNING id, code, title, scene, active, system, updated_at`,
id, code, in.Title, in.Scene, in.Active,
).Scan(&row.ID, &row.Code, &row.Title, &row.Scene, &row.Active, &row.System, &row.UpdatedAt)
if err != nil {
return nil, mapReportTemplateWriteErr(err)
}
if meta == nil {
meta = json.RawMessage(`{}`)
}
if _, err := tx.Exec(ctx, `
INSERT INTO admin_audit_logs(admin_id, action, target_type, target_id, meta)
VALUES ($1,'growth.report_template.update','report_template',$2,$3)`,
adminID, id.String(), meta,
); err != nil {
return nil, err
}
if err := tx.Commit(ctx); err != nil {
return nil, err
}
return &row, nil
}
func mapReportTemplateWriteErr(err error) error {
var pgErr *pgconn.PgError
if errors.As(err, &pgErr) && pgErr.Code == "23505" {
return errString("report template code conflict")
}
return err
}
// ReportTemplateCodeConflict reports unique violation.
func ReportTemplateCodeConflict(err error) bool {
return err != nil && strings.Contains(err.Error(), "report template code conflict")
}