feat: reconcile posted articles against live posts table, revert orphaned articles to discovered
This commit is contained in:
parent
52e18daef0
commit
82e9246fdd
|
|
@ -514,7 +514,29 @@ func (s *OfficialAccountsService) PostNextArticle(ctx context.Context, configID
|
|||
return &art, postID, nil
|
||||
}
|
||||
|
||||
// ReconcilePostedArticles checks for articles marked 'posted' whose post no longer
|
||||
// exists in the posts table, and reverts them to 'discovered' so they can be re-posted.
|
||||
func (s *OfficialAccountsService) ReconcilePostedArticles(ctx context.Context, configID string) (int, error) {
|
||||
tag, err := s.pool.Exec(ctx, `
|
||||
UPDATE official_account_articles a
|
||||
SET status = 'discovered', post_id = NULL, posted_at = NULL
|
||||
WHERE a.config_id = $1
|
||||
AND a.status = 'posted'
|
||||
AND a.post_id IS NOT NULL
|
||||
AND NOT EXISTS (SELECT 1 FROM public.posts p WHERE p.id::text = a.post_id)
|
||||
`, configID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
reverted := int(tag.RowsAffected())
|
||||
if reverted > 0 {
|
||||
log.Info().Int("reverted", reverted).Str("config", configID).Msg("[OfficialAccounts] Reconciled orphaned articles back to discovered")
|
||||
}
|
||||
return reverted, nil
|
||||
}
|
||||
|
||||
// GetArticleQueue returns articles for a config filtered by status.
|
||||
// For 'posted' status, only returns articles whose post still exists in the posts table.
|
||||
func (s *OfficialAccountsService) GetArticleQueue(ctx context.Context, configID string, status string, limit int) ([]CachedArticle, error) {
|
||||
if limit <= 0 {
|
||||
limit = 50
|
||||
|
|
@ -524,12 +546,17 @@ func (s *OfficialAccountsService) GetArticleQueue(ctx context.Context, configID
|
|||
orderDir = "ASC" // oldest first (next to be posted)
|
||||
}
|
||||
|
||||
// For 'posted', reconcile first to catch deleted posts, then query
|
||||
if status == "posted" {
|
||||
_, _ = s.ReconcilePostedArticles(ctx, configID)
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
SELECT id, config_id, guid, title, link, source_name, source_url, description, pub_date,
|
||||
status, post_id, error_message, discovered_at, posted_at
|
||||
FROM official_account_articles
|
||||
WHERE config_id = $1 AND status = $2
|
||||
ORDER BY discovered_at %s
|
||||
SELECT a.id, a.config_id, a.guid, a.title, a.link, a.source_name, a.source_url, a.description, a.pub_date,
|
||||
a.status, a.post_id, a.error_message, a.discovered_at, a.posted_at
|
||||
FROM official_account_articles a
|
||||
WHERE a.config_id = $1 AND a.status = $2
|
||||
ORDER BY a.discovered_at %s
|
||||
LIMIT $3
|
||||
`, orderDir)
|
||||
|
||||
|
|
@ -564,7 +591,11 @@ type ArticleStats struct {
|
|||
}
|
||||
|
||||
// GetArticleStats returns article counts by status for a config.
|
||||
// Reconciles orphaned articles first so counts reflect reality.
|
||||
func (s *OfficialAccountsService) GetArticleStats(ctx context.Context, configID string) (*ArticleStats, error) {
|
||||
// Reconcile first — revert articles whose posts were deleted
|
||||
_, _ = s.ReconcilePostedArticles(ctx, configID)
|
||||
|
||||
rows, err := s.pool.Query(ctx, `
|
||||
SELECT status, COUNT(*) FROM official_account_articles
|
||||
WHERE config_id = $1
|
||||
|
|
|
|||
Loading…
Reference in a new issue