98 lines
4.0 KiB
Go
98 lines
4.0 KiB
Go
package useCases
|
|
|
|
import (
|
|
"RenewCMS/internal/domain/article"
|
|
"RenewCMS/internal/domain/site"
|
|
"slices"
|
|
"strings"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
func metaTitle(art article.Article) (string, string) {
|
|
if art.SEOTitle != "" {
|
|
return art.SEOTitle, article.SEOSourceSEOTitle
|
|
}
|
|
return art.Title, article.SEOSourceTitle
|
|
}
|
|
|
|
func resolveDescription(art article.Article, owner site.Site, facts bodyFacts) (string, string) {
|
|
if art.SEODescription != "" {
|
|
return art.SEODescription, article.SEOSourceSEODescription
|
|
}
|
|
if art.Excerpt != "" {
|
|
return art.Excerpt, article.SEOSourceExcerpt
|
|
}
|
|
if sentence := firstSentence(facts.spacedText); sentence != "" {
|
|
return sentence, article.SEOSourceBody
|
|
}
|
|
if owner.DefaultDescription != "" {
|
|
return owner.DefaultDescription, article.SEOSourceSite
|
|
}
|
|
return "", article.SEOSourceNone
|
|
}
|
|
|
|
func suggestion(code string, field string, params map[string]int) article.SEOSuggestion {
|
|
return article.SEOSuggestion{Code: code, Field: field, Params: params}
|
|
}
|
|
|
|
func rawSuggestions(art article.Article, owner site.Site, facts bodyFacts) []article.SEOSuggestion {
|
|
suggestions := []article.SEOSuggestion{}
|
|
title, _ := metaTitle(art)
|
|
titleRunes := utf8.RuneCountInString(title)
|
|
if titleRunes > article.SEOTitleMaxRunes {
|
|
suggestions = append(suggestions, suggestion(article.DismissTitleLong, article.SEOFieldTitle, map[string]int{"length": titleRunes, "max": article.SEOTitleMaxRunes}))
|
|
}
|
|
if strings.TrimSpace(title) == "" {
|
|
suggestions = append(suggestions, suggestion(article.DismissTitleEmpty, article.SEOFieldTitle, map[string]int{}))
|
|
}
|
|
description, _ := resolveDescription(art, owner, facts)
|
|
descriptionRunes := utf8.RuneCountInString(description)
|
|
if descriptionRunes < article.SEODescriptionMinRunes {
|
|
suggestions = append(suggestions, suggestion(article.DismissDescShort, article.SEOFieldDescription, map[string]int{"length": descriptionRunes, "min": article.SEODescriptionMinRunes}))
|
|
}
|
|
if descriptionRunes > article.SEODescriptionMaxRunes {
|
|
suggestions = append(suggestions, suggestion(article.DismissDescLong, article.SEOFieldDescription, map[string]int{"length": descriptionRunes, "max": article.SEODescriptionMaxRunes}))
|
|
}
|
|
if art.CoverImageID != nil && strings.TrimSpace(art.CoverImageAlt) == "" {
|
|
suggestions = append(suggestions, suggestion(article.DismissCoverAlt, article.SEOFieldCoverAlt, map[string]int{}))
|
|
}
|
|
if art.CoverImageID == nil {
|
|
suggestions = append(suggestions, suggestion(article.DismissCoverNone, article.SEOFieldCoverID, map[string]int{}))
|
|
}
|
|
slugRunes := utf8.RuneCountInString(art.Slug)
|
|
if slugRunes > article.SEOSlugMaxRunes {
|
|
suggestions = append(suggestions, suggestion(article.DismissSlugLong, article.SEOFieldSlug, map[string]int{"length": slugRunes, "max": article.SEOSlugMaxRunes}))
|
|
}
|
|
if len(art.Authors) == 0 {
|
|
suggestions = append(suggestions, suggestion(article.DismissNoAuthor, article.SEOFieldAuthors, map[string]int{}))
|
|
}
|
|
if facts.textRunes >= article.SEOHeadingMinTextRunes && !facts.hasSubheading {
|
|
suggestions = append(suggestions, suggestion(article.DismissNoHeading, article.SEOFieldBody, map[string]int{}))
|
|
}
|
|
if facts.imagesWithoutAlt > 0 {
|
|
suggestions = append(suggestions, suggestion(article.DismissBodyAlt, article.SEOFieldBody, map[string]int{"count": facts.imagesWithoutAlt}))
|
|
}
|
|
if facts.textRunes < article.SEOShortBodyRunes {
|
|
suggestions = append(suggestions, suggestion(article.DismissShort, article.SEOFieldBody, map[string]int{"length": facts.textRunes, "min": article.SEOShortBodyRunes}))
|
|
}
|
|
return suggestions
|
|
}
|
|
|
|
func assessSEO(art article.Article, owner site.Site) article.SEOAssessment {
|
|
facts := analyzeBody(art.Body)
|
|
kept := []article.SEOSuggestion{}
|
|
for _, found := range rawSuggestions(art, owner, facts) {
|
|
if !slices.Contains(art.SEODismissed, found.Code) {
|
|
kept = append(kept, found)
|
|
}
|
|
}
|
|
status := article.SEOStatusReady
|
|
if len(kept) > 0 {
|
|
status = article.SEOStatusSuggestions
|
|
}
|
|
if art.Noindex {
|
|
status = article.SEOStatusHidden
|
|
}
|
|
return article.SEOAssessment{Status: status, Suggestions: kept}
|
|
}
|