package placement import "strings" // ConnectionPrefsInput mirrors persisted account connection prefs without importing threads_account. type ConnectionPrefsInput struct { DevMode bool SearchSourceMode string } // MemberContext is resolved per login member (email account) + active Threads operating account. type MemberContext struct { TenantID string OwnerUID string ActiveAccountID string DevMode bool SearchSourceMode SearchSourceMode AllowsThreadsAPI bool AllowsBrave bool AllowsCrawler bool BraveAPIKey string BraveCountry string BraveSearchLang string ApiConnected bool BrowserConnected bool ThreadsAPIAccessToken string ScrapeReplies bool RepliesPerPost int } type ResearchSettings struct { BraveAPIKey string BraveCountry string BraveSearchLang string ExpandStrategy string } func BuildMemberContext( tenantID, ownerUID, activeAccountID string, prefs ConnectionPrefsInput, apiConnected, browserConnected bool, research ResearchSettings, scrapeReplies bool, repliesPerPost int, ) MemberContext { mode := ParseSearchSourceMode(prefs.SearchSourceMode) allowsCrawler := ModeAllowsCrawler(mode) allowsThreads := ModeAllowsThreadsAPI(mode) allowsBrave := ModeAllowsBrave(mode) if !prefs.DevMode { mode = WithoutCrawler(mode) allowsCrawler = false } else { mode = SearchSourceCrawler allowsCrawler = true allowsThreads = false allowsBrave = false } country := strings.TrimSpace(research.BraveCountry) if country == "" { country = "tw" } lang := strings.TrimSpace(research.BraveSearchLang) if lang == "" { lang = "zh-hant" } if repliesPerPost <= 0 { repliesPerPost = 10 } return MemberContext{ TenantID: tenantID, OwnerUID: ownerUID, ActiveAccountID: activeAccountID, DevMode: prefs.DevMode, SearchSourceMode: mode, AllowsThreadsAPI: allowsThreads, AllowsBrave: allowsBrave, AllowsCrawler: allowsCrawler, BraveAPIKey: strings.TrimSpace(research.BraveAPIKey), BraveCountry: country, BraveSearchLang: lang, ApiConnected: apiConnected, BrowserConnected: browserConnected, ScrapeReplies: scrapeReplies, RepliesPerPost: repliesPerPost, } } func (c MemberContext) PayloadFields() map[string]any { return map[string]any{ "tenant_id": c.TenantID, "owner_uid": c.OwnerUID, "threads_account_id": c.ActiveAccountID, "dev_mode": c.DevMode, "search_source_mode": string(c.SearchSourceMode), "allows_threads_api": c.AllowsThreadsAPI, "allows_brave": c.AllowsBrave, "allows_crawler": c.AllowsCrawler, "brave_country": c.BraveCountry, "brave_search_lang": c.BraveSearchLang, "api_connected": c.ApiConnected, "browser_connected": c.BrowserConnected, "scrape_replies": c.ScrapeReplies, "replies_per_post": c.RepliesPerPost, } }