diff --git a/helper/slice/slice.go b/helper/slice/slice.go index 0a74454..5ed208f 100644 --- a/helper/slice/slice.go +++ b/helper/slice/slice.go @@ -66,6 +66,13 @@ func Reduce[R, T any](arr []T, fn func(T, R) R, r R) R { return r } +func ReverseReduce[R, T any](a []T, fn func(T, R) R, r R) R { + for i := len(a) - 1; i >= 0; i-- { + r = fn(a[i], r) + } + return r +} + func Reverse[T any](arr []T) []T { var r = make([]T, 0, len(arr)) for i := len(arr); i > 0; i-- { diff --git a/helper/slice/slice_test.go b/helper/slice/slice_test.go index e4b9968..e54e2c5 100644 --- a/helper/slice/slice_test.go +++ b/helper/slice/slice_test.go @@ -840,3 +840,36 @@ func TestShift(t *testing.T) { }) } } + +func TestReverseReduce(t *testing.T) { + type args[T int, R string] struct { + a []T + fn func(T, R) R + r R + } + type testCase[T int, R string] struct { + name string + args args[T, R] + want R + } + tests := []testCase[int, string]{ + { + name: "t1", + args: args[int, string]{ + a: number.Range(1, 10, 1), + fn: func(i int, r string) string { + return fmt.Sprintf("%s%d", r, i) + }, + r: "", + }, + want: "10987654321", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := ReverseReduce(tt.args.a, tt.args.fn, tt.args.r); !reflect.DeepEqual(got, tt.want) { + t.Errorf("ReverseReduce() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/helper/slice/sort.go b/helper/slice/sort.go index 359b4dc..2685c98 100644 --- a/helper/slice/sort.go +++ b/helper/slice/sort.go @@ -29,10 +29,8 @@ func SortSelf[T any](arr []T, fn func(i, j T) bool) { } func Sort[T any](arr []T, fn func(i, j T) bool) (r []T) { - r = make([]T, 0, len(arr)) - for _, t := range arr { - r = append(r, t) - } + r = make([]T, len(arr)) + copy(r, arr) slice := anyArr[T]{ data: r, fn: fn, diff --git a/internal/actions/detail.go b/internal/actions/detail.go index f8ff6bf..37dd564 100644 --- a/internal/actions/detail.go +++ b/internal/actions/detail.go @@ -8,6 +8,7 @@ import ( "github.com/fthvgb1/wp-go/internal/pkg/models" "github.com/fthvgb1/wp-go/internal/plugins" "github.com/fthvgb1/wp-go/internal/theme" + "github.com/fthvgb1/wp-go/internal/theme/common" "github.com/fthvgb1/wp-go/internal/wpconfig" "github.com/gin-contrib/sessions" "github.com/gin-gonic/gin" @@ -31,6 +32,8 @@ func Detail(c *gin.Context) { } isApproveComment := false status := plugins.Ok + pw := sessions.Default(c).Get("post_password") + defer func() { code := http.StatusOK if err != nil { @@ -44,7 +47,14 @@ func Detail(c *gin.Context) { } t := theme.GetTemplateName() - theme.Hook(t, code, c, ginH, plugins.Detail, status) + theme.Hook(t, common.Handle{ + C: c, + GinH: ginH, + Password: "", + Scene: plugins.Detail, + Code: code, + Stats: status, + }) }() ID := str.ToInteger[uint64](c.Param("id"), 0) @@ -57,7 +67,6 @@ func Detail(c *gin.Context) { if post.Id == 0 || err != nil || post.PostStatus != "publish" { return } - pw := sessions.Default(c).Get("post_password") showComment := false if post.CommentCount > 0 || post.CommentStatus == "open" { showComment = true @@ -77,7 +86,6 @@ func Detail(c *gin.Context) { isApproveComment = true return } - plugins.ApplyPlugin(plugins.NewPostPlugin(c, plugins.Detail), &post) comments, err := cache.PostComments(c, post.Id) logs.ErrPrintln(err, "get post comment", post.Id) ginH["comments"] = comments diff --git a/internal/actions/feed.go b/internal/actions/feed.go index 1095bdb..640a88d 100644 --- a/internal/actions/feed.go +++ b/internal/actions/feed.go @@ -27,16 +27,17 @@ func isCacheExpired(c *gin.Context, lastTime time.Time) bool { func Feed(c *gin.Context) { if !isCacheExpired(c, cache.FeedCache().GetLastSetTime()) { c.Status(http.StatusNotModified) - } else { - r, err := cache.FeedCache().GetCache(c, time.Second, c) - if err != nil { - c.Status(http.StatusInternalServerError) - c.Abort() - c.Error(err) - return - } - setFeed(r[0], c, cache.FeedCache().GetLastSetTime()) + return } + + r, err := cache.FeedCache().GetCache(c, time.Second, c) + if err != nil { + c.Status(http.StatusInternalServerError) + c.Abort() + c.Error(err) + return + } + setFeed(r[0], c, cache.FeedCache().GetLastSetTime()) } func setFeed(s string, c *gin.Context, t time.Time) { @@ -52,29 +53,29 @@ func PostFeed(c *gin.Context) { id := c.Param("id") if !isCacheExpired(c, cache.PostFeedCache().GetLastSetTime(c, id)) { c.Status(http.StatusNotModified) - } else { - s, err := cache.PostFeedCache().GetCache(c, id, time.Second, c, id) - if err != nil { - c.Status(http.StatusInternalServerError) - c.Abort() - c.Error(err) - return - } - setFeed(s, c, cache.PostFeedCache().GetLastSetTime(c, id)) + return } + s, err := cache.PostFeedCache().GetCache(c, id, time.Second, c, id) + if err != nil { + c.Status(http.StatusInternalServerError) + c.Abort() + c.Error(err) + return + } + setFeed(s, c, cache.PostFeedCache().GetLastSetTime(c, id)) } func CommentsFeed(c *gin.Context) { if !isCacheExpired(c, cache.CommentsFeedCache().GetLastSetTime()) { c.Status(http.StatusNotModified) - } else { - r, err := cache.CommentsFeedCache().GetCache(c, time.Second, c) - if err != nil { - c.Status(http.StatusInternalServerError) - c.Abort() - c.Error(err) - return - } - setFeed(r[0], c, cache.CommentsFeedCache().GetLastSetTime()) + return } + r, err := cache.CommentsFeedCache().GetCache(c, time.Second, c) + if err != nil { + c.Status(http.StatusInternalServerError) + c.Abort() + c.Error(err) + return + } + setFeed(r[0], c, cache.CommentsFeedCache().GetLastSetTime()) } diff --git a/internal/actions/index.go b/internal/actions/index.go index bc77bc6..1afc260 100644 --- a/internal/actions/index.go +++ b/internal/actions/index.go @@ -14,6 +14,7 @@ import ( "github.com/fthvgb1/wp-go/internal/pkg/models" "github.com/fthvgb1/wp-go/internal/plugins" "github.com/fthvgb1/wp-go/internal/theme" + "github.com/fthvgb1/wp-go/internal/theme/common" "github.com/fthvgb1/wp-go/internal/wpconfig" "github.com/fthvgb1/wp-go/model" "github.com/fthvgb1/wp-go/plugin/pagination" @@ -49,7 +50,7 @@ type indexHandle struct { header string paginationStep int scene int - status int + stats int } func newIndexHandle(ctx *gin.Context) *indexHandle { @@ -71,7 +72,7 @@ func newIndexHandle(ctx *gin.Context) *indexHandle { postType: []any{"post"}, postStatus: []any{"publish"}, scene: plugins.Home, - status: plugins.Ok, + stats: plugins.Ok, } } @@ -233,20 +234,32 @@ func Index(c *gin.Context) { "recentComments": recentComments, "posts": posts, } + pw := h.session.Get("post_password") + pws, ok := pw.(string) + if !ok { + pws = "" + } defer func() { code := http.StatusOK if err != nil { code = http.StatusNotFound - if h.status == plugins.InternalErr { + if h.stats == plugins.InternalErr { code = http.StatusInternalServerError c.Error(err) return } c.Error(err) - h.status = plugins.Error + h.stats = plugins.Error } t := theme.GetTemplateName() - theme.Hook(t, code, c, ginH, h.scene, h.status) + theme.Hook(t, common.Handle{ + C: c, + GinH: ginH, + Password: pws, + Scene: h.scene, + Code: code, + Stats: h.stats, + }) }() err = h.parseParams() if err != nil { @@ -264,29 +277,15 @@ func Index(c *gin.Context) { posts, totalRaw, err = cache.PostLists(c, h.getSearchKey(), c, h.where, h.page, h.pageSize, model.SqlBuilder{{h.orderBy, h.order}}, h.join, h.postType, h.postStatus) } if err != nil { - h.status = plugins.Error + h.stats = plugins.Error logs.ErrPrintln(err, "获取数据错误") return } if len(posts) < 1 && h.category != "" { h.titleL = "未找到页面" - h.status = plugins.Empty404 + h.stats = plugins.Empty404 } - - pw := h.session.Get("post_password") - plug := plugins.NewPostPlugin(c, h.scene) - for i, post := range posts { - if post.PostPassword != "" { - plugins.PasswordProjectTitle(&posts[i]) - if pw != post.PostPassword { - plugins.PasswdProjectContent(&posts[i]) - } - } else { - plugins.ApplyPlugin(plug, &posts[i]) - } - } - q := c.Request.URL.Query().Encode() if q != "" { q = fmt.Sprintf("?%s", q) diff --git a/internal/pkg/cache/feed.go b/internal/pkg/cache/feed.go index e4a5518..7f1428a 100644 --- a/internal/pkg/cache/feed.go +++ b/internal/pkg/cache/feed.go @@ -25,7 +25,7 @@ func InitFeed() { AtomLink: fmt.Sprintf("%s/feed", wpconfig.Options.Value("home")), Link: wpconfig.Options.Value("siteurl"), Description: wpconfig.Options.Value("blogdescription"), - Language: "zh-CN", + Language: wpconfig.GetLang(), UpdatePeriod: "hourly", UpdateFrequency: 1, Generator: wpconfig.Options.Value("home"), diff --git a/internal/plugins/digest.go b/internal/plugins/digest.go index d2d97fd..93d46e4 100644 --- a/internal/plugins/digest.go +++ b/internal/plugins/digest.go @@ -7,7 +7,6 @@ import ( "github.com/fthvgb1/wp-go/internal/pkg/config" "github.com/fthvgb1/wp-go/internal/pkg/models" "github.com/fthvgb1/wp-go/plugin/digest" - "github.com/gin-gonic/gin" "strings" "time" ) @@ -30,7 +29,7 @@ func FlushCache() { func digestRaw(arg ...any) (string, error) { str := arg[0].(string) id := arg[1].(uint64) - limit := config.GetConfig().DigestWordCount + limit := arg[2].(int) if limit < 0 { return str, nil } else if limit == 0 { @@ -39,20 +38,11 @@ func digestRaw(arg ...any) (string, error) { return digest.Raw(str, limit, fmt.Sprintf("/p/%d", id)), nil } -func Digest(p *Plugin[models.Posts], c *gin.Context, post *models.Posts, scene int) { - if scene == Detail { - return - } - if post.PostExcerpt != "" { - post.PostContent = strings.Replace(post.PostExcerpt, "\n", "
", -1) - } else { - post.PostContent = DigestCache(c, post.Id, post.PostContent) - - } - p.Next() +func Digest(ctx context.Context, post *models.Posts, limit int) { + content, _ := digestCache.GetCache(ctx, post.Id, time.Second, post.PostContent, post.Id, limit) + post.PostContent = content } -func DigestCache(ctx *gin.Context, id uint64, str string) string { - content, _ := digestCache.GetCache(ctx, id, time.Second, str, id) - return content +func PostExcerpt(post *models.Posts) { + post.PostContent = strings.Replace(post.PostExcerpt, "\n", "
", -1) } diff --git a/internal/plugins/plugins.go b/internal/plugins/plugins.go index 13568c7..81387e8 100644 --- a/internal/plugins/plugins.go +++ b/internal/plugins/plugins.go @@ -35,18 +35,3 @@ type Plugin[T any] struct { scene int c *gin.Context } - -func NewPlugin[T any](calls []Func[T], index int, post *T, scene int, c *gin.Context) *Plugin[T] { - return &Plugin[T]{calls: calls, index: index, post: post, scene: scene, c: c} -} - -func (p *Plugin[T]) Push(call ...Func[T]) { - p.calls = append(p.calls, call...) -} - -func (p *Plugin[T]) Next() { - p.index++ - for ; p.index < len(p.calls); p.index++ { - p.calls[p.index](p, p.c, p.post, p.scene) - } -} diff --git a/internal/plugins/posts.go b/internal/plugins/posts.go index 711728d..c241f32 100644 --- a/internal/plugins/posts.go +++ b/internal/plugins/posts.go @@ -3,21 +3,8 @@ package plugins import ( "fmt" "github.com/fthvgb1/wp-go/internal/pkg/models" - "github.com/gin-gonic/gin" ) -func NewPostPlugin(ctx *gin.Context, scene int) *Plugin[models.Posts] { - p := NewPlugin[models.Posts](nil, -1, nil, scene, ctx) - p.Push(Digest) - return p -} - -func ApplyPlugin(p *Plugin[models.Posts], post *models.Posts) { - p.post = post - p.Next() - p.index = -1 -} - func PasswordProjectTitle(post *models.Posts) { post.PostTitle = fmt.Sprintf("密码保护:%s", post.PostTitle) } diff --git a/internal/theme/common/common.go b/internal/theme/common/common.go new file mode 100644 index 0000000..ba85789 --- /dev/null +++ b/internal/theme/common/common.go @@ -0,0 +1,55 @@ +package common + +import ( + "github.com/fthvgb1/wp-go/helper/slice" + "github.com/fthvgb1/wp-go/internal/pkg/config" + "github.com/fthvgb1/wp-go/internal/pkg/models" + "github.com/fthvgb1/wp-go/internal/plugins" + "github.com/gin-gonic/gin" +) + +type Handle struct { + C *gin.Context + GinH gin.H + Password string + Scene int + Code int + Stats int +} + +type Fn[T any] func(T) T +type Plugin[T any] func(next Fn[T], h Handle, t T) T + +func PluginFn[T any](a []Plugin[T], h Handle, fn Fn[T]) Fn[T] { + return slice.ReverseReduce(a, func(next Plugin[T], forward Fn[T]) Fn[T] { + return func(t T) T { + return next(forward, h, t) + } + }, fn) +} + +func Default[T any](t T) T { + return t +} + +func PasswordProject(next Fn[models.Posts], h Handle, post models.Posts) (r models.Posts) { + r = post + if post.PostPassword != "" { + plugins.PasswordProjectTitle(&r) + if h.Password != post.PostPassword { + plugins.PasswdProjectContent(&r) + return + } + } + r = next(r) + return +} + +func Digest(next Fn[models.Posts], h Handle, post models.Posts) models.Posts { + if post.PostExcerpt != "" { + plugins.PostExcerpt(&post) + } else { + plugins.Digest(h.C, &post, config.GetConfig().DigestWordCount) + } + return next(post) +} diff --git a/internal/theme/hook.go b/internal/theme/hook.go index 3c7fa88..bb010ae 100644 --- a/internal/theme/hook.go +++ b/internal/theme/hook.go @@ -1,30 +1,25 @@ package theme import ( - "errors" - "github.com/fthvgb1/wp-go/internal/pkg/logs" - "github.com/fthvgb1/wp-go/internal/pkg/models" - "github.com/fthvgb1/wp-go/internal/plugins" - "github.com/fthvgb1/wp-go/plugin/pagination" - "github.com/gin-gonic/gin" + "github.com/fthvgb1/wp-go/internal/theme/common" ) -var themeMap = map[string]func(int, *gin.Context, gin.H, int, int){} +var themeMap = map[string]func(handle common.Handle){} -func addThemeHookFunc(name string, fn func(int, *gin.Context, gin.H, int, int)) { +func addThemeHookFunc(name string, fn func(handle common.Handle)) { if _, ok := themeMap[name]; ok { panic("exists same name theme") } themeMap[name] = fn } -func Hook(themeName string, code int, c *gin.Context, h gin.H, scene, status int) { +func Hook(themeName string, handle common.Handle) { fn, ok := themeMap[themeName] if ok && fn != nil { - fn(code, c, h, scene, status) + fn(handle) return } - if _, ok := plugins.IndexSceneMap[scene]; ok { + /*if _, ok := plugins.IndexSceneMap[scene]; ok { p, ok := h["pagination"] if ok { pp, ok := p.(pagination.ParsePagination) @@ -39,5 +34,5 @@ func Hook(themeName string, code int, c *gin.Context, h gin.H, scene, status int c.HTML(code, "twentyfifteen/posts/detail.gohtml", h) return } - logs.ErrPrintln(errors.New("what happening"), " how reached here", themeName, code, h, scene, status) + logs.ErrPrintln(errors.New("what happening"), " how reached here", themeName, code, h, scene, status)*/ } diff --git a/internal/theme/twentyseventeen/twentyseventeen.go b/internal/theme/twentyseventeen/twentyseventeen.go index 7f3df32..61b11d6 100644 --- a/internal/theme/twentyseventeen/twentyseventeen.go +++ b/internal/theme/twentyseventeen/twentyseventeen.go @@ -8,6 +8,7 @@ import ( "github.com/fthvgb1/wp-go/internal/pkg/logs" "github.com/fthvgb1/wp-go/internal/pkg/models" "github.com/fthvgb1/wp-go/internal/plugins" + "github.com/fthvgb1/wp-go/internal/theme/common" "github.com/fthvgb1/wp-go/plugin/pagination" "github.com/gin-gonic/gin" "strings" @@ -26,53 +27,52 @@ var paginate = func() plugins.PageEle { }() type handle struct { - c *gin.Context - ginH gin.H - scene int - status int - stats int - templ string + common.Handle + templ string } -func Hook(status int, c *gin.Context, ginH gin.H, scene, stats int) { +func Hook(h2 common.Handle) { h := handle{ - c: c, - ginH: ginH, - scene: scene, - status: status, - stats: stats, + Handle: h2, templ: "twentyseventeen/posts/index.gohtml", } - ginH["HeaderImage"] = h.getHeaderImage(c) - if stats == plugins.Empty404 { - c.HTML(status, h.templ, ginH) + h.GinH["HeaderImage"] = h.getHeaderImage(h.C) + if h.Stats == plugins.Empty404 { + h.C.HTML(h.Code, h.templ, h.GinH) return } - if scene == plugins.Detail { + if h.Scene == plugins.Detail { h.detail() return } h.index() +} +var plugin = []common.Plugin[models.Posts]{ + common.PasswordProject, common.Digest, } func (h handle) index() { - posts := h.ginH["posts"].([]models.Posts) - p, ok := h.ginH["pagination"] - if ok { - pp, ok := p.(pagination.ParsePagination) + if h.Stats != plugins.Empty404 { + posts := h.GinH["posts"].([]models.Posts) + posts = slice.Map(posts, common.PluginFn(plugin, h.Handle, common.Default[models.Posts])) + p, ok := h.GinH["pagination"] if ok { - h.ginH["pagination"] = pagination.Paginate(paginate, pp) + pp, ok := p.(pagination.ParsePagination) + if ok { + h.GinH["pagination"] = pagination.Paginate(paginate, pp) + } } + h.GinH["posts"] = h.postThumbnail(posts, h.Scene) } - h.ginH["bodyClass"] = h.bodyClass() - h.ginH["posts"] = h.postThumbnail(posts, h.scene) - h.c.HTML(h.status, h.templ, h.ginH) + + h.GinH["bodyClass"] = h.bodyClass() + h.C.HTML(h.Code, h.templ, h.GinH) } func (h handle) detail() { - post := h.ginH["post"].(models.Posts) - h.ginH["bodyClass"] = h.bodyClass() + post := h.GinH["post"].(models.Posts) + h.GinH["bodyClass"] = h.bodyClass() //host, _ := wpconfig.Options.Load("siteurl") host := "" img := plugins.Thumbnail(post.Thumbnail.OriginAttachmentData, "thumbnail", host, "thumbnail", "post-thumbnail") @@ -81,12 +81,12 @@ func (h handle) detail() { img.Sizes = "100vw" img.Srcset = fmt.Sprintf("%s %dw, %s", img.Path, img.Width, img.Srcset) post.Thumbnail = img - h.ginH["post"] = post - comments := h.ginH["comments"].([]models.Comments) - dep := h.ginH["maxDep"].(int) - h.ginH["comments"] = plugins.FormatComments(h.c, comment{}, comments, dep) + h.GinH["post"] = post + comments := h.GinH["comments"].([]models.Comments) + dep := h.GinH["maxDep"].(int) + h.GinH["comments"] = plugins.FormatComments(h.C, comment{}, comments, dep) h.templ = "twentyseventeen/posts/detail.gohtml" - h.c.HTML(h.status, h.templ, h.ginH) + h.C.HTML(h.Code, h.templ, h.GinH) } type comment struct { @@ -137,18 +137,18 @@ func (h handle) getHeaderImage(c *gin.Context) (r models.PostThumbnail) { func (h handle) bodyClass() string { s := "" - switch h.scene { + switch h.Scene { case plugins.Search: s = "search-no-results" - if len(h.ginH["posts"].([]models.Posts)) > 0 { + if len(h.GinH["posts"].([]models.Posts)) > 0 { s = "search-results" } case plugins.Category, plugins.Tag: - cat := h.c.Param("category") + cat := h.C.Param("category") if cat == "" { - cat = h.c.Param("tag") + cat = h.C.Param("tag") } - _, cate := slice.SearchFirst(cache.CategoriesTags(h.c, h.scene), func(my models.TermsMy) bool { + _, cate := slice.SearchFirst(cache.CategoriesTags(h.C, h.Scene), func(my models.TermsMy) bool { return my.Name == cat }) if cate.Slug[0] != '%' { @@ -156,9 +156,9 @@ func (h handle) bodyClass() string { } s = fmt.Sprintf("category-%d %v", cate.Terms.TermId, s) case plugins.Detail: - s = fmt.Sprintf("postid-%d", h.ginH["post"].(models.Posts).Id) + s = fmt.Sprintf("postid-%d", h.GinH["post"].(models.Posts).Id) } - return str.Join(class[h.scene], s) + return str.Join(class[h.Scene], s) } var class = map[int]string{