package app import ( "encoding/json" "strconv" "strings" ) 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 } func parsePlatformIDs(value string) []string { if strings.TrimSpace(value) == "" { return nil } return normalizePlatformIDs(strings.Split(value, ",")) } func serializePlatformIDs(platformIDs []string) string { normalized := normalizePlatformIDs(platformIDs) if len(normalized) == 0 { return "" } return strings.Join(normalized, ",") } func resolveArticlePlatforms(wizardStateJSON, inputParamsJSON []byte) []string { if platforms := extractPlatformsFromJSONPayload(wizardStateJSON); len(platforms) > 0 { return platforms } if platforms := extractPlatformsFromJSONPayload(inputParamsJSON); len(platforms) > 0 { return platforms } return []string{} } func extractPlatformsFromJSONPayload(raw []byte) []string { if len(raw) == 0 { return nil } var payload map[string]interface{} if err := json.Unmarshal(raw, &payload); err != nil { return nil } if platforms := normalizePlatformsFromValue(payload["platforms"]); len(platforms) > 0 { return platforms } if platforms := normalizePlatformsFromValue(payload["target_platforms"]); len(platforms) > 0 { return platforms } if targetPlatform, ok := payload["target_platform"].(string); ok { return parsePlatformIDs(targetPlatform) } return nil } 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 normalizePlatformsFromValue(raw interface{}) []string { switch typed := raw.(type) { case nil: return nil case string: return parsePlatformIDs(typed) case []string: return normalizePlatformIDs(typed) case []interface{}: values := make([]string, 0, len(typed)) for _, item := range typed { value, ok := item.(string) if !ok { continue } values = append(values, value) } return normalizePlatformIDs(values) default: return nil } } func mergeArticleWizardState(raw []byte, title string, platforms []string, coverAssetURL *string, coverImageAssetID NullableInt64Input) ([]byte, error) { state := make(map[string]interface{}) if len(raw) > 0 { _ = json.Unmarshal(raw, &state) } trimmedTitle := strings.TrimSpace(title) if trimmedTitle != "" { state["title"] = trimmedTitle } if platforms != nil { normalized := normalizePlatformIDs(platforms) if len(normalized) == 0 { delete(state, "platforms") delete(state, "target_platform") } else { state["platforms"] = normalized state["target_platform"] = strings.Join(normalized, ",") } } 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) }