Files
RenewCMS/internal/infrastructure/useCases/ResolvePublicArticle.go
T

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
}