feat: SEO backend output (2/4)
This commit is contained in:
1 parent
0eb46b0d74
commit
eb9876fde3
32 files changed
+3859
-65
No files matched your search
@@ -0,0 +1,87 @@
|
||||
package site
|
||||
|
||||
import (
|
||||
"RenewCMS/api/pkg/apperr"
|
||||
validator "RenewCMS/api/pkg/validator"
|
||||
"RenewCMS/internal/infrastructure/useCases"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultSitemapPage = 1
|
||||
defaultSitemapSize = 100
|
||||
totalCountHeader = "X-Total-Count"
|
||||
)
|
||||
|
||||
type SitemapHandler struct {
|
||||
ListUseCase *useCases.ListSitemapUseCase
|
||||
}
|
||||
|
||||
func NewSitemapHandler(list *useCases.ListSitemapUseCase) *SitemapHandler {
|
||||
return &SitemapHandler{ListUseCase: list}
|
||||
}
|
||||
|
||||
type sitemapQuery struct {
|
||||
Page int `validate:"gte=1"`
|
||||
Size int `validate:"oneof=25 50 100 500"`
|
||||
}
|
||||
|
||||
type sitemapItem struct {
|
||||
URL string `json:"url"`
|
||||
ModifiedAt string `json:"modified_at"`
|
||||
Noindex bool `json:"noindex"`
|
||||
}
|
||||
|
||||
func sitemapIntParam(values url.Values, name string, fallback int) (int, error) {
|
||||
if !values.Has(name) {
|
||||
return fallback, nil
|
||||
}
|
||||
return strconv.Atoi(values.Get(name))
|
||||
}
|
||||
|
||||
func readSitemapQuery(values url.Values) (sitemapQuery, error) {
|
||||
page, err := sitemapIntParam(values, "page", defaultSitemapPage)
|
||||
if err != nil {
|
||||
return sitemapQuery{}, err
|
||||
}
|
||||
size, err := sitemapIntParam(values, "size", defaultSitemapSize)
|
||||
if err != nil {
|
||||
return sitemapQuery{}, err
|
||||
}
|
||||
return sitemapQuery{Page: page, Size: size}, nil
|
||||
}
|
||||
|
||||
func (h *SitemapHandler) Sitemap(w http.ResponseWriter, r *http.Request) {
|
||||
query, err := readSitemapQuery(r.URL.Query())
|
||||
if err != nil || validator.Validate.Struct(query) != nil {
|
||||
http.Error(w, apperr.BodyErrorMessage, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
page, err := h.ListUseCase.List(chi.URLParam(r, "key"), query.Page, query.Size)
|
||||
if err != nil {
|
||||
writeSiteError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
items := make([]sitemapItem, 0, len(page.Entries))
|
||||
for _, entry := range page.Entries {
|
||||
items = append(items, sitemapItem{URL: entry.URL, ModifiedAt: entry.ModifiedAt.UTC().Format(time.RFC3339), Noindex: entry.Noindex})
|
||||
}
|
||||
body, err := json.Marshal(items)
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set(totalCountHeader, strconv.Itoa(page.Total))
|
||||
if _, err := w.Write(body); err != nil {
|
||||
log.Printf("Failed to write response: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user