fix bug,improve pagination cache and revise comment render
This commit is contained in:
parent
57d345e445
commit
088fc306de
|
@ -134,9 +134,14 @@ func PostComment(c *gin.Context) {
|
||||||
err = er
|
err = er
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cache.NewCommentCache().Set(c, up.RawQuery, string(s))
|
uuu := ""
|
||||||
uu, _ := url.Parse(res.Header.Get("Location"))
|
uu, _ := url.Parse(res.Header.Get("Location"))
|
||||||
uuu := str.Join(uu.Path, "?", uu.RawQuery)
|
if up.RawQuery != "" {
|
||||||
|
cache.NewCommentCache().Set(c, up.RawQuery, string(s))
|
||||||
|
uuu = str.Join(uu.Path, "?", uu.RawQuery)
|
||||||
|
} else {
|
||||||
|
uuu = str.Join(uu.Path)
|
||||||
|
}
|
||||||
c.Redirect(http.StatusFound, uuu)
|
c.Redirect(http.StatusFound, uuu)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
30
app/pkg/cache/cache.go
vendored
30
app/pkg/cache/cache.go
vendored
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/models"
|
"github.com/fthvgb1/wp-go/app/pkg/models"
|
||||||
"github.com/fthvgb1/wp-go/cache"
|
"github.com/fthvgb1/wp-go/cache"
|
||||||
"github.com/fthvgb1/wp-go/cache/cachemanager"
|
"github.com/fthvgb1/wp-go/cache/cachemanager"
|
||||||
|
"github.com/fthvgb1/wp-go/helper"
|
||||||
"github.com/fthvgb1/wp-go/helper/slice"
|
"github.com/fthvgb1/wp-go/helper/slice"
|
||||||
"github.com/fthvgb1/wp-go/safety"
|
"github.com/fthvgb1/wp-go/safety"
|
||||||
"time"
|
"time"
|
||||||
|
@ -52,15 +53,30 @@ func InitActionsCommonCache() {
|
||||||
return config.GetConfig().CacheTime.RecentCommentsCacheTime
|
return config.GetConfig().CacheTime.RecentCommentsCacheTime
|
||||||
})
|
})
|
||||||
|
|
||||||
cachemanager.NewMemoryMapCache(nil, dao.PostComments, c.CacheTime.PostCommentsCacheTime,
|
cachemanager.NewMemoryMapCache(nil, dao.CommentNum, 30*time.Second, "commentNumber", func() time.Duration {
|
||||||
"postCommentIds",
|
return config.GetConfig().CacheTime.CommentsIncreaseUpdateTime
|
||||||
func() time.Duration {
|
})
|
||||||
|
|
||||||
|
cachemanager.NewPaginationCache(
|
||||||
|
cachemanager.NewMemoryMapCache[string, helper.PaginationData[uint64]](nil, nil, 30*time.Second,
|
||||||
|
"PostCommentsIds", func() time.Duration {
|
||||||
return config.GetConfig().CacheTime.PostCommentsCacheTime
|
return config.GetConfig().CacheTime.PostCommentsCacheTime
|
||||||
},
|
},
|
||||||
cache.NewIncreaseUpdate("comment-increaseUpdate", dao.GetIncreaseComment, 30*time.Second,
|
cache.NewIncreaseUpdate("PostCommentsIds-increaseUpdate", CommentDataIncreaseUpdate, 30*time.Second,
|
||||||
func() time.Duration {
|
func() time.Duration {
|
||||||
return config.GetConfig().CacheTime.CommentsIncreaseUpdateTime
|
return config.GetConfig().CacheTime.CommentsIncreaseUpdateTime
|
||||||
}))
|
}),
|
||||||
|
),
|
||||||
|
|
||||||
|
1000, dao.PostCommentsIds, dao.PostCommentLocal, nil, nil, 300, "PostCommentsIds")
|
||||||
|
|
||||||
|
cachemanager.NewMemoryMapCache(dao.CommentDates, nil, time.Hour, "postCommentData", func() time.Duration {
|
||||||
|
return config.GetConfig().CacheTime.CommentsCacheTime
|
||||||
|
})
|
||||||
|
|
||||||
|
cachemanager.NewMemoryMapCache[uint64, []models.Comments](nil, CommentDataIncreaseUpdates, time.Hour, func() time.Duration {
|
||||||
|
return config.GetConfig().CacheTime.CommentsCacheTime
|
||||||
|
}, "increaseComment30s", cache.NewIncreaseUpdate("increaseComment30s", IncreaseUpdates, 30*time.Second, nil))
|
||||||
|
|
||||||
cachemanager.NewVarMemoryCache(dao.GetMaxPostId, c.CacheTime.MaxPostIdCacheTime, "maxPostId", func() time.Duration {
|
cachemanager.NewVarMemoryCache(dao.GetMaxPostId, c.CacheTime.MaxPostIdCacheTime, "maxPostId", func() time.Duration {
|
||||||
return config.GetConfig().CacheTime.MaxPostIdCacheTime
|
return config.GetConfig().CacheTime.MaxPostIdCacheTime
|
||||||
|
@ -74,10 +90,6 @@ func InitActionsCommonCache() {
|
||||||
return config.GetConfig().CacheTime.UserInfoCacheTime
|
return config.GetConfig().CacheTime.UserInfoCacheTime
|
||||||
})
|
})
|
||||||
|
|
||||||
cachemanager.NewMemoryMapCache(dao.GetCommentByIds, nil, c.CacheTime.CommentsCacheTime, "commentData", func() time.Duration {
|
|
||||||
return config.GetConfig().CacheTime.CommentsCacheTime
|
|
||||||
})
|
|
||||||
|
|
||||||
cachemanager.NewVarMemoryCache(dao.AllUsername, c.CacheTime.UserInfoCacheTime, "allUsername", func() time.Duration {
|
cachemanager.NewVarMemoryCache(dao.AllUsername, c.CacheTime.UserInfoCacheTime, "allUsername", func() time.Duration {
|
||||||
return config.GetConfig().CacheTime.UserInfoCacheTime
|
return config.GetConfig().CacheTime.UserInfoCacheTime
|
||||||
})
|
})
|
||||||
|
|
100
app/pkg/cache/comments.go
vendored
100
app/pkg/cache/comments.go
vendored
|
@ -2,11 +2,16 @@ package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/fthvgb1/wp-go/app/pkg/dao"
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/logs"
|
"github.com/fthvgb1/wp-go/app/pkg/logs"
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/models"
|
"github.com/fthvgb1/wp-go/app/pkg/models"
|
||||||
|
"github.com/fthvgb1/wp-go/app/wpconfig"
|
||||||
"github.com/fthvgb1/wp-go/cache"
|
"github.com/fthvgb1/wp-go/cache"
|
||||||
"github.com/fthvgb1/wp-go/cache/cachemanager"
|
"github.com/fthvgb1/wp-go/cache/cachemanager"
|
||||||
|
"github.com/fthvgb1/wp-go/helper"
|
||||||
"github.com/fthvgb1/wp-go/helper/number"
|
"github.com/fthvgb1/wp-go/helper/number"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/slice"
|
||||||
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -20,23 +25,104 @@ func RecentComments(ctx context.Context, n int) (r []models.Comments) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func PostComments(ctx context.Context, Id uint64) ([]models.Comments, error) {
|
func PostComments(ctx context.Context, Id uint64) ([]models.PostComments, error) {
|
||||||
ids, err := cachemanager.Get[[]uint64]("postCommentIds", ctx, Id, time.Second)
|
ids, err := cachemanager.Get[[]uint64]("PostCommentsIds", ctx, Id, time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return GetCommentByIds(ctx, ids)
|
return GetCommentDataByIds(ctx, ids)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCommentById(ctx context.Context, id uint64) (models.Comments, error) {
|
func GetCommentById(ctx context.Context, id uint64) (models.PostComments, error) {
|
||||||
return cachemanager.Get[models.Comments]("commentData", ctx, id, time.Second)
|
return cachemanager.Get[models.PostComments]("postCommentData", ctx, id, time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCommentByIds(ctx context.Context, ids []uint64) ([]models.Comments, error) {
|
func GetCommentDataByIds(ctx context.Context, ids []uint64) ([]models.PostComments, error) {
|
||||||
return cachemanager.GetMultiple[models.Comments]("commentData", ctx, ids, time.Second)
|
return cachemanager.GetMultiple[models.PostComments]("postCommentData", ctx, ids, time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCommentCache() *cache.MapCache[string, string] {
|
func NewCommentCache() *cache.MapCache[string, string] {
|
||||||
r, _ := cachemanager.GetMapCache[string, string]("NewComment")
|
r, _ := cachemanager.GetMapCache[string, string]("NewComment")
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CommentDataIncreaseUpdates(_ context.Context, _ uint64, _ ...any) ([]models.Comments, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
func IncreaseUpdates(ctx context.Context, currentData []models.Comments, postId uint64, t time.Time, _ ...any) ([]models.Comments, bool, bool, error) {
|
||||||
|
var maxId uint64
|
||||||
|
if len(currentData) > 0 {
|
||||||
|
maxId = currentData[len(currentData)-1].CommentId
|
||||||
|
} else {
|
||||||
|
maxId, err := dao.LatestCommentId(ctx, postId)
|
||||||
|
return []models.Comments{{CommentId: maxId}}, true, false, err
|
||||||
|
}
|
||||||
|
v, err := dao.IncreaseCommentData(ctx, postId, maxId, t)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, false, err
|
||||||
|
}
|
||||||
|
if len(v) < 1 {
|
||||||
|
return nil, false, true, nil
|
||||||
|
}
|
||||||
|
m, err := dao.CommentDates(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, false, err
|
||||||
|
}
|
||||||
|
CommentData, _ := cachemanager.GetMapCache[uint64, models.PostComments]("postCommentData")
|
||||||
|
data := slice.Map(v, func(t uint64) models.Comments {
|
||||||
|
comments := m[t].Comments
|
||||||
|
if comments.CommentParent > 0 {
|
||||||
|
vv, ok := CommentData.Get(ctx, comments.CommentParent)
|
||||||
|
if ok && !slice.IsContained(vv.Children, comments.CommentId) {
|
||||||
|
vv.Children = append(vv.Children, comments.CommentId)
|
||||||
|
CommentData.Set(ctx, comments.CommentParent, vv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CommentData.Set(ctx, comments.CommentId, models.PostComments{Comments: comments})
|
||||||
|
return comments
|
||||||
|
})
|
||||||
|
return data, true, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CommentDataIncreaseUpdate(ctx context.Context, currentData helper.PaginationData[uint64], postId string, _ time.Time, _ ...any) (data helper.PaginationData[uint64], save bool, refresh bool, err error) {
|
||||||
|
refresh = true
|
||||||
|
increaseUpdateData, _ := cachemanager.GetMapCache[uint64, []models.Comments]("increaseComment30s")
|
||||||
|
v, ok := increaseUpdateData.Get(ctx, str.ToInt[uint64](postId))
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(v) < 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(currentData.Data) > 0 {
|
||||||
|
if slice.IsContained(currentData.Data, v[0].CommentId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dat := slice.FilterAndMap(v, func(t models.Comments) (uint64, bool) {
|
||||||
|
if wpconfig.GetOption("thread_comments") != "1" || "1" == wpconfig.GetOption("thread_comments_depth") {
|
||||||
|
return t.CommentId, t.CommentId > 0
|
||||||
|
}
|
||||||
|
return t.CommentId, t.CommentId > 0 && t.CommentParent == 0
|
||||||
|
})
|
||||||
|
if len(dat) > 0 {
|
||||||
|
save = true
|
||||||
|
refresh = false
|
||||||
|
var a []uint64
|
||||||
|
a = append(currentData.Data, dat...)
|
||||||
|
slice.Sorts(a, wpconfig.GetOption("comment_order"))
|
||||||
|
data.Data = a
|
||||||
|
data.TotalRaw = len(data.Data)
|
||||||
|
}
|
||||||
|
return data, save, refresh, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateCommentCache(ctx context.Context, timeout time.Duration, postId uint64) (err error) {
|
||||||
|
c, _ := cachemanager.GetPaginationCache[uint64, uint64]("PostCommentsIds")
|
||||||
|
if c.IsSwitchDB(postId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = cachemanager.Get[[]models.Comments]("increaseComment30s", ctx, postId, timeout)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
13
app/pkg/cache/feed.go
vendored
13
app/pkg/cache/feed.go
vendored
|
@ -106,7 +106,12 @@ func postFeed(c context.Context, id string, _ ...any) (x string, err error) {
|
||||||
if post.Id == 0 || err != nil {
|
if post.Id == 0 || err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
comments, err := PostComments(c, post.Id)
|
limit := str.ToInteger(wpconfig.GetOption("comments_per_page"), 10)
|
||||||
|
ids, _, err := cachemanager.Pagination[uint64]("PostCommentsIds", c, time.Second, ID, 1, limit, "desc")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
comments, err := cachemanager.GetMultiple[models.PostComments]("postCommentData", c, ids, time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -135,7 +140,7 @@ func postFeed(c context.Context, id string, _ ...any) (x string, err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rs.Items = slice.Map(comments, func(t models.Comments) rss2.Item {
|
rs.Items = slice.Map(comments, func(t models.PostComments) rss2.Item {
|
||||||
return rss2.Item{
|
return rss2.Item{
|
||||||
Title: fmt.Sprintf("评价者:%s", t.CommentAuthor),
|
Title: fmt.Sprintf("评价者:%s", t.CommentAuthor),
|
||||||
Link: fmt.Sprintf("%s/p/%d#comment-%d", site, post.Id, t.CommentId),
|
Link: fmt.Sprintf("%s/p/%d#comment-%d", site, post.Id, t.CommentId),
|
||||||
|
@ -158,13 +163,13 @@ func commentsFeed(c context.Context, _ ...any) (r []string, err error) {
|
||||||
rs.LastBuildDate = time.Now().Format(timeFormat)
|
rs.LastBuildDate = time.Now().Format(timeFormat)
|
||||||
site := wpconfig.GetOption("siteurl")
|
site := wpconfig.GetOption("siteurl")
|
||||||
rs.AtomLink = fmt.Sprintf("%s/comments/feed", site)
|
rs.AtomLink = fmt.Sprintf("%s/comments/feed", site)
|
||||||
com, err := GetCommentByIds(c, slice.Map(commens, func(t models.Comments) uint64 {
|
com, err := GetCommentDataByIds(c, slice.Map(commens, func(t models.Comments) uint64 {
|
||||||
return t.CommentId
|
return t.CommentId
|
||||||
}))
|
}))
|
||||||
if nil != err {
|
if nil != err {
|
||||||
return []string{}, err
|
return []string{}, err
|
||||||
}
|
}
|
||||||
rs.Items = slice.Map(com, func(t models.Comments) rss2.Item {
|
rs.Items = slice.Map(com, func(t models.PostComments) rss2.Item {
|
||||||
post, _ := GetPostById(c, t.CommentPostId)
|
post, _ := GetPostById(c, t.CommentPostId)
|
||||||
desc := "评论受保护:要查看请输入密码。"
|
desc := "评论受保护:要查看请输入密码。"
|
||||||
content := t.CommentContent
|
content := t.CommentContent
|
||||||
|
|
|
@ -5,9 +5,11 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/models"
|
"github.com/fthvgb1/wp-go/app/pkg/models"
|
||||||
|
"github.com/fthvgb1/wp-go/app/wpconfig"
|
||||||
"github.com/fthvgb1/wp-go/helper"
|
"github.com/fthvgb1/wp-go/helper"
|
||||||
"github.com/fthvgb1/wp-go/helper/number"
|
"github.com/fthvgb1/wp-go/helper/number"
|
||||||
"github.com/fthvgb1/wp-go/helper/slice"
|
"github.com/fthvgb1/wp-go/helper/slice"
|
||||||
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
"github.com/fthvgb1/wp-go/model"
|
"github.com/fthvgb1/wp-go/model"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -81,12 +83,13 @@ func GetCommentByIds(ctx context.Context, ids []uint64, _ ...any) (map[uint64]mo
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetIncreaseComment(ctx context.Context, currentData []uint64, k uint64, t time.Time, _ ...any) (data []uint64, save bool, refresh bool, err error) {
|
func GetIncreaseComment(ctx context.Context, currentData []uint64, k uint64, _ time.Time, _ ...any) (data []uint64, save bool, refresh bool, err error) {
|
||||||
r, err := model.ChunkFind[models.Comments](ctx, 1000, model.Conditions(
|
r, err := model.ChunkFind[models.Comments](ctx, 1000, model.Conditions(
|
||||||
model.Where(model.SqlBuilder{
|
model.Where(model.SqlBuilder{
|
||||||
{"comment_approved", "1"},
|
{"comment_approved", "1"},
|
||||||
{"comment_post_ID", "=", number.IntToString(k), "int"},
|
{"comment_post_ID", "=", number.IntToString(k), "int"},
|
||||||
{"comment_date", ">=", t.Format(time.DateTime)},
|
//{"comment_date", ">=", t.Format(time.DateTime)},
|
||||||
|
{"comment_ID", ">", number.IntToString(currentData[len(currentData)-1])},
|
||||||
}),
|
}),
|
||||||
model.Fields("comment_ID"),
|
model.Fields("comment_ID"),
|
||||||
model.Order(model.SqlBuilder{
|
model.Order(model.SqlBuilder{
|
||||||
|
@ -112,3 +115,156 @@ func GetIncreaseComment(ctx context.Context, currentData []uint64, k uint64, t t
|
||||||
save = true
|
save = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CommentDates(ctx context.Context, CommentIds []uint64, _ ...any) (map[uint64]models.PostComments, error) {
|
||||||
|
if len(CommentIds) < 1 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
m := make(map[uint64]models.PostComments)
|
||||||
|
off := 0
|
||||||
|
threadComments := wpconfig.GetOption("thread_comments")
|
||||||
|
where := model.SqlBuilder{
|
||||||
|
{"comment_approved", "1"},
|
||||||
|
}
|
||||||
|
var in [][]any
|
||||||
|
if threadComments == "1" {
|
||||||
|
where = append(where, []string{"and", "comment_ID", "in", "", "", "or", "comment_parent", "in", "", ""})
|
||||||
|
} else {
|
||||||
|
where = append(where, []string{"comment_ID", "in", ""})
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
id := slice.Slice(CommentIds, off, 200)
|
||||||
|
if len(id) < 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if threadComments == "1" {
|
||||||
|
in = [][]any{slice.ToAnySlice(id), slice.ToAnySlice(id)}
|
||||||
|
} else {
|
||||||
|
in = [][]any{slice.ToAnySlice(id)}
|
||||||
|
}
|
||||||
|
r, err := model.Finds[models.Comments](ctx, model.Conditions(
|
||||||
|
model.Where(where),
|
||||||
|
model.Fields("*"),
|
||||||
|
model.In(in...),
|
||||||
|
))
|
||||||
|
if err != nil {
|
||||||
|
return m, err
|
||||||
|
}
|
||||||
|
rr := slice.GroupBy(r, func(t models.Comments) (uint64, models.Comments) {
|
||||||
|
return t.CommentParent, t
|
||||||
|
})
|
||||||
|
mm := map[uint64][]uint64{}
|
||||||
|
for u, comments := range rr {
|
||||||
|
slice.SimpleSort(comments, slice.ASC, func(t models.Comments) uint64 {
|
||||||
|
return t.CommentId
|
||||||
|
})
|
||||||
|
mm[u] = slice.Map(comments, func(t models.Comments) uint64 {
|
||||||
|
return t.CommentId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for _, comments := range r {
|
||||||
|
var children []uint64
|
||||||
|
if threadComments == "1" {
|
||||||
|
children = mm[comments.CommentId]
|
||||||
|
}
|
||||||
|
v := models.PostComments{
|
||||||
|
Comments: comments,
|
||||||
|
Children: children,
|
||||||
|
}
|
||||||
|
m[comments.CommentId] = v
|
||||||
|
}
|
||||||
|
off += 200
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CommentNum(ctx context.Context, postId uint64, _ ...any) (int, error) {
|
||||||
|
n, err := model.GetField[models.Posts](ctx, "comment_count", model.Conditions(
|
||||||
|
model.Where(model.SqlBuilder{{"ID", "=", number.IntToString(postId), "int"}})))
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return str.ToInteger(n, 0), err
|
||||||
|
}
|
||||||
|
func PostCommentLocal(_ context.Context, data []uint64, _ uint64, page, limit int, _ ...any) ([]uint64, int, error) {
|
||||||
|
/*order := wpconfig.GetOption("comment_order")
|
||||||
|
if order == "desc" {
|
||||||
|
r := slice.ReversePagination(data, page, limit)
|
||||||
|
if len(r) < 1 {
|
||||||
|
return nil, 0, nil
|
||||||
|
}
|
||||||
|
r = slice.SortsNew(r, slice.DESC)
|
||||||
|
return r, len(data), nil
|
||||||
|
}*/
|
||||||
|
return slice.Pagination(data, page, limit), len(data), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostCommentsIds(ctx context.Context, postId uint64, page, limit, totalRaw int, _ ...any) ([]uint64, int, error) {
|
||||||
|
order := wpconfig.GetOption("comment_order")
|
||||||
|
threadComments := wpconfig.GetOption("thread_comments")
|
||||||
|
where := model.SqlBuilder{
|
||||||
|
{"comment_approved", "1"},
|
||||||
|
{"comment_post_ID", "=", number.IntToString(postId), "int"},
|
||||||
|
}
|
||||||
|
if threadComments == "1" || "1" == wpconfig.GetOption("thread_comments_depth") {
|
||||||
|
where = append(where, []string{"comment_parent", "0"})
|
||||||
|
}
|
||||||
|
r, total, err := model.Pagination[models.Comments](ctx, model.Conditions(
|
||||||
|
model.Where(where),
|
||||||
|
model.TotalRaw(totalRaw),
|
||||||
|
model.Fields("comment_ID"),
|
||||||
|
model.Order(model.SqlBuilder{
|
||||||
|
{"comment_date_gmt", order},
|
||||||
|
{"comment_ID", "asc"},
|
||||||
|
}),
|
||||||
|
), page, limit)
|
||||||
|
if err != nil && errors.Is(err, sql.ErrNoRows) {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
return slice.Map(r, func(t models.Comments) uint64 {
|
||||||
|
return t.CommentId
|
||||||
|
}), total, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func IncreaseCommentData(ctx context.Context, postId, maxCommentId uint64, _ time.Time) ([]uint64, error) {
|
||||||
|
r, err := model.ChunkFind[models.Comments](ctx, 1000, model.Conditions(
|
||||||
|
model.Where(model.SqlBuilder{
|
||||||
|
{"comment_approved", "1"},
|
||||||
|
{"comment_post_ID", "=", number.IntToString(postId), "int"},
|
||||||
|
{"comment_ID", ">", number.IntToString(maxCommentId), "int"},
|
||||||
|
}),
|
||||||
|
model.Fields("comment_ID"),
|
||||||
|
model.Order(model.SqlBuilder{
|
||||||
|
{"comment_date_gmt", "asc"},
|
||||||
|
{"comment_ID", "asc"},
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
err = nil
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return slice.Map(r, func(t models.Comments) uint64 {
|
||||||
|
return t.CommentId
|
||||||
|
}), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func LatestCommentId(ctx context.Context, postId uint64) (uint64, error) {
|
||||||
|
v, err := model.GetField[models.Comments](ctx, "comment_ID", model.Conditions(
|
||||||
|
model.Where(model.SqlBuilder{
|
||||||
|
{"comment_approved", "1"},
|
||||||
|
{"comment_post_ID", "=", number.IntToString(postId), "int"},
|
||||||
|
}),
|
||||||
|
model.Order(model.SqlBuilder{{"comment_ID", "desc"}}),
|
||||||
|
model.Limit(1),
|
||||||
|
))
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return str.ToInteger[uint64](v, 0), err
|
||||||
|
}
|
||||||
|
|
|
@ -3,14 +3,17 @@ package db
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/config"
|
"github.com/fthvgb1/wp-go/app/pkg/config"
|
||||||
|
"github.com/fthvgb1/wp-go/cache/reload"
|
||||||
"github.com/fthvgb1/wp-go/model"
|
"github.com/fthvgb1/wp-go/model"
|
||||||
"github.com/fthvgb1/wp-go/safety"
|
"github.com/fthvgb1/wp-go/safety"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"log"
|
"log"
|
||||||
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
var safeDb = safety.NewVar[*sqlx.DB](nil)
|
var safeDb = safety.NewVar[*sqlx.DB](nil)
|
||||||
|
var showQuerySql func() bool
|
||||||
|
|
||||||
func InitDb() (*safety.Var[*sqlx.DB], error) {
|
func InitDb() (*safety.Var[*sqlx.DB], error) {
|
||||||
c := config.GetConfig()
|
c := config.GetConfig()
|
||||||
|
@ -36,6 +39,9 @@ func InitDb() (*safety.Var[*sqlx.DB], error) {
|
||||||
if preDb != nil {
|
if preDb != nil {
|
||||||
_ = preDb.Close()
|
_ = preDb.Close()
|
||||||
}
|
}
|
||||||
|
showQuerySql = reload.FnVal("showQuerySql", false, func() bool {
|
||||||
|
return config.GetConfig().ShowQuerySql
|
||||||
|
})
|
||||||
return safeDb, err
|
return safeDb, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,14 +50,20 @@ func QueryDb(db *safety.Var[*sqlx.DB]) *model.SqlxQuery {
|
||||||
nil,
|
nil,
|
||||||
nil))
|
nil))
|
||||||
model.SetSelect(query, func(ctx context.Context, a any, s string, args ...any) error {
|
model.SetSelect(query, func(ctx context.Context, a any, s string, args ...any) error {
|
||||||
if config.GetConfig().ShowQuerySql {
|
if showQuerySql() {
|
||||||
go log.Println(model.FormatSql(s, args...))
|
_, f, l, _ := runtime.Caller(5)
|
||||||
|
go func() {
|
||||||
|
log.Printf("%v:%v %v\n", f, l, model.FormatSql(s, args...))
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
return query.Selects(ctx, a, s, args...)
|
return query.Selects(ctx, a, s, args...)
|
||||||
})
|
})
|
||||||
model.SetGet(query, func(ctx context.Context, a any, s string, args ...any) error {
|
model.SetGet(query, func(ctx context.Context, a any, s string, args ...any) error {
|
||||||
if config.GetConfig().ShowQuerySql {
|
if showQuerySql() {
|
||||||
go log.Println(model.FormatSql(s, args...))
|
_, f, l, _ := runtime.Caller(5)
|
||||||
|
go func() {
|
||||||
|
log.Printf("%v:%v %v\n", f, l, model.FormatSql(s, args...))
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
return query.Gets(ctx, a, s, args...)
|
return query.Gets(ctx, a, s, args...)
|
||||||
})
|
})
|
||||||
|
|
|
@ -29,3 +29,8 @@ func (w Comments) PrimaryKey() string {
|
||||||
func (w Comments) Table() string {
|
func (w Comments) Table() string {
|
||||||
return "wp_comments"
|
return "wp_comments"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PostComments struct {
|
||||||
|
Comments
|
||||||
|
Children []uint64
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package plugins
|
package plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/models"
|
"github.com/fthvgb1/wp-go/app/pkg/models"
|
||||||
"github.com/fthvgb1/wp-go/app/wpconfig"
|
"github.com/fthvgb1/wp-go/app/wpconfig"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/number"
|
||||||
"github.com/fthvgb1/wp-go/helper/slice"
|
"github.com/fthvgb1/wp-go/helper/slice"
|
||||||
str "github.com/fthvgb1/wp-go/helper/strings"
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
@ -17,6 +19,7 @@ type CommentHandler struct {
|
||||||
depth int
|
depth int
|
||||||
isTls bool
|
isTls bool
|
||||||
i CommentHtml
|
i CommentHtml
|
||||||
|
isThreadComments bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Comments struct {
|
type Comments struct {
|
||||||
|
@ -25,7 +28,8 @@ type Comments struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommentHtml interface {
|
type CommentHtml interface {
|
||||||
FormatLi(c *gin.Context, m models.Comments, depth int, isTls bool, eo, parent string) string
|
FormatLi(c context.Context, m models.Comments, depth, maxDepth, page int, isTls, isThreadComments bool, eo, parent string) string
|
||||||
|
FloorOrder(wpOrder string, i, j models.PostComments) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func FormatComments(c *gin.Context, i CommentHtml, comments []models.Comments, maxDepth int) string {
|
func FormatComments(c *gin.Context, i CommentHtml, comments []models.Comments, maxDepth int) string {
|
||||||
|
@ -45,10 +49,10 @@ func FormatComments(c *gin.Context, i CommentHtml, comments []models.Comments, m
|
||||||
isTls: isTls,
|
isTls: isTls,
|
||||||
i: i,
|
i: i,
|
||||||
}
|
}
|
||||||
return h.formatComment(h.comments, true)
|
return h.formatComment(h.comments)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d CommentHandler) formatComment(comments []*Comments, isTop bool) (html string) {
|
func (d CommentHandler) formatComment(comments []*Comments) (html string) {
|
||||||
s := str.NewBuilder()
|
s := str.NewBuilder()
|
||||||
if d.depth >= d.maxDepth {
|
if d.depth >= d.maxDepth {
|
||||||
comments = d.findComments(comments)
|
comments = d.findComments(comments)
|
||||||
|
@ -71,13 +75,11 @@ func (d CommentHandler) formatComment(comments []*Comments, isTop bool) (html st
|
||||||
parent = "parent"
|
parent = "parent"
|
||||||
fl = true
|
fl = true
|
||||||
}
|
}
|
||||||
s.WriteString(d.i.FormatLi(d.Context, comment.Comments, d.depth, d.isTls, eo, parent))
|
s.WriteString(d.i.FormatLi(d.Context, comment.Comments, d.depth, d.maxDepth, 1, d.isTls, d.isThreadComments, eo, parent))
|
||||||
if fl {
|
if fl {
|
||||||
d.depth++
|
d.depth++
|
||||||
s.WriteString(`<ol class="children">`, d.formatComment(comment.Children, false), `</ol>`)
|
s.WriteString(`<ol class="children">`, d.formatComment(comment.Children), `</ol>`)
|
||||||
if isTop {
|
d.depth--
|
||||||
d.depth = 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
s.WriteString("</li><!-- #comment-## -->")
|
s.WriteString("</li><!-- #comment-## -->")
|
||||||
}
|
}
|
||||||
|
@ -140,8 +142,24 @@ func CommentRender() CommonCommentFormat {
|
||||||
type CommonCommentFormat struct {
|
type CommonCommentFormat struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c CommonCommentFormat) FormatLi(ctx *gin.Context, m models.Comments, depth int, isTls bool, eo, parent string) string {
|
func (c CommonCommentFormat) FormatLi(_ context.Context, m models.Comments, currentDepth, maxDepth, page int, isTls, isThreadComments bool, eo, parent string) string {
|
||||||
return FormatLi(CommonLi(), ctx, m, depth, isTls, eo, parent)
|
return FormatLi(CommonLi(), m, currentDepth, maxDepth, page, isTls, isThreadComments, eo, parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c CommonCommentFormat) FloorOrder(wpOrder string, i, j models.PostComments) bool {
|
||||||
|
return i.CommentId > j.CommentId
|
||||||
|
}
|
||||||
|
func respond(m models.Comments, isShow bool) string {
|
||||||
|
if !isShow {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
pId := number.IntToString(m.CommentPostId)
|
||||||
|
cId := number.IntToString(m.CommentId)
|
||||||
|
return str.Replace(respondTml, map[string]string{
|
||||||
|
"{{PostId}}": pId,
|
||||||
|
"{{CommentId}}": cId,
|
||||||
|
"{{CommentAuthor}}": m.CommentAuthor,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var li = `
|
var li = `
|
||||||
|
@ -153,14 +171,11 @@ var li = `
|
||||||
src="{{Gravatar}}"
|
src="{{Gravatar}}"
|
||||||
srcset="{{Gravatar}} 2x"
|
srcset="{{Gravatar}} 2x"
|
||||||
class="avatar avatar-56 photo" height="56" width="56" loading="lazy">
|
class="avatar avatar-56 photo" height="56" width="56" loading="lazy">
|
||||||
<b class="fn">
|
<b class="fn">{{CommentAuthor}}</b>
|
||||||
<a href="{{CommentAuthorUrl}}" rel="external nofollow ugc"
|
|
||||||
class="url">{{CommentAuthor}}</a>
|
|
||||||
</b>
|
|
||||||
<span class="says">说道:</span></div><!-- .comment-author -->
|
<span class="says">说道:</span></div><!-- .comment-author -->
|
||||||
|
|
||||||
<div class="comment-metadata">
|
<div class="comment-metadata">
|
||||||
<a href="/p/{{PostId}}#comment-{{CommentId}}">
|
<a href="/p/{{PostId}}/comment-page-{{page}}#comment-{{CommentId}}">
|
||||||
<time datetime="{{CommentDateGmt}}">{{CommentDate}}</time>
|
<time datetime="{{CommentDateGmt}}">{{CommentDate}}</time>
|
||||||
</a></div><!-- .comment-metadata -->
|
</a></div><!-- .comment-metadata -->
|
||||||
|
|
||||||
|
@ -170,30 +185,38 @@ var li = `
|
||||||
<p>{{CommentContent}}</p>
|
<p>{{CommentContent}}</p>
|
||||||
</div><!-- .comment-content -->
|
</div><!-- .comment-content -->
|
||||||
|
|
||||||
<div class="reply">
|
{{respond}}
|
||||||
|
</article><!-- .comment-body -->
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
var respondTml = `<div class="reply">
|
||||||
<a rel="nofollow" class="comment-reply-link"
|
<a rel="nofollow" class="comment-reply-link"
|
||||||
href="/p/{{PostId}}?replytocom={{CommentId}}#respond" data-commentid="{{CommentId}}" data-postid="{{PostId}}"
|
href="/p/{{PostId}}?replytocom={{CommentId}}#respond" data-commentid="{{CommentId}}" data-postid="{{PostId}}"
|
||||||
data-belowelement="div-comment-{{CommentId}}" data-respondelement="respond"
|
data-belowelement="div-comment-{{CommentId}}" data-respondelement="respond"
|
||||||
data-replyto="回复给{{CommentAuthor}}"
|
data-replyto="回复给{{CommentAuthor}}"
|
||||||
aria-label="回复给{{CommentAuthor}}">回复</a>
|
aria-label="回复给{{CommentAuthor}}">回复</a>
|
||||||
</div>
|
</div>`
|
||||||
</article><!-- .comment-body -->
|
|
||||||
|
|
||||||
`
|
func FormatLi(li string, comments models.Comments, currentDepth, maxDepth, page int, isTls, isThreadComments bool, eo, parent string) string {
|
||||||
|
isShow := false
|
||||||
func FormatLi(li string, c *gin.Context, comments models.Comments, depth int, isTls bool, eo, parent string) string {
|
if isThreadComments && currentDepth < maxDepth {
|
||||||
|
isShow = true
|
||||||
|
}
|
||||||
for k, v := range map[string]string{
|
for k, v := range map[string]string{
|
||||||
"{{CommentId}}": strconv.FormatUint(comments.CommentId, 10),
|
"{{CommentId}}": strconv.FormatUint(comments.CommentId, 10),
|
||||||
"{{Depth}}": strconv.Itoa(depth),
|
"{{Depth}}": strconv.Itoa(currentDepth),
|
||||||
"{{Gravatar}}": Gravatar(comments.CommentAuthorEmail, isTls),
|
"{{Gravatar}}": Gravatar(comments.CommentAuthorEmail, isTls),
|
||||||
"{{CommentAuthorUrl}}": comments.CommentAuthorUrl,
|
"{{CommentAuthorUrl}}": comments.CommentAuthorUrl,
|
||||||
"{{CommentAuthor}}": comments.CommentAuthor,
|
"{{CommentAuthor}}": comments.CommentAuthor,
|
||||||
"{{PostId}}": strconv.FormatUint(comments.CommentPostId, 10),
|
"{{PostId}}": strconv.FormatUint(comments.CommentPostId, 10),
|
||||||
|
"{{page}}": strconv.Itoa(page),
|
||||||
"{{CommentDateGmt}}": comments.CommentDateGmt.String(),
|
"{{CommentDateGmt}}": comments.CommentDateGmt.String(),
|
||||||
"{{CommentDate}}": comments.CommentDate.Format("2006-01-02 15:04"),
|
"{{CommentDate}}": comments.CommentDate.Format("2006-01-02 15:04"),
|
||||||
"{{CommentContent}}": comments.CommentContent,
|
"{{CommentContent}}": comments.CommentContent,
|
||||||
"{{eo}}": eo,
|
"{{eo}}": eo,
|
||||||
"{{parent}}": parent,
|
"{{parent}}": parent,
|
||||||
|
"{{respond}}": respond(comments, isShow),
|
||||||
} {
|
} {
|
||||||
li = strings.Replace(li, k, v, -1)
|
li = strings.Replace(li, k, v, -1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/fthvgb1/wp-go/app/wpconfig"
|
||||||
|
"github.com/fthvgb1/wp-go/helper"
|
||||||
str "github.com/fthvgb1/wp-go/helper/strings"
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -18,6 +20,13 @@ type PageEle struct {
|
||||||
func TwentyFifteenPagination() PageEle {
|
func TwentyFifteenPagination() PageEle {
|
||||||
return twentyFifteen
|
return twentyFifteen
|
||||||
}
|
}
|
||||||
|
func TwentyFifteenCommentPagination() CommentPageEle {
|
||||||
|
return twentyFifteenComment
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommentPageEle struct {
|
||||||
|
PageEle
|
||||||
|
}
|
||||||
|
|
||||||
var twentyFifteen = PageEle{
|
var twentyFifteen = PageEle{
|
||||||
PrevEle: `<a class="prev page-numbers" href="%s">上一页</a>`,
|
PrevEle: `<a class="prev page-numbers" href="%s">上一页</a>`,
|
||||||
|
@ -28,6 +37,12 @@ var twentyFifteen = PageEle{
|
||||||
CurrentEle: `<span aria-current="page" class="page-numbers current">
|
CurrentEle: `<span aria-current="page" class="page-numbers current">
|
||||||
<span class="meta-nav screen-reader-text">页 </span>%d</span>`,
|
<span class="meta-nav screen-reader-text">页 </span>%d</span>`,
|
||||||
}
|
}
|
||||||
|
var twentyFifteenComment = CommentPageEle{
|
||||||
|
PageEle{
|
||||||
|
PrevEle: `<div class="nav-previous"><a href="%s#comments">%s</a></div>`,
|
||||||
|
NextEle: `<div class="nav-next"><a href="%s#comments">%s</a></div>`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
func (p PageEle) Current(page, totalPage, totalRow int) string {
|
func (p PageEle) Current(page, totalPage, totalRow int) string {
|
||||||
return fmt.Sprintf(p.CurrentEle, page)
|
return fmt.Sprintf(p.CurrentEle, page)
|
||||||
|
@ -50,6 +65,7 @@ func (p PageEle) Middle(page int, url string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
var reg = regexp.MustCompile(`(/page)/(\d+)`)
|
var reg = regexp.MustCompile(`(/page)/(\d+)`)
|
||||||
|
var commentReg = regexp.MustCompile(`/comment-page-(\d+)`)
|
||||||
|
|
||||||
func (p PageEle) Url(path, query string, page int) string {
|
func (p PageEle) Url(path, query string, page int) string {
|
||||||
if !strings.Contains(path, "/page/") {
|
if !strings.Contains(path, "/page/") {
|
||||||
|
@ -67,3 +83,32 @@ func (p PageEle) Url(path, query string, page int) string {
|
||||||
}
|
}
|
||||||
return str.Join(path, query)
|
return str.Join(path, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p CommentPageEle) Url(path, query string, page int) string {
|
||||||
|
if !strings.Contains(path, "/comment-page-") {
|
||||||
|
path = fmt.Sprintf("%s%s", path, "/comment-page-1")
|
||||||
|
}
|
||||||
|
path = commentReg.ReplaceAllString(path, fmt.Sprintf("/comment-page-%d", page))
|
||||||
|
path = strings.Replace(path, "//", "/", -1)
|
||||||
|
if path == "" {
|
||||||
|
path = "/"
|
||||||
|
}
|
||||||
|
return str.Join(path, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p CommentPageEle) Middle(page int, url string) string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
func (p CommentPageEle) Dots() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
func (p CommentPageEle) Current(page, totalPage, totalRow int) string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
func (p CommentPageEle) Prev(url string) string {
|
||||||
|
return fmt.Sprintf(p.PrevEle, url, helper.Or(wpconfig.GetOption("comment_order") == "asc", "较早评论", "较新评论"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p CommentPageEle) Next(url string) string {
|
||||||
|
return fmt.Sprintf(p.NextEle, url, helper.Or(wpconfig.GetOption("comment_order") == "asc", "较新评论", "较早评论"))
|
||||||
|
}
|
||||||
|
|
|
@ -52,14 +52,30 @@
|
||||||
|
|
||||||
{{ if .showComment}}
|
{{ if .showComment}}
|
||||||
<div id="comments" class="comments-area">
|
<div id="comments" class="comments-area">
|
||||||
{{ if gt .post.CommentCount 0}}
|
{{ if ne .comments ""}}
|
||||||
<h2 class="comments-title">《{{.post.PostTitle}}》上有{{.post.CommentCount}}条评论 </h2>
|
<h2 class="comments-title">《{{.post.PostTitle}}》上有{{.totalCommentNum}}条评论 </h2>
|
||||||
|
{{if gt .totalCommentPage 1}}
|
||||||
|
<nav class="navigation comment-navigation">
|
||||||
|
<h2 class="screen-reader-text">评论导航</h2>
|
||||||
|
<div class="nav-links">
|
||||||
|
{{ .commentPageNav|unescaped}}
|
||||||
|
</div><!-- .nav-links -->
|
||||||
|
</nav>
|
||||||
|
{{end}}
|
||||||
<ol class="comment-list">
|
<ol class="comment-list">
|
||||||
{{.comments|unescaped}}
|
{{.comments|unescaped}}
|
||||||
</ol>
|
</ol>
|
||||||
|
{{if gt .totalCommentPage 1}}
|
||||||
|
<nav class="navigation comment-navigation">
|
||||||
|
<h2 class="screen-reader-text">评论导航</h2>
|
||||||
|
<div class="nav-links">
|
||||||
|
{{ .commentPageNav|unescaped}}
|
||||||
|
</div><!-- .nav-links -->
|
||||||
|
</nav>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if and (eq .post.CommentStatus "open") (eq ( "thread_comments" |getOption ) "1")}}
|
{{if eq .post.CommentStatus "open"}}
|
||||||
<div id="respond" class="comment-respond">
|
<div id="respond" class="comment-respond">
|
||||||
<h3 id="reply-title" class="comment-reply-title">发表回复
|
<h3 id="reply-title" class="comment-reply-title">发表回复
|
||||||
<small>
|
<small>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package twentyseventeen
|
package twentyseventeen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/constraints"
|
"github.com/fthvgb1/wp-go/app/pkg/constraints"
|
||||||
"github.com/fthvgb1/wp-go/app/pkg/constraints/widgets"
|
"github.com/fthvgb1/wp-go/app/pkg/constraints/widgets"
|
||||||
|
@ -14,7 +15,6 @@ import (
|
||||||
"github.com/fthvgb1/wp-go/cache/reload"
|
"github.com/fthvgb1/wp-go/cache/reload"
|
||||||
"github.com/fthvgb1/wp-go/helper"
|
"github.com/fthvgb1/wp-go/helper"
|
||||||
str "github.com/fthvgb1/wp-go/helper/strings"
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ type comment struct {
|
||||||
plugins.CommonCommentFormat
|
plugins.CommonCommentFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c comment) FormatLi(ctx *gin.Context, m models.Comments, depth int, isTls bool, eo, parent string) string {
|
func (c comment) FormatLi(_ context.Context, m models.Comments, depth, maxDepth, page int, isTls, isThreadComments bool, eo, parent string) string {
|
||||||
templ := plugins.CommonLi()
|
templ := plugins.CommonLi()
|
||||||
templ = strings.ReplaceAll(templ, `<a rel="nofollow" class="comment-reply-link"
|
templ = strings.ReplaceAll(templ, `<a rel="nofollow" class="comment-reply-link"
|
||||||
href="/p/{{PostId}}?replytocom={{CommentId}}#respond" data-commentid="{{CommentId}}" data-postid="{{PostId}}"
|
href="/p/{{PostId}}?replytocom={{CommentId}}#respond" data-commentid="{{CommentId}}" data-postid="{{PostId}}"
|
||||||
|
@ -114,7 +114,7 @@ func (c comment) FormatLi(ctx *gin.Context, m models.Comments, depth int, isTls
|
||||||
data-belowelement="div-comment-{{CommentId}}" data-respondelement="respond"
|
data-belowelement="div-comment-{{CommentId}}" data-respondelement="respond"
|
||||||
data-replyto="回复给{{CommentAuthor}}"
|
data-replyto="回复给{{CommentAuthor}}"
|
||||||
aria-label="回复给{{CommentAuthor}}"><svg class="icon icon-mail-reply" aria-hidden="true" role="img"> <use href="#icon-mail-reply" xlink:href="#icon-mail-reply"></use> </svg>回复</a>`)
|
aria-label="回复给{{CommentAuthor}}"><svg class="icon icon-mail-reply" aria-hidden="true" role="img"> <use href="#icon-mail-reply" xlink:href="#icon-mail-reply"></use> </svg>回复</a>`)
|
||||||
return plugins.FormatLi(templ, ctx, m, depth, isTls, eo, parent)
|
return plugins.FormatLi(templ, m, depth, maxDepth, page, isTls, isThreadComments, eo, parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func postThumbnail(h *wp.Handle, posts *models.Posts) {
|
func postThumbnail(h *wp.Handle, posts *models.Posts) {
|
||||||
|
|
103
app/theme/wp/comments.go
Normal file
103
app/theme/wp/comments.go
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package wp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/fthvgb1/wp-go/app/pkg/models"
|
||||||
|
"github.com/fthvgb1/wp-go/app/plugins"
|
||||||
|
"github.com/fthvgb1/wp-go/app/wpconfig"
|
||||||
|
"github.com/fthvgb1/wp-go/cache"
|
||||||
|
"github.com/fthvgb1/wp-go/cache/cachemanager"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/slice"
|
||||||
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RenderComment(ctx context.Context, page int, render plugins.CommentHtml, ids []uint64, timeout time.Duration, isTLS bool) (string, error) {
|
||||||
|
ca, _ := cachemanager.GetMapCache[uint64, models.PostComments]("postCommentData")
|
||||||
|
h := CommentHandle{
|
||||||
|
maxDepth: str.ToInteger(wpconfig.GetOption("thread_comments_depth"), 5),
|
||||||
|
depth: 1,
|
||||||
|
isTls: isTLS,
|
||||||
|
html: render,
|
||||||
|
order: wpconfig.GetOption("comment_order"),
|
||||||
|
ca: ca,
|
||||||
|
threadComments: wpconfig.GetOption("thread_comments") == "1",
|
||||||
|
page: page,
|
||||||
|
}
|
||||||
|
return h.formatComments(ctx, ids, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommentHandle struct {
|
||||||
|
maxDepth int
|
||||||
|
depth int
|
||||||
|
isTls bool
|
||||||
|
html plugins.CommentHtml
|
||||||
|
order string
|
||||||
|
page int
|
||||||
|
ca *cache.MapCache[uint64, models.PostComments]
|
||||||
|
threadComments bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c CommentHandle) findComments(ctx context.Context, timeout time.Duration, comments []models.PostComments) ([]models.PostComments, error) {
|
||||||
|
rr := slice.FilterAndMap(comments, func(t models.PostComments) ([]uint64, bool) {
|
||||||
|
return t.Children, len(t.Children) > 0
|
||||||
|
})
|
||||||
|
if len(rr) < 1 {
|
||||||
|
slice.Sort(comments, func(i, j models.PostComments) bool {
|
||||||
|
return c.html.FloorOrder(c.order, i, j)
|
||||||
|
})
|
||||||
|
return comments, nil
|
||||||
|
}
|
||||||
|
ids := slice.Decompress(rr)
|
||||||
|
r, err := c.ca.GetCacheBatch(ctx, ids, timeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rrr, err := c.findComments(ctx, timeout, r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
comments = slice.Map(comments, func(t models.PostComments) models.PostComments {
|
||||||
|
t.Children = nil
|
||||||
|
return t
|
||||||
|
})
|
||||||
|
comments = append(comments, rrr...)
|
||||||
|
return comments, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c CommentHandle) formatComments(ctx context.Context, ids []uint64, timeout time.Duration) (html string, err error) {
|
||||||
|
comments, err := c.ca.GetCacheBatch(ctx, ids, timeout)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if c.depth >= c.maxDepth {
|
||||||
|
comments, err = c.findComments(ctx, timeout, comments)
|
||||||
|
}
|
||||||
|
s := str.NewBuilder()
|
||||||
|
for i, comment := range comments {
|
||||||
|
eo := "even"
|
||||||
|
if (i+1)%2 == 0 {
|
||||||
|
eo = "odd"
|
||||||
|
}
|
||||||
|
parent := ""
|
||||||
|
fl := false
|
||||||
|
if c.threadComments && len(comment.Children) > 0 && c.depth < c.maxDepth+1 {
|
||||||
|
parent = "parent"
|
||||||
|
fl = true
|
||||||
|
}
|
||||||
|
s.WriteString(c.html.FormatLi(ctx, comment.Comments, c.depth, c.maxDepth, c.page, c.isTls, c.threadComments, eo, parent))
|
||||||
|
if fl {
|
||||||
|
c.depth++
|
||||||
|
ss, err := c.formatComments(ctx, comment.Children, timeout)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
s.WriteString(`<ol class="children">`, ss, `</ol>`)
|
||||||
|
c.depth--
|
||||||
|
}
|
||||||
|
s.WriteString("</li><!-- #comment-## -->")
|
||||||
|
}
|
||||||
|
|
||||||
|
html = s.String()
|
||||||
|
return
|
||||||
|
}
|
|
@ -10,15 +10,22 @@ import (
|
||||||
"github.com/fthvgb1/wp-go/app/plugins"
|
"github.com/fthvgb1/wp-go/app/plugins"
|
||||||
"github.com/fthvgb1/wp-go/app/plugins/wpposts"
|
"github.com/fthvgb1/wp-go/app/plugins/wpposts"
|
||||||
"github.com/fthvgb1/wp-go/app/wpconfig"
|
"github.com/fthvgb1/wp-go/app/wpconfig"
|
||||||
|
"github.com/fthvgb1/wp-go/cache/cachemanager"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/number"
|
||||||
str "github.com/fthvgb1/wp-go/helper/strings"
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
|
"github.com/fthvgb1/wp-go/plugin/pagination"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DetailHandle struct {
|
type DetailHandle struct {
|
||||||
*Handle
|
*Handle
|
||||||
CommentRender plugins.CommentHtml
|
CommentRender plugins.CommentHtml
|
||||||
Comments []models.Comments
|
Comments []uint64
|
||||||
|
Page int
|
||||||
|
Limit int
|
||||||
Post models.Posts
|
Post models.Posts
|
||||||
|
TotalRaw int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDetailHandle(handle *Handle) *DetailHandle {
|
func NewDetailHandle(handle *Handle) *DetailHandle {
|
||||||
|
@ -80,11 +87,29 @@ func (d *DetailHandle) PasswordProject() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (d *DetailHandle) Comment() {
|
func (d *DetailHandle) Comment() {
|
||||||
comments, err := cache.PostComments(d.C, d.Post.Id)
|
err := cache.UpdateCommentCache(d.C, time.Second, d.Post.Id)
|
||||||
logs.IfError(err, "get d.Post comment", d.Post.Id)
|
d.ginH["totalCommentNum"] = 0
|
||||||
d.ginH["comments"] = comments
|
d.ginH["totalCommentPage"] = 1
|
||||||
d.Comments = comments
|
d.ginH["commentPageNav"] = ""
|
||||||
|
d.ginH["commentOrder"] = wpconfig.GetOption("comment_order")
|
||||||
|
logs.IfError(err, "increase update comments err")
|
||||||
|
d.Page = str.ToInteger(d.C.Param("page"), 1)
|
||||||
|
d.ginH["currentPage"] = d.Page
|
||||||
|
d.Limit = str.ToInteger(wpconfig.GetOption("comments_per_page"), 5)
|
||||||
|
ids, totalCommentNum, err := cachemanager.Pagination[uint64]("PostCommentsIds", d.C, time.Second, d.Post.Id, d.Page, d.Limit, "desc")
|
||||||
|
if err != nil {
|
||||||
|
d.SetErr(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.TotalRaw = totalCommentNum
|
||||||
|
num, err := cachemanager.Get[int]("commentNumber", d.C, d.Post.Id, time.Second)
|
||||||
|
if err != nil {
|
||||||
|
d.SetErr(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.ginH["totalCommentNum"] = num
|
||||||
|
d.ginH["totalCommentPage"] = number.DivideCeil(totalCommentNum, d.Limit)
|
||||||
|
d.Comments = ids
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DetailHandle) RenderComment() {
|
func (d *DetailHandle) RenderComment() {
|
||||||
|
@ -97,10 +122,19 @@ func (d *DetailHandle) RenderComment() {
|
||||||
ableComment = false
|
ableComment = false
|
||||||
}
|
}
|
||||||
d.ginH["showComment"] = ableComment
|
d.ginH["showComment"] = ableComment
|
||||||
if len(d.Comments) > 0 && ableComment {
|
d.ginH["comments"] = ""
|
||||||
dep := str.ToInteger(wpconfig.GetOption("thread_comments_depth"), 5)
|
if len(d.Comments) < 0 || !ableComment {
|
||||||
d.ginH["comments"] = plugins.FormatComments(d.C, d.CommentRender, d.Comments, dep)
|
return
|
||||||
}
|
}
|
||||||
|
var err error
|
||||||
|
d.ginH["comments"], err = RenderComment(d.C, d.Page, d.CommentRender, d.Comments, 2*time.Second, d.IsHttps())
|
||||||
|
if err != nil {
|
||||||
|
d.SetErr(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
paginations := pagination.NewParsePagination(d.TotalRaw, d.Limit, d.Page, 1, d.C.Request.URL.RawQuery, d.C.Request.URL.Path)
|
||||||
|
d.ginH["commentPageNav"] = pagination.Paginate(plugins.TwentyFifteenCommentPagination(), paginations)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DetailHandle) ContextPost() {
|
func (d *DetailHandle) ContextPost() {
|
||||||
|
|
33
cache/cachemanager/manger.go
vendored
33
cache/cachemanager/manger.go
vendored
|
@ -185,7 +185,9 @@ func NewPaginationCache[K comparable, V any](m *cache.MapCache[string, helper.Pa
|
||||||
if fet == nil {
|
if fet == nil {
|
||||||
fet = reload.FnVal(str.Join("paginationCache-", name, "-fetchNum"), fetchNum, nil)
|
fet = reload.FnVal(str.Join("paginationCache-", name, "-fetchNum"), fetchNum, nil)
|
||||||
}
|
}
|
||||||
return cache.NewPagination(m, ma, dbFn, localFn, dbKeyFn, localKeyFn, fet, name)
|
p := cache.NewPagination(m, ma, dbFn, localFn, dbKeyFn, localKeyFn, fet, name)
|
||||||
|
mapCache.Store(name, p)
|
||||||
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMapCache[K comparable, V any](data cache.Cache[K, V], batchFn cache.MapBatchFn[K, V], fn cache.MapSingleFn[K, V], args ...any) *cache.MapCache[K, V] {
|
func NewMapCache[K comparable, V any](data cache.Cache[K, V], batchFn cache.MapBatchFn[K, V], fn cache.MapSingleFn[K, V], args ...any) *cache.MapCache[K, V] {
|
||||||
|
@ -219,9 +221,9 @@ func SetExpireTime(c cache.SetTime, name string, expireTime time.Duration, expir
|
||||||
c.SetExpiredTime(fn)
|
c.SetExpiredTime(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChangeExpireTime(t time.Duration, name ...string) {
|
func ChangeExpireTime(t time.Duration, coverConf bool, name ...string) {
|
||||||
for _, s := range name {
|
for _, s := range name {
|
||||||
reload.ChangeFnVal(s, t)
|
reload.ChangeFnVal(s, t, coverConf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,3 +293,28 @@ func GetMapCache[K comparable, V any](name string) (*cache.MapCache[K, V], bool)
|
||||||
vv, err := getMap[K, V](name)
|
vv, err := getMap[K, V](name)
|
||||||
return vv, err == nil
|
return vv, err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetPaginationCache[K comparable, V any](name string) (*cache.Pagination[K, V], bool) {
|
||||||
|
v, err := getPagination[K, V](name)
|
||||||
|
return v, err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Pagination[V any, K comparable](name string, ctx context.Context, timeout time.Duration, k K, page, limit int, a ...any) ([]V, int, error) {
|
||||||
|
v, err := getPagination[K, V](name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return v.Pagination(ctx, timeout, k, page, limit, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPagination[K comparable, T any](name string) (*cache.Pagination[K, T], error) {
|
||||||
|
m, ok := mapCache.Load(name)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New(str.Join("cache ", name, " doesn't exist"))
|
||||||
|
}
|
||||||
|
vk, ok := m.(*cache.Pagination[K, T])
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New(str.Join("cache ", name, " type error"))
|
||||||
|
}
|
||||||
|
return vk, nil
|
||||||
|
}
|
||||||
|
|
2
cache/cachemanager/manger_test.go
vendored
2
cache/cachemanager/manger_test.go
vendored
|
@ -72,7 +72,7 @@ func TestSetExpireTime(t *testing.T) {
|
||||||
fmt.Println(c.Get(ctx, "xx"))
|
fmt.Println(c.Get(ctx, "xx"))
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
fmt.Println(c.Get(ctx, "xx"))
|
fmt.Println(c.Get(ctx, "xx"))
|
||||||
ChangeExpireTime(3*time.Second, "xx")
|
ChangeExpireTime(3*time.Second, true, "xx")
|
||||||
c.Set(ctx, "xx", "yyy")
|
c.Set(ctx, "xx", "yyy")
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
fmt.Println(c.Get(ctx, "xx"))
|
fmt.Println(c.Get(ctx, "xx"))
|
||||||
|
|
31
cache/pagination.go
vendored
31
cache/pagination.go
vendored
|
@ -30,7 +30,14 @@ type DbFn[K comparable, V any] func(ctx context.Context, k K, page, limit, total
|
||||||
|
|
||||||
type LocalFn[K comparable, V any] func(ctx context.Context, data []V, k K, page, limit int, a ...any) ([]V, int, error)
|
type LocalFn[K comparable, V any] func(ctx context.Context, data []V, k K, page, limit int, a ...any) ([]V, int, error)
|
||||||
|
|
||||||
func NewPagination[K comparable, V any](m *MapCache[string, helper.PaginationData[V]], maxNum func() int, dbFn DbFn[K, V], localFn LocalFn[K, V], dbKeyFn, localKeyFn func(K, ...any) string, batchFetchNum func() int, name string) *Pagination[K, V] {
|
func (p *Pagination[K, V]) IsSwitchDB(k K) bool {
|
||||||
|
v, _ := p.isSwitch.Load(k)
|
||||||
|
return v == true
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPagination[K comparable, V any](m *MapCache[string, helper.PaginationData[V]], maxNum func() int,
|
||||||
|
dbFn DbFn[K, V], localFn LocalFn[K, V], dbKeyFn, localKeyFn func(K, ...any) string,
|
||||||
|
batchFetchNum func() int, name string) *Pagination[K, V] {
|
||||||
if dbKeyFn == nil {
|
if dbKeyFn == nil {
|
||||||
dbKeyFn = func(k K, a ...any) string {
|
dbKeyFn = func(k K, a ...any) string {
|
||||||
s := str.NewBuilder()
|
s := str.NewBuilder()
|
||||||
|
@ -66,6 +73,7 @@ func (p *Pagination[K, V]) Pagination(ctx context.Context, timeout time.Duration
|
||||||
data, total, err := p.paginationByLocal(ctx, timeout, k, page, limit, a...)
|
data, total, err := p.paginationByLocal(ctx, timeout, k, page, limit, a...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, switchDb) {
|
if errors.Is(err, switchDb) {
|
||||||
|
p.isSwitch.Store(k, true)
|
||||||
err = nil
|
err = nil
|
||||||
return p.paginationByDB(ctx, timeout, k, page, limit, total, a...)
|
return p.paginationByDB(ctx, timeout, k, page, limit, total, a...)
|
||||||
}
|
}
|
||||||
|
@ -101,11 +109,15 @@ func (p *Pagination[K, V]) paginationByLocal(ctx context.Context, timeout time.D
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
if totalRaw < 1 {
|
||||||
|
data.Data = nil
|
||||||
|
data.TotalRaw = 0
|
||||||
|
p.Set(ctx, key, data)
|
||||||
|
return nil, 0, nil
|
||||||
|
}
|
||||||
if totalRaw >= p.maxNum() {
|
if totalRaw >= p.maxNum() {
|
||||||
p.isSwitch.Store(k, true)
|
|
||||||
return nil, totalRaw, switchDb
|
return nil, totalRaw, switchDb
|
||||||
}
|
}
|
||||||
if len(da) < totalRaw {
|
|
||||||
totalPage := number.DivideCeil(totalRaw, batchNum)
|
totalPage := number.DivideCeil(totalRaw, batchNum)
|
||||||
for i := 1; i <= totalPage; i++ {
|
for i := 1; i <= totalPage; i++ {
|
||||||
daa, _, err := p.fetchDb(ctx, timeout, k, i, batchNum, totalRaw, a...)
|
daa, _, err := p.fetchDb(ctx, timeout, k, i, batchNum, totalRaw, a...)
|
||||||
|
@ -117,20 +129,27 @@ func (p *Pagination[K, V]) paginationByLocal(ctx context.Context, timeout time.D
|
||||||
data.Data = da
|
data.Data = da
|
||||||
data.TotalRaw = totalRaw
|
data.TotalRaw = totalRaw
|
||||||
p.Set(ctx, key, data)
|
p.Set(ctx, key, data)
|
||||||
}
|
|
||||||
|
|
||||||
return p.localFn(ctx, data.Data, k, page, limit, a...)
|
return p.localFn(ctx, data.Data, k, page, limit, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Pagination[K, V]) dbGet(ctx context.Context, key string) (helper.PaginationData[V], bool) {
|
||||||
|
data, ok := p.Get(ctx, key)
|
||||||
|
if ok && p.increaseUpdate != nil && p.increaseUpdate.CycleTime() > p.GetExpireTime(ctx)-p.Ttl(ctx, key) {
|
||||||
|
return data, true
|
||||||
|
}
|
||||||
|
return data, false
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Pagination[K, V]) paginationByDB(ctx context.Context, timeout time.Duration, k K, page, limit, totalRaw int, a ...any) ([]V, int, error) {
|
func (p *Pagination[K, V]) paginationByDB(ctx context.Context, timeout time.Duration, k K, page, limit, totalRaw int, a ...any) ([]V, int, error) {
|
||||||
key := p.dbKeyFn(k, append([]any{page, limit}, a...)...)
|
key := p.dbKeyFn(k, append([]any{page, limit}, a...)...)
|
||||||
data, ok := p.Get(ctx, key)
|
data, ok := p.dbGet(ctx, key)
|
||||||
if ok {
|
if ok {
|
||||||
return data.Data, data.TotalRaw, nil
|
return data.Data, data.TotalRaw, nil
|
||||||
}
|
}
|
||||||
p.mux.Lock()
|
p.mux.Lock()
|
||||||
defer p.mux.Unlock()
|
defer p.mux.Unlock()
|
||||||
data, ok = p.Get(ctx, key)
|
data, ok = p.dbGet(ctx, key)
|
||||||
if ok {
|
if ok {
|
||||||
return data.Data, data.TotalRaw, nil
|
return data.Data, data.TotalRaw, nil
|
||||||
}
|
}
|
||||||
|
|
4
cache/reload/reload.go
vendored
4
cache/reload/reload.go
vendored
|
@ -304,7 +304,7 @@ func FnVal[T any](name string, t T, fn func() T) func() T {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChangeFnVal[T any](name string, val T) {
|
func ChangeFnVal[T any](name string, val T, coverConf bool) {
|
||||||
v, ok := anyMap.Load(name)
|
v, ok := anyMap.Load(name)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
|
@ -313,7 +313,7 @@ func ChangeFnVal[T any](name string, val T) {
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !vv.isUseManger.Load() {
|
if coverConf && !vv.isUseManger.Load() {
|
||||||
vv.isUseManger.Store(true)
|
vv.isUseManger.Store(true)
|
||||||
}
|
}
|
||||||
vv.v.Store(val)
|
vv.v.Store(val)
|
||||||
|
|
12
cache/reload/reload_test.go
vendored
12
cache/reload/reload_test.go
vendored
|
@ -8,22 +8,22 @@ import (
|
||||||
func TestFlushMapVal(t *testing.T) {
|
func TestFlushMapVal(t *testing.T) {
|
||||||
t.Run("t1", func(t *testing.T) {
|
t.Run("t1", func(t *testing.T) {
|
||||||
c := 0
|
c := 0
|
||||||
v := GetAnyValMapBy("key", 2, struct{}{}, func(a struct{}) int {
|
v := GetAnyValMapBy("key", 2, struct{}{}, func(a struct{}) (int, bool) {
|
||||||
c++
|
c++
|
||||||
return 33
|
return 33, true
|
||||||
})
|
})
|
||||||
fmt.Println(v)
|
fmt.Println(v)
|
||||||
FlushMapVal("key", 2)
|
FlushMapVal("key", 2)
|
||||||
|
|
||||||
v = GetAnyValMapBy("key", 2, struct{}{}, func(a struct{}) int {
|
v = GetAnyValMapBy("key", 2, struct{}{}, func(a struct{}) (int, bool) {
|
||||||
fmt.Println("xxxxx")
|
fmt.Println("xxxxx")
|
||||||
return 33
|
return 33, true
|
||||||
})
|
})
|
||||||
fmt.Println(v)
|
fmt.Println(v)
|
||||||
FlushAnyVal("key")
|
FlushAnyVal("key")
|
||||||
v = GetAnyValMapBy("key", 2, struct{}{}, func(a struct{}) int {
|
v = GetAnyValMapBy[int, int, struct{}]("key", 2, struct{}{}, func(a struct{}) (int, bool) {
|
||||||
fmt.Println("yyyy")
|
fmt.Println("yyyy")
|
||||||
return 33
|
return 33, true
|
||||||
})
|
})
|
||||||
fmt.Println(v)
|
fmt.Println(v)
|
||||||
})
|
})
|
||||||
|
|
|
@ -185,7 +185,7 @@ func DescEahByKey[K constraints.Ordered, V any](m map[K]V, fn func(K, V)) {
|
||||||
orderedEahByKey(m, slice.ASC, fn)
|
orderedEahByKey(m, slice.ASC, fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func orderedEahByKey[K constraints.Ordered, V any](m map[K]V, ordered int, fn func(K, V)) {
|
func orderedEahByKey[K constraints.Ordered, V any](m map[K]V, ordered string, fn func(K, V)) {
|
||||||
keys := Keys(m)
|
keys := Keys(m)
|
||||||
slice.Sorts(keys, ordered)
|
slice.Sorts(keys, ordered)
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
|
|
|
@ -125,12 +125,23 @@ func Pagination[T any](arr []T, page, pageSize int) []T {
|
||||||
if start > l {
|
if start > l {
|
||||||
start = l
|
start = l
|
||||||
}
|
}
|
||||||
end := page * pageSize
|
end := start + pageSize
|
||||||
if l < end {
|
if l < end {
|
||||||
end = l
|
end = l
|
||||||
}
|
}
|
||||||
return arr[start:end]
|
return arr[start:end]
|
||||||
}
|
}
|
||||||
|
func ReversePagination[T any](arr []T, page, pageSize int) []T {
|
||||||
|
end := len(arr) - (page-1)*pageSize
|
||||||
|
if end <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
start := end - pageSize
|
||||||
|
if start < 0 {
|
||||||
|
start = 0
|
||||||
|
}
|
||||||
|
return arr[start:end]
|
||||||
|
}
|
||||||
|
|
||||||
func Chunk[T any](arr []T, size int) [][]T {
|
func Chunk[T any](arr []T, size int) [][]T {
|
||||||
var r [][]T
|
var r [][]T
|
||||||
|
|
|
@ -6,8 +6,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ASC = iota
|
ASC = "asc"
|
||||||
DESC
|
DESC = "desc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type anyArr[T any] struct {
|
type anyArr[T any] struct {
|
||||||
|
@ -44,7 +44,7 @@ func StableSort[T any](arr []T, fn func(i, j T) bool) {
|
||||||
sort.Stable(slice)
|
sort.Stable(slice)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Sorts[T constraints.Ordered](a []T, order int) {
|
func Sorts[T constraints.Ordered](a []T, order string) {
|
||||||
slice := anyArr[T]{
|
slice := anyArr[T]{
|
||||||
data: a,
|
data: a,
|
||||||
fn: func(i, j T) bool {
|
fn: func(i, j T) bool {
|
||||||
|
@ -56,8 +56,23 @@ func Sorts[T constraints.Ordered](a []T, order int) {
|
||||||
}
|
}
|
||||||
sort.Sort(slice)
|
sort.Sort(slice)
|
||||||
}
|
}
|
||||||
|
func SortsNew[T constraints.Ordered](a []T, order string) []T {
|
||||||
|
r := make([]T, len(a))
|
||||||
|
copy(r, a)
|
||||||
|
slice := anyArr[T]{
|
||||||
|
data: r,
|
||||||
|
fn: func(i, j T) bool {
|
||||||
|
if order == DESC {
|
||||||
|
return i > j
|
||||||
|
}
|
||||||
|
return i < j
|
||||||
|
},
|
||||||
|
}
|
||||||
|
sort.Sort(slice)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
func SimpleSort[T any, O constraints.Ordered](a []T, order int, fn func(t T) O) {
|
func SimpleSort[T any, O constraints.Ordered](a []T, order string, fn func(t T) O) {
|
||||||
slice := anyArr[T]{
|
slice := anyArr[T]{
|
||||||
data: a,
|
data: a,
|
||||||
fn: func(i, j T) bool {
|
fn: func(i, j T) bool {
|
||||||
|
|
|
@ -74,7 +74,7 @@ func TestSort(t *testing.T) {
|
||||||
func TestSorts(t *testing.T) {
|
func TestSorts(t *testing.T) {
|
||||||
type args[T constraints.Ordered] struct {
|
type args[T constraints.Ordered] struct {
|
||||||
a []T
|
a []T
|
||||||
order int
|
order string
|
||||||
}
|
}
|
||||||
type testCase[T constraints.Ordered] struct {
|
type testCase[T constraints.Ordered] struct {
|
||||||
name string
|
name string
|
||||||
|
@ -169,7 +169,7 @@ func TestSimpleSort(t *testing.T) {
|
||||||
|
|
||||||
type args[T any, O constraints.Ordered] struct {
|
type args[T any, O constraints.Ordered] struct {
|
||||||
a []T
|
a []T
|
||||||
order int
|
order string
|
||||||
fn func(t T) O
|
fn func(t T) O
|
||||||
}
|
}
|
||||||
type testCase[T any, O constraints.Ordered] struct {
|
type testCase[T any, O constraints.Ordered] struct {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user