thread-master/old/backend/internal/model/publish_inventory/usecase/usecase.go

175 lines
5.4 KiB
Go
Raw Normal View History

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/publish_inventory/domain/entity"
domrepo "haixun-backend/internal/model/publish_inventory/domain/repository"
domusecase "haixun-backend/internal/model/publish_inventory/domain/usecase"
threadsaccountdomain "haixun-backend/internal/model/threads_account/domain/usecase"
"github.com/google/uuid"
)
type inventoryUseCase struct {
repo domrepo.Repository
threadsAccount threadsaccountdomain.UseCase
}
func NewUseCase(repo domrepo.Repository, threadsAccount threadsaccountdomain.UseCase) domusecase.UseCase {
return &inventoryUseCase{repo: repo, threadsAccount: threadsAccount}
}
func (u *inventoryUseCase) Get(ctx context.Context, tenantID, ownerUID, accountID string) (*domusecase.PolicySummary, error) {
if err := u.require(ctx, tenantID, ownerUID, accountID); err != nil {
return nil, err
}
item, err := u.repo.Get(ctx, tenantID, ownerUID, accountID)
if err != nil {
if strings.Contains(err.Error(), "not found") {
item = defaultPolicy(tenantID, ownerUID, accountID)
} else {
return nil, err
}
}
out := toSummary(item)
return &out, nil
}
func (u *inventoryUseCase) Upsert(ctx context.Context, req domusecase.UpsertRequest) (*domusecase.PolicySummary, error) {
if err := u.require(ctx, req.TenantID, req.OwnerUID, req.AccountID); err != nil {
return nil, err
}
item := defaultPolicy(req.TenantID, req.OwnerUID, req.AccountID)
item.Enabled = req.Enabled
if req.TargetDailyCount > 0 {
item.TargetDailyCount = req.TargetDailyCount
}
if req.LowStockThreshold > 0 {
item.LowStockThreshold = req.LowStockThreshold
}
if req.LookaheadDays > 0 {
item.LookaheadDays = req.LookaheadDays
}
if strings.TrimSpace(req.Timezone) != "" {
item.Timezone = strings.TrimSpace(req.Timezone)
}
item.Slots = slotsToEntity(req.Slots)
item.SourceRefs = sourceRefsToEntity(req.SourceRefs)
now := clock.NowUnixNano()
item.UpdateAt = now
saved, err := u.repo.Upsert(ctx, item)
if err != nil {
return nil, err
}
out := toSummary(saved)
return &out, nil
}
func (u *inventoryUseCase) ListEnabled(ctx context.Context, limit int) ([]domusecase.PolicySummary, error) {
items, err := u.repo.ListEnabled(ctx, limit)
if err != nil {
return nil, err
}
out := make([]domusecase.PolicySummary, 0, len(items))
for _, item := range items {
summary := toSummary(&item)
out = append(out, summary)
}
return out, nil
}
func (u *inventoryUseCase) require(ctx context.Context, 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")
}
if u.threadsAccount != nil {
_, err := u.threadsAccount.Get(ctx, tenantID, ownerUID, accountID)
return err
}
return nil
}
func defaultPolicy(tenantID, ownerUID, accountID string) *entity.Policy {
now := clock.NowUnixNano()
return &entity.Policy{
ID: uuid.NewString(),
TenantID: strings.TrimSpace(tenantID),
OwnerUID: strings.TrimSpace(ownerUID),
AccountID: strings.TrimSpace(accountID),
Enabled: false,
TargetDailyCount: 2,
LowStockThreshold: 3,
LookaheadDays: 7,
Timezone: "Asia/Taipei",
Slots: []entity.Slot{
{Weekday: 1, Time: "09:30"},
{Weekday: 3, Time: "12:30"},
{Weekday: 5, Time: "18:30"},
},
CreateAt: now,
UpdateAt: now,
}
}
func toSummary(item *entity.Policy) domusecase.PolicySummary {
if item == nil {
return domusecase.PolicySummary{}
}
return domusecase.PolicySummary{
AccountID: item.AccountID, Enabled: item.Enabled, TargetDailyCount: item.TargetDailyCount,
LowStockThreshold: item.LowStockThreshold, LookaheadDays: item.LookaheadDays,
Timezone: item.Timezone, Slots: slotsFromEntity(item.Slots), SourceRefs: sourceRefsFromEntity(item.SourceRefs), UpdateAt: item.UpdateAt,
}
}
func slotsToEntity(items []domusecase.Slot) []entity.Slot {
out := make([]entity.Slot, 0, len(items))
for _, item := range items {
if strings.TrimSpace(item.Time) == "" {
continue
}
out = append(out, entity.Slot{Weekday: item.Weekday, Time: strings.TrimSpace(item.Time)})
}
return out
}
func slotsFromEntity(items []entity.Slot) []domusecase.Slot {
out := make([]domusecase.Slot, 0, len(items))
for _, item := range items {
out = append(out, domusecase.Slot{Weekday: item.Weekday, Time: item.Time})
}
return out
}
func sourceRefsToEntity(items []domusecase.SourceRef) []entity.SourceRef {
out := make([]entity.SourceRef, 0, len(items))
for _, item := range items {
if strings.TrimSpace(item.Type) == "" {
continue
}
out = append(out, entity.SourceRef{
Type: strings.TrimSpace(item.Type), PersonaID: strings.TrimSpace(item.PersonaID),
CopyMissionID: strings.TrimSpace(item.CopyMissionID), ScanPostID: strings.TrimSpace(item.ScanPostID), ManualSeed: strings.TrimSpace(item.ManualSeed),
})
}
return out
}
func sourceRefsFromEntity(items []entity.SourceRef) []domusecase.SourceRef {
out := make([]domusecase.SourceRef, 0, len(items))
for _, item := range items {
out = append(out, domusecase.SourceRef{
Type: item.Type, PersonaID: item.PersonaID, CopyMissionID: item.CopyMissionID, ScanPostID: item.ScanPostID, ManualSeed: item.ManualSeed,
})
}
return out
}