package useCases import ( "RenewCMS/internal/domain/article" "RenewCMS/internal/domain/localization" "RenewCMS/internal/domain/site" "errors" ) const seoRefreshBatchSize = 500 type RefreshArticleSEOUseCase struct { index article.SEOIndex sites site.Repository localization localization.Repository } func NewRefreshArticleSEOUseCase(index article.SEOIndex, sites site.Repository, localizationRepository localization.Repository) *RefreshArticleSEOUseCase { return &RefreshArticleSEOUseCase{index: index, sites: sites, localization: localizationRepository} } func (u *RefreshArticleSEOUseCase) RefreshStale() error { afterID := uint32(0) for { stale, err := u.index.StaleSEO(afterID, seoRefreshBatchSize) if err != nil || len(stale) == 0 { return err } context := u.siteContextReadAfter() records := make([]article.SEORecord, 0, len(stale)) for _, version := range stale { summary, err := context.assess(version) if err != nil { return err } records = append(records, article.SEORecord{ArticleID: version.ID, Version: version.SEOVersion, Summary: summary}) } if err := u.index.StoreSEO(records); err != nil { return err } afterID = stale[len(stale)-1].ID } } func (u *RefreshArticleSEOUseCase) siteContextReadAfter() *seoSiteContext { return &seoSiteContext{sites: u.sites, localization: u.localization, owners: map[uint32]site.Site{}, defaults: map[uint32]string{}} } type seoSiteContext struct { sites site.Repository localization localization.Repository owners map[uint32]site.Site defaults map[uint32]string } func (c *seoSiteContext) assess(version article.Article) (article.SEOSummary, error) { owner, err := c.owner(version.SiteID) if err != nil { return article.SEOSummary{}, err } defaultTag, err := c.defaultTag(version.SiteID) if err != nil { return article.SEOSummary{}, err } return assessSEO(version, owner, localization.SiteTextAllowed(defaultTag, version.Lang)).Summary(), nil } func (c *seoSiteContext) owner(siteID uint32) (site.Site, error) { if owner, cached := c.owners[siteID]; cached { return owner, nil } owner, err := c.sites.Get(siteID) if err != nil && !errors.Is(err, site.ErrSiteNotFound) { return site.Site{}, err } c.owners[siteID] = owner return owner, nil } func (c *seoSiteContext) defaultTag(siteID uint32) (string, error) { if tag, cached := c.defaults[siteID]; cached { return tag, nil } rows, err := c.localization.Rows(siteID) if err != nil { return "", err } c.defaults[siteID] = localization.ConfirmedDefaultTag(rows) return c.defaults[siteID], nil }