diff --git a/actions/common/common.go b/actions/common/common.go index 8c7f5f7..c39dca3 100644 --- a/actions/common/common.go +++ b/actions/common/common.go @@ -8,6 +8,7 @@ import ( "github/fthvgb1/wp-go/models" "github/fthvgb1/wp-go/vars" "log" + "strconv" "strings" "sync" "time" @@ -21,6 +22,7 @@ var categoryCaches *cache.SliceCache[models.WpTermsMy] var recentPostsCaches *cache.SliceCache[models.WpPosts] var monthCaches *cache.MapCache[string, []models.WpPosts] var recentCommentsCaches *cache.SliceCache[models.WpComments] +var postCommentCaches *cache.MapCache[uint64, []models.WpComments] func InitCache() { archivesCaches = &Arch{ @@ -31,6 +33,7 @@ func InitCache() { recentPostsCaches = cache.NewSliceCache[models.WpPosts](recentPosts, vars.Conf.RecentPostCacheTime) monthCaches = cache.NewMapCache[string, []models.WpPosts](getMonthPost, 30*time.Minute) recentCommentsCaches = cache.NewSliceCache[models.WpComments](recentComments, vars.Conf.RecentCommentsCacheTime) + postCommentCaches = cache.NewMapCache[uint64, []models.WpComments](postComments, time.Minute*5) } type Arch struct { @@ -68,6 +71,21 @@ func GetMonthPost(ctx context.Context, year, month string) ([]models.WpPosts, er return monthCaches.GetCache(ctx, fmt.Sprintf("%s%s", year, month), time.Second, year, month) } +func PostComments(ctx context.Context, Id uint64) ([]models.WpComments, error) { + return postCommentCaches.GetCache(ctx, Id, time.Second, Id) +} + +func postComments(args ...any) ([]models.WpComments, error) { + postId := args[0].(uint64) + return models.Find[models.WpComments](models.SqlBuilder{ + {"comment_approved", "1"}, + {"comment_post_ID", "=", strconv.FormatUint(postId, 10), "int"}, + }, "*", "", models.SqlBuilder{ + {"comment_date_gmt", "asc"}, + {"comment_ID", "asc"}, + }, nil, 0) +} + func RecentComments(ctx context.Context) (r []models.WpComments) { r, _ = recentCommentsCaches.GetCache(ctx, time.Second) return diff --git a/actions/detail.go b/actions/detail.go index 870267a..e15d498 100644 --- a/actions/detail.go +++ b/actions/detail.go @@ -8,7 +8,9 @@ import ( "github/fthvgb1/wp-go/actions/common" "github/fthvgb1/wp-go/models" "net/http" + "sort" "strconv" + "strings" ) func Detail(c *gin.Context) { @@ -17,14 +19,14 @@ func Detail(c *gin.Context) { recent := common.RecentPosts(ctx) archive := common.Archives() categoryItems := common.Categories(ctx) - comments := common.RecentComments(ctx) + recentComments := common.RecentComments(ctx) var h = gin.H{ - "title": models.Options["blogname"], - "options": models.Options, - "recentPosts": recent, - "archives": archive, - "categories": categoryItems, - "comments": comments, + "title": models.Options["blogname"], + "options": models.Options, + "recentPosts": recent, + "archives": archive, + "categories": categoryItems, + "recentComments": recentComments, } defer func() { c.HTML(http.StatusOK, "posts/detail.gohtml", h) @@ -63,10 +65,164 @@ func Detail(c *gin.Context) { common.PasswdProjectContent(&post) showComment = false } + comments, err := common.PostComments(ctx, post.Id) + commentss := treeComments(comments) prev, next, err := common.GetContextPost(post.Id, post.PostDate) h["title"] = fmt.Sprintf("%s-%s", post.PostTitle, models.Options["blogname"]) h["post"] = post h["showComment"] = showComment h["prev"] = prev + h["comments"] = formatComment(commentss, 1) h["next"] = next } + +type Comment struct { + models.WpComments + Children []*Comment +} + +type Comments []*Comment + +func (c Comments) Len() int { + return len(c) +} + +func (c Comments) Less(i, j int) bool { + return c[i].CommentId < c[j].CommentId +} + +func (c Comments) Swap(i, j int) { + c[i], c[j] = c[j], c[i] +} + +func formatComment(comments Comments, depth int) (html string) { + s := strings.Builder{} + if depth > 5 { + comments = findComments(comments) + } + sort.Sort(comments) + for i, comment := range comments { + eo := "even" + if (i+1)%2 == 0 { + eo = "odd" + } + p := "" + + fl := false + if len(comment.Children) > 0 && depth < 6 { + p = "parent" + fl = true + } + s.WriteString(formatLi(comment.WpComments, depth, eo, p)) + if fl { + depth++ + s.WriteString(`
    `) + s.WriteString(formatComment(comment.Children, depth)) + s.WriteString(`
`) + } + s.WriteString("") + i++ + if i >= len(comments) { + break + } + } + + html = s.String() + return +} + +func findComments(comments Comments) Comments { + var r Comments + for _, comment := range comments { + tmp := comment + tmp.Children = nil + r = append(r, tmp) + if len(comment.Children) > 0 { + t := findComments(comment.Children) + r = append(r, t...) + } + } + return r +} + +func treeComments(comments []models.WpComments) Comments { + var r = map[uint64]*Comment{ + 0: { + WpComments: models.WpComments{}, + }, + } + var top []*Comment + for _, comment := range comments { + c := Comment{ + WpComments: comment, + Children: []*Comment{}, + } + r[comment.CommentId] = &c + if comment.CommentParent == 0 { + top = append(top, &c) + } + } + for id, son := range r { + if id == son.CommentParent { + continue + } + parent := r[son.CommentParent] + parent.Children = append(parent.Children, son) + } + return top +} + +func formatLi(comments models.WpComments, d int, eo, parent string) string { + li := ` +
  • +
    + + +
    +

    {{CommentContent}}

    +
    + +
    + 回复 +
    +
    + +` + for k, v := range map[string]string{ + "{{CommentId}}": strconv.FormatUint(comments.CommentId, 10), + "{{Depth}}": strconv.Itoa(d), + "{{Gravatar}}": "http://1.gravatar.com/avatar/d7a973c7dab26985da5f961be7b74480?s=56&d=mm&r=g", + "{{CommentAuthorUrl}}": comments.CommentAuthorUrl, + "{{CommentAuthor}}": comments.CommentAuthor, + "{{PostId}}": strconv.FormatUint(comments.CommentPostId, 10), + "{{CommentDateGmt}}": comments.CommentDateGmt.String(), + "{{CommentDate}}": comments.CommentDate.Format("2006-01-02 15:04"), + "{{CommentContent}}": comments.CommentContent, + "{{eo}}": eo, + "{{parent}}": parent, + } { + li = strings.Replace(li, k, v, -1) + } + return li +} diff --git a/actions/index.go b/actions/index.go index c7e3b94..6065f92 100644 --- a/actions/index.go +++ b/actions/index.go @@ -153,16 +153,16 @@ func Index(c *gin.Context) { archive := common.Archives() recent := common.RecentPosts(ctx) categoryItems := common.Categories(ctx) - comments := common.RecentComments(ctx) + recentComments := common.RecentComments(ctx) ginH := gin.H{ - "options": models.Options, - "recentPosts": recent, - "archives": archive, - "categories": categoryItems, - "search": h.search, - "header": h.header, - "title": h.getTitle(), - "comments": comments, + "options": models.Options, + "recentPosts": recent, + "archives": archive, + "categories": categoryItems, + "search": h.search, + "header": h.header, + "title": h.getTitle(), + "recentComments": recentComments, } postIds, totalRaw, err := models.SimplePagination[models.WpPosts](h.where, "ID", "", h.page, h.pageSize, h.orderBy, h.join, h.postType, h.status) defer func() { diff --git a/models/model.go b/models/model.go index 1ba2b43..9621b2b 100644 --- a/models/model.go +++ b/models/model.go @@ -39,7 +39,7 @@ func (w SqlBuilder) parseField(ss []string, s *strings.Builder) { } func (w SqlBuilder) parseIn(ss []string, s *strings.Builder, c *int, args *[]any, in [][]any) (t bool) { - if ss[1] == "in" && len(in) > 0 { + if helper.IsContainInArr(ss[1], []string{"in", "not in"}) && len(in) > 0 { s.WriteString(" (") for _, p := range in[*c] { s.WriteString("?,") diff --git a/templates/layout/base.gohtml b/templates/layout/base.gohtml index 550232f..8785021 100644 --- a/templates/layout/base.gohtml +++ b/templates/layout/base.gohtml @@ -1,12 +1,13 @@ {{ define "layout/base"}} - + {{template "layout/head" .}} {{block "head" .}} {{end}} +