refac: migration crash, real-database tests, site deleted during create, ruels out of the repo, lists

This commit is contained in:
Florian Sylvain committed 2026-11-03 05:06:04 +01:00
1 parent 680b9a1308
commit 9d284e65a9
62 files changed
+1858 -987

No files matched your search

@@ -375,10 +375,7 @@ func (a *ArticleRepository) Create(article domain.Article) (domain.Article, erro
return err
}
}
if err := ensureStoryLanguageFree(tx, created.StoryID, created.Lang); err != nil {
return err
}
if err := ensureSlugFree(tx, created.SiteID, created.Lang, created.Slug, 0); err != nil {
if err := requireStory(tx, created.StoryID); err != nil {
return err
}
if err := openStory(tx, &created); err != nil {
@@ -390,12 +387,12 @@ func (a *ArticleRepository) Create(article domain.Article) (domain.Article, erro
return replaceCredits(tx, created.ID, authordomain.BylineIDs(article.Authors))
})
if err != nil {
return domain.Article{}, a.explainSlugFailure(created.SiteID, created.Lang, created.Slug, 0, err)
return domain.Article{}, a.explainUniqueViolation(created, 0, err)
}
return a.withAuthorsOne(a.db, mappers.ArticleToDomain(created))
}
func ensureStoryLanguageFree(tx *gorm.DB, storyID uint32, lang string) error {
func requireStory(tx *gorm.DB, storyID uint32) error {
if storyID == 0 {
return nil
}
@@ -406,13 +403,6 @@ func ensureStoryLanguageFree(tx *gorm.DB, storyID uint32, lang string) error {
if stories == 0 {
return domain.ErrArticleNotFound
}
var versions int64
if err := tx.Model(&entity.Article{}).Where("story_id = ? AND lang = ?", storyID, lang).Count(&versions).Error; err != nil {
return err
}
if versions > 0 {
return domain.ErrLanguageTaken
}
return nil
}
@@ -434,26 +424,21 @@ func articleSlugInLanguage(db *gorm.DB, siteID uint32, lang string, slug string,
return total > 0, err
}
func ensureSlugFree(db *gorm.DB, siteID uint32, lang string, slug string, exceptID uint32) error {
if slug == "" {
return nil
}
taken, err := articleSlugInLanguage(db, siteID, lang, slug, exceptID)
if err != nil {
return err
}
if taken {
return domain.ErrSlugTaken
}
return nil
func storyLanguageInUse(db *gorm.DB, storyID uint32, lang string, exceptID uint32) (bool, error) {
var total int64
err := db.Unscoped().Model(&entity.Article{}).Where("story_id = ? AND lang = ? AND retired_id = ? AND id <> ?", storyID, lang, 0, exceptID).Count(&total).Error
return total > 0, err
}
func (a *ArticleRepository) explainSlugFailure(siteID uint32, lang string, slug string, exceptID uint32, cause error) error {
if errors.Is(cause, domain.ErrSlugTaken) {
func (a *ArticleRepository) explainUniqueViolation(written entity.Article, exceptID uint32, cause error) error {
if !database.IsUniqueViolation(a.db, cause) {
return cause
}
if err := ensureSlugFree(a.db, siteID, lang, slug, exceptID); err != nil && errors.Is(err, domain.ErrSlugTaken) {
return err
if taken, err := articleSlugInLanguage(a.db, written.SiteID, written.Lang, written.Slug, exceptID); err == nil && taken {
return domain.ErrSlugTaken
}
if taken, err := storyLanguageInUse(a.db, written.StoryID, written.Lang, exceptID); err == nil && taken {
return domain.ErrLanguageTaken
}
return cause
}
@@ -528,11 +513,6 @@ func (a *ArticleRepository) updateAt(id uint32, update domain.Update, probedSite
}
before := localArticle
applyUpdate(&localArticle, update)
if update.Slug != nil || update.SiteID != nil {
if err := ensureSlugFree(tx, localArticle.SiteID, localArticle.Lang, localArticle.Slug, id); err != nil {
return err
}
}
authorsChanged, err := authorsDiffer(tx, id, update.AuthorIDs)
if err != nil {
return err
@@ -554,7 +534,7 @@ func (a *ArticleRepository) updateAt(id uint32, update domain.Update, probedSite
return domain.Article{}, err
}
if err != nil {
return domain.Article{}, a.explainSlugFailure(localArticle.SiteID, localArticle.Lang, localArticle.Slug, id, err)
return domain.Article{}, a.explainUniqueViolation(localArticle, id, err)
}
return a.withAuthorsOne(a.db, mappers.ArticleToDomain(localArticle))
}
@@ -722,15 +702,13 @@ func (a *ArticleRepository) ListByStory(storyID uint32) ([]domain.Article, error
}
func (a *ArticleRepository) MoveToSite(ids []uint32, siteID uint32) error {
return a.db.Transaction(func(tx *gorm.DB) error {
var moving entity.Article
err := a.db.Transaction(func(tx *gorm.DB) error {
for _, id := range ids {
var moving entity.Article
moving = entity.Article{}
if err := tx.First(&moving, id).Error; err != nil {
return mapNotFoundErr(err, domain.ErrArticleNotFound)
}
if err := ensureSlugFree(tx, siteID, moving.Lang, moving.Slug, id); err != nil {
return err
}
moved := map[string]any{"site_id": siteID, "edit_revision": gorm.Expr("edit_revision + 1")}
if err := tx.Model(&entity.Article{}).Where("id = ?", id).Updates(moved).Error; err != nil {
return err
@@ -738,6 +716,11 @@ func (a *ArticleRepository) MoveToSite(ids []uint32, siteID uint32) error {
}
return nil
})
if err != nil {
moving.SiteID = siteID
return a.explainUniqueViolation(moving, moving.ID, err)
}
return nil
}
func (a *ArticleRepository) FindByBodyContaining(filename string) ([]domain.Article, error) {