feed
This commit is contained in:
parent
7bdc47559a
commit
be5accaa10
|
@ -26,6 +26,7 @@ var postListIdsCache *cache.MapCache[string, PostIds]
|
||||||
var searchPostIdsCache *cache.MapCache[string, PostIds]
|
var searchPostIdsCache *cache.MapCache[string, PostIds]
|
||||||
var maxPostIdCache *cache.SliceCache[uint64]
|
var maxPostIdCache *cache.SliceCache[uint64]
|
||||||
var TotalRaw int
|
var TotalRaw int
|
||||||
|
var usersCache *cache.MapCache[uint64, models.WpUsers]
|
||||||
|
|
||||||
func InitActionsCommonCache() {
|
func InitActionsCommonCache() {
|
||||||
archivesCaches = &Arch{
|
archivesCaches = &Arch{
|
||||||
|
@ -53,6 +54,9 @@ func InitActionsCommonCache() {
|
||||||
postCommentCaches = cache.NewMapCacheByFn[uint64, []models.WpComments](postComments, vars.Conf.CommentsCacheTime)
|
postCommentCaches = cache.NewMapCacheByFn[uint64, []models.WpComments](postComments, vars.Conf.CommentsCacheTime)
|
||||||
|
|
||||||
maxPostIdCache = cache.NewSliceCache[uint64](getMaxPostId, vars.Conf.MaxPostIdCacheTime)
|
maxPostIdCache = cache.NewSliceCache[uint64](getMaxPostId, vars.Conf.MaxPostIdCacheTime)
|
||||||
|
|
||||||
|
usersCache = cache.NewMapCacheByBatchFn[uint64, models.WpUsers](getUsers, time.Hour)
|
||||||
|
usersCache.SetCacheFunc(getUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ClearCache() {
|
func ClearCache() {
|
||||||
|
@ -147,8 +151,11 @@ func postComments(args ...any) ([]models.WpComments, error) {
|
||||||
}, nil, 0)
|
}, nil, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RecentComments(ctx context.Context) (r []models.WpComments) {
|
func RecentComments(ctx context.Context, n int) (r []models.WpComments) {
|
||||||
r, err := recentCommentsCaches.GetCache(ctx, time.Second)
|
r, err := recentCommentsCaches.GetCache(ctx, time.Second)
|
||||||
|
if len(r) > n {
|
||||||
|
r = r[0:n]
|
||||||
|
}
|
||||||
logs.ErrPrintln(err, "get recent comment")
|
logs.ErrPrintln(err, "get recent comment")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -158,7 +165,7 @@ func recentComments(...any) (r []models.WpComments, err error) {
|
||||||
{"post_status", "publish"},
|
{"post_status", "publish"},
|
||||||
}, "comment_ID,comment_author,comment_post_ID,post_title", "", models.SqlBuilder{{"comment_date_gmt", "desc"}}, models.SqlBuilder{
|
}, "comment_ID,comment_author,comment_post_ID,post_title", "", models.SqlBuilder{{"comment_date_gmt", "desc"}}, models.SqlBuilder{
|
||||||
{"a", "left join", "wp_posts b", "a.comment_post_ID=b.ID"},
|
{"a", "left join", "wp_posts b", "a.comment_post_ID=b.ID"},
|
||||||
}, 5)
|
}, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetContextPost(ctx context.Context, id uint64, date time.Time) (prev, next models.WpPosts, err error) {
|
func GetContextPost(ctx context.Context, id uint64, date time.Time) (prev, next models.WpPosts, err error) {
|
||||||
|
@ -177,7 +184,7 @@ func getPostContext(arg ...any) (r PostContext, err error) {
|
||||||
{"post_date", ">", t.Format("2006-01-02 15:04:05")},
|
{"post_date", ">", t.Format("2006-01-02 15:04:05")},
|
||||||
{"post_status", "in", ""},
|
{"post_status", "in", ""},
|
||||||
{"post_type", "post"},
|
{"post_type", "post"},
|
||||||
}, "ID,post_title,post_password", nil, []any{"publish", "private"})
|
}, "ID,post_title,post_password", nil, []any{"publish"})
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
|
@ -188,7 +195,7 @@ func getPostContext(arg ...any) (r PostContext, err error) {
|
||||||
{"post_date", "<", t.Format("2006-01-02 15:04:05")},
|
{"post_date", "<", t.Format("2006-01-02 15:04:05")},
|
||||||
{"post_status", "in", ""},
|
{"post_status", "in", ""},
|
||||||
{"post_type", "post"},
|
{"post_type", "post"},
|
||||||
}, "ID,post_title", models.SqlBuilder{{"post_date", "desc"}}, []any{"publish", "private"})
|
}, "ID,post_title", models.SqlBuilder{{"post_date", "desc"}}, []any{"publish"})
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
|
@ -239,15 +246,18 @@ func categories(...any) (terms []models.WpTermsMy, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func RecentPosts(ctx context.Context) (r []models.WpPosts) {
|
func RecentPosts(ctx context.Context, n int) (r []models.WpPosts) {
|
||||||
r, err := recentPostsCaches.GetCache(ctx, time.Second)
|
r, err := recentPostsCaches.GetCache(ctx, time.Second)
|
||||||
|
if n < len(r) {
|
||||||
|
r = r[:n]
|
||||||
|
}
|
||||||
logs.ErrPrintln(err, "get recent post")
|
logs.ErrPrintln(err, "get recent post")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func recentPosts(...any) (r []models.WpPosts, err error) {
|
func recentPosts(...any) (r []models.WpPosts, err error) {
|
||||||
r, err = models.Find[models.WpPosts](models.SqlBuilder{{
|
r, err = models.Find[models.WpPosts](models.SqlBuilder{{
|
||||||
"post_type", "post",
|
"post_type", "post",
|
||||||
}, {"post_status", "publish"}}, "ID,post_title,post_password", "", models.SqlBuilder{{"post_date", "desc"}}, nil, 5)
|
}, {"post_status", "publish"}}, "ID,post_title,post_password", "", models.SqlBuilder{{"post_date", "desc"}}, nil, 10)
|
||||||
for i, post := range r {
|
for i, post := range r {
|
||||||
if post.PostPassword != "" {
|
if post.PostPassword != "" {
|
||||||
PasswordProjectTitle(&r[i])
|
PasswordProjectTitle(&r[i])
|
||||||
|
|
28
actions/common/users.go
Normal file
28
actions/common/users.go
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github/fthvgb1/wp-go/logs"
|
||||||
|
"github/fthvgb1/wp-go/models"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getUsers(...any) (m map[uint64]models.WpUsers, err error) {
|
||||||
|
m = make(map[uint64]models.WpUsers)
|
||||||
|
r, err := models.Find[models.WpUsers](nil, "*", "", nil, nil, 0)
|
||||||
|
for _, user := range r {
|
||||||
|
m[user.Id] = user
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUser(a ...any) (r models.WpUsers, err error) {
|
||||||
|
id := a[0].(uint64)
|
||||||
|
return models.FindOneById[models.WpUsers](id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUser(ctx *gin.Context, uid uint64) models.WpUsers {
|
||||||
|
r, err := usersCache.GetCache(ctx, uid, time.Second, uid)
|
||||||
|
logs.ErrPrintln(err, "get user", uid)
|
||||||
|
return r
|
||||||
|
}
|
|
@ -27,10 +27,10 @@ func Detail(c *gin.Context) {
|
||||||
hh := detailHandler{
|
hh := detailHandler{
|
||||||
c,
|
c,
|
||||||
}
|
}
|
||||||
recent := common.RecentPosts(c)
|
recent := common.RecentPosts(c, 5)
|
||||||
archive := common.Archives()
|
archive := common.Archives()
|
||||||
categoryItems := common.Categories(c)
|
categoryItems := common.Categories(c)
|
||||||
recentComments := common.RecentComments(c)
|
recentComments := common.RecentComments(c, 5)
|
||||||
var h = gin.H{
|
var h = gin.H{
|
||||||
"title": models.Options["blogname"],
|
"title": models.Options["blogname"],
|
||||||
"options": models.Options,
|
"options": models.Options,
|
||||||
|
|
90
actions/feed.go
Normal file
90
actions/feed.go
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
package actions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github/fthvgb1/wp-go/actions/common"
|
||||||
|
"github/fthvgb1/wp-go/helper"
|
||||||
|
"github/fthvgb1/wp-go/logs"
|
||||||
|
"github/fthvgb1/wp-go/models"
|
||||||
|
"github/fthvgb1/wp-go/plugins"
|
||||||
|
"github/fthvgb1/wp-go/templates"
|
||||||
|
"html"
|
||||||
|
"html/template"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Feed() func(ctx *gin.Context) {
|
||||||
|
fs, err := template.ParseFS(templates.TemplateFs, "feed/feed.gohtml")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
c.Header("Content-Type", "application/rss+xml; charset=UTF-8")
|
||||||
|
c.Header("Cache-Control", "no-cache, must-revalidate, max-age=0")
|
||||||
|
c.Header("Expires", "Wed, 11 Jan 1984 05:00:00 GMT")
|
||||||
|
//c.Header("Last-Modified", "false")
|
||||||
|
c.Header("ETag", helper.StringMd5("gmt"))
|
||||||
|
r := common.RecentPosts(c, 10)
|
||||||
|
ids := helper.SliceMap(r, func(t models.WpPosts) uint64 {
|
||||||
|
return t.Id
|
||||||
|
})
|
||||||
|
posts, err := common.GetPostsByIds(c, ids)
|
||||||
|
if err != nil {
|
||||||
|
c.Status(http.StatusInternalServerError)
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
type p struct {
|
||||||
|
models.WpPosts
|
||||||
|
Cates string
|
||||||
|
CommentLink string
|
||||||
|
Username string
|
||||||
|
Category string
|
||||||
|
Link string
|
||||||
|
Description string
|
||||||
|
Date string
|
||||||
|
}
|
||||||
|
rr := helper.SliceMap(posts, func(t models.WpPosts) p {
|
||||||
|
common.PasswordProjectTitle(&t)
|
||||||
|
if t.PostPassword != "" {
|
||||||
|
common.PasswdProjectContent(&t)
|
||||||
|
}
|
||||||
|
l := ""
|
||||||
|
if t.CommentStatus == "open" {
|
||||||
|
l = fmt.Sprintf("%s/p/%d#comments", models.Options["siteurl"], t.Id)
|
||||||
|
}
|
||||||
|
user := common.GetUser(c, t.PostAuthor)
|
||||||
|
content := plugins.DigestRaw(t.PostContent, utf8.RuneCountInString(t.PostContent), t.Id)
|
||||||
|
t.PostContent = content
|
||||||
|
return p{
|
||||||
|
WpPosts: t,
|
||||||
|
Cates: strings.Join(t.Categories, "、"),
|
||||||
|
CommentLink: l,
|
||||||
|
Username: user.DisplayName,
|
||||||
|
Link: fmt.Sprintf("%s/p/%d", models.Options["siteurl"], t.Id),
|
||||||
|
Description: plugins.DigestRaw(content, 55, t.Id),
|
||||||
|
Date: t.PostDateGmt.Format(time.RFC1123Z),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
h := gin.H{
|
||||||
|
"posts": rr,
|
||||||
|
"options": models.Options,
|
||||||
|
"now": time.Now().Format(time.RFC1123Z),
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
err = fs.Execute(&buf, h)
|
||||||
|
if err != nil {
|
||||||
|
logs.ErrPrintln(err, "parse template")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.String(http.StatusOK, html.UnescapeString(buf.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -133,8 +133,6 @@ func (h *indexHandle) parseParams() {
|
||||||
h.setTitleLR(helper.StrJoin(`"`, s, `"`, "的搜索结果"), models.Options["blogname"])
|
h.setTitleLR(helper.StrJoin(`"`, s, `"`, "的搜索结果"), models.Options["blogname"])
|
||||||
h.search = s
|
h.search = s
|
||||||
h.scene = plugins.Search
|
h.scene = plugins.Search
|
||||||
} else {
|
|
||||||
h.status = append(h.status, "private")
|
|
||||||
}
|
}
|
||||||
p := h.c.Query("paged")
|
p := h.c.Query("paged")
|
||||||
if p == "" {
|
if p == "" {
|
||||||
|
@ -162,9 +160,9 @@ func Index(c *gin.Context) {
|
||||||
h := newIndexHandle(c)
|
h := newIndexHandle(c)
|
||||||
h.parseParams()
|
h.parseParams()
|
||||||
archive := common.Archives()
|
archive := common.Archives()
|
||||||
recent := common.RecentPosts(c)
|
recent := common.RecentPosts(c, 5)
|
||||||
categoryItems := common.Categories(c)
|
categoryItems := common.Categories(c)
|
||||||
recentComments := common.RecentComments(c)
|
recentComments := common.RecentComments(c, 5)
|
||||||
ginH := gin.H{
|
ginH := gin.H{
|
||||||
"options": models.Options,
|
"options": models.Options,
|
||||||
"recentPosts": recent,
|
"recentPosts": recent,
|
||||||
|
|
60
helper/html.go
Normal file
60
helper/html.go
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var entitlesMap = map[int][]string{
|
||||||
|
EntCompat: {"&", """, "<", ">"},
|
||||||
|
EntQuotes: {"&", """, "'", "<", ">"},
|
||||||
|
EntNoQuotes: {"&", "<", ">"},
|
||||||
|
EntSpace: {" "},
|
||||||
|
}
|
||||||
|
var unEntitlesMap = map[int][]string{
|
||||||
|
EntCompat: {"&", "\"", "<", ">"},
|
||||||
|
EntQuotes: {"&", "\"", "'", "<", ">"},
|
||||||
|
EntNoQuotes: {"&", "<", ">"},
|
||||||
|
EntSpace: {" "},
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
EntCompat = 1
|
||||||
|
EntQuotes = 2
|
||||||
|
EntNoQuotes = 4
|
||||||
|
EntSpace = 8
|
||||||
|
)
|
||||||
|
|
||||||
|
func htmlSpecialChars(text string, flags int) string {
|
||||||
|
r, ok := unEntitlesMap[flags]
|
||||||
|
e := entitlesMap[flags]
|
||||||
|
if !ok {
|
||||||
|
r = unEntitlesMap[EntCompat]
|
||||||
|
e = entitlesMap[EntCompat]
|
||||||
|
}
|
||||||
|
if flags&EntSpace == EntSpace {
|
||||||
|
r = append(r, unEntitlesMap[EntSpace]...)
|
||||||
|
e = append(e, entitlesMap[EntSpace]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, entitle := range r {
|
||||||
|
text = strings.Replace(text, entitle, e[i], -1)
|
||||||
|
}
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
func htmlSpecialCharsDecode(text string, flags int) string {
|
||||||
|
r, ok := entitlesMap[flags]
|
||||||
|
u := unEntitlesMap[flags]
|
||||||
|
if !ok {
|
||||||
|
r = entitlesMap[EntCompat]
|
||||||
|
u = unEntitlesMap[EntCompat]
|
||||||
|
}
|
||||||
|
if flags&EntSpace == EntSpace {
|
||||||
|
r = append(r, entitlesMap[EntSpace]...)
|
||||||
|
u = append(u, unEntitlesMap[EntSpace]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, entitle := range r {
|
||||||
|
text = strings.Replace(text, entitle, u[i], -1)
|
||||||
|
}
|
||||||
|
return text
|
||||||
|
}
|
92
helper/html_test.go
Normal file
92
helper/html_test.go
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func Test_htmlSpecialChars(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
text string
|
||||||
|
flags int
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "t1",
|
||||||
|
args: args{text: "<a href='test'>Test</a>", flags: EntQuotes},
|
||||||
|
want: "<a href='test'>Test</a>",
|
||||||
|
}, {
|
||||||
|
name: "t2",
|
||||||
|
args: args{text: "<a href='test'>Test</a>", flags: EntCompat},
|
||||||
|
want: "<a href='test'>Test</a>",
|
||||||
|
}, {
|
||||||
|
name: "t3",
|
||||||
|
args: args{text: "<a href='test'>T est</a>", flags: EntCompat | EntSpace},
|
||||||
|
want: "<a href='test'>T est</a>",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := htmlSpecialChars(tt.args.text, tt.args.flags); got != tt.want {
|
||||||
|
t.Errorf("htmlSpecialChars() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_htmlSpecialCharsDecode(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
text string
|
||||||
|
flags int
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "t1",
|
||||||
|
args: args{
|
||||||
|
text: "<a href='test'>Test</a>",
|
||||||
|
flags: EntCompat,
|
||||||
|
},
|
||||||
|
want: "<a href='test'>Test</a>",
|
||||||
|
}, {
|
||||||
|
name: "t2",
|
||||||
|
args: args{
|
||||||
|
text: "<a href='test'>Test</a>",
|
||||||
|
flags: EntQuotes,
|
||||||
|
},
|
||||||
|
want: "<a href='test'>Test</a>",
|
||||||
|
}, {
|
||||||
|
name: "t3",
|
||||||
|
args: args{
|
||||||
|
text: "<p>this -> "</p>\n",
|
||||||
|
flags: EntNoQuotes,
|
||||||
|
},
|
||||||
|
want: "<p>this -> "</p>\n",
|
||||||
|
}, {
|
||||||
|
name: "t4",
|
||||||
|
args: args{
|
||||||
|
text: "<p>this -> "</p>\n",
|
||||||
|
flags: EntCompat,
|
||||||
|
},
|
||||||
|
want: "<p>this -> \"</p>\n",
|
||||||
|
}, {
|
||||||
|
name: "t5",
|
||||||
|
args: args{
|
||||||
|
text: "<p>this -> "</p>\n",
|
||||||
|
flags: EntCompat | EntSpace,
|
||||||
|
},
|
||||||
|
want: "<p>this -> \"</p>\n",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := htmlSpecialCharsDecode(tt.args.text, tt.args.flags); got != tt.want {
|
||||||
|
t.Errorf("htmlSpecialCharsDecode() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -213,7 +213,7 @@ func SimplePagination[T Model](where ParseWhere, fields, group string, page, pag
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindOneById[T Model](id int) (T, error) {
|
func FindOneById[T Model, I ~int | ~uint64 | ~int64 | ~int32](id I) (T, error) {
|
||||||
var r T
|
var r T
|
||||||
sql := fmt.Sprintf("select * from `%s` where `%s`=?", r.Table(), r.PrimaryKey())
|
sql := fmt.Sprintf("select * from `%s` where `%s`=?", r.Table(), r.PrimaryKey())
|
||||||
err := db.Db.Get(&r, sql, id)
|
err := db.Db.Get(&r, sql, id)
|
||||||
|
|
24
models/wp_users.go
Normal file
24
models/wp_users.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type WpUsers struct {
|
||||||
|
Id uint64 `gorm:"column:ID" db:"ID" json:"ID"`
|
||||||
|
UserLogin string `gorm:"column:user_login" db:"user_login" json:"user_login"`
|
||||||
|
UserPass string `gorm:"column:user_pass" db:"user_pass" json:"user_pass"`
|
||||||
|
UserNicename string `gorm:"column:user_nicename" db:"user_nicename" json:"user_nicename"`
|
||||||
|
UserEmail string `gorm:"column:user_email" db:"user_email" json:"user_email"`
|
||||||
|
UserUrl string `gorm:"column:user_url" db:"user_url" json:"user_url"`
|
||||||
|
UserRegistered time.Time `gorm:"column:user_registered" db:"user_registered" json:"user_registered"`
|
||||||
|
UserActivationKey string `gorm:"column:user_activation_key" db:"user_activation_key" json:"user_activation_key"`
|
||||||
|
UserStatus int `gorm:"column:user_status" db:"user_status" json:"user_status"`
|
||||||
|
DisplayName string `gorm:"column:display_name" db:"display_name" json:"display_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u WpUsers) Table() string {
|
||||||
|
return "wp_users"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u WpUsers) PrimaryKey() string {
|
||||||
|
return "ID"
|
||||||
|
}
|
|
@ -52,6 +52,7 @@ func SetupRouter() *gin.Engine {
|
||||||
r.GET("/p/date/:year/:month/page/:page", actions.Index)
|
r.GET("/p/date/:year/:month/page/:page", actions.Index)
|
||||||
r.POST("/login", actions.Login)
|
r.POST("/login", actions.Login)
|
||||||
r.GET("/p/:id", actions.Detail)
|
r.GET("/p/:id", actions.Detail)
|
||||||
|
r.GET("/feed", actions.Feed())
|
||||||
if helper.IsContainInArr(gin.Mode(), []string{gin.DebugMode, gin.TestMode}) {
|
if helper.IsContainInArr(gin.Mode(), []string{gin.DebugMode, gin.TestMode}) {
|
||||||
pprof.Register(r, "dev/pprof")
|
pprof.Register(r, "dev/pprof")
|
||||||
}
|
}
|
||||||
|
|
44
templates/feed/feed.gohtml
Normal file
44
templates/feed/feed.gohtml
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<rss version="2.0"
|
||||||
|
xmlns:content="http://purl.org/rss/1.0/modules/content/"
|
||||||
|
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:atom="http://www.w3.org/2005/Atom"
|
||||||
|
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
|
||||||
|
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
|
||||||
|
>
|
||||||
|
|
||||||
|
<channel>
|
||||||
|
<title>{{ .options.blogname }}</title>
|
||||||
|
<atom:link href="{{.options.home}}/feed" rel="self" type="application/rss+xml"/>
|
||||||
|
<link>{{.options.siteurl}}/</link>
|
||||||
|
<description>{{.options.blogdescription}}</description>
|
||||||
|
<lastBuildDate>{{.now}}</lastBuildDate>
|
||||||
|
<language>zh-CN</language>
|
||||||
|
<sy:updatePeriod>
|
||||||
|
hourly
|
||||||
|
</sy:updatePeriod>
|
||||||
|
<sy:updateFrequency>
|
||||||
|
1
|
||||||
|
</sy:updateFrequency>
|
||||||
|
<generator>https://wordpress.org/?v=6.0.2</generator>
|
||||||
|
{{range $k,$v := .posts}}
|
||||||
|
<item>
|
||||||
|
<title>{{$v.PostTitle}}</title>
|
||||||
|
<link>{{$v.Link}}</link>
|
||||||
|
<comments>{{ $v.CommentLink}}</comments>
|
||||||
|
<dc:creator><![CDATA[{{$v.Username}}]]></dc:creator>
|
||||||
|
<pubDate>{{$v.Date}}</pubDate>
|
||||||
|
<category><![CDATA[{{$v.Cates}}]]></category>
|
||||||
|
<guid isPermaLink="false">{{$v.Guid}}</guid>
|
||||||
|
<description><![CDATA[{{$v.Description}}]]></description>
|
||||||
|
<content:encoded><![CDATA[{{$v.PostContent}}]]></content:encoded>
|
||||||
|
{{if gt $v.CommentCount 0 }}
|
||||||
|
<wfw:commentRss>{{$v.CommentLink}}</wfw:commentRss>
|
||||||
|
<slash:comments>{{$v.CommentCount}}</slash:comments>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
</item>
|
||||||
|
{{end}}
|
||||||
|
</channel>
|
||||||
|
</rss>
|
|
@ -58,7 +58,6 @@
|
||||||
<aside id="meta-2" class="widget widget_meta"><h2 class="widget-title">其他操作</h2>
|
<aside id="meta-2" class="widget widget_meta"><h2 class="widget-title">其他操作</h2>
|
||||||
<nav aria-label="其他操作">
|
<nav aria-label="其他操作">
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="/wp-login.php">登录</a></li>
|
|
||||||
<li><a href="/feed">条目feed</a></li>
|
<li><a href="/feed">条目feed</a></li>
|
||||||
<li><a href="/comments/feed">评论feed</a></li>
|
<li><a href="/comments/feed">评论feed</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed posts layout
|
//go:embed posts layout feed
|
||||||
var TemplateFs embed.FS
|
var TemplateFs embed.FS
|
||||||
|
|
||||||
type FsTemplate struct {
|
type FsTemplate struct {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user