GoBlog/sitemap.go

229 lines
6.0 KiB
Go
Raw Normal View History

2020-09-22 15:15:17 +00:00
package main
import (
"database/sql"
2021-08-04 13:45:58 +00:00
"encoding/xml"
2023-01-24 13:30:53 +00:00
"io"
2020-09-22 15:15:17 +00:00
"net/http"
2021-08-18 12:47:31 +00:00
"time"
2020-10-15 15:32:46 +00:00
"github.com/araddon/dateparse"
"github.com/snabb/sitemap"
"go.goblog.app/app/pkgs/contenttype"
2020-09-22 15:15:17 +00:00
)
const (
sitemapPath = "/sitemap.xml"
sitemapBlogPath = "/sitemap-blog.xml"
sitemapBlogFeaturesPath = "/sitemap-blog-features.xml"
sitemapBlogArchivesPath = "/sitemap-blog-archives.xml"
sitemapBlogPostsPath = "/sitemap-blog-posts.xml"
)
2020-10-15 17:50:34 +00:00
2022-04-10 09:46:35 +00:00
func (a *goBlog) serveSitemap(w http.ResponseWriter, r *http.Request) {
// Create sitemap
sm := sitemap.NewSitemapIndex()
// Add blog sitemap indices
2021-08-18 12:47:31 +00:00
now := time.Now().UTC()
for _, bc := range a.cfg.Blogs {
sm.Add(&sitemap.URL{
2021-08-18 12:47:31 +00:00
Loc: a.getFullAddress(bc.getRelativePath(sitemapBlogPath)),
LastMod: &now,
})
}
// Write sitemap
2022-04-10 09:46:35 +00:00
a.writeSitemapXML(w, r, sm)
}
func (a *goBlog) serveSitemapBlog(w http.ResponseWriter, r *http.Request) {
// Create sitemap
sm := sitemap.NewSitemapIndex()
// Add blog sitemaps
_, bc := a.getBlog(r)
2021-08-18 12:47:31 +00:00
now := time.Now().UTC()
sm.Add(&sitemap.URL{
Loc: a.getFullAddress(bc.getRelativePath(sitemapBlogFeaturesPath)),
2021-08-18 12:47:31 +00:00
LastMod: &now,
})
sm.Add(&sitemap.URL{
Loc: a.getFullAddress(bc.getRelativePath(sitemapBlogArchivesPath)),
2021-08-18 12:47:31 +00:00
LastMod: &now,
})
sm.Add(&sitemap.URL{
Loc: a.getFullAddress(bc.getRelativePath(sitemapBlogPostsPath)),
2021-08-18 12:47:31 +00:00
LastMod: &now,
})
// Write sitemap
2022-04-10 09:46:35 +00:00
a.writeSitemapXML(w, r, sm)
}
func (a *goBlog) serveSitemapBlogFeatures(w http.ResponseWriter, r *http.Request) {
// Create sitemap
2020-10-15 17:50:34 +00:00
sm := sitemap.New()
// Add features to sitemap
_, bc := a.getBlog(r)
// Home
sm.Add(&sitemap.URL{
Loc: a.getFullAddress(bc.getRelativePath("")),
})
// Photos
if pc := bc.Photos; pc != nil && pc.Enabled {
2021-03-09 20:35:17 +00:00
sm.Add(&sitemap.URL{
Loc: a.getFullAddress(bc.getRelativePath(defaultIfEmpty(pc.Path, defaultPhotosPath))),
2021-03-09 20:35:17 +00:00
})
}
// Search
if bsc := bc.Search; bsc != nil && bsc.Enabled {
sm.Add(&sitemap.URL{
Loc: a.getFullAddress(bc.getRelativePath(defaultIfEmpty(bsc.Path, defaultSearchPath))),
})
}
// Stats
if bsc := bc.BlogStats; bsc != nil && bsc.Enabled {
sm.Add(&sitemap.URL{
Loc: a.getFullAddress(bc.getRelativePath(defaultIfEmpty(bsc.Path, defaultBlogStatsPath))),
})
}
// Blogroll
if brc := bc.Blogroll; brc != nil && brc.Enabled {
sm.Add(&sitemap.URL{
Loc: a.getFullAddress(bc.getRelativePath(defaultIfEmpty(brc.Path, defaultBlogrollPath))),
})
}
// Geo map
if mc := bc.Map; mc != nil && mc.Enabled {
sm.Add(&sitemap.URL{
Loc: a.getFullAddress(bc.getRelativePath(defaultIfEmpty(mc.Path, defaultGeoMapPath))),
})
}
// Contact
if cc := bc.Contact; cc != nil && cc.Enabled {
sm.Add(&sitemap.URL{
Loc: a.getFullAddress(bc.getRelativePath(defaultIfEmpty(cc.Path, defaultContactPath))),
})
}
// Write sitemap
2022-04-10 09:46:35 +00:00
a.writeSitemapXML(w, r, sm)
}
func (a *goBlog) serveSitemapBlogArchives(w http.ResponseWriter, r *http.Request) {
// Create sitemap
sm := sitemap.New()
// Add archives to sitemap
b, bc := a.getBlog(r)
// Sections
for _, section := range bc.Sections {
if section.Name != "" {
sm.Add(&sitemap.URL{
Loc: a.getFullAddress(bc.getRelativePath(section.Name)),
2021-05-08 19:22:48 +00:00
})
}
}
// Taxonomies
for _, taxonomy := range bc.Taxonomies {
if taxonomy.Name != "" {
// Taxonomy
taxPath := bc.getRelativePath("/" + taxonomy.Name)
2021-07-22 12:04:46 +00:00
sm.Add(&sitemap.URL{
Loc: a.getFullAddress(taxPath),
2021-07-22 12:04:46 +00:00
})
// Values
if taxValues, err := a.db.allTaxonomyValues(b, taxonomy.Name); err == nil {
for _, tv := range taxValues {
sm.Add(&sitemap.URL{
Loc: a.getFullAddress(taxPath + "/" + urlize(tv)),
})
}
}
2021-07-22 12:04:46 +00:00
}
}
// Date based archives
datePaths, _ := a.sitemapDatePaths(b)
for _, p := range datePaths {
sm.Add(&sitemap.URL{
Loc: a.getFullAddress(bc.getRelativePath(p)),
})
}
// Write sitemap
2022-04-10 09:46:35 +00:00
a.writeSitemapXML(w, r, sm)
}
// Serve sitemap with all the blog's posts
func (a *goBlog) serveSitemapBlogPosts(w http.ResponseWriter, r *http.Request) {
// Create sitemap
sm := sitemap.New()
// Request posts
blog, _ := a.getBlog(r)
2021-08-05 06:09:34 +00:00
posts, _ := a.getPosts(&postsRequestConfig{
status: []postStatus{statusPublished},
visibility: []postVisibility{visibilityPublic},
blog: blog,
withoutParameters: true,
})
// Add posts to sitemap
for _, p := range posts {
item := &sitemap.URL{Loc: a.fullPostURL(p)}
lastMod := timeNoErr(dateparse.ParseLocal(defaultIfEmpty(p.Updated, p.Published)))
if !lastMod.IsZero() {
item.LastMod = &lastMod
2021-03-09 20:35:17 +00:00
}
sm.Add(item)
2021-03-09 20:35:17 +00:00
}
// Write sitemap
2022-04-10 09:46:35 +00:00
a.writeSitemapXML(w, r, sm)
}
2022-04-10 09:46:35 +00:00
func (a *goBlog) writeSitemapXML(w http.ResponseWriter, r *http.Request, sm any) {
2023-01-24 13:30:53 +00:00
pr, pw := io.Pipe()
go func() {
_, _ = io.WriteString(pw, xml.Header)
_, _ = io.WriteString(pw, `<?xml-stylesheet type="text/xsl" href="`)
_, _ = io.WriteString(pw, a.assetFileName("sitemap.xsl"))
_, _ = io.WriteString(pw, `" ?>`)
_ = pw.CloseWithError(xml.NewEncoder(pw).Encode(sm))
}()
w.Header().Set(contentType, contenttype.XMLUTF8)
2023-01-24 13:30:53 +00:00
_ = pr.CloseWithError(a.min.Get().Minify(contenttype.XML, w, pr))
}
const sitemapDatePathsSql = `
with alldates as (
select distinct
substr(published, 1, 4) as year,
substr(published, 6, 2) as month,
substr(published, 9, 2) as day
from (
select tolocal(coalesce(published, '')) as published
from posts
where blog = @blog and status = @status and published != ''
)
)
select distinct '/' || year from alldates
union
select distinct '/' || year || '/' || month from alldates
union
select distinct '/' || year || '/' || month || '/' || day from alldates
union
select distinct '/x/' || month from alldates
union
select distinct '/x/' || month || '/' || day from alldates
union
select distinct '/x/x/' || day from alldates;
`
func (a *goBlog) sitemapDatePaths(blog string) (paths []string, err error) {
rows, err := a.db.Query(sitemapDatePathsSql, sql.Named("blog", blog), sql.Named("status", statusPublished))
if err != nil {
return nil, err
}
var path string
for rows.Next() {
err = rows.Scan(&path)
if err != nil {
return nil, err
2020-09-22 15:15:17 +00:00
}
paths = append(paths, path)
2020-09-22 15:15:17 +00:00
}
return
2020-09-22 15:15:17 +00:00
}