package app import ( "context" "net/url" "strings" ) func (s *DesktopTaskService) syncMonitoringArticleAlias(ctx context.Context, input *monitoringArticleAliasInput) error { if s == nil || s.monitoringPool == nil || input == nil { return nil } originalURL, confidence := monitoringAliasOriginalURL(input) if originalURL == "" { return nil } normalizedURL := normalizeCitationURL(originalURL) if normalizedURL == "" { return nil } host, registrableDomain, _, _ := deriveCitationURLParts(originalURL, normalizedURL) if registrableDomain == "" { registrableDomain = host } siteKey := host if siteKey == "" { siteKey = registrableDomain } lastPathSegment := monitoringAliasLastPathSegment(normalizedURL) _, err := s.monitoringPool.Exec(ctx, ` INSERT INTO monitoring_article_url_aliases ( tenant_id, article_id, publish_record_id, platform_id, publish_platform_name_snapshot, external_article_id, article_title_snapshot, original_url, normalized_url, host, registrable_domain, site_key, last_path_segment, confidence ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14 ) ON CONFLICT (tenant_id, normalized_url) DO UPDATE SET article_id = EXCLUDED.article_id, publish_record_id = EXCLUDED.publish_record_id, platform_id = EXCLUDED.platform_id, publish_platform_name_snapshot = EXCLUDED.publish_platform_name_snapshot, external_article_id = EXCLUDED.external_article_id, article_title_snapshot = EXCLUDED.article_title_snapshot, original_url = EXCLUDED.original_url, host = EXCLUDED.host, registrable_domain = EXCLUDED.registrable_domain, site_key = EXCLUDED.site_key, last_path_segment = EXCLUDED.last_path_segment, confidence = EXCLUDED.confidence, updated_at = NOW() `, input.TenantID, input.ArticleID, input.PublishRecordID, strings.TrimSpace(input.PlatformID), strings.TrimSpace(input.PlatformName), normalizeStringPointer(input.ExternalArticleID), strings.TrimSpace(input.ArticleTitle), originalURL, normalizedURL, host, registrableDomain, siteKey, nullableString(lastPathSegment), confidence, ) if err != nil { return err } if confidence == "high" { _, err = s.monitoringPool.Exec(ctx, ` UPDATE monitoring_citation_facts SET content_source_type = 'published_article', content_source_id = $3, article_id = COALESCE(article_id, $3), publish_record_id = COALESCE(publish_record_id, $4) WHERE tenant_id = $1 AND normalized_url = $2 AND ( content_source_type IS DISTINCT FROM 'published_article' OR content_source_id IS DISTINCT FROM $3 ) `, input.TenantID, normalizedURL, input.ArticleID, input.PublishRecordID) } return err } func monitoringAliasOriginalURL(input *monitoringArticleAliasInput) (string, string) { if input == nil { return "", "" } switch strings.TrimSpace(input.PlatformID) { case "baijiahao": if articleID := strings.TrimSpace(monitoringStringValue(input.ExternalArticleID)); articleID != "" { return baijiahaoPublishedArticleURL(articleID), "high" } case "wangyihao": if articleID := strings.TrimSpace(monitoringStringValue(input.ExternalArticleID)); articleID != "" { return wangyihaoPublishedArticleURL(articleID), "high" } } if value := strings.TrimSpace(monitoringStringValue(input.ExternalArticleURL)); value != "" { return value, "high" } if value := strings.TrimSpace(monitoringStringValue(input.ExternalManageURL)); value != "" { return value, "medium" } return "", "" } func monitoringAliasLastPathSegment(rawURL string) *string { parsed, err := url.Parse(strings.TrimSpace(rawURL)) if err != nil { return nil } segments := strings.Split(strings.Trim(parsed.Path, "/"), "/") for index := len(segments) - 1; index >= 0; index-- { if segment := strings.TrimSpace(segments[index]); segment != "" { return &segment } } return nil }