2026-07-01 08:42:51 +00:00
|
|
|
package usecase
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"haixun-backend/internal/library/clock"
|
|
|
|
|
app "haixun-backend/internal/library/errors"
|
|
|
|
|
"haixun-backend/internal/library/errors/code"
|
|
|
|
|
"haixun-backend/internal/model/content_formula/domain/entity"
|
|
|
|
|
domrepo "haixun-backend/internal/model/content_formula/domain/repository"
|
|
|
|
|
domusecase "haixun-backend/internal/model/content_formula/domain/usecase"
|
|
|
|
|
|
|
|
|
|
"github.com/google/uuid"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type useCase struct {
|
|
|
|
|
repo domrepo.Repository
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewUseCase(repo domrepo.Repository) domusecase.UseCase {
|
|
|
|
|
return &useCase{repo: repo}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (u *useCase) Create(ctx context.Context, req domusecase.CreateRequest) (*domusecase.FormulaSummary, error) {
|
|
|
|
|
if err := requireActor(req.TenantID, req.OwnerUID, req.AccountID); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
label := strings.TrimSpace(req.Label)
|
|
|
|
|
if label == "" {
|
|
|
|
|
label = "未命名公式"
|
|
|
|
|
}
|
|
|
|
|
sourceType := strings.TrimSpace(req.SourceType)
|
|
|
|
|
if sourceType == "" {
|
|
|
|
|
sourceType = entity.SourcePaste
|
|
|
|
|
}
|
|
|
|
|
formulaText := strings.TrimSpace(req.Formula)
|
|
|
|
|
if formulaText == "" && strings.TrimSpace(req.PostTemplate) == "" {
|
|
|
|
|
return nil, app.For(code.ThreadsAccount).InputMissingRequired("formula or post_template is required")
|
|
|
|
|
}
|
|
|
|
|
now := clock.NowUnixNano()
|
|
|
|
|
item := &entity.ContentFormula{
|
|
|
|
|
ID: uuid.NewString(),
|
|
|
|
|
TenantID: req.TenantID,
|
|
|
|
|
OwnerUID: req.OwnerUID,
|
|
|
|
|
AccountID: req.AccountID,
|
|
|
|
|
Label: label,
|
|
|
|
|
SourceType: sourceType,
|
|
|
|
|
SourceRef: strings.TrimSpace(req.SourceRef),
|
|
|
|
|
SourcePostText: strings.TrimSpace(req.SourcePostText),
|
|
|
|
|
SourceAuthor: strings.TrimSpace(req.SourceAuthor),
|
|
|
|
|
SourcePermalink: strings.TrimSpace(req.SourcePermalink),
|
|
|
|
|
SourceMetrics: req.SourceMetrics,
|
|
|
|
|
Summary: strings.TrimSpace(req.Summary),
|
|
|
|
|
Wins: req.Wins,
|
|
|
|
|
Improvements: req.Improvements,
|
|
|
|
|
Formula: formulaText,
|
|
|
|
|
PostTemplate: strings.TrimSpace(req.PostTemplate),
|
|
|
|
|
HookPattern: strings.TrimSpace(req.HookPattern),
|
|
|
|
|
Structure: strings.TrimSpace(req.Structure),
|
|
|
|
|
ReplicationTips: req.ReplicationTips,
|
|
|
|
|
Avoid: req.Avoid,
|
|
|
|
|
Tags: req.Tags,
|
|
|
|
|
CreateAt: now,
|
|
|
|
|
UpdateAt: now,
|
|
|
|
|
}
|
|
|
|
|
if err := u.repo.Create(ctx, item); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
summary := toSummary(*item)
|
|
|
|
|
return &summary, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (u *useCase) Get(ctx context.Context, tenantID, ownerUID, accountID, formulaID string) (*domusecase.FormulaSummary, error) {
|
|
|
|
|
if err := requireActor(tenantID, ownerUID, accountID); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
item, err := u.repo.Get(ctx, tenantID, ownerUID, accountID, formulaID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
summary := toSummary(*item)
|
|
|
|
|
return &summary, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (u *useCase) Update(ctx context.Context, req domusecase.UpdateRequest) (*domusecase.FormulaSummary, error) {
|
|
|
|
|
if err := requireActor(req.TenantID, req.OwnerUID, req.AccountID); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
patch := map[string]interface{}{"update_at": clock.NowUnixNano()}
|
|
|
|
|
if req.Label != nil {
|
|
|
|
|
patch["label"] = strings.TrimSpace(*req.Label)
|
|
|
|
|
}
|
|
|
|
|
if req.Formula != nil {
|
|
|
|
|
patch["formula"] = strings.TrimSpace(*req.Formula)
|
|
|
|
|
}
|
|
|
|
|
if req.PostTemplate != nil {
|
|
|
|
|
patch["post_template"] = strings.TrimSpace(*req.PostTemplate)
|
|
|
|
|
}
|
|
|
|
|
if req.HookPattern != nil {
|
|
|
|
|
patch["hook_pattern"] = strings.TrimSpace(*req.HookPattern)
|
|
|
|
|
}
|
|
|
|
|
if req.Structure != nil {
|
|
|
|
|
patch["structure"] = strings.TrimSpace(*req.Structure)
|
|
|
|
|
}
|
|
|
|
|
if req.Tags != nil {
|
|
|
|
|
patch["tags"] = req.Tags
|
|
|
|
|
}
|
|
|
|
|
if len(patch) == 1 {
|
|
|
|
|
return nil, app.For(code.ThreadsAccount).InputMissingRequired("no fields to update")
|
|
|
|
|
}
|
|
|
|
|
item, err := u.repo.Update(ctx, req.TenantID, req.OwnerUID, req.AccountID, req.FormulaID, patch)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
summary := toSummary(*item)
|
|
|
|
|
return &summary, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (u *useCase) Delete(ctx context.Context, tenantID, ownerUID, accountID, formulaID string) error {
|
|
|
|
|
if err := requireActor(tenantID, ownerUID, accountID); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return u.repo.Delete(ctx, tenantID, ownerUID, accountID, formulaID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (u *useCase) List(ctx context.Context, req domusecase.ListRequest) (*domusecase.ListResult, error) {
|
|
|
|
|
if err := requireActor(req.TenantID, req.OwnerUID, req.AccountID); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
result, err := u.repo.List(ctx, domrepo.ListFilter{
|
|
|
|
|
TenantID: req.TenantID,
|
|
|
|
|
OwnerUID: req.OwnerUID,
|
|
|
|
|
AccountID: req.AccountID,
|
|
|
|
|
SourceType: req.SourceType,
|
|
|
|
|
Tag: req.Tag,
|
|
|
|
|
Page: req.Page,
|
|
|
|
|
PageSize: req.PageSize,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
out := make([]domusecase.FormulaSummary, 0, len(result.Items))
|
|
|
|
|
for _, item := range result.Items {
|
|
|
|
|
out = append(out, toSummary(item))
|
|
|
|
|
}
|
|
|
|
|
return &domusecase.ListResult{Items: out, Total: result.Total}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func requireActor(tenantID, ownerUID, accountID string) error {
|
|
|
|
|
if strings.TrimSpace(tenantID) == "" || strings.TrimSpace(ownerUID) == "" {
|
|
|
|
|
return app.For(code.Auth).AuthUnauthorized("missing actor")
|
|
|
|
|
}
|
|
|
|
|
if strings.TrimSpace(accountID) == "" {
|
|
|
|
|
return app.For(code.ThreadsAccount).InputMissingRequired("account_id is required")
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func toSummary(item entity.ContentFormula) domusecase.FormulaSummary {
|
|
|
|
|
return domusecase.FormulaSummary{
|
|
|
|
|
ID: item.ID,
|
|
|
|
|
AccountID: item.AccountID,
|
|
|
|
|
Label: item.Label,
|
|
|
|
|
SourceType: item.SourceType,
|
|
|
|
|
SourceRef: item.SourceRef,
|
|
|
|
|
SourcePostText: item.SourcePostText,
|
|
|
|
|
SourceAuthor: item.SourceAuthor,
|
|
|
|
|
SourcePermalink: item.SourcePermalink,
|
|
|
|
|
SourceMetrics: item.SourceMetrics,
|
|
|
|
|
Summary: item.Summary,
|
|
|
|
|
Wins: item.Wins,
|
|
|
|
|
Improvements: item.Improvements,
|
|
|
|
|
Formula: item.Formula,
|
|
|
|
|
PostTemplate: item.PostTemplate,
|
|
|
|
|
HookPattern: item.HookPattern,
|
|
|
|
|
Structure: item.Structure,
|
|
|
|
|
ReplicationTips: item.ReplicationTips,
|
|
|
|
|
Avoid: item.Avoid,
|
|
|
|
|
Tags: item.Tags,
|
|
|
|
|
CreateAt: item.CreateAt,
|
|
|
|
|
UpdateAt: item.UpdateAt,
|
|
|
|
|
}
|
2026-07-03 14:42:19 +00:00
|
|
|
}
|