feat: Refactor template handling and brand management
- Removed schema_json from article templates and related queries. - Updated brand service to include website field in requests and responses. - Simplified template wizard view by eliminating unused schema fields and related logic. - Added tests for ark text format handling. - Created migrations for dropping schema_json and adding website to brands.
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
|
||||
@@ -27,12 +28,14 @@ func NewBrandService(pool *pgxpool.Pool, auditLogs *auditlog.AsyncWriter) *Brand
|
||||
|
||||
type BrandRequest struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Website *string `json:"website"`
|
||||
Description *string `json:"description"`
|
||||
}
|
||||
|
||||
type BrandResponse struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Website *string `json:"website"`
|
||||
Description *string `json:"description"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
@@ -42,7 +45,7 @@ type BrandResponse struct {
|
||||
func (s *BrandService) List(ctx context.Context) ([]BrandResponse, error) {
|
||||
actor := auth.MustActor(ctx)
|
||||
rows, err := s.pool.Query(ctx, `
|
||||
SELECT id, name, description, status, created_at, updated_at
|
||||
SELECT id, name, website, description, status, created_at, updated_at
|
||||
FROM brands WHERE tenant_id = $1 AND deleted_at IS NULL ORDER BY created_at DESC
|
||||
`, actor.TenantID)
|
||||
if err != nil {
|
||||
@@ -54,7 +57,7 @@ func (s *BrandService) List(ctx context.Context) ([]BrandResponse, error) {
|
||||
for rows.Next() {
|
||||
var b BrandResponse
|
||||
var ca, ua interface{}
|
||||
if err := rows.Scan(&b.ID, &b.Name, &b.Description, &b.Status, &ca, &ua); err != nil {
|
||||
if err := rows.Scan(&b.ID, &b.Name, &b.Website, &b.Description, &b.Status, &ca, &ua); err != nil {
|
||||
return nil, response.ErrInternal(50010, "scan_failed", err.Error())
|
||||
}
|
||||
b.CreatedAt = fmt.Sprintf("%v", ca)
|
||||
@@ -69,12 +72,16 @@ func (s *BrandService) List(ctx context.Context) ([]BrandResponse, error) {
|
||||
|
||||
func (s *BrandService) Create(ctx context.Context, req BrandRequest) (*BrandResponse, error) {
|
||||
actor := auth.MustActor(ctx)
|
||||
normalizeBrandRequest(&req)
|
||||
if req.Name == "" {
|
||||
return nil, response.ErrBadRequest(40001, "invalid_params", "name is required")
|
||||
}
|
||||
var id int64
|
||||
var ca interface{}
|
||||
err := s.pool.QueryRow(ctx, `
|
||||
INSERT INTO brands (tenant_id, name, description, status)
|
||||
VALUES ($1, $2, $3, 'active') RETURNING id, created_at
|
||||
`, actor.TenantID, req.Name, req.Description).Scan(&id, &ca)
|
||||
INSERT INTO brands (tenant_id, name, website, description, status)
|
||||
VALUES ($1, $2, $3, $4, 'active') RETURNING id, created_at
|
||||
`, actor.TenantID, req.Name, req.Website, req.Description).Scan(&id, &ca)
|
||||
if err != nil {
|
||||
return nil, response.ErrConflict(40901, "brand_exists", "brand with this name already exists")
|
||||
}
|
||||
@@ -95,7 +102,14 @@ func (s *BrandService) Create(ctx context.Context, req BrandRequest) (*BrandResp
|
||||
Result: &result,
|
||||
})
|
||||
|
||||
return &BrandResponse{ID: id, Name: req.Name, Description: req.Description, Status: "active", CreatedAt: fmt.Sprintf("%v", ca)}, nil
|
||||
return &BrandResponse{
|
||||
ID: id,
|
||||
Name: req.Name,
|
||||
Website: req.Website,
|
||||
Description: req.Description,
|
||||
Status: "active",
|
||||
CreatedAt: fmt.Sprintf("%v", ca),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *BrandService) Detail(ctx context.Context, id int64) (*BrandResponse, error) {
|
||||
@@ -103,9 +117,9 @@ func (s *BrandService) Detail(ctx context.Context, id int64) (*BrandResponse, er
|
||||
var b BrandResponse
|
||||
var ca, ua interface{}
|
||||
err := s.pool.QueryRow(ctx, `
|
||||
SELECT id, name, description, status, created_at, updated_at
|
||||
SELECT id, name, website, description, status, created_at, updated_at
|
||||
FROM brands WHERE id = $1 AND tenant_id = $2 AND deleted_at IS NULL
|
||||
`, id, actor.TenantID).Scan(&b.ID, &b.Name, &b.Description, &b.Status, &ca, &ua)
|
||||
`, id, actor.TenantID).Scan(&b.ID, &b.Name, &b.Website, &b.Description, &b.Status, &ca, &ua)
|
||||
if err != nil {
|
||||
return nil, response.ErrNotFound(40420, "brand_not_found", "brand not found")
|
||||
}
|
||||
@@ -116,16 +130,33 @@ func (s *BrandService) Detail(ctx context.Context, id int64) (*BrandResponse, er
|
||||
|
||||
func (s *BrandService) Update(ctx context.Context, id int64, req BrandRequest) error {
|
||||
actor := auth.MustActor(ctx)
|
||||
normalizeBrandRequest(&req)
|
||||
if req.Name == "" {
|
||||
return response.ErrBadRequest(40001, "invalid_params", "name is required")
|
||||
}
|
||||
tag, err := s.pool.Exec(ctx, `
|
||||
UPDATE brands SET name = $1, description = $2, updated_at = NOW()
|
||||
WHERE id = $3 AND tenant_id = $4 AND deleted_at IS NULL
|
||||
`, req.Name, req.Description, id, actor.TenantID)
|
||||
UPDATE brands SET name = $1, website = $2, description = $3, updated_at = NOW()
|
||||
WHERE id = $4 AND tenant_id = $5 AND deleted_at IS NULL
|
||||
`, req.Name, req.Website, req.Description, id, actor.TenantID)
|
||||
if err != nil || tag.RowsAffected() == 0 {
|
||||
return response.ErrNotFound(40420, "brand_not_found", "brand not found")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func normalizeBrandRequest(req *BrandRequest) {
|
||||
req.Name = strings.TrimSpace(req.Name)
|
||||
req.Website = normalizeOptionalString(req.Website)
|
||||
req.Description = normalizeOptionalString(req.Description)
|
||||
}
|
||||
|
||||
func normalizeOptionalString(value *string) *string {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
return nilIfEmptyString(*value)
|
||||
}
|
||||
|
||||
func (s *BrandService) Delete(ctx context.Context, id int64) error {
|
||||
actor := auth.MustActor(ctx)
|
||||
tx, err := s.pool.Begin(ctx)
|
||||
|
||||
@@ -93,7 +93,6 @@ type TemplateListItem struct {
|
||||
OriginType string `json:"origin_type"`
|
||||
TemplateKey string `json:"template_key"`
|
||||
TemplateName string `json:"template_name"`
|
||||
SchemaJSON map[string]interface{} `json:"schema_json"`
|
||||
PromptVisibility string `json:"prompt_visibility"`
|
||||
CardConfigJSON map[string]interface{} `json:"card_config"`
|
||||
Status string `json:"status"`
|
||||
@@ -122,7 +121,6 @@ func (s *TemplateService) List(ctx context.Context) ([]TemplateListItem, error)
|
||||
VersionNo: row.VersionNo,
|
||||
CreatedAt: row.CreatedAt,
|
||||
}
|
||||
_ = json.Unmarshal(row.SchemaJSON, &item.SchemaJSON)
|
||||
_ = json.Unmarshal(row.CardConfigJSON, &item.CardConfigJSON)
|
||||
items = append(items, item)
|
||||
}
|
||||
@@ -142,7 +140,7 @@ func (s *TemplateService) Detail(ctx context.Context, id int64) (*TemplateDetail
|
||||
return nil, response.ErrNotFound(40410, "template_not_found", "template not found")
|
||||
}
|
||||
|
||||
detail := &TemplateDetail{
|
||||
detail := &TemplateDetail{
|
||||
TemplateListItem: TemplateListItem{
|
||||
ID: record.ID,
|
||||
Scope: record.Scope,
|
||||
@@ -156,7 +154,6 @@ func (s *TemplateService) Detail(ctx context.Context, id int64) (*TemplateDetail
|
||||
CreatedAt: record.CreatedAt,
|
||||
},
|
||||
}
|
||||
_ = json.Unmarshal(record.SchemaJSON, &detail.SchemaJSON)
|
||||
_ = json.Unmarshal(record.CardConfigJSON, &detail.CardConfigJSON)
|
||||
|
||||
if canViewPromptTemplate(record, actor.TenantID) {
|
||||
@@ -166,18 +163,6 @@ func (s *TemplateService) Detail(ctx context.Context, id int64) (*TemplateDetail
|
||||
return detail, nil
|
||||
}
|
||||
|
||||
func (s *TemplateService) Schema(ctx context.Context, id int64) (map[string]interface{}, error) {
|
||||
actor := auth.MustActor(ctx)
|
||||
record, err := s.templates.GetTemplateByID(ctx, id, actor.TenantID)
|
||||
if err != nil {
|
||||
return nil, response.ErrNotFound(40410, "template_not_found", "template not found")
|
||||
}
|
||||
|
||||
schema := map[string]interface{}{}
|
||||
_ = json.Unmarshal(record.SchemaJSON, &schema)
|
||||
return schema, nil
|
||||
}
|
||||
|
||||
func canViewPromptTemplate(record *repository.TemplateRecord, actorTenantID int64) bool {
|
||||
if record == nil || record.TenantID == nil {
|
||||
return false
|
||||
|
||||
Reference in New Issue
Block a user