feat: SEO backend data (1/4)
This commit is contained in:
1 parent
cb1410f0b0
commit
0eb46b0d74
90 files changed
+6094
-350
No files matched your search
@@ -2,22 +2,136 @@ package useCases
|
||||
|
||||
import (
|
||||
"RenewCMS/internal/domain/article"
|
||||
"RenewCMS/internal/domain/author"
|
||||
"RenewCMS/internal/domain/image"
|
||||
"RenewCMS/internal/domain/site"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
UsageTypeArticle = "article"
|
||||
UsageTypeAuthor = "author"
|
||||
UsageTypeSite = "site"
|
||||
|
||||
UsageFieldBody = "body"
|
||||
UsageFieldCover = "cover"
|
||||
UsageFieldSocial = "social"
|
||||
UsageFieldAvatar = "avatar"
|
||||
UsageFieldDefaultSocialImage = "default_social_image"
|
||||
)
|
||||
|
||||
type MediaUsage struct {
|
||||
Type string
|
||||
ID uint32
|
||||
Title string
|
||||
Published *bool
|
||||
Fields []string
|
||||
}
|
||||
|
||||
type GetMediaUsageUseCase struct {
|
||||
imageRepository image.Repository
|
||||
articleRepository article.Repository
|
||||
sites site.Repository
|
||||
authors author.Repository
|
||||
}
|
||||
|
||||
func NewGetMediaUsageUseCase(imageRepository image.Repository, articleRepository article.Repository) *GetMediaUsageUseCase {
|
||||
return &GetMediaUsageUseCase{imageRepository, articleRepository}
|
||||
func NewGetMediaUsageUseCase(imageRepository image.Repository, articleRepository article.Repository, sites site.Repository, authors author.Repository) *GetMediaUsageUseCase {
|
||||
return &GetMediaUsageUseCase{imageRepository: imageRepository, articleRepository: articleRepository, sites: sites, authors: authors}
|
||||
}
|
||||
|
||||
func (u *GetMediaUsageUseCase) Usage(id uint32) ([]article.Article, error) {
|
||||
func (u *GetMediaUsageUseCase) Usage(id uint32) ([]MediaUsage, error) {
|
||||
img, err := u.imageRepository.Get(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return u.articleRepository.FindByBodyContaining(image.StoredName(img.Path))
|
||||
usages, err := u.articleUsages(img)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authorUsages, err := u.authorUsages(img)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
siteUsages, err := u.siteUsages(img)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return slices.Concat(usages, authorUsages, siteUsages), nil
|
||||
}
|
||||
|
||||
func (u *GetMediaUsageUseCase) articleUsages(img image.Image) ([]MediaUsage, error) {
|
||||
storedName := image.StoredName(img.Path)
|
||||
inBody, err := u.articleRepository.FindByBodyContaining(storedName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
referencing, err := u.articleRepository.FindByImage(img.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
byID := map[uint32]*MediaUsage{}
|
||||
for _, found := range inBody {
|
||||
if !strings.Contains(found.Body, storedName) {
|
||||
continue
|
||||
}
|
||||
entry := usageFor(byID, found)
|
||||
entry.Fields = append(entry.Fields, UsageFieldBody)
|
||||
}
|
||||
for _, found := range referencing {
|
||||
entry := usageFor(byID, found)
|
||||
if found.CoverImageID != nil && *found.CoverImageID == img.ID {
|
||||
entry.Fields = append(entry.Fields, UsageFieldCover)
|
||||
}
|
||||
if found.SocialImageID != nil && *found.SocialImageID == img.ID {
|
||||
entry.Fields = append(entry.Fields, UsageFieldSocial)
|
||||
}
|
||||
}
|
||||
usages := make([]MediaUsage, 0, len(byID))
|
||||
for _, entry := range byID {
|
||||
usages = append(usages, *entry)
|
||||
}
|
||||
slices.SortFunc(usages, func(a, b MediaUsage) int { return int(a.ID) - int(b.ID) })
|
||||
return usages, nil
|
||||
}
|
||||
|
||||
func usageFor(byID map[uint32]*MediaUsage, found article.Article) *MediaUsage {
|
||||
if entry, ok := byID[found.ID]; ok {
|
||||
return entry
|
||||
}
|
||||
published := found.IsOnline
|
||||
entry := &MediaUsage{Type: UsageTypeArticle, ID: found.ID, Title: found.Title, Published: &published, Fields: []string{}}
|
||||
byID[found.ID] = entry
|
||||
return entry
|
||||
}
|
||||
|
||||
func (u *GetMediaUsageUseCase) authorUsages(img image.Image) ([]MediaUsage, error) {
|
||||
found, err := u.authors.FindByAvatar(img.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
usages := make([]MediaUsage, 0, len(found))
|
||||
for _, a := range found {
|
||||
usages = append(usages, MediaUsage{Type: UsageTypeAuthor, ID: a.ID, Title: a.Name, Fields: []string{UsageFieldAvatar}})
|
||||
}
|
||||
return usages, nil
|
||||
}
|
||||
|
||||
func (u *GetMediaUsageUseCase) siteUsages(img image.Image) ([]MediaUsage, error) {
|
||||
all, err := u.sites.List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
usages := []MediaUsage{}
|
||||
for _, s := range all {
|
||||
if s.DefaultSocialImageID != nil && *s.DefaultSocialImageID == img.ID {
|
||||
usages = append(usages, MediaUsage{Type: UsageTypeSite, ID: s.ID, Title: s.Name, Fields: []string{UsageFieldDefaultSocialImage}})
|
||||
}
|
||||
}
|
||||
slices.SortFunc(usages, func(a, b MediaUsage) int { return int(a.ID) - int(b.ID) })
|
||||
return usages, nil
|
||||
}
|
||||
|
||||
func articleMentionsImage(a article.Article, img image.Image) bool {
|
||||
return strings.Contains(a.Body, image.StoredName(img.Path)) || a.UsesImage(img.ID)
|
||||
}
|
||||
Reference in new issue
Block a user