feat: SEO backend data (1/4)
This commit is contained in:
1 parent
cb1410f0b0
commit
0eb46b0d74
90 files changed
+6094
-350
No files matched your search
@@ -23,6 +23,8 @@ type mockArticleRepo struct {
|
||||
createCalled bool
|
||||
credits map[uint32][]uint32
|
||||
authors *mockAuthorRepo
|
||||
reportSlugRace bool
|
||||
createAlwaysRaces bool
|
||||
}
|
||||
|
||||
func newMockArticleRepo() *mockArticleRepo {
|
||||
@@ -193,11 +195,107 @@ func (m *mockArticleRepo) GetAll() []article.Article {
|
||||
return result
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) slugUsedOn(siteID uint32, slug string, exceptID uint32) bool {
|
||||
if slug == "" {
|
||||
return false
|
||||
}
|
||||
for id, other := range m.articles {
|
||||
if id != exceptID && other.SiteID == siteID && other.Slug == slug {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) SlugTaken(siteID uint32, slug string, exceptID uint32) (bool, error) {
|
||||
if err := m.fail.trigger("SlugTaken"); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return m.slugUsedOn(siteID, slug, exceptID), nil
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) FindByImage(imageID uint32) ([]article.Article, error) {
|
||||
if err := m.fail.trigger("FindByImage"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]article.Article, 0)
|
||||
for _, id := range m.sortedIds() {
|
||||
if a := m.articles[id]; a.UsesImage(imageID) {
|
||||
result = append(result, a)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) ClearImage(imageID uint32) (article.ImageReferences, error) {
|
||||
if err := m.fail.trigger("ClearImage"); err != nil {
|
||||
return article.ImageReferences{}, err
|
||||
}
|
||||
references := article.ImageReferences{Cover: []uint32{}, Social: []uint32{}}
|
||||
for _, id := range m.sortedIds() {
|
||||
a := m.articles[id]
|
||||
if a.CoverImageID != nil && *a.CoverImageID == imageID {
|
||||
a.CoverImageID = nil
|
||||
references.Cover = append(references.Cover, id)
|
||||
}
|
||||
if a.SocialImageID != nil && *a.SocialImageID == imageID {
|
||||
a.SocialImageID = nil
|
||||
references.Social = append(references.Social, id)
|
||||
}
|
||||
m.articles[id] = a
|
||||
}
|
||||
return references, nil
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) RestoreImage(references article.ImageReferences, imageID uint32) error {
|
||||
for _, id := range references.Cover {
|
||||
a := m.articles[id]
|
||||
a.CoverImageID = idPointer(imageID)
|
||||
m.articles[id] = a
|
||||
}
|
||||
for _, id := range references.Social {
|
||||
a := m.articles[id]
|
||||
a.SocialImageID = idPointer(imageID)
|
||||
m.articles[id] = a
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) RepointImage(fromImageIDs []uint32, toImageID uint32) ([]uint32, error) {
|
||||
if err := m.fail.trigger("RepointImage"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changed := []uint32{}
|
||||
for _, id := range m.sortedIds() {
|
||||
a := m.articles[id]
|
||||
touched := false
|
||||
if a.CoverImageID != nil && containsID(fromImageIDs, *a.CoverImageID) {
|
||||
a.CoverImageID = idPointer(toImageID)
|
||||
touched = true
|
||||
}
|
||||
if a.SocialImageID != nil && containsID(fromImageIDs, *a.SocialImageID) {
|
||||
a.SocialImageID = idPointer(toImageID)
|
||||
touched = true
|
||||
}
|
||||
if touched {
|
||||
m.articles[id] = a
|
||||
changed = append(changed, id)
|
||||
}
|
||||
}
|
||||
return changed, nil
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) Create(a article.Article) (article.Article, error) {
|
||||
m.createCalled = true
|
||||
if err := m.fail.trigger("Create"); err != nil {
|
||||
return article.Article{}, err
|
||||
}
|
||||
if m.createAlwaysRaces {
|
||||
return article.Article{}, article.ErrSlugTaken
|
||||
}
|
||||
if m.slugUsedOn(a.SiteID, a.Slug, 0) {
|
||||
return article.Article{}, article.ErrSlugTaken
|
||||
}
|
||||
m.nextID++
|
||||
a.ID = m.nextID
|
||||
m.articles[a.ID] = a
|
||||
@@ -244,6 +342,16 @@ func (m *mockArticleRepo) Update(id uint32, update article.Update) (article.Arti
|
||||
if update.SiteID != nil {
|
||||
a.SiteID = *update.SiteID
|
||||
}
|
||||
if update.Slug != nil {
|
||||
a.Slug = *update.Slug
|
||||
}
|
||||
if m.reportSlugRace && (update.Slug != nil || update.SiteID != nil) {
|
||||
return article.Article{}, article.ErrSlugTaken
|
||||
}
|
||||
if m.slugUsedOn(a.SiteID, a.Slug, id) {
|
||||
return article.Article{}, article.ErrSlugTaken
|
||||
}
|
||||
applySeoUpdate(&a, update)
|
||||
if update.AuthorIDs != nil {
|
||||
m.credits[id] = append([]uint32{}, *update.AuthorIDs...)
|
||||
}
|
||||
@@ -251,6 +359,33 @@ func (m *mockArticleRepo) Update(id uint32, update article.Update) (article.Arti
|
||||
return m.withAuthors(a), nil
|
||||
}
|
||||
|
||||
func applySeoUpdate(a *article.Article, update article.Update) {
|
||||
assign := func(target *string, value *string) {
|
||||
if value != nil {
|
||||
*target = *value
|
||||
}
|
||||
}
|
||||
assign(&a.Excerpt, update.Excerpt)
|
||||
assign(&a.SEOTitle, update.SEOTitle)
|
||||
assign(&a.SEODescription, update.SEODescription)
|
||||
assign(&a.CoverImageAlt, update.CoverImageAlt)
|
||||
assign(&a.SocialTitle, update.SocialTitle)
|
||||
assign(&a.SocialDescription, update.SocialDescription)
|
||||
assign(&a.CanonicalURL, update.CanonicalURL)
|
||||
if update.CoverImageID.Set {
|
||||
a.CoverImageID = update.CoverImageID.Value
|
||||
}
|
||||
if update.SocialImageID.Set {
|
||||
a.SocialImageID = update.SocialImageID.Value
|
||||
}
|
||||
if update.Noindex != nil {
|
||||
a.Noindex = *update.Noindex
|
||||
}
|
||||
if update.SEODismissed != nil {
|
||||
a.SEODismissed = append([]string{}, *update.SEODismissed...)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) UpdateIsOnline(id uint32, isOnline bool) (article.Article, error) {
|
||||
if err := m.fail.trigger("UpdateIsOnline"); err != nil {
|
||||
return article.Article{}, err
|
||||
|
||||
Reference in new issue
Block a user