feat: Authors feature backend (and upgraded deprecated mods)
This commit is contained in:
1 parent
a11338094e
commit
b34a173d83
103 files changed
+6454
-240
No files matched your search
@@ -2,6 +2,7 @@ package persistence
|
||||
|
||||
import (
|
||||
domain "RenewCMS/internal/domain/article"
|
||||
authordomain "RenewCMS/internal/domain/author"
|
||||
"RenewCMS/internal/infrastructure/persistence/mappers"
|
||||
entity "RenewCMS/internal/infrastructure/persistence/models"
|
||||
|
||||
@@ -89,7 +90,11 @@ func (a *ArticleRepository) FindPage(filters domain.Filters) (domain.PageResult,
|
||||
if err != nil {
|
||||
return domain.PageResult{}, err
|
||||
}
|
||||
return domain.PageResult{Items: toDomainArticles(entityArticles), Total: int(total)}, nil
|
||||
items, err := a.withAuthors(a.db, toDomainArticles(entityArticles))
|
||||
if err != nil {
|
||||
return domain.PageResult{}, err
|
||||
}
|
||||
return domain.PageResult{Items: items, Total: int(total)}, nil
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) findMatchingTitle(filters domain.Filters) (domain.PageResult, error) {
|
||||
@@ -125,7 +130,11 @@ func (a *ArticleRepository) findMatchingTitle(filters domain.Filters) (domain.Pa
|
||||
ordered = append(ordered, entityArticle)
|
||||
}
|
||||
}
|
||||
page.Items = toDomainArticles(ordered)
|
||||
items, err := a.withAuthors(a.db, toDomainArticles(ordered))
|
||||
if err != nil {
|
||||
return domain.PageResult{}, err
|
||||
}
|
||||
page.Items = items
|
||||
return page, nil
|
||||
}
|
||||
|
||||
@@ -150,6 +159,77 @@ func toDomainArticles(entityArticles []entity.Article) []domain.Article {
|
||||
return domainArticles
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) withAuthors(db *gorm.DB, articles []domain.Article) ([]domain.Article, error) {
|
||||
ids := make([]uint32, 0, len(articles))
|
||||
for _, article := range articles {
|
||||
ids = append(ids, article.ID)
|
||||
}
|
||||
bylines, err := loadBylines(db, ids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for index := range articles {
|
||||
articles[index].Authors = bylines[articles[index].ID]
|
||||
if articles[index].Authors == nil {
|
||||
articles[index].Authors = []authordomain.Byline{}
|
||||
}
|
||||
}
|
||||
return articles, nil
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) withAuthorsOne(db *gorm.DB, article domain.Article) (domain.Article, error) {
|
||||
loaded, err := a.withAuthors(db, []domain.Article{article})
|
||||
if err != nil {
|
||||
return domain.Article{}, err
|
||||
}
|
||||
return loaded[0], nil
|
||||
}
|
||||
|
||||
func loadBylines(db *gorm.DB, articleIDs []uint32) (map[uint32][]authordomain.Byline, error) {
|
||||
bylines := make(map[uint32][]authordomain.Byline, len(articleIDs))
|
||||
if len(articleIDs) == 0 {
|
||||
return bylines, nil
|
||||
}
|
||||
var credits []entity.ArticleAuthor
|
||||
if err := db.Where("article_id IN ?", articleIDs).Order("position ASC, id ASC").Find(&credits).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(credits) == 0 {
|
||||
return bylines, nil
|
||||
}
|
||||
authorIDs := make([]uint32, 0, len(credits))
|
||||
for _, credit := range credits {
|
||||
authorIDs = append(authorIDs, credit.AuthorID)
|
||||
}
|
||||
var found []entity.Author
|
||||
if err := db.Where("id IN ?", authorIDs).Find(&found).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
byID := make(map[uint32]entity.Author, len(found))
|
||||
for _, model := range found {
|
||||
byID[model.ID] = model
|
||||
}
|
||||
for _, credit := range credits {
|
||||
if model, ok := byID[credit.AuthorID]; ok {
|
||||
bylines[credit.ArticleID] = append(bylines[credit.ArticleID], mappers.AuthorToDomain(model, 0).Byline())
|
||||
}
|
||||
}
|
||||
return bylines, nil
|
||||
}
|
||||
|
||||
func replaceCredits(tx *gorm.DB, articleID uint32, authorIDs []uint32) error {
|
||||
if err := tx.Where("article_id = ?", articleID).Delete(&entity.ArticleAuthor{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
for position, authorID := range authorIDs {
|
||||
credit := entity.ArticleAuthor{ArticleID: articleID, AuthorID: authorID, Position: position}
|
||||
if err := tx.Create(&credit).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func foldForSearch(value string) string {
|
||||
folder := transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
|
||||
folded, _, err := transform.String(folder, value)
|
||||
@@ -166,7 +246,7 @@ func (a *ArticleRepository) Get(id uint32) (domain.Article, error) {
|
||||
return domain.Article{}, mapNotFoundErr(err, domain.ErrArticleNotFound)
|
||||
}
|
||||
|
||||
return mappers.ArticleToDomain(article), nil
|
||||
return a.withAuthorsOne(a.db, mappers.ArticleToDomain(article))
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) GetByName(name string) (domain.Article, error) {
|
||||
@@ -176,7 +256,7 @@ func (a *ArticleRepository) GetByName(name string) (domain.Article, error) {
|
||||
return domain.Article{}, mapNotFoundErr(err, domain.ErrArticleNotFound)
|
||||
}
|
||||
|
||||
return mappers.ArticleToDomain(article), nil
|
||||
return a.withAuthorsOne(a.db, mappers.ArticleToDomain(article))
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) Create(article domain.Article) (domain.Article, error) {
|
||||
@@ -192,12 +272,23 @@ func (a *ArticleRepository) Create(article domain.Article) (domain.Article, erro
|
||||
return err
|
||||
}
|
||||
}
|
||||
return tx.Create(&created).Error
|
||||
if err := tx.Create(&created).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return replaceCredits(tx, created.ID, bylineIDs(article.Authors))
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Article{}, err
|
||||
}
|
||||
return mappers.ArticleToDomain(created), nil
|
||||
return a.withAuthorsOne(a.db, mappers.ArticleToDomain(created))
|
||||
}
|
||||
|
||||
func bylineIDs(bylines []authordomain.Byline) []uint32 {
|
||||
ids := make([]uint32, 0, len(bylines))
|
||||
for _, byline := range bylines {
|
||||
ids = append(ids, byline.ID)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) GetAll() []domain.Article {
|
||||
@@ -228,9 +319,7 @@ func (a *ArticleRepository) UpdateBody(id uint32, body string) (domain.Article,
|
||||
return domain.Article{}, err
|
||||
}
|
||||
|
||||
newArticle := mappers.ArticleToDomain(localArticle)
|
||||
|
||||
return newArticle, nil
|
||||
return a.withAuthorsOne(a.db, mappers.ArticleToDomain(localArticle))
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) Update(id uint32, update domain.Update) (domain.Article, error) {
|
||||
@@ -250,12 +339,18 @@ func (a *ArticleRepository) Update(id uint32, update domain.Update) (domain.Arti
|
||||
if update.SiteID != nil {
|
||||
localArticle.SiteID = *update.SiteID
|
||||
}
|
||||
return tx.Save(&localArticle).Error
|
||||
if err := tx.Save(&localArticle).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if update.AuthorIDs != nil {
|
||||
return replaceCredits(tx, id, *update.AuthorIDs)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Article{}, err
|
||||
}
|
||||
return mappers.ArticleToDomain(localArticle), nil
|
||||
return a.withAuthorsOne(a.db, mappers.ArticleToDomain(localArticle))
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) UpdateIsOnline(id uint32, isOnline bool) (domain.Article, error) {
|
||||
@@ -271,12 +366,16 @@ func (a *ArticleRepository) UpdateIsOnline(id uint32, isOnline bool) (domain.Art
|
||||
return domain.Article{}, err
|
||||
}
|
||||
|
||||
return mappers.ArticleToDomain(localArticle), nil
|
||||
return a.withAuthorsOne(a.db, mappers.ArticleToDomain(localArticle))
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) Delete(id uint32) error {
|
||||
result := a.db.Delete(&entity.Article{}, id)
|
||||
return deleteOrNotFound(result, domain.ErrArticleNotFound)
|
||||
return a.db.Transaction(func(tx *gorm.DB) error {
|
||||
if err := deleteOrNotFound(tx.Delete(&entity.Article{}, id), domain.ErrArticleNotFound); err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Where("article_id = ?", id).Delete(&entity.ArticleAuthor{}).Error
|
||||
})
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) FindByBodyContaining(filename string) ([]domain.Article, error) {
|
||||
|
||||
Reference in new issue
Block a user