153 lines
4.7 KiB
Go
153 lines
4.7 KiB
Go
package useCases
|
|
|
|
import (
|
|
"RenewCMS/internal/domain/article"
|
|
"RenewCMS/internal/domain/language"
|
|
"RenewCMS/internal/domain/localization"
|
|
"RenewCMS/internal/domain/site"
|
|
"errors"
|
|
)
|
|
|
|
type ResolvePublicArticleUseCase struct {
|
|
articles article.Repository
|
|
sites site.Repository
|
|
localization localization.Repository
|
|
bodyRenderer article.BodyRenderer
|
|
}
|
|
|
|
func NewResolvePublicArticleUseCase(articles article.Repository, sites site.Repository, localizationRepository localization.Repository, bodyRenderer article.BodyRenderer) *ResolvePublicArticleUseCase {
|
|
return &ResolvePublicArticleUseCase{articles: articles, sites: sites, localization: localizationRepository, bodyRenderer: bodyRenderer}
|
|
}
|
|
|
|
type PublicArticle struct {
|
|
Article article.Article
|
|
Viewer ContentCaller
|
|
Context ArticleContext
|
|
Alternates []article.Alternate
|
|
RequestedLang string
|
|
Fallback bool
|
|
}
|
|
|
|
type PublicStoryQuery struct {
|
|
SiteKey string
|
|
StoryID uint32
|
|
Lang *string
|
|
FallbackDefault bool
|
|
Format article.BodyFormat
|
|
}
|
|
|
|
type PublicLookupQuery struct {
|
|
SiteKey string
|
|
Lang string
|
|
Slug string
|
|
Format article.BodyFormat
|
|
}
|
|
|
|
func (u *ResolvePublicArticleUseCase) ByLangSlug(query PublicLookupQuery) (PublicArticle, error) {
|
|
tag, err := language.Normalize(query.Lang)
|
|
if errors.Is(err, language.ErrInvalidLanguage) {
|
|
return PublicArticle{}, err
|
|
}
|
|
unsupported := errors.Is(err, language.ErrUnsupportedLanguage)
|
|
owner, err := u.sites.GetByKey(query.SiteKey)
|
|
if err != nil {
|
|
return PublicArticle{}, err
|
|
}
|
|
if unsupported {
|
|
return PublicArticle{}, article.ErrArticleNotFound
|
|
}
|
|
found, err := u.articles.GetByLangSlug(owner.ID, tag, query.Slug)
|
|
if err != nil {
|
|
return PublicArticle{}, err
|
|
}
|
|
if !found.IsOnline {
|
|
return PublicArticle{}, article.ErrArticleNotFound
|
|
}
|
|
rows, err := u.localization.Rows(owner.ID)
|
|
if err != nil {
|
|
return PublicArticle{}, err
|
|
}
|
|
versions, err := storyVersions(u.articles, found)
|
|
if err != nil {
|
|
return PublicArticle{}, err
|
|
}
|
|
return u.present(owner, rows, versions, found, query.Format)
|
|
}
|
|
|
|
func (u *ResolvePublicArticleUseCase) ByStory(query PublicStoryQuery) (PublicArticle, error) {
|
|
requested := ""
|
|
unsupported := false
|
|
if query.Lang != nil {
|
|
tag, err := language.Normalize(*query.Lang)
|
|
if errors.Is(err, language.ErrInvalidLanguage) {
|
|
return PublicArticle{}, err
|
|
}
|
|
requested = tag
|
|
unsupported = errors.Is(err, language.ErrUnsupportedLanguage)
|
|
}
|
|
owner, err := u.sites.GetByKey(query.SiteKey)
|
|
if err != nil {
|
|
return PublicArticle{}, err
|
|
}
|
|
rows, err := u.localization.Rows(owner.ID)
|
|
if err != nil {
|
|
return PublicArticle{}, err
|
|
}
|
|
if unsupported {
|
|
return PublicArticle{}, article.ErrLanguageNotAvailable
|
|
}
|
|
defaultTag := confirmedDefault(rows)
|
|
if query.Lang == nil {
|
|
requested = defaultTag
|
|
}
|
|
versions, err := u.articles.ListByStory(query.StoryID)
|
|
if err != nil {
|
|
return PublicArticle{}, err
|
|
}
|
|
chosen, fallback, ok := chooseStoryVersion(owner, versions, requested, defaultTag, query.FallbackDefault)
|
|
if !ok {
|
|
return PublicArticle{}, article.ErrLanguageNotAvailable
|
|
}
|
|
presented, err := u.present(owner, rows, versions, chosen, query.Format)
|
|
if err != nil {
|
|
return PublicArticle{}, err
|
|
}
|
|
presented.RequestedLang = requested
|
|
presented.Fallback = fallback
|
|
return presented, nil
|
|
}
|
|
|
|
func chooseStoryVersion(owner site.Site, versions []article.Article, requested string, defaultTag string, fallbackDefault bool) (article.Article, bool, bool) {
|
|
if requested == "" {
|
|
return article.Article{}, false, false
|
|
}
|
|
if found, ok := publishedVersion(owner, versions, requested); ok {
|
|
return found, false, true
|
|
}
|
|
if fallbackDefault && defaultTag != "" && defaultTag != requested {
|
|
if found, ok := publishedVersion(owner, versions, defaultTag); ok {
|
|
return found, true, true
|
|
}
|
|
}
|
|
return article.Article{}, false, false
|
|
}
|
|
|
|
func publishedVersion(owner site.Site, versions []article.Article, tag string) (article.Article, bool) {
|
|
for _, version := range versions {
|
|
if version.SiteID == owner.ID && version.Lang == tag && version.IsOnline {
|
|
return version, true
|
|
}
|
|
}
|
|
return article.Article{}, false
|
|
}
|
|
|
|
func (u *ResolvePublicArticleUseCase) present(owner site.Site, rows []localization.Row, versions []article.Article, found article.Article, format article.BodyFormat) (PublicArticle, error) {
|
|
rendered, err := renderArticle(u.bodyRenderer, found, format)
|
|
if err != nil {
|
|
return PublicArticle{}, err
|
|
}
|
|
viewer := ContentCaller{}
|
|
described := ArticleContext{Capabilities: viewer.capabilitiesFor(found), Translations: []article.Translation{}}
|
|
return PublicArticle{Article: rendered, Viewer: viewer, Context: described, Alternates: alternatesOf(owner, eligibleSiblings(rows, versions, found))}, nil
|
|
}
|