fix media supply citation attribution
Desktop Client Build / Resolve Build Metadata (push) Successful in 26s
Frontend CI / Frontend (push) Successful in 2m53s
Backend CI / Backend (push) Successful in 16m37s
Desktop Client Build / Build Desktop Client (push) Successful in 23m40s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 28s
Desktop Client Build / Resolve Build Metadata (push) Successful in 26s
Frontend CI / Frontend (push) Successful in 2m53s
Backend CI / Backend (push) Successful in 16m37s
Desktop Client Build / Build Desktop Client (push) Successful in 23m40s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 28s
This commit is contained in:
@@ -32,7 +32,78 @@ type monitoringAliasQuerier interface {
|
||||
Query(ctx context.Context, sql string, args ...interface{}) (pgx.Rows, error)
|
||||
}
|
||||
|
||||
func loadMonitoringPublishedAliasIndex(ctx context.Context, q monitoringAliasQuerier, tenantID int64) (monitoringPublishedAliasIndex, error) {
|
||||
const (
|
||||
monitoringContentSourcePublishedArticle = "published_article"
|
||||
monitoringContentSourceManualMark = "manual_mark"
|
||||
monitoringContentSourceMediaSupplyOrderItem = "media_supply_order_item"
|
||||
monitoringMediaSupplySubmissionCitationLabel = "投稿引用"
|
||||
)
|
||||
|
||||
func loadMonitoringMediaSupplyPublishedAliases(ctx context.Context, q monitoringAliasQuerier, tenantID int64) ([]monitoringPublishedAlias, error) {
|
||||
if q == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
rows, err := q.Query(ctx, `
|
||||
SELECT
|
||||
o.article_id,
|
||||
i.id,
|
||||
COALESCE(NULLIF(o.title, ''), NULLIF(i.resource_name_snapshot, ''), '未命名文章') AS article_title,
|
||||
COALESCE(NULLIF(i.resource_name_snapshot, ''), $2) AS publish_platform,
|
||||
i.external_article_url
|
||||
FROM media_supply_order_items i
|
||||
JOIN media_supply_orders o ON o.id = i.order_id
|
||||
WHERE o.tenant_id = $1
|
||||
AND o.deleted_at IS NULL
|
||||
AND NULLIF(TRIM(COALESCE(i.external_article_url, '')), '') IS NOT NULL
|
||||
ORDER BY i.updated_at DESC, i.id DESC
|
||||
`, tenantID, monitoringMediaSupplySubmissionCitationLabel)
|
||||
if err != nil {
|
||||
return nil, responseInternalAliasLookupError()
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
items := make([]monitoringPublishedAlias, 0)
|
||||
for rows.Next() {
|
||||
var articleID sql.NullInt64
|
||||
var itemID int64
|
||||
var articleTitle string
|
||||
var publishPlatform string
|
||||
var originalURL string
|
||||
if scanErr := rows.Scan(
|
||||
&articleID,
|
||||
&itemID,
|
||||
&articleTitle,
|
||||
&publishPlatform,
|
||||
&originalURL,
|
||||
); scanErr != nil {
|
||||
return nil, responseInternalAliasScanError()
|
||||
}
|
||||
normalizedURL := normalizeCitationURL(originalURL)
|
||||
if normalizedURL == "" {
|
||||
continue
|
||||
}
|
||||
item := monitoringPublishedAlias{
|
||||
ArticleTitle: articleTitle,
|
||||
PublishPlatform: publishPlatform,
|
||||
OriginalURL: strings.TrimSpace(originalURL),
|
||||
NormalizedURL: normalizedURL,
|
||||
SourceType: monitoringContentSourceMediaSupplyOrderItem,
|
||||
SourceID: itemID,
|
||||
SourcePriority: 1,
|
||||
}
|
||||
if articleID.Valid {
|
||||
item.ArticleID = articleID.Int64
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, responseInternalAliasScanError()
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func loadMonitoringPublishedAliasIndex(ctx context.Context, q monitoringAliasQuerier, businessQ monitoringAliasQuerier, tenantID int64) (monitoringPublishedAliasIndex, error) {
|
||||
rows, err := q.Query(ctx, `
|
||||
WITH alias_sources AS (
|
||||
SELECT
|
||||
@@ -42,11 +113,11 @@ func loadMonitoringPublishedAliasIndex(ctx context.Context, q monitoringAliasQue
|
||||
COALESCE(publish_platform_name_snapshot, '已发布内容') AS publish_platform,
|
||||
original_url,
|
||||
normalized_url,
|
||||
'published_article' AS source_type,
|
||||
article_id AS source_id,
|
||||
1 AS source_priority,
|
||||
updated_at AS sort_updated_at,
|
||||
id AS sort_id
|
||||
'published_article' AS source_type,
|
||||
article_id AS source_id,
|
||||
2 AS source_priority,
|
||||
updated_at AS sort_updated_at,
|
||||
id AS sort_id
|
||||
FROM monitoring_article_url_aliases
|
||||
WHERE tenant_id = $1
|
||||
AND confidence = 'high'
|
||||
@@ -58,11 +129,11 @@ func loadMonitoringPublishedAliasIndex(ctx context.Context, q monitoringAliasQue
|
||||
COALESCE(NULLIF(publish_platform, ''), '外部文章') AS publish_platform,
|
||||
original_url,
|
||||
normalized_url,
|
||||
'manual_mark' AS source_type,
|
||||
id AS source_id,
|
||||
2 AS source_priority,
|
||||
updated_at AS sort_updated_at,
|
||||
id AS sort_id
|
||||
'manual_mark' AS source_type,
|
||||
id AS source_id,
|
||||
3 AS source_priority,
|
||||
updated_at AS sort_updated_at,
|
||||
id AS sort_id
|
||||
FROM monitoring_user_marked_articles
|
||||
WHERE tenant_id = $1
|
||||
AND expires_at > NOW()
|
||||
@@ -74,9 +145,9 @@ func loadMonitoringPublishedAliasIndex(ctx context.Context, q monitoringAliasQue
|
||||
publish_platform,
|
||||
original_url,
|
||||
normalized_url,
|
||||
source_type,
|
||||
source_id,
|
||||
source_priority
|
||||
source_type,
|
||||
source_id,
|
||||
source_priority
|
||||
FROM alias_sources
|
||||
ORDER BY source_priority ASC, sort_updated_at DESC, sort_id DESC
|
||||
`, tenantID)
|
||||
@@ -111,32 +182,44 @@ func loadMonitoringPublishedAliasIndex(ctx context.Context, q monitoringAliasQue
|
||||
item.PublishRecordID = nullableInt64Value(publishRecordID)
|
||||
item.OriginalURL = originalURL
|
||||
item.NormalizedURL = normalizedURL
|
||||
for _, key := range monitoringCitationCandidateKeys(originalURL, normalizedURL) {
|
||||
existing, exists := index[key]
|
||||
if exists && existing.SourcePriority < item.SourcePriority {
|
||||
continue
|
||||
}
|
||||
if exists && item.SourcePriority < existing.SourcePriority {
|
||||
index[key] = item
|
||||
continue
|
||||
}
|
||||
if exists && (existing.SourceType != item.SourceType || existing.SourceID != item.SourceID) {
|
||||
existing.Ambiguous = true
|
||||
index[key] = existing
|
||||
continue
|
||||
}
|
||||
if !exists {
|
||||
index[key] = item
|
||||
}
|
||||
}
|
||||
addMonitoringPublishedAliasToIndex(index, item)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, responseInternalAliasScanError()
|
||||
}
|
||||
|
||||
mediaAliases, err := loadMonitoringMediaSupplyPublishedAliases(ctx, businessQ, tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, item := range mediaAliases {
|
||||
addMonitoringPublishedAliasToIndex(index, item)
|
||||
}
|
||||
|
||||
return index, nil
|
||||
}
|
||||
|
||||
func addMonitoringPublishedAliasToIndex(index monitoringPublishedAliasIndex, item monitoringPublishedAlias) {
|
||||
for _, key := range monitoringCitationCandidateKeys(item.OriginalURL, item.NormalizedURL) {
|
||||
existing, exists := index[key]
|
||||
if exists && existing.SourcePriority < item.SourcePriority {
|
||||
continue
|
||||
}
|
||||
if exists && item.SourcePriority < existing.SourcePriority {
|
||||
index[key] = item
|
||||
continue
|
||||
}
|
||||
if exists && (existing.SourceType != item.SourceType || existing.SourceID != item.SourceID) {
|
||||
existing.Ambiguous = true
|
||||
index[key] = existing
|
||||
continue
|
||||
}
|
||||
if !exists {
|
||||
index[key] = item
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (index monitoringPublishedAliasIndex) Match(rawURL, normalizedURL string) (monitoringPublishedAlias, bool) {
|
||||
for _, key := range monitoringCitationCandidateKeys(rawURL, normalizedURL) {
|
||||
item, ok := index[key]
|
||||
|
||||
Reference in New Issue
Block a user