Files
geo/server/internal/tenant/app/publish_platforms.go
T
root 37d75597f9
Frontend CI / Frontend (push) Successful in 3m1s
Backend CI / Backend (push) Failing after 6m51s
feat: enhance schedule publish account handling and caching mechanisms
2026-06-21 09:11:37 +08:00

248 lines
5.9 KiB
Go

package app
import (
"context"
"encoding/json"
"strconv"
"strings"
"github.com/jackc/pgx/v5"
)
func normalizePlatformIDs(platformIDs []string) []string {
if len(platformIDs) == 0 {
return nil
}
seen := make(map[string]struct{}, len(platformIDs))
normalized := make([]string, 0, len(platformIDs))
for _, platformID := range platformIDs {
next := strings.TrimSpace(platformID)
if next == "" {
continue
}
if _, exists := seen[next]; exists {
continue
}
seen[next] = struct{}{}
normalized = append(normalized, next)
}
if len(normalized) == 0 {
return nil
}
return normalized
}
type scheduleAutoPublishPlatformQuerier interface {
Query(context.Context, string, ...interface{}) (pgx.Rows, error)
}
func loadScheduleAutoPublishPlatforms(
ctx context.Context,
db scheduleAutoPublishPlatformQuerier,
tenantID int64,
inputParamsJSON []byte,
) ([]string, error) {
if db == nil || tenantID <= 0 || len(inputParamsJSON) == 0 {
return []string{}, nil
}
var payload map[string]interface{}
if err := json.Unmarshal(inputParamsJSON, &payload); err != nil {
return []string{}, nil
}
if !extractBool(payload, "schedule_auto_publish") {
return []string{}, nil
}
accountIDs := normalizeSchedulePublishAccountIDs(extractStringList(payload["schedule_publish_account_ids"], 64))
if len(accountIDs) == 0 {
return []string{}, nil
}
return loadPublishAccountPlatformsByIDs(ctx, db, tenantID, accountIDs)
}
func loadPublishAccountPlatformsByIDs(
ctx context.Context,
db scheduleAutoPublishPlatformQuerier,
tenantID int64,
accountIDs []string,
) ([]string, error) {
_, platformIDs, err := loadExistingPublishAccountIDsAndPlatformsByIDs(ctx, db, tenantID, 0, accountIDs)
return platformIDs, err
}
func LoadExistingSchedulePublishAccountIDsAndPlatformsByIDs(
ctx context.Context,
db scheduleAutoPublishPlatformQuerier,
tenantID int64,
workspaceID int64,
accountIDs []string,
) ([]string, []string, error) {
return loadExistingPublishAccountIDsAndPlatformsByIDs(ctx, db, tenantID, workspaceID, accountIDs)
}
func loadExistingPublishAccountIDsAndPlatformsByIDs(
ctx context.Context,
db scheduleAutoPublishPlatformQuerier,
tenantID int64,
workspaceID int64,
accountIDs []string,
) ([]string, []string, error) {
accountIDs = normalizeSchedulePublishAccountIDs(accountIDs)
if db == nil || tenantID <= 0 || len(accountIDs) == 0 {
return []string{}, []string{}, nil
}
rows, err := db.Query(ctx, `
SELECT DISTINCT desktop_id::text, platform_id
FROM platform_accounts
WHERE tenant_id = $1
AND desktop_id::text = ANY($2::text[])
AND ($3::bigint <= 0 OR workspace_id = $3)
AND deleted_at IS NULL
`, tenantID, accountIDs, workspaceID)
if err != nil {
return nil, nil, err
}
defer rows.Close()
platformsByAccount := make(map[string][]string, len(accountIDs))
existingByAccount := make(map[string]struct{}, len(accountIDs))
for rows.Next() {
var accountID string
var platformID string
if err := rows.Scan(&accountID, &platformID); err != nil {
return nil, nil, err
}
platformsByAccount[accountID] = append(platformsByAccount[accountID], platformID)
existingByAccount[accountID] = struct{}{}
}
if err := rows.Err(); err != nil {
return nil, nil, err
}
existingAccountIDs := make([]string, 0, len(accountIDs))
platformIDs := make([]string, 0, len(accountIDs))
for _, accountID := range accountIDs {
if _, ok := existingByAccount[accountID]; !ok {
continue
}
existingAccountIDs = append(existingAccountIDs, accountID)
platformIDs = append(platformIDs, platformsByAccount[accountID]...)
}
return emptyStringSliceIfNil(existingAccountIDs), emptyStringSliceIfNil(normalizePlatformIDs(platformIDs)), nil
}
func emptyStringSliceIfNil(values []string) []string {
if values == nil {
return []string{}
}
return values
}
func resolveArticleCoverAssetURL(wizardStateJSON []byte) *string {
value := strings.TrimSpace(extractStringFromJSONPayload(wizardStateJSON, "cover_asset_url"))
if value == "" {
return nil
}
return &value
}
func resolveArticleCoverImageAssetID(wizardStateJSON []byte) *int64 {
value, ok := extractInt64FromJSONPayload(wizardStateJSON, "cover_image_asset_id")
if !ok || value <= 0 {
return nil
}
return &value
}
func extractStringFromJSONPayload(raw []byte, key string) string {
if len(raw) == 0 {
return ""
}
var payload map[string]interface{}
if err := json.Unmarshal(raw, &payload); err != nil {
return ""
}
value, ok := payload[key].(string)
if !ok {
return ""
}
return strings.TrimSpace(value)
}
func extractInt64FromJSONPayload(raw []byte, key string) (int64, bool) {
if len(raw) == 0 {
return 0, false
}
var payload map[string]interface{}
if err := json.Unmarshal(raw, &payload); err != nil {
return 0, false
}
switch value := payload[key].(type) {
case nil:
return 0, false
case float64:
return int64(value), true
case int64:
return value, true
case int:
return int64(value), true
case string:
value = strings.TrimSpace(value)
if value == "" {
return 0, false
}
parsed, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return 0, false
}
return parsed, true
default:
return 0, false
}
}
func mergeArticleWizardState(raw []byte, title string, coverAssetURL *string, coverImageAssetID NullableInt64Input) ([]byte, error) {
state := make(map[string]interface{})
if len(raw) > 0 {
_ = json.Unmarshal(raw, &state)
}
delete(state, "platforms")
delete(state, "target_platforms")
delete(state, "target_platform")
trimmedTitle := strings.TrimSpace(title)
if trimmedTitle != "" {
state["title"] = trimmedTitle
}
if coverAssetURL != nil {
trimmedCoverURL := strings.TrimSpace(*coverAssetURL)
if trimmedCoverURL == "" {
delete(state, "cover_asset_url")
} else {
state["cover_asset_url"] = trimmedCoverURL
}
}
if coverImageAssetID.Set {
if coverImageAssetID.Value == nil {
delete(state, "cover_image_asset_id")
} else {
state["cover_image_asset_id"] = *coverImageAssetID.Value
}
}
return json.Marshal(state)
}