mirror of https://github.com/go-sonic/sonic.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
5.6 KiB
Go
188 lines
5.6 KiB
Go
package content
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/go-sonic/sonic/consts"
|
|
"github.com/go-sonic/sonic/model/entity"
|
|
"github.com/go-sonic/sonic/model/param"
|
|
"github.com/go-sonic/sonic/model/property"
|
|
"github.com/go-sonic/sonic/model/vo"
|
|
"github.com/go-sonic/sonic/service"
|
|
"github.com/go-sonic/sonic/service/assembler"
|
|
"github.com/go-sonic/sonic/template"
|
|
"github.com/go-sonic/sonic/util"
|
|
)
|
|
|
|
type FeedHandler struct {
|
|
OptionService service.OptionService
|
|
PostService service.PostService
|
|
PostCategoryService service.PostCategoryService
|
|
CategoryService service.CategoryService
|
|
PostAssembler assembler.PostAssembler
|
|
}
|
|
|
|
func NewFeedHandler(optionService service.OptionService, postService service.PostService, categoryService service.CategoryService, postCategoryService service.PostCategoryService, postAssembler assembler.PostAssembler) *FeedHandler {
|
|
return &FeedHandler{
|
|
OptionService: optionService,
|
|
PostService: postService,
|
|
CategoryService: categoryService,
|
|
PostCategoryService: postCategoryService,
|
|
PostAssembler: postAssembler,
|
|
}
|
|
}
|
|
|
|
func (f *FeedHandler) Feed(ctx *gin.Context, model template.Model) (string, error) {
|
|
_, err := f.Atom(ctx, model)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
ctx.Header("Content-Type", "application/xml; charset=utf-8")
|
|
return "common/web/rss", nil
|
|
}
|
|
|
|
func (f *FeedHandler) CategoryFeed(ctx *gin.Context, model template.Model) (string, error) {
|
|
_, err := f.CategoryAtom(ctx, model)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
ctx.Header("Content-Type", "application/xml; charset=utf-8")
|
|
return "common/web/rss", nil
|
|
}
|
|
|
|
func (f *FeedHandler) Atom(ctx *gin.Context, model template.Model) (string, error) {
|
|
rssPageSize := f.OptionService.GetOrByDefault(ctx, property.RssPageSize).(int)
|
|
postQuery := param.PostQuery{
|
|
Page: param.Page{PageNum: 0, PageSize: rssPageSize},
|
|
Sort: ¶m.Sort{Fields: []string{"createTime,desc"}},
|
|
Statuses: []*consts.PostStatus{consts.PostStatusPublished.Ptr()},
|
|
}
|
|
posts, _, err := f.PostService.Page(ctx, postQuery)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
postDetailVOs, err := f.buildPost(ctx, posts)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
lastModified := f.getLastModifiedTime(posts)
|
|
ctx.Header("Last-Modified", lastModified.Format(http.TimeFormat))
|
|
ctx.Header("Content-Type", "application/xml; charset=utf-8")
|
|
model["lastModified"] = lastModified
|
|
model["posts"] = postDetailVOs
|
|
return "common/web/atom", nil
|
|
}
|
|
|
|
func (f *FeedHandler) CategoryAtom(ctx *gin.Context, model template.Model) (string, error) {
|
|
slug, err := util.ParamString(ctx, "slug")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
slug = strings.TrimSuffix(slug, ".xml")
|
|
category, err := f.CategoryService.GetBySlug(ctx, slug)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
categoryDTO, err := f.CategoryService.ConvertToCategoryDTO(ctx, category)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
posts, err := f.PostCategoryService.ListByCategoryID(ctx, category.ID, consts.PostStatusPublished)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
postDetailVOs, err := f.buildPost(ctx, posts)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
lastModified := f.getLastModifiedTime(posts)
|
|
|
|
model["category"] = categoryDTO
|
|
model["posts"] = postDetailVOs
|
|
model["lastModified"] = lastModified
|
|
ctx.Header("Content-Type", "application/xml; charset=utf-8")
|
|
return "common/web/atom", nil
|
|
}
|
|
|
|
func (f *FeedHandler) Robots(ctx *gin.Context, model template.Model) (string, error) {
|
|
ctx.Header("Content-Type", "text/plain;charset=utf-8")
|
|
return "common/web/robots", nil
|
|
}
|
|
|
|
func (f *FeedHandler) SitemapXML(ctx *gin.Context, model template.Model) (string, error) {
|
|
posts, _, err := f.PostService.Page(ctx, param.PostQuery{
|
|
Page: param.Page{PageNum: 0, PageSize: int(^uint(0) >> 1)},
|
|
Sort: ¶m.Sort{Fields: []string{"createTime,desc"}},
|
|
Statuses: []*consts.PostStatus{consts.PostStatusPublished.Ptr()},
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
postDetailVOs, err := f.buildPost(ctx, posts)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
model["posts"] = postDetailVOs
|
|
|
|
ctx.Header("Content-Type", "application/xml; charset=utf-8")
|
|
return "common/web/sitemap_xml", nil
|
|
}
|
|
|
|
func (f *FeedHandler) SitemapHTML(ctx *gin.Context, model template.Model) (string, error) {
|
|
posts, _, err := f.PostService.Page(ctx, param.PostQuery{
|
|
Page: param.Page{PageNum: 0, PageSize: int(^uint(0) >> 1)},
|
|
Sort: ¶m.Sort{Fields: []string{"createTime,desc"}},
|
|
Statuses: []*consts.PostStatus{consts.PostStatusPublished.Ptr()},
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
postDetailVOs, err := f.buildPost(ctx, posts)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
model["posts"] = postDetailVOs
|
|
return "common/web/sitemap_html", nil
|
|
}
|
|
|
|
func (f *FeedHandler) getLastModifiedTime(posts []*entity.Post) time.Time {
|
|
lastModifiedTime := time.Time{}
|
|
for _, post := range posts {
|
|
if post.EditTime != nil {
|
|
if post.EditTime.After(lastModifiedTime) {
|
|
lastModifiedTime = *post.EditTime
|
|
}
|
|
} else {
|
|
if post.CreateTime.After(lastModifiedTime) {
|
|
lastModifiedTime = post.CreateTime
|
|
}
|
|
}
|
|
}
|
|
if lastModifiedTime == (time.Time{}) {
|
|
lastModifiedTime = time.Now()
|
|
}
|
|
return lastModifiedTime
|
|
}
|
|
|
|
var xmlInValidChar = regexp.MustCompile("[\x00-\x1F\x7F]")
|
|
|
|
func (f *FeedHandler) buildPost(ctx context.Context, posts []*entity.Post) ([]*vo.PostDetailVO, error) {
|
|
postDetailVOs, err := f.PostAssembler.ConvertToDetailVOs(ctx, posts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, postDetailVO := range postDetailVOs {
|
|
postDetailVO.Content = xmlInValidChar.ReplaceAllString(postDetailVO.Content, "")
|
|
postDetailVO.Summary = xmlInValidChar.ReplaceAllString(postDetailVO.Summary, "")
|
|
}
|
|
return postDetailVOs, nil
|
|
}
|