refac: migration crash, real-database tests, site deleted during create, ruels out of the repo, lists
This commit is contained in:
1 parent
680b9a1308
commit
9d284e65a9
62 files changed
+1858
-987
No files matched your search
@@ -0,0 +1,36 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"RenewCMS/internal/domain/language"
|
||||
"RenewCMS/internal/domain/transaction"
|
||||
"context"
|
||||
)
|
||||
|
||||
type ConfirmDefaultLanguageUseCase struct {
|
||||
transactor transaction.Transactor
|
||||
}
|
||||
|
||||
func NewConfirmDefaultLanguageUseCase(transactor transaction.Transactor) *ConfirmDefaultLanguageUseCase {
|
||||
return &ConfirmDefaultLanguageUseCase{transactor}
|
||||
}
|
||||
|
||||
func (u *ConfirmDefaultLanguageUseCase) Confirm(ctx context.Context, siteID uint32) error {
|
||||
return u.transactor.Run(ctx, func(tx transaction.Repositories) error {
|
||||
languages, err := tx.Languages.LockSiteLanguages(siteID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defaultLanguage, found := language.DefaultOf(languages)
|
||||
if !found {
|
||||
return language.ErrNoDefaultLanguage
|
||||
}
|
||||
if defaultLanguage.Confirmed {
|
||||
return nil
|
||||
}
|
||||
if err := tx.Languages.MarkConfirmed(siteID, defaultLanguage.Tag); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.Articles.AssignUnassignedLanguage(siteID, defaultLanguage.Tag)
|
||||
return err
|
||||
})
|
||||
}
|
||||
@@ -124,10 +124,14 @@ func (g *CreateArticleUseCase) createWithFreeSlug(ctx context.Context, requested
|
||||
func (g *CreateArticleUseCase) createInTransaction(ctx context.Context, requested string, draft article.Article) (article.Article, error) {
|
||||
var created article.Article
|
||||
err := g.transactor.Run(ctx, func(tx transaction.Repositories) error {
|
||||
lang, err := tx.Languages.LockStartingLanguage(draft.SiteID)
|
||||
languages, err := tx.Languages.LockSiteLanguages(draft.SiteID)
|
||||
if errors.Is(err, site.ErrSiteNotFound) {
|
||||
return article.ErrTargetSiteDeleted
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lang := language.StartingTag(languages)
|
||||
if requested != language.Unassigned {
|
||||
lang, err = chooseLanguage(tx.Localization, draft.SiteID, requested)
|
||||
if err != nil {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"RenewCMS/internal/domain/localization"
|
||||
"RenewCMS/internal/domain/role"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -64,12 +65,8 @@ func (u *ListArticlesUseCase) ListStoriesPage(command ListStoriesCommand) (Story
|
||||
if err != nil {
|
||||
return StoryRowsPage{}, err
|
||||
}
|
||||
if command.SEO != "" {
|
||||
allowed, err := u.versionsWithSEOStatus(command, filters, summaries)
|
||||
if err != nil {
|
||||
return StoryRowsPage{}, err
|
||||
}
|
||||
filters.VersionIDs = &allowed
|
||||
if filters.VersionIDs, err = u.versionRestriction(command, filters, summaries); err != nil {
|
||||
return StoryRowsPage{}, err
|
||||
}
|
||||
counts, err := u.articleRepository.CountStories(filters)
|
||||
if err != nil {
|
||||
@@ -88,7 +85,7 @@ func (u *ListArticlesUseCase) ListStoriesPage(command ListStoriesCommand) (Story
|
||||
if len(found.Refs) == 0 {
|
||||
return empty, nil
|
||||
}
|
||||
rows, err := u.storyRows(command, found.Refs, creatable, owners)
|
||||
rows, err := u.storyRows(command, filters, found.Refs, creatable, storyVersionsByID(visibleVersions), summaries)
|
||||
if err != nil {
|
||||
return StoryRowsPage{}, err
|
||||
}
|
||||
@@ -105,7 +102,6 @@ func storyFilters(command ListStoriesCommand, visibility articleVisibility, skip
|
||||
Missing: command.Tab == article.TabMissing,
|
||||
Status: command.Status,
|
||||
AuthorID: command.Author,
|
||||
Q: command.Q,
|
||||
Sort: command.Sort,
|
||||
Page: command.Page,
|
||||
Size: command.Size,
|
||||
@@ -121,23 +117,39 @@ func (u *ListArticlesUseCase) summarizeVisibleVersions(visibility articleVisibil
|
||||
return summaries, found.Items, err
|
||||
}
|
||||
|
||||
func (u *ListArticlesUseCase) versionsWithSEOStatus(command ListStoriesCommand, filters article.StoryFilters, summaries map[uint32]article.SEOSummary) ([]uint32, error) {
|
||||
narrowed := article.Filters{VisibleTo: filters.VisibleTo, SiteID: filters.SiteID, AuthorID: filters.AuthorID, Q: filters.Q, Unpaged: true}
|
||||
if filters.OnlyOnline {
|
||||
online := true
|
||||
narrowed.IsOnline = &online
|
||||
func (u *ListArticlesUseCase) versionRestriction(command ListStoriesCommand, filters article.StoryFilters, summaries map[uint32]article.SEOSummary) (*[]uint32, error) {
|
||||
var allowed *[]uint32
|
||||
if query := strings.TrimSpace(command.Q); query != "" {
|
||||
matching, err := u.articleRepository.FindTitleMatches(query, filters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
allowed = &matching
|
||||
}
|
||||
found, err := u.articleRepository.FindPage(narrowed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if command.SEO == "" {
|
||||
return allowed, nil
|
||||
}
|
||||
allowed := []uint32{}
|
||||
for _, version := range found.Items {
|
||||
if summaries[version.ID].Status == command.SEO {
|
||||
allowed = append(allowed, version.ID)
|
||||
matchingTitle := map[uint32]bool{}
|
||||
if allowed != nil {
|
||||
for _, id := range *allowed {
|
||||
matchingTitle[id] = true
|
||||
}
|
||||
}
|
||||
return allowed, nil
|
||||
withStatus := []uint32{}
|
||||
for id, summary := range summaries {
|
||||
if summary.Status == command.SEO && (allowed == nil || matchingTitle[id]) {
|
||||
withStatus = append(withStatus, id)
|
||||
}
|
||||
}
|
||||
return &withStatus, nil
|
||||
}
|
||||
|
||||
func storyVersionsByID(versions []article.Article) map[uint32]article.Article {
|
||||
byID := make(map[uint32]article.Article, len(versions))
|
||||
for _, version := range versions {
|
||||
byID[version.ID] = version
|
||||
}
|
||||
return byID
|
||||
}
|
||||
|
||||
func countSuggestedStories(versions []article.Article, summaries map[uint32]article.SEOSummary) int {
|
||||
@@ -156,12 +168,12 @@ func countSuggestedStories(versions []article.Article, summaries map[uint32]arti
|
||||
return len(stories) + standalone
|
||||
}
|
||||
|
||||
func (u *ListArticlesUseCase) storyRows(command ListStoriesCommand, refs []article.StoryRef, creatable bool, owners *siteOwners) ([]StoryRow, error) {
|
||||
func (u *ListArticlesUseCase) storyRows(command ListStoriesCommand, filters article.StoryFilters, refs []article.StoryRef, creatable bool, visible map[uint32]article.Article, summaries map[uint32]article.SEOSummary) ([]StoryRow, error) {
|
||||
storyIDs := make([]uint32, 0, len(refs))
|
||||
for _, ref := range refs {
|
||||
storyIDs = append(storyIDs, ref.StoryID)
|
||||
}
|
||||
loaded, err := u.articleRepository.ListByStories(storyIDs)
|
||||
loaded, err := u.articleRepository.ListByStories(storyIDs, filters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -174,8 +186,9 @@ func (u *ListArticlesUseCase) storyRows(command ListStoriesCommand, refs []artic
|
||||
representatives := make([]article.Article, 0, len(refs))
|
||||
for _, ref := range refs {
|
||||
versions := byStory[ref.StoryID]
|
||||
representative, found := versionByID(versions, ref.ArticleID)
|
||||
if !found {
|
||||
_, listed := versionByID(versions, ref.ArticleID)
|
||||
representative, found := visible[ref.ArticleID]
|
||||
if !listed || !found {
|
||||
continue
|
||||
}
|
||||
languages, cached := siteRows[representative.SiteID]
|
||||
@@ -188,10 +201,6 @@ func (u *ListArticlesUseCase) storyRows(command ListStoriesCommand, refs []artic
|
||||
rows = append(rows, buildStoryRow(command.Caller, representative, versions, languages, creatable))
|
||||
representatives = append(representatives, representative)
|
||||
}
|
||||
summaries, err := u.summarize(representatives, owners)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rendered, err := renderArticles(u.bodyRenderer, representatives, command.Format)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -37,6 +37,7 @@ var failureReasons = []failureReason{
|
||||
{article.ErrSourceOtherStory, "The chosen source version belongs to another article."},
|
||||
{article.ErrStoryMoveRequired, "The article has other versions, so the whole story must be moved."},
|
||||
{article.ErrSlugConflict, "An address of the article is already used on the destination site."},
|
||||
{article.ErrTargetSiteDeleted, "The site was deleted while the article was being created."},
|
||||
{image.ErrImageTypeNotAllowed, "The file must be a PNG, JPEG, WEBP or SVG image."},
|
||||
{image.ErrImageTooLarge, "The file is too large to upload."},
|
||||
{image.ErrImageUnreadable, "The image could not be read."},
|
||||
|
||||
Reference in new issue
Block a user