2025-05-29 11:49:16 +02:00

195 lines
4.6 KiB
Go

package seo
import (
"encoding/json"
"encoding/xml"
"fmt"
"net/http"
"path"
"time"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/router"
)
type MenuRecord struct {
Active bool `json:"active"`
CollectionID string `json:"collectionId"`
CollectionName string `json:"collectionName"`
Created string `json:"created"`
ID string `json:"id"`
IDLang string `json:"id_lang"`
IDPage string `json:"id_page"`
IDParent string `json:"id_parent"`
IsDefault bool `json:"is_default"`
IsRoot bool `json:"is_root"`
LinkRewrite string `json:"link_rewrite"`
LinkTitle string `json:"link_title"`
MetaDescription string `json:"meta_description"`
MetaTitle string `json:"meta_title"`
Name string `json:"name"`
PageName string `json:"page_name"`
PositionID int `json:"position_id"`
Updated string `json:"updated"`
Url string `json:"url"`
}
type UrlSet struct {
XMLName xml.Name `xml:"urlset"`
Xmlns string `xml:"xmlns,attr"`
Urls []Url `xml:"url"`
}
type Url struct {
Loc string `xml:"loc"`
LastMod string `xml:"lastmod,omitempty"`
ChangeFreq string `xml:"changefreq,omitempty"`
Priority string `xml:"priority,omitempty"`
}
func ServeFeeds(app *pocketbase.PocketBase, se *core.ServeEvent) *router.Route[*core.RequestEvent] {
return se.Router.GET("/feeds/{lang}/sitemap.xml", func(e *core.RequestEvent) error {
lang := e.Request.PathValue("lang")
urls, err := getLocations(app, lang)
if err != nil {
return err
}
xx := UrlSet{
Xmlns: "http://www.sitemaps.org/schemas/sitemap/0.9",
Urls: urls,
}
bytes, err := xml.MarshalIndent(xx, "", " ")
if err != nil {
return err
}
e.Response.Header().Add("content-type", "text/xml")
return e.String(http.StatusOK, xml.Header+string(bytes))
})
}
func getLocations(app *pocketbase.PocketBase, lang string) ([]Url, error) {
records, err := app.FindRecordsByFilter("menu_view", fmt.Sprintf("id_lang='%s'&&active=true", lang), "position_id", 200, 0)
if err != nil {
return nil, err
}
baseUrl, err := getBaseUrl(app)
if err != nil {
return nil, err
}
locations := []Url{}
lastMod := time.Now().Add(time.Hour * 24 * 7 * -1).Format("2006-01-02")
for _, r := range records {
rec := MenuRecord{}
x, _ := r.MarshalJSON()
json.Unmarshal(x, &rec)
if rec.IsRoot {
continue
}
if len(rec.Url) > 0 {
continue
}
if rec.IsDefault {
locations = append(locations, Url{
Loc: baseUrl + path.Join(lang),
LastMod: lastMod,
ChangeFreq: "weekly",
Priority: "1.0",
})
}
locations = append(locations, Url{
Loc: baseUrl + path.Join(lang, rec.IDPage, rec.LinkRewrite),
LastMod: lastMod,
ChangeFreq: "weekly",
Priority: "1.0",
})
}
return locations, nil
}
type BaseUrl struct {
BaseURL string `json:"baseUrl"`
}
func getBaseUrl(app *pocketbase.PocketBase) (string, error) {
record, err := app.FindFirstRecordByFilter("settings", "key='baseUrl'", nil)
if err != nil {
return "", err
}
settings := BaseUrl{}
json.Unmarshal([]byte(record.GetString("value")), &settings)
if err != nil {
return "", err
}
return settings.BaseURL, nil
}
type SitemapIndex struct {
XMLName xml.Name `xml:"sitemapindex"`
Xmlns string `xml:"xmlns,attr"`
Sitemaps []Sitemap `xml:"sitemap"`
}
// Sitemap represents each <sitemap> entry
type Sitemap struct {
Loc string `xml:"loc"`
LastMod string `xml:"lastmod"`
}
func ServeFeedsIndex(app *pocketbase.PocketBase, se *core.ServeEvent) *router.Route[*core.RequestEvent] {
return se.Router.GET("/feeds/index.xml", func(e *core.RequestEvent) error {
index, err := makeSiteMapIndex(app)
if err != nil {
return err
}
bytes, err := xml.MarshalIndent(index, "", " ")
if err != nil {
return err
}
e.Response.Header().Add("content-type", "text/xml")
return e.String(http.StatusOK, xml.Header+string(bytes))
})
}
func makeSiteMapIndex(app *pocketbase.PocketBase) (*SitemapIndex, error) {
index := &SitemapIndex{
Xmlns: "http://www.sitemaps.org/schemas/sitemap/0.9",
}
bseUrl, err := getBaseUrl(app)
if err != nil {
return nil, err
}
langs, err := app.FindRecordsByFilter("lang", "active=true", "", 200, 0)
if err != nil {
return index, err
}
lastMod := time.Now().Add(time.Hour * 24 * 7 * -1).Format("2006-01-02")
for _, l := range langs {
index.Sitemaps = append(index.Sitemaps, Sitemap{
Loc: bseUrl + path.Join("feeds/", l.Id, "sitemap.xml"),
LastMod: lastMod,
})
}
return index, nil
}