169 lines
5.6 KiB
Go
169 lines
5.6 KiB
Go
package usecase
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"strings"
|
||
|
||
app "haixun-backend/internal/library/errors"
|
||
"haixun-backend/internal/library/errors/code"
|
||
libthreads "haixun-backend/internal/library/threadsapi"
|
||
domusecase "haixun-backend/internal/model/threads_account/domain/usecase"
|
||
)
|
||
|
||
func (u *threadsAccountUseCase) RunAPISmokeTest(
|
||
ctx context.Context,
|
||
tenantID, ownerUID, accountID string,
|
||
) ([]domusecase.APISmokeTestItem, error) {
|
||
account, err := u.assertOwned(ctx, tenantID, ownerUID, accountID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
token, err := u.ResolveAccountAPIAccessToken(ctx, tenantID, ownerUID, accountID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
client := libthreads.NewClient(token)
|
||
if !client.Enabled() {
|
||
return nil, app.For(code.ThreadsAccount).InputMissingRequired("Threads API token 無效")
|
||
}
|
||
|
||
var out []domusecase.APISmokeTestItem
|
||
add := func(scope, name, status, message string, count int) {
|
||
out = append(out, domusecase.APISmokeTestItem{
|
||
Scope: scope, Name: name, Status: status, Message: message, Count: count,
|
||
})
|
||
}
|
||
run := func(scope, name string, fn func() (int, string, error)) {
|
||
count, detail, err := fn()
|
||
if err != nil {
|
||
msg := err.Error()
|
||
if libthreads.IsPermissionError(err) {
|
||
msg += "(請確認 Meta App 已授權此 scope,且帳號在測試人員名單)"
|
||
}
|
||
add(scope, name, "error", msg, 0)
|
||
return
|
||
}
|
||
if detail != "" {
|
||
add(scope, name, "ok", detail, count)
|
||
return
|
||
}
|
||
add(scope, name, "ok", fmt.Sprintf("成功(%d 筆)", count), count)
|
||
}
|
||
|
||
profile, profileErr := libthreads.GetMeProfile(ctx, token)
|
||
userID := strings.TrimSpace(account.ThreadsUserID)
|
||
username := strings.TrimSpace(account.Username)
|
||
if profileErr == nil && profile != nil {
|
||
if userID == "" {
|
||
userID = profile.ID.String()
|
||
}
|
||
if username == "" {
|
||
username = profile.Username
|
||
}
|
||
}
|
||
|
||
run("threads_basic", "GET /me 個人資料", func() (int, string, error) {
|
||
if profileErr != nil {
|
||
return 0, "", profileErr
|
||
}
|
||
return 1, "user_id=" + profile.ID.String() + " @" + profile.Username, nil
|
||
})
|
||
|
||
if userID == "" {
|
||
add("threads_basic", "GET /{user-id}/threads 貼文列表", "error", "缺少 threads_user_id,請重新 OAuth", 0)
|
||
} else {
|
||
var sampleMediaID string
|
||
run("threads_basic", "GET /{user-id}/threads 貼文列表", func() (int, string, error) {
|
||
items, err := client.UserThreads(ctx, userID, 5)
|
||
if err != nil {
|
||
return 0, "", err
|
||
}
|
||
if len(items) > 0 {
|
||
sampleMediaID = items[0].ID
|
||
}
|
||
return len(items), "", nil
|
||
})
|
||
if sampleMediaID != "" {
|
||
run("threads_manage_insights", "GET /{media-id}/insights 貼文互動", func() (int, string, error) {
|
||
stats, err := client.GetMediaStats(ctx, sampleMediaID)
|
||
if err != nil {
|
||
return 0, "", err
|
||
}
|
||
return 1, fmt.Sprintf("likes=%d replies=%d views=%d", stats.LikeCount, stats.ReplyCount, stats.Views), nil
|
||
})
|
||
run("threads_read_replies", "GET /{media-id}/replies 留言列表", func() (int, string, error) {
|
||
items, err := client.MediaReplies(ctx, sampleMediaID, 5)
|
||
if err != nil {
|
||
return 0, "", err
|
||
}
|
||
return len(items), "", nil
|
||
})
|
||
} else {
|
||
add("threads_manage_insights", "GET /{media-id}/insights 貼文互動", "skip", "帳號尚無貼文,略過", 0)
|
||
add("threads_read_replies", "GET /{media-id}/replies 留言列表", "skip", "帳號尚無貼文,略過", 0)
|
||
}
|
||
}
|
||
|
||
run("threads_keyword_search", "GET /keyword_search 關鍵字搜尋", func() (int, string, error) {
|
||
items, err := client.KeywordSearch(ctx, libthreads.KeywordSearchOptions{
|
||
Query: "threads", Limit: 5, SearchType: "TOP",
|
||
})
|
||
if err != nil {
|
||
return 0, "", err
|
||
}
|
||
return len(items), "", nil
|
||
})
|
||
|
||
if username != "" {
|
||
run("threads_profile_discovery", "GET /profile_lookup 帳號查詢", func() (int, string, error) {
|
||
res, err := client.ProfileLookup(ctx, username)
|
||
if err != nil {
|
||
return 0, "", err
|
||
}
|
||
return 1, "@" + res.Username + " name=" + res.Name, nil
|
||
})
|
||
} else {
|
||
add("threads_profile_discovery", "GET /profile_lookup 帳號查詢", "skip", "缺少 username,略過", 0)
|
||
}
|
||
|
||
if userID != "" {
|
||
run("threads_manage_mentions", "GET /{user-id}/mentions 提及", func() (int, string, error) {
|
||
items, err := client.UserMentions(ctx, userID, 5)
|
||
if err != nil {
|
||
return 0, "", err
|
||
}
|
||
return len(items), "", nil
|
||
})
|
||
run("threads_manage_insights", "GET /{user-id}/threads_insights 洞察", func() (int, string, error) {
|
||
items, err := client.UserInsights(ctx, userID, nil)
|
||
if err != nil {
|
||
return 0, "", err
|
||
}
|
||
return len(items), fmt.Sprintf("%d 項指標", len(items)), nil
|
||
})
|
||
} else {
|
||
add("threads_manage_mentions", "GET /{user-id}/mentions 提及", "skip", "缺少 threads_user_id", 0)
|
||
add("threads_manage_insights", "GET /{user-id}/threads_insights 洞察", "skip", "缺少 threads_user_id", 0)
|
||
}
|
||
|
||
run("threads_location_tagging", "GET /location_search 地點搜尋", func() (int, string, error) {
|
||
items, err := client.LocationSearch(ctx, "Taipei", 5)
|
||
if err != nil {
|
||
return 0, "", err
|
||
}
|
||
return len(items), "", nil
|
||
})
|
||
|
||
add("threads_content_publish", "POST 發文 / 回覆", "manual",
|
||
"請用產品 API:POST /personas/:id/copy-drafts/:draftId/publish 或 outreach-drafts/publish", 0)
|
||
add("threads_delete", "DELETE /{media-id} 刪文", "manual",
|
||
"會真的刪除貼文,請在 Threads 後台或自行呼叫 DeleteMedia 測試", 0)
|
||
add("threads_manage_replies", "POST 隱藏留言", "manual",
|
||
"會改變留言狀態,請用 HideReply(reply_id) 手動測試", 0)
|
||
add("threads_share_to_instagram", "POST 同步到 IG", "manual",
|
||
"需已連結 IG 且會真的 crosspost,請用 ShareToInstagram(media_id) 手動測試", 0)
|
||
|
||
return out, nil
|
||
}
|