package threads_account import ( guarddomain "haixun-backend/internal/model/publish_guard/domain/usecase" inventorydomain "haixun-backend/internal/model/publish_inventory/domain/usecase" pqdomain "haixun-backend/internal/model/publish_queue/domain/usecase" eventdomain "haixun-backend/internal/model/publish_queue_event/domain/usecase" domusecase "haixun-backend/internal/model/threads_account/domain/usecase" "haixun-backend/internal/types" ) func toThreadsAccountData(item domusecase.AccountSummary) types.ThreadsAccountData { return types.ThreadsAccountData{ ID: item.ID, DisplayName: item.DisplayName, Username: item.Username, ThreadsUserID: item.ThreadsUserID, PersonaID: item.PersonaID, BrowserConnected: item.BrowserConnected, ApiConnected: item.ApiConnected, APITokenExpiresAt: item.APITokenExpiresAt, Status: item.Status, CreateAt: item.CreateAt, UpdateAt: item.UpdateAt, } } func toPostPerformanceData(result *domusecase.PostPerformanceResult) *types.ThreadsPostPerformanceData { if result == nil { return &types.ThreadsPostPerformanceData{Posts: []types.ThreadsPostPerformanceItem{}} } caps := make([]types.ThreadsPostMetricCapability, 0, len(result.Capabilities)) for _, item := range result.Capabilities { caps = append(caps, types.ThreadsPostMetricCapability{ Scope: item.Scope, Name: item.Name, Metrics: item.Metrics, Trackable: item.Trackable, Note: item.Note, }) } metrics := make([]types.ThreadsInsightMetricItem, 0, len(result.AccountInsights.Metrics)) for _, item := range result.AccountInsights.Metrics { metrics = append(metrics, types.ThreadsInsightMetricItem{Name: item.Name, Value: item.Value}) } posts := make([]types.ThreadsPostPerformanceItem, 0, len(result.Posts)) for _, item := range result.Posts { posts = append(posts, types.ThreadsPostPerformanceItem{ MediaID: item.MediaID, Text: item.Text, Permalink: item.Permalink, Timestamp: item.Timestamp, MediaType: item.MediaType, MediaURL: item.MediaURL, ThumbnailURL: item.ThumbnailURL, TopicTag: item.TopicTag, Shortcode: item.Shortcode, LikeCount: item.LikeCount, ReplyCount: item.ReplyCount, RepostCount: item.RepostCount, QuoteCount: item.QuoteCount, Views: item.Views, Shares: item.Shares, InsightsStatus: item.InsightsStatus, InsightsMessage: item.InsightsMessage, }) } return &types.ThreadsPostPerformanceData{ AccountID: result.AccountID, Username: result.Username, ThreadsUserID: result.ThreadsUserID, FetchedAt: result.FetchedAt, Capabilities: caps, AccountInsights: types.ThreadsAccountInsightsBlock{ Status: result.AccountInsights.Status, Message: result.AccountInsights.Message, Metrics: metrics, }, Posts: posts, } } func toListData(result *domusecase.ListResult) *types.ListThreadsAccountsData { if result == nil { return &types.ListThreadsAccountsData{List: []types.ThreadsAccountData{}} } list := make([]types.ThreadsAccountData, 0, len(result.List)) for _, item := range result.List { list = append(list, toThreadsAccountData(item)) } return &types.ListThreadsAccountsData{ List: list, ActiveAccountID: result.ActiveAccountID, } } func toConnectionData(data *domusecase.ConnectionData) *types.ThreadsAccountConnectionData { if data == nil { return nil } return &types.ThreadsAccountConnectionData{ AccountID: data.AccountID, AccountName: data.AccountName, Username: data.Username, BrowserConnected: data.BrowserConnected, ApiConnected: data.ApiConnected, Prefs: types.ThreadsAccountConnectionPrefs{ SearchViaApi: data.Prefs.SearchViaApi, SearchSourceMode: data.Prefs.SearchSourceMode, PublishViaApi: data.Prefs.PublishViaApi, DevMode: data.Prefs.DevMode, ScrapeReplies: data.Prefs.ScrapeReplies, RepliesPerPost: data.Prefs.RepliesPerPost, PublishHeaded: data.Prefs.PublishHeaded, PlaywrightDebug: data.Prefs.PlaywrightDebug, }, } } func toPublishQueueItemData(item *pqdomain.QueueItemSummary) *types.PublishQueueItemData { if item == nil { return nil } return &types.PublishQueueItemData{ ID: item.ID, AccountID: item.AccountID, PersonaID: item.PersonaID, CopyMissionID: item.CopyMissionID, CopyDraftID: item.CopyDraftID, Text: item.Text, ImageKey: item.ImageKey, ImageKeys: item.ImageKeys, TopicTag: item.TopicTag, ScheduledAt: item.ScheduledAt, Status: item.Status, MediaID: item.MediaID, Permalink: item.Permalink, PublishedAt: item.PublishedAt, ErrorMessage: item.ErrorMessage, RetryCount: item.RetryCount, LastAttemptAt: item.LastAttemptAt, NextAttemptAt: item.NextAttemptAt, MissedAt: item.MissedAt, PausedReason: item.PausedReason, CreateAt: item.CreateAt, UpdateAt: item.UpdateAt, } } func toInventoryPolicyData(item *inventorydomain.PolicySummary) *types.PublishInventoryPolicyData { if item == nil { return nil } slots := make([]types.PublishSlotData, 0, len(item.Slots)) for _, slot := range item.Slots { slots = append(slots, types.PublishSlotData{Weekday: slot.Weekday, Time: slot.Time}) } refs := make([]types.PublishSourceRefData, 0, len(item.SourceRefs)) for _, ref := range item.SourceRefs { refs = append(refs, types.PublishSourceRefData{ Type: ref.Type, PersonaID: ref.PersonaID, CopyMissionID: ref.CopyMissionID, ScanPostID: ref.ScanPostID, ManualSeed: ref.ManualSeed, }) } return &types.PublishInventoryPolicyData{ AccountID: item.AccountID, Enabled: item.Enabled, TargetDailyCount: item.TargetDailyCount, LowStockThreshold: item.LowStockThreshold, LookaheadDays: item.LookaheadDays, Timezone: item.Timezone, Slots: slots, SourceRefs: refs, UpdateAt: item.UpdateAt, } } func toGuardPolicyData(item *guarddomain.PolicySummary) *types.PublishGuardPolicyData { if item == nil { return nil } return &types.PublishGuardPolicyData{ AccountID: item.AccountID, Enabled: item.Enabled, MaxDailyPosts: item.MaxDailyPosts, MinIntervalMinutes: item.MinIntervalMinutes, ConsecutiveFailurePauseLimit: item.ConsecutiveFailurePauseLimit, Paused: item.Paused, PausedReason: item.PausedReason, UpdateAt: item.UpdateAt, } } func toQueueEventData(items []eventdomain.EventSummary) []types.PublishQueueEventData { out := make([]types.PublishQueueEventData, 0, len(items)) for _, item := range items { out = append(out, types.PublishQueueEventData{ ID: item.ID, QueueID: item.QueueID, EventType: item.EventType, FromStatus: item.FromStatus, ToStatus: item.ToStatus, Message: item.Message, CreateAt: item.CreateAt, }) } return out } func firstNonEmpty(values ...string) string { for _, value := range values { if value != "" { return value } } return "" } func toPublishQueueListData(result *pqdomain.ListResult) *types.PublishQueueListData { if result == nil { return &types.PublishQueueListData{List: []types.PublishQueueItemData{}} } list := make([]types.PublishQueueItemData, 0, len(result.Items)) for _, item := range result.Items { if data := toPublishQueueItemData(&item); data != nil { list = append(list, *data) } } return &types.PublishQueueListData{ Pagination: types.PaginationData{ Total: result.Total, Page: int64(result.Page), PageSize: int64(result.PageSize), TotalPages: int64(result.TotalPages), }, List: list, } } func toPublishHealthData(result *pqdomain.PublishHealthResult) *types.ThreadsPublishHealthData { if result == nil { return &types.ThreadsPublishHealthData{List: []types.ThreadsPublishHealthItem{}} } list := make([]types.ThreadsPublishHealthItem, 0, len(result.Items)) for _, item := range result.Items { cps := make([]types.ThreadsPublishHealthCheckpoint, 0, len(item.Checkpoints)) for _, cp := range item.Checkpoints { cps = append(cps, types.ThreadsPublishHealthCheckpoint{ Checkpoint: cp.Checkpoint, LikeCount: cp.LikeCount, ReplyCount: cp.ReplyCount, RepostCount: cp.RepostCount, QuoteCount: cp.QuoteCount, Views: cp.Views, CheckedAt: cp.CheckedAt, }) } list = append(list, types.ThreadsPublishHealthItem{ MediaID: item.MediaID, Permalink: item.Permalink, Text: item.Text, PublishedAt: item.PublishedAt, LikeCount: item.LikeCount, ReplyCount: item.ReplyCount, RepostCount: item.RepostCount, QuoteCount: item.QuoteCount, Views: item.Views, Shares: item.Shares, Checkpoints: cps, }) } return &types.ThreadsPublishHealthData{ Summary: types.ThreadsPublishHealthSummary{ PendingScheduled: result.Summary.PendingScheduled, FailedCount: result.Summary.FailedCount, Published7d: result.Summary.Published7d, TotalLikes7d: result.Summary.TotalLikes7d, TotalReplies7d: result.Summary.TotalReplies7d, }, Pagination: types.PaginationData{ Total: result.Total, Page: int64(result.Page), PageSize: int64(result.PageSize), TotalPages: int64(result.TotalPages), }, List: list, } } func toConnectionPatch(req *types.UpdateThreadsAccountConnectionReq) domusecase.ConnectionPrefsPatch { if req == nil { return domusecase.ConnectionPrefsPatch{} } return domusecase.ConnectionPrefsPatch{ SearchViaApi: req.SearchViaApi, SearchSourceMode: req.SearchSourceMode, PublishViaApi: req.PublishViaApi, DevMode: req.DevMode, ScrapeReplies: req.ScrapeReplies, RepliesPerPost: req.RepliesPerPost, PublishHeaded: req.PublishHeaded, PlaywrightDebug: req.PlaywrightDebug, } }