refac: article reads, story delete, no leaks, stored SEO status, rate limit, cleanup (%site%, article repo split, old lang repos, one default per site rule to domain)
This commit is contained in:
1 parent
9d284e65a9
commit
7c15206170
85 files changed
+1788
-593
No files matched your search
@@ -0,0 +1,148 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"RenewCMS/internal/domain/article"
|
||||
"reflect"
|
||||
"slices"
|
||||
)
|
||||
|
||||
var _ article.ListingRepository = &mockArticleRepo{}
|
||||
|
||||
type assessedVersion struct {
|
||||
inputs article.Article
|
||||
credits []uint32
|
||||
}
|
||||
|
||||
func seoInputsOf(version article.Article) article.Article {
|
||||
version.SEO = article.SEOSummary{}
|
||||
version.SEOVersion = 0
|
||||
version.UpdatedAt = version.UpdatedAt.UTC()
|
||||
return version
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) seoFresh(version article.Article) bool {
|
||||
assessed, found := m.assessed[version.ID]
|
||||
return found && !version.SEO.Stale() && reflect.DeepEqual(assessed.inputs, seoInputsOf(version)) && slices.Equal(assessed.credits, m.credits[version.ID])
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) StaleSEO(afterID uint32, limit int) ([]article.Article, error) {
|
||||
if err := m.fail.trigger("StaleSEO"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stale := []article.Article{}
|
||||
for _, id := range m.sortedIds() {
|
||||
version := m.articles[id]
|
||||
if id <= afterID || m.seoFresh(version) {
|
||||
continue
|
||||
}
|
||||
version.SEO = article.SEOSummary{}
|
||||
stale = append(stale, m.withAuthors(version))
|
||||
if len(stale) == limit {
|
||||
break
|
||||
}
|
||||
}
|
||||
return stale, nil
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) StoreSEO(records []article.SEORecord) error {
|
||||
if err := m.fail.trigger("StoreSEO"); err != nil {
|
||||
return err
|
||||
}
|
||||
if m.assessed == nil {
|
||||
m.assessed = map[uint32]assessedVersion{}
|
||||
}
|
||||
for _, record := range records {
|
||||
version, found := m.articles[record.ArticleID]
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
version.SEO = record.Summary
|
||||
m.articles[record.ArticleID] = version
|
||||
m.assessed[record.ArticleID] = assessedVersion{inputs: seoInputsOf(version), credits: slices.Clone(m.credits[record.ArticleID])}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) MarkSiteSEOStale(siteID uint32) error {
|
||||
for id, version := range m.articles {
|
||||
if version.SiteID == siteID {
|
||||
delete(m.assessed, id)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) CountSuggestions(filters article.Filters) (int, error) {
|
||||
if err := m.fail.trigger("CountSuggestions"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
total := 0
|
||||
for _, version := range m.articles {
|
||||
if mockVisible(version, filters.IsOnline != nil && *filters.IsOnline, filters.VisibleTo) && version.SEO.Status == article.SEOStatusSuggestions {
|
||||
total++
|
||||
}
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) CountSuggestedStories(readable article.StoryFilters) (int, error) {
|
||||
m.listCalls++
|
||||
if err := m.fail.trigger("CountSuggestedStories"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
stories := map[uint32]bool{}
|
||||
standalone := 0
|
||||
for _, version := range m.articles {
|
||||
if !mockVisible(version, readable.OnlyOnline, readable.VisibleTo) || version.SEO.Status != article.SEOStatusSuggestions {
|
||||
continue
|
||||
}
|
||||
if version.StoryID == 0 {
|
||||
standalone++
|
||||
continue
|
||||
}
|
||||
stories[version.StoryID] = true
|
||||
}
|
||||
return len(stories) + standalone, nil
|
||||
}
|
||||
|
||||
func mockVisible(version article.Article, onlineOnly bool, visibleTo *uint32) bool {
|
||||
if version.IsOnline {
|
||||
return true
|
||||
}
|
||||
if onlineOnly {
|
||||
return false
|
||||
}
|
||||
return visibleTo == nil || version.CreatedBy == *visibleTo
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) ListVersions(ids []uint32) ([]article.Article, error) {
|
||||
m.listCalls++
|
||||
if err := m.fail.trigger("ListVersions"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
found := []article.Article{}
|
||||
for _, id := range ids {
|
||||
if version, ok := m.articles[id]; ok {
|
||||
found = append(found, m.withAuthors(version))
|
||||
}
|
||||
}
|
||||
return found, nil
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) DeleteStory(storyID uint32) error {
|
||||
if err := m.fail.trigger("DeleteStory"); err != nil {
|
||||
return err
|
||||
}
|
||||
deleted := 0
|
||||
for id, version := range m.articles {
|
||||
if version.StoryID == storyID {
|
||||
delete(m.articles, id)
|
||||
delete(m.credits, id)
|
||||
deleted++
|
||||
}
|
||||
}
|
||||
if deleted == 0 {
|
||||
return article.ErrArticleNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in new issue
Block a user