feat: editor write path
This commit is contained in:
1 parent
d9158025d4
commit
a0b3c58c52
88 files changed
+5738
-263
No files matched your search
@@ -6,6 +6,7 @@ import (
|
||||
"RenewCMS/internal/domain/language"
|
||||
"RenewCMS/internal/infrastructure/useCases"
|
||||
"errors"
|
||||
"maps"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -30,6 +31,12 @@ type mockArticleRepo struct {
|
||||
createAlwaysRaces bool
|
||||
afterFindByBody func()
|
||||
updateBodyIDs []uint32
|
||||
moveFailsAt int
|
||||
beforeCreate func()
|
||||
beforeUpdate func()
|
||||
beforeMove func()
|
||||
onGet func(id uint32) error
|
||||
reverseStory bool
|
||||
}
|
||||
|
||||
func newMockArticleRepo() *mockArticleRepo {
|
||||
@@ -210,6 +217,11 @@ func (m *mockArticleRepo) Get(id uint32) (article.Article, error) {
|
||||
if err := m.fail.trigger("Get"); err != nil {
|
||||
return article.Article{}, err
|
||||
}
|
||||
if m.onGet != nil {
|
||||
if err := m.onGet(id); err != nil {
|
||||
return article.Article{}, err
|
||||
}
|
||||
}
|
||||
a, ok := m.articles[id]
|
||||
if !ok {
|
||||
return article.Article{}, article.ErrArticleNotFound
|
||||
@@ -330,6 +342,10 @@ func (m *mockArticleRepo) RepointImage(fromImageIDs []uint32, toImageID uint32)
|
||||
|
||||
func (m *mockArticleRepo) Create(a article.Article) (article.Article, error) {
|
||||
m.createCalled = true
|
||||
if hook := m.beforeCreate; hook != nil {
|
||||
m.beforeCreate = nil
|
||||
hook()
|
||||
}
|
||||
if err := m.fail.trigger("Create"); err != nil {
|
||||
return article.Article{}, err
|
||||
}
|
||||
@@ -343,6 +359,16 @@ func (m *mockArticleRepo) Create(a article.Article) (article.Article, error) {
|
||||
if m.slugUsedOn(a.SiteID, a.Lang, a.Slug, 0) {
|
||||
return article.Article{}, article.ErrSlugTaken
|
||||
}
|
||||
if a.StoryID != 0 {
|
||||
if !m.storyHasVersions(a.StoryID) {
|
||||
return article.Article{}, article.ErrArticleNotFound
|
||||
}
|
||||
if m.storyHasLanguage(a.StoryID, a.Lang) {
|
||||
return article.Article{}, article.ErrLanguageTaken
|
||||
}
|
||||
}
|
||||
a.ContentRevision = 1
|
||||
a.EditRevision = 1
|
||||
m.nextID++
|
||||
a.ID = m.nextID
|
||||
m.articles[a.ID] = a
|
||||
@@ -373,6 +399,70 @@ func (m *mockArticleRepo) UpdateBody(id uint32, body string) (article.Article, e
|
||||
return m.withAuthors(a), nil
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) storyHasVersions(storyID uint32) bool {
|
||||
for _, stored := range m.articles {
|
||||
if stored.StoryID == storyID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) storyHasLanguage(storyID uint32, lang string) bool {
|
||||
for _, stored := range m.articles {
|
||||
if stored.StoryID == storyID && stored.Lang == lang {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) ListByStory(storyID uint32) ([]article.Article, error) {
|
||||
if err := m.fail.trigger("ListByStory"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
versions := []article.Article{}
|
||||
for _, id := range m.sortedIds() {
|
||||
if stored := m.articles[id]; stored.StoryID == storyID {
|
||||
versions = append(versions, m.withAuthors(stored))
|
||||
}
|
||||
}
|
||||
if m.reverseStory {
|
||||
slices.Reverse(versions)
|
||||
}
|
||||
return versions, nil
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) MoveToSite(ids []uint32, siteID uint32) error {
|
||||
if err := m.fail.trigger("MoveToSite"); err != nil {
|
||||
return err
|
||||
}
|
||||
if hook := m.beforeMove; hook != nil {
|
||||
m.beforeMove = nil
|
||||
hook()
|
||||
}
|
||||
snapshot := maps.Clone(m.articles)
|
||||
for position, id := range ids {
|
||||
moving, ok := m.articles[id]
|
||||
if !ok {
|
||||
m.articles = snapshot
|
||||
return article.ErrArticleNotFound
|
||||
}
|
||||
if m.moveFailsAt == position+1 {
|
||||
m.articles = snapshot
|
||||
return errRepositoryFailure
|
||||
}
|
||||
if m.slugUsedOn(siteID, moving.Lang, moving.Slug, id) {
|
||||
m.articles = snapshot
|
||||
return article.ErrSlugTaken
|
||||
}
|
||||
moving.SiteID = siteID
|
||||
moving.EditRevision++
|
||||
m.articles[id] = moving
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockArticleRepo) Update(id uint32, update article.Update) (article.Article, error) {
|
||||
if err := m.fail.trigger("Update"); err != nil {
|
||||
return article.Article{}, err
|
||||
@@ -381,6 +471,18 @@ func (m *mockArticleRepo) Update(id uint32, update article.Update) (article.Arti
|
||||
if !ok {
|
||||
return article.Article{}, article.ErrArticleNotFound
|
||||
}
|
||||
if hook := m.beforeUpdate; hook != nil {
|
||||
m.beforeUpdate = nil
|
||||
hook()
|
||||
a = m.articles[id]
|
||||
}
|
||||
if update.IfRevision != nil && a.EditRevision != *update.IfRevision {
|
||||
return article.Article{}, &article.RevisionConflictError{Current: a.EditRevision}
|
||||
}
|
||||
before := a
|
||||
if update.Title != nil {
|
||||
a.Title = *update.Title
|
||||
}
|
||||
if update.Body != nil {
|
||||
if err, failing := m.failUpdateBodyFor[id]; failing {
|
||||
return article.Article{}, err
|
||||
@@ -400,9 +502,13 @@ func (m *mockArticleRepo) Update(id uint32, update article.Update) (article.Arti
|
||||
return article.Article{}, article.ErrSlugTaken
|
||||
}
|
||||
applySeoUpdate(&a, update)
|
||||
authorsChanged := update.AuthorIDs != nil && !slices.Equal(m.credits[id], *update.AuthorIDs)
|
||||
if update.AuthorIDs != nil {
|
||||
m.credits[id] = append([]uint32{}, *update.AuthorIDs...)
|
||||
}
|
||||
if before.EditRevision > 0 {
|
||||
a = a.Revised(article.ImpactOf(before, a, authorsChanged))
|
||||
}
|
||||
m.articles[id] = a
|
||||
return m.withAuthors(a), nil
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user