commit
d69a04e65d
|
@ -27,30 +27,42 @@ ssl:
|
||||||
cert: ""
|
cert: ""
|
||||||
key: ""
|
key: ""
|
||||||
|
|
||||||
# 最近文章缓存时间
|
cacheTime:
|
||||||
recentPostCacheTime: 5m
|
# 静态资源缓存时间Cache-Control
|
||||||
# 分类缓存时间
|
cacheControl: 5d
|
||||||
categoryCacheTime: 5m
|
# 最近文章缓存时间
|
||||||
# 上下篇缓存时间
|
recentPostCacheTime: 5m
|
||||||
contextPostCacheTime: 10h
|
# 分类缓存时间
|
||||||
# 最近评论缓存时间
|
categoryCacheTime: 5m
|
||||||
recentCommentsCacheTime: 5m
|
# 上下篇缓存时间
|
||||||
# 摘要缓存时间
|
contextPostCacheTime: 10h
|
||||||
digestCacheTime: 5m
|
# 最近评论缓存时间
|
||||||
|
recentCommentsCacheTime: 5m
|
||||||
|
# 摘要缓存时间
|
||||||
|
digestCacheTime: 5m
|
||||||
|
# 文档列表id页缓存 包括默认列表、分类
|
||||||
|
postListCacheTime: 1h
|
||||||
|
# 搜索文档id缓存时间
|
||||||
|
searchPostCacheTime: 5m
|
||||||
|
# 月归档文章id缓存时间
|
||||||
|
monthPostCacheTime: 1h
|
||||||
|
# 文档数据缓存时间
|
||||||
|
postDataCacheTime: 1h
|
||||||
|
# 文章评论缓存时间
|
||||||
|
postCommentsCacheTime: 5m
|
||||||
|
# 定时清理缓存周期时间
|
||||||
|
crontabClearCacheTime: 5m
|
||||||
|
# 文档最大id缓存时间
|
||||||
|
maxPostIdCacheTime: 1h
|
||||||
|
# 用户信息缓存时间
|
||||||
|
userInfoCacheTime: 24h
|
||||||
|
# 单独评论缓存时间
|
||||||
|
commentsCacheTime: 24h
|
||||||
|
# 主题的页眉图片缓存时间
|
||||||
|
themeHeaderImagCacheTime: 5m
|
||||||
# 摘要字数
|
# 摘要字数
|
||||||
digestWordCount: 300
|
digestWordCount: 300
|
||||||
# 文档列表id页缓存 包括默认列表、分类
|
|
||||||
postListCacheTime: 1h
|
|
||||||
# 搜索文档id缓存时间
|
|
||||||
searchPostCacheTime: 5m
|
|
||||||
# 月归档文章id缓存时间
|
|
||||||
monthPostCacheTime: 1h
|
|
||||||
# 文档数据缓存时间
|
|
||||||
postDataCacheTime: 1h
|
|
||||||
# 文章评论缓存时间
|
|
||||||
postCommentsCacheTime: 5m
|
|
||||||
# 定时清理缓存周期时间
|
|
||||||
crontabClearCacheTime: 5m
|
|
||||||
# 到达指定并发请求数时随机sleep
|
# 到达指定并发请求数时随机sleep
|
||||||
maxRequestSleepNum: 100
|
maxRequestSleepNum: 100
|
||||||
# 随机sleep时间
|
# 随机sleep时间
|
||||||
|
@ -59,14 +71,7 @@ sleepTime: [1s,3s]
|
||||||
maxRequestNum: 500
|
maxRequestNum: 500
|
||||||
# 单ip同时最大搜索请求数
|
# 单ip同时最大搜索请求数
|
||||||
singleIpSearchNum: 10
|
singleIpSearchNum: 10
|
||||||
# 文档最大id缓存时间
|
|
||||||
maxPostIdCacheTime: 1h
|
|
||||||
# 用户信息缓存时间
|
|
||||||
userInfoCacheTime: 24h
|
|
||||||
# 单独评论缓存时间
|
|
||||||
commentsCacheTime: 24h
|
|
||||||
# 主题的页眉图片缓存时间
|
|
||||||
themeHeaderImagCacheTime: 5m
|
|
||||||
|
|
||||||
# Gzip
|
# Gzip
|
||||||
gzip: false
|
gzip: false
|
||||||
|
|
|
@ -8,6 +8,13 @@ func ToAny[T any](v T) any {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Or[T any](is bool, left, right T) T {
|
||||||
|
if is {
|
||||||
|
return left
|
||||||
|
}
|
||||||
|
return right
|
||||||
|
}
|
||||||
|
|
||||||
func StructColumnToSlice[T any, M any](arr []M, field string) (r []T) {
|
func StructColumnToSlice[T any, M any](arr []M, field string) (r []T) {
|
||||||
for i := 0; i < len(arr); i++ {
|
for i := 0; i < len(arr); i++ {
|
||||||
v := reflect.ValueOf(arr[i]).FieldByName(field).Interface()
|
v := reflect.ValueOf(arr[i]).FieldByName(field).Interface()
|
||||||
|
|
|
@ -49,6 +49,11 @@ func AnyAnyToStrAny(m map[any]any) (r map[string]any) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsExists[K comparable, V any](m map[K]V, k K) bool {
|
||||||
|
_, ok := m[k]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
func Reduce[T, V any, K comparable](m map[K]V, fn func(K, V, T) T, r T) T {
|
func Reduce[T, V any, K comparable](m map[K]V, fn func(K, V, T) T, r T) T {
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
r = fn(k, v, r)
|
r = fn(k, v, r)
|
||||||
|
|
|
@ -2,6 +2,7 @@ package number
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"golang.org/x/exp/constraints"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -195,10 +196,10 @@ func TestRand(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAbs(t *testing.T) {
|
func TestAbs(t *testing.T) {
|
||||||
type args[T Number] struct {
|
type args[T constraints.Integer | constraints.Float] struct {
|
||||||
n T
|
n T
|
||||||
}
|
}
|
||||||
type testCase[T Number] struct {
|
type testCase[T constraints.Integer | constraints.Float] struct {
|
||||||
name string
|
name string
|
||||||
args args[T]
|
args args[T]
|
||||||
want T
|
want T
|
||||||
|
|
|
@ -3,7 +3,9 @@ package strings
|
||||||
import (
|
import (
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"golang.org/x/exp/constraints"
|
||||||
"io"
|
"io"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -20,6 +22,17 @@ func Join(s ...string) (str string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ToInteger[T constraints.Integer](s string, defaults T) T {
|
||||||
|
if s == "" {
|
||||||
|
return defaults
|
||||||
|
}
|
||||||
|
i, err := strconv.ParseInt(s, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return defaults
|
||||||
|
}
|
||||||
|
return T(i)
|
||||||
|
}
|
||||||
|
|
||||||
func Md5(str string) string {
|
func Md5(str string) string {
|
||||||
h := md5.New()
|
h := md5.New()
|
||||||
_, err := io.WriteString(h, str)
|
_, err := io.WriteString(h, str)
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package strings
|
package strings
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"golang.org/x/exp/constraints"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
func TestStrJoin(t *testing.T) {
|
func TestStrJoin(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
|
@ -21,3 +24,32 @@ func TestStrJoin(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestToInteger(t *testing.T) {
|
||||||
|
type args[T constraints.Integer] struct {
|
||||||
|
s string
|
||||||
|
z T
|
||||||
|
}
|
||||||
|
type testCase[T constraints.Integer] struct {
|
||||||
|
name string
|
||||||
|
args args[T]
|
||||||
|
want T
|
||||||
|
}
|
||||||
|
tests := []testCase[int64]{
|
||||||
|
{
|
||||||
|
name: "t1",
|
||||||
|
args: args[int64]{
|
||||||
|
"10",
|
||||||
|
0,
|
||||||
|
},
|
||||||
|
want: int64(10),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := ToInteger[int64](tt.args.s, tt.args.z); got != tt.want {
|
||||||
|
t.Errorf("StrToInt() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"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/internal/mail"
|
"github.com/fthvgb1/wp-go/internal/mail"
|
||||||
"github.com/fthvgb1/wp-go/internal/pkg/cache"
|
"github.com/fthvgb1/wp-go/internal/pkg/cache"
|
||||||
"github.com/fthvgb1/wp-go/internal/pkg/config"
|
"github.com/fthvgb1/wp-go/internal/pkg/config"
|
||||||
|
@ -14,7 +15,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -34,6 +34,7 @@ func PostComment(c *gin.Context) {
|
||||||
c.Writer.WriteString(err.Error())
|
c.Writer.WriteString(err.Error())
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
conf := config.GetConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -43,7 +44,7 @@ func PostComment(c *gin.Context) {
|
||||||
m := c.PostForm("email")
|
m := c.PostForm("email")
|
||||||
comment := c.PostForm("comment")
|
comment := c.PostForm("comment")
|
||||||
c.Request.Body = io.NopCloser(bytes.NewBuffer(data))
|
c.Request.Body = io.NopCloser(bytes.NewBuffer(data))
|
||||||
req, err := http.NewRequest("POST", config.Conf.Load().PostCommentUrl, strings.NewReader(c.Request.PostForm.Encode()))
|
req, err := http.NewRequest("POST", conf.PostCommentUrl, strings.NewReader(c.Request.PostForm.Encode()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -68,7 +69,7 @@ func PostComment(c *gin.Context) {
|
||||||
err = er
|
err = er
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cu, er := url.Parse(config.Conf.Load().PostCommentUrl)
|
cu, er := url.Parse(conf.PostCommentUrl)
|
||||||
if er != nil {
|
if er != nil {
|
||||||
err = er
|
err = er
|
||||||
return
|
return
|
||||||
|
@ -91,8 +92,8 @@ func PostComment(c *gin.Context) {
|
||||||
}
|
}
|
||||||
cc := c.Copy()
|
cc := c.Copy()
|
||||||
go func() {
|
go func() {
|
||||||
id, err := strconv.ParseUint(i, 10, 64)
|
id := str.ToInteger[uint64](i, 0)
|
||||||
if err != nil {
|
if id <= 0 {
|
||||||
logs.ErrPrintln(err, "获取文档id", i)
|
logs.ErrPrintln(err, "获取文档id", i)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -102,8 +103,8 @@ func PostComment(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
su := fmt.Sprintf("%s: %s[%s]发表了评论对文档[%v]的评论", wpconfig.Options.Value("siteurl"), author, m, post.PostTitle)
|
su := fmt.Sprintf("%s: %s[%s]发表了评论对文档[%v]的评论", wpconfig.Options.Value("siteurl"), author, m, post.PostTitle)
|
||||||
err = mail.SendMail([]string{config.Conf.Load().Mail.User}, su, comment)
|
err = mail.SendMail([]string{conf.Mail.User}, su, comment)
|
||||||
logs.ErrPrintln(err, "发送邮件", config.Conf.Load().Mail.User, su, comment)
|
logs.ErrPrintln(err, "发送邮件", conf.Mail.User, su, comment)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
s, er := io.ReadAll(ress.Body)
|
s, er := io.ReadAll(ress.Body)
|
||||||
|
|
|
@ -2,15 +2,16 @@ package actions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
"github.com/fthvgb1/wp-go/internal/pkg/cache"
|
"github.com/fthvgb1/wp-go/internal/pkg/cache"
|
||||||
"github.com/fthvgb1/wp-go/internal/pkg/logs"
|
"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/plugins"
|
||||||
"github.com/fthvgb1/wp-go/internal/theme"
|
"github.com/fthvgb1/wp-go/internal/theme"
|
||||||
"github.com/fthvgb1/wp-go/internal/wpconfig"
|
"github.com/fthvgb1/wp-go/internal/wpconfig"
|
||||||
"github.com/gin-contrib/sessions"
|
"github.com/gin-contrib/sessions"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type detailHandler struct {
|
type detailHandler struct {
|
||||||
|
@ -19,9 +20,10 @@ type detailHandler struct {
|
||||||
|
|
||||||
func Detail(c *gin.Context) {
|
func Detail(c *gin.Context) {
|
||||||
var err error
|
var err error
|
||||||
recent := cache.RecentPosts(c, 5)
|
var post models.Posts
|
||||||
|
recent := cache.RecentPosts(c, 5, true)
|
||||||
archive := cache.Archives(c)
|
archive := cache.Archives(c)
|
||||||
categoryItems := cache.Categories(c)
|
categoryItems := cache.CategoriesTags(c, plugins.Category)
|
||||||
recentComments := cache.RecentComments(c, 5)
|
recentComments := cache.RecentComments(c, 5)
|
||||||
var ginH = gin.H{
|
var ginH = gin.H{
|
||||||
"title": wpconfig.Options.Value("blogname"),
|
"title": wpconfig.Options.Value("blogname"),
|
||||||
|
@ -29,6 +31,7 @@ func Detail(c *gin.Context) {
|
||||||
"archives": archive,
|
"archives": archive,
|
||||||
"categories": categoryItems,
|
"categories": categoryItems,
|
||||||
"recentComments": recentComments,
|
"recentComments": recentComments,
|
||||||
|
"post": post,
|
||||||
}
|
}
|
||||||
isApproveComment := false
|
isApproveComment := false
|
||||||
status := plugins.Ok
|
status := plugins.Ok
|
||||||
|
@ -47,21 +50,14 @@ func Detail(c *gin.Context) {
|
||||||
t := theme.GetTemplateName()
|
t := theme.GetTemplateName()
|
||||||
theme.Hook(t, code, c, ginH, plugins.Detail, status)
|
theme.Hook(t, code, c, ginH, plugins.Detail, status)
|
||||||
}()
|
}()
|
||||||
id := c.Param("id")
|
ID := str.ToInteger[uint64](c.Param("id"), 0)
|
||||||
Id := 0
|
|
||||||
if id != "" {
|
|
||||||
Id, err = strconv.Atoi(id)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ID := uint64(Id)
|
|
||||||
maxId, err := cache.GetMaxPostId(c)
|
maxId, err := cache.GetMaxPostId(c)
|
||||||
logs.ErrPrintln(err, "get max post id")
|
logs.ErrPrintln(err, "get max post id")
|
||||||
if ID > maxId || err != nil {
|
if ID > maxId || ID <= 0 || err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
post, err := cache.GetPostById(c, ID)
|
post, err = cache.GetPostById(c, ID)
|
||||||
if post.Id == 0 || err != nil || post.PostStatus != "publish" {
|
if post.Id == 0 || err != nil || post.PostStatus != "publish" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -71,10 +67,13 @@ func Detail(c *gin.Context) {
|
||||||
showComment = true
|
showComment = true
|
||||||
}
|
}
|
||||||
user := cache.GetUserById(c, post.PostAuthor)
|
user := cache.GetUserById(c, post.PostAuthor)
|
||||||
plugins.PasswordProjectTitle(&post)
|
|
||||||
if post.PostPassword != "" && pw != post.PostPassword {
|
if post.PostPassword != "" {
|
||||||
plugins.PasswdProjectContent(&post)
|
plugins.PasswordProjectTitle(&post)
|
||||||
showComment = false
|
if pw != post.PostPassword {
|
||||||
|
plugins.PasswdProjectContent(&post)
|
||||||
|
showComment = false
|
||||||
|
}
|
||||||
} else if s, ok := cache.NewCommentCache().Get(c, c.Request.URL.RawQuery); ok && s != "" && (post.PostPassword == "" || post.PostPassword != "" && pw == post.PostPassword) {
|
} else if s, ok := cache.NewCommentCache().Get(c, c.Request.URL.RawQuery); ok && s != "" && (post.PostPassword == "" || post.PostPassword != "" && pw == post.PostPassword) {
|
||||||
c.Writer.WriteHeader(http.StatusOK)
|
c.Writer.WriteHeader(http.StatusOK)
|
||||||
c.Writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
c.Writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
@ -92,12 +91,7 @@ func Detail(c *gin.Context) {
|
||||||
ginH["post"] = post
|
ginH["post"] = post
|
||||||
ginH["showComment"] = showComment
|
ginH["showComment"] = showComment
|
||||||
ginH["prev"] = prev
|
ginH["prev"] = prev
|
||||||
depth := wpconfig.Options.Value("thread_comments_depth")
|
d := str.ToInteger(wpconfig.Options.Value("thread_comments_depth"), 5)
|
||||||
d, err := strconv.Atoi(depth)
|
|
||||||
if err != nil {
|
|
||||||
logs.ErrPrintln(err, "get comment depth ", depth)
|
|
||||||
d = 5
|
|
||||||
}
|
|
||||||
ginH["maxDep"] = d
|
ginH["maxDep"] = d
|
||||||
ginH["next"] = next
|
ginH["next"] = next
|
||||||
ginH["user"] = user
|
ginH["user"] = user
|
||||||
|
|
|
@ -3,6 +3,7 @@ package actions
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/maps"
|
||||||
"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"
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
|
@ -52,13 +53,12 @@ type indexHandle struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newIndexHandle(ctx *gin.Context) *indexHandle {
|
func newIndexHandle(ctx *gin.Context) *indexHandle {
|
||||||
size := wpconfig.Options.Value("posts_per_page")
|
size := str.ToInteger(wpconfig.Options.Value("posts_per_page"), 10)
|
||||||
si, _ := strconv.Atoi(size)
|
|
||||||
return &indexHandle{
|
return &indexHandle{
|
||||||
c: ctx,
|
c: ctx,
|
||||||
session: sessions.Default(ctx),
|
session: sessions.Default(ctx),
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: si,
|
pageSize: size,
|
||||||
paginationStep: 1,
|
paginationStep: 1,
|
||||||
titleL: wpconfig.Options.Value("blogname"),
|
titleL: wpconfig.Options.Value("blogname"),
|
||||||
titleR: wpconfig.Options.Value("blogdescription"),
|
titleR: wpconfig.Options.Value("blogdescription"),
|
||||||
|
@ -93,24 +93,20 @@ func (h *indexHandle) getSearchKey() string {
|
||||||
return fmt.Sprintf("action:%s|%s|%s|%s|%s|%s|%d|%d", h.author, h.search, h.orderBy, h.order, h.category, h.categoryType, h.page, h.pageSize)
|
return fmt.Sprintf("action:%s|%s|%s|%s|%s|%s|%d|%d", h.author, h.search, h.orderBy, h.order, h.category, h.categoryType, h.page, h.pageSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
var orders = []string{"asc", "desc"}
|
var orders = map[string]struct{}{"asc": {}, "desc": {}}
|
||||||
|
|
||||||
func (h *indexHandle) parseParams() (err error) {
|
func (h *indexHandle) parseParams() (err error) {
|
||||||
h.order = h.c.Query("order")
|
h.order = h.c.Query("order")
|
||||||
|
if !maps.IsExists(orders, h.order) {
|
||||||
if !slice.IsContained(h.order, orders) {
|
order := config.GetConfig().PostOrder
|
||||||
order := config.Conf.Load().PostOrder
|
|
||||||
h.order = "asc"
|
h.order = "asc"
|
||||||
if order != "" && slice.IsContained(order, orders) {
|
if order != "" && maps.IsExists(orders, order) {
|
||||||
h.order = order
|
h.order = order
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
year := h.c.Param("year")
|
year := h.c.Param("year")
|
||||||
if year != "" {
|
if year != "" {
|
||||||
y, er := strconv.Atoi(year)
|
y := str.ToInteger(year, -1)
|
||||||
if er != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if y > time.Now().Year() || y <= 1970 {
|
if y > time.Now().Year() || y <= 1970 {
|
||||||
return errors.New(str.Join("year err : ", year))
|
return errors.New(str.Join("year err : ", year))
|
||||||
}
|
}
|
||||||
|
@ -120,11 +116,8 @@ func (h *indexHandle) parseParams() (err error) {
|
||||||
}
|
}
|
||||||
month := h.c.Param("month")
|
month := h.c.Param("month")
|
||||||
if month != "" {
|
if month != "" {
|
||||||
m, err := strconv.Atoi(month)
|
m := str.ToInteger(month, -1)
|
||||||
if err != nil {
|
if !maps.IsExists(months, m) {
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, ok := months[m]; !ok {
|
|
||||||
return errors.New(str.Join("months err ", month))
|
return errors.New(str.Join("months err ", month))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,27 +130,26 @@ func (h *indexHandle) parseParams() (err error) {
|
||||||
h.scene = plugins.Archive
|
h.scene = plugins.Archive
|
||||||
}
|
}
|
||||||
category := h.c.Param("category")
|
category := h.c.Param("category")
|
||||||
if category == "" {
|
if category != "" {
|
||||||
category = h.c.Param("tag")
|
|
||||||
if category != "" {
|
|
||||||
h.scene = plugins.Tag
|
|
||||||
allNames := cache.AllTagsNames(h.c)
|
|
||||||
if _, ok := allNames[category]; !ok {
|
|
||||||
return errors.New(str.Join("not exists tag ", category))
|
|
||||||
}
|
|
||||||
h.categoryType = "post_tag"
|
|
||||||
h.header = fmt.Sprintf("标签: <span>%s</span>", category)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
h.scene = plugins.Category
|
h.scene = plugins.Category
|
||||||
allNames := cache.AllCategoryNames(h.c)
|
if !maps.IsExists(cache.AllCategoryTagsNames(h.c, plugins.Category), category) {
|
||||||
if _, ok := allNames[category]; !ok {
|
|
||||||
return errors.New(str.Join("not exists category ", category))
|
return errors.New(str.Join("not exists category ", category))
|
||||||
}
|
}
|
||||||
h.categoryType = "category"
|
h.categoryType = "category"
|
||||||
h.header = fmt.Sprintf("分类: <span>%s</span>", category)
|
h.header = fmt.Sprintf("分类: <span>%s</span>", category)
|
||||||
|
h.category = category
|
||||||
}
|
}
|
||||||
h.category = category
|
tag := h.c.Param("tag")
|
||||||
|
if tag != "" {
|
||||||
|
h.scene = plugins.Tag
|
||||||
|
if !maps.IsExists(cache.AllCategoryTagsNames(h.c, plugins.Tag), tag) {
|
||||||
|
return errors.New(str.Join("not exists tag ", tag))
|
||||||
|
}
|
||||||
|
h.categoryType = "post_tag"
|
||||||
|
h.header = fmt.Sprintf("标签: <span>%s</span>", tag)
|
||||||
|
h.category = tag
|
||||||
|
}
|
||||||
|
|
||||||
username := h.c.Param("author")
|
username := h.c.Param("author")
|
||||||
if username != "" {
|
if username != "" {
|
||||||
allUsername, er := cache.GetAllUsername(h.c)
|
allUsername, er := cache.GetAllUsername(h.c)
|
||||||
|
@ -165,7 +157,7 @@ func (h *indexHandle) parseParams() (err error) {
|
||||||
err = er
|
err = er
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if _, ok := allUsername[username]; !ok {
|
if !maps.IsExists(allUsername, username) {
|
||||||
err = errors.New(str.Join("user ", username, " is not exists"))
|
err = errors.New(str.Join("user ", username, " is not exists"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -179,9 +171,9 @@ func (h *indexHandle) parseParams() (err error) {
|
||||||
"post_author", "=", strconv.FormatUint(user.Id, 10), "int",
|
"post_author", "=", strconv.FormatUint(user.Id, 10), "int",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if category != "" {
|
if h.category != "" {
|
||||||
h.where = append(h.where, []string{
|
h.where = append(h.where, []string{
|
||||||
"d.name", category,
|
"d.name", h.category,
|
||||||
}, []string{"taxonomy", h.categoryType})
|
}, []string{"taxonomy", h.categoryType})
|
||||||
h.join = append(h.join, []string{
|
h.join = append(h.join, []string{
|
||||||
"a", "left join", "wp_term_relationships b", "a.Id=b.object_id",
|
"a", "left join", "wp_term_relationships b", "a.Id=b.object_id",
|
||||||
|
@ -190,7 +182,7 @@ func (h *indexHandle) parseParams() (err error) {
|
||||||
}, []string{
|
}, []string{
|
||||||
"left join", "wp_terms d", "c.term_id=d.term_id",
|
"left join", "wp_terms d", "c.term_id=d.term_id",
|
||||||
})
|
})
|
||||||
h.setTitleLR(category, wpconfig.Options.Value("blogname"))
|
h.setTitleLR(h.category, wpconfig.Options.Value("blogname"))
|
||||||
}
|
}
|
||||||
s := h.c.Query("s")
|
s := h.c.Query("s")
|
||||||
if s != "" && strings.Replace(s, " ", "", -1) != "" {
|
if s != "" && strings.Replace(s, " ", "", -1) != "" {
|
||||||
|
@ -206,15 +198,7 @@ func (h *indexHandle) parseParams() (err error) {
|
||||||
h.search = s
|
h.search = s
|
||||||
h.scene = plugins.Search
|
h.scene = plugins.Search
|
||||||
}
|
}
|
||||||
p := h.c.Query("paged")
|
h.page = str.ToInteger(h.c.Param("page"), 1)
|
||||||
if p == "" {
|
|
||||||
p = h.c.Param("page")
|
|
||||||
}
|
|
||||||
if p != "" {
|
|
||||||
if pa, err := strconv.Atoi(p); err == nil {
|
|
||||||
h.page = pa
|
|
||||||
}
|
|
||||||
}
|
|
||||||
total := int(atomic.LoadInt64(&dao.TotalRaw))
|
total := int(atomic.LoadInt64(&dao.TotalRaw))
|
||||||
if total > 0 && total < (h.page-1)*h.pageSize {
|
if total > 0 && total < (h.page-1)*h.pageSize {
|
||||||
h.page = 1
|
h.page = 1
|
||||||
|
@ -236,8 +220,8 @@ func Index(c *gin.Context) {
|
||||||
var totalRaw int
|
var totalRaw int
|
||||||
var err error
|
var err error
|
||||||
archive := cache.Archives(c)
|
archive := cache.Archives(c)
|
||||||
recent := cache.RecentPosts(c, 5)
|
recent := cache.RecentPosts(c, 5, true)
|
||||||
categoryItems := cache.Categories(c)
|
categoryItems := cache.CategoriesTags(c, plugins.Category)
|
||||||
recentComments := cache.RecentComments(c, 5)
|
recentComments := cache.RecentComments(c, 5)
|
||||||
ginH := gin.H{
|
ginH := gin.H{
|
||||||
"err": err,
|
"err": err,
|
||||||
|
@ -247,6 +231,7 @@ func Index(c *gin.Context) {
|
||||||
"search": h.search,
|
"search": h.search,
|
||||||
"header": h.header,
|
"header": h.header,
|
||||||
"recentComments": recentComments,
|
"recentComments": recentComments,
|
||||||
|
"posts": posts,
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
code := http.StatusOK
|
code := http.StatusOK
|
||||||
|
@ -292,18 +277,16 @@ func Index(c *gin.Context) {
|
||||||
pw := h.session.Get("post_password")
|
pw := h.session.Get("post_password")
|
||||||
plug := plugins.NewPostPlugin(c, h.scene)
|
plug := plugins.NewPostPlugin(c, h.scene)
|
||||||
for i, post := range posts {
|
for i, post := range posts {
|
||||||
plugins.PasswordProjectTitle(&posts[i])
|
if post.PostPassword != "" {
|
||||||
if post.PostPassword != "" && pw != post.PostPassword {
|
plugins.PasswordProjectTitle(&posts[i])
|
||||||
plugins.PasswdProjectContent(&posts[i])
|
if pw != post.PostPassword {
|
||||||
|
plugins.PasswdProjectContent(&posts[i])
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
plugins.ApplyPlugin(plug, &posts[i])
|
plugins.ApplyPlugin(plug, &posts[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i, post := range recent {
|
|
||||||
if post.PostPassword != "" && pw != post.PostPassword {
|
|
||||||
plugins.PasswdProjectContent(&recent[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
q := c.Request.URL.Query().Encode()
|
q := c.Request.URL.Query().Encode()
|
||||||
if q != "" {
|
if q != "" {
|
||||||
q = fmt.Sprintf("?%s", q)
|
q = fmt.Sprintf("?%s", q)
|
||||||
|
|
|
@ -55,11 +55,11 @@ func initConf(c string) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = db.InitDb()
|
database, err := db.InitDb()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
model.InitDB(db.NewSqlxDb(db.Db))
|
model.InitDB(model.NewSqlxQuery(database))
|
||||||
err = wpconfig.InitOptions()
|
err = wpconfig.InitOptions()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -72,7 +72,7 @@ func initConf(c string) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func cronClearCache() {
|
func cronClearCache() {
|
||||||
t := time.NewTicker(config.Conf.Load().CrontabClearCacheTime)
|
t := time.NewTicker(config.GetConfig().CacheTime.CrontabClearCacheTime)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-t.C:
|
case <-t.C:
|
||||||
|
@ -85,7 +85,7 @@ func cronClearCache() {
|
||||||
func flushCache() {
|
func flushCache() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
err := mail.SendMail([]string{config.Conf.Load().Mail.User}, "清空缓存失败", fmt.Sprintf("err:[%s]", r))
|
err := mail.SendMail([]string{config.GetConfig().Mail.User}, "清空缓存失败", fmt.Sprintf("err:[%s]", r))
|
||||||
logs.ErrPrintln(err, "发邮件失败")
|
logs.ErrPrintln(err, "发邮件失败")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -129,7 +129,7 @@ func signalNotify() {
|
||||||
func main() {
|
func main() {
|
||||||
go signalNotify()
|
go signalNotify()
|
||||||
Gin, reloadFn := route.SetupRouter()
|
Gin, reloadFn := route.SetupRouter()
|
||||||
c := config.Conf.Load()
|
c := config.GetConfig()
|
||||||
middleWareReloadFn = reloadFn
|
middleWareReloadFn = reloadFn
|
||||||
if c.Ssl.Key != "" && c.Ssl.Cert != "" {
|
if c.Ssl.Key != "" && c.Ssl.Cert != "" {
|
||||||
err := Gin.RunTLS(address, c.Ssl.Cert, c.Ssl.Key)
|
err := Gin.RunTLS(address, c.Ssl.Cert, c.Ssl.Key)
|
||||||
|
|
|
@ -18,7 +18,7 @@ func SetupRouter() (*gin.Engine, func()) {
|
||||||
// Disable Console Color
|
// Disable Console Color
|
||||||
// gin.DisableConsoleColor()
|
// gin.DisableConsoleColor()
|
||||||
r := gin.New()
|
r := gin.New()
|
||||||
c := config.Conf.Load()
|
c := config.GetConfig()
|
||||||
if len(c.TrustIps) > 0 {
|
if len(c.TrustIps) > 0 {
|
||||||
err := r.SetTrustedProxies(c.TrustIps)
|
err := r.SetTrustedProxies(c.TrustIps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -29,7 +29,7 @@ func SetupRouter() (*gin.Engine, func()) {
|
||||||
r.HTMLRender = theme.GetTemplate()
|
r.HTMLRender = theme.GetTemplate()
|
||||||
|
|
||||||
validServerName, reloadValidServerNameFn := middleware.ValidateServerNames()
|
validServerName, reloadValidServerNameFn := middleware.ValidateServerNames()
|
||||||
fl, flReload := middleware.FlowLimit(c.MaxRequestSleepNum, c.MaxRequestNum, c.SleepTime)
|
fl, flReload := middleware.FlowLimit(c.MaxRequestSleepNum, c.MaxRequestNum, c.CacheTime.SleepTime)
|
||||||
r.Use(
|
r.Use(
|
||||||
gin.Logger(),
|
gin.Logger(),
|
||||||
validServerName,
|
validServerName,
|
||||||
|
@ -76,15 +76,15 @@ func SetupRouter() (*gin.Engine, func()) {
|
||||||
r.GET("/p/:id/feed", actions.PostFeed)
|
r.GET("/p/:id/feed", actions.PostFeed)
|
||||||
r.GET("/feed", actions.Feed)
|
r.GET("/feed", actions.Feed)
|
||||||
r.GET("/comments/feed", actions.CommentsFeed)
|
r.GET("/comments/feed", actions.CommentsFeed)
|
||||||
cfl, _ := middleware.FlowLimit(c.MaxRequestSleepNum, 5, c.SleepTime)
|
cfl, _ := middleware.FlowLimit(c.MaxRequestSleepNum, 5, c.CacheTime.SleepTime)
|
||||||
r.POST("/comment", cfl, actions.PostComment)
|
r.POST("/comment", cfl, actions.PostComment)
|
||||||
if c.Pprof != "" {
|
if c.Pprof != "" {
|
||||||
pprof.Register(r, c.Pprof)
|
pprof.Register(r, c.Pprof)
|
||||||
}
|
}
|
||||||
fn := func() {
|
fn := func() {
|
||||||
reloadValidServerNameFn()
|
reloadValidServerNameFn()
|
||||||
c := config.Conf.Load()
|
c := config.GetConfig()
|
||||||
flReload(c.MaxRequestSleepNum, c.MaxRequestNum, c.SleepTime)
|
flReload(c.MaxRequestSleepNum, c.MaxRequestNum, c.CacheTime.SleepTime)
|
||||||
slRload(c.SingleIpSearchNum)
|
slRload(c.SingleIpSearchNum)
|
||||||
}
|
}
|
||||||
return r, fn
|
return r, fn
|
||||||
|
|
|
@ -18,7 +18,7 @@ func SendMail(mailTo []string, subject string, body string, files ...string) err
|
||||||
m := gomail.NewMessage(
|
m := gomail.NewMessage(
|
||||||
gomail.SetEncoding(gomail.Base64),
|
gomail.SetEncoding(gomail.Base64),
|
||||||
)
|
)
|
||||||
c := config.Conf.Load()
|
c := config.GetConfig()
|
||||||
m.SetHeader("From",
|
m.SetHeader("From",
|
||||||
m.FormatAddress(c.Mail.User,
|
m.FormatAddress(c.Mail.User,
|
||||||
c.Mail.Alias,
|
c.Mail.Alias,
|
||||||
|
|
|
@ -43,7 +43,7 @@ func RecoverAndSendMail(w io.Writer) func(ctx *gin.Context) {
|
||||||
)
|
)
|
||||||
|
|
||||||
er := mail.SendMail(
|
er := mail.SendMail(
|
||||||
[]string{config.Conf.Load().Mail.User},
|
[]string{config.GetConfig().Mail.User},
|
||||||
fmt.Sprintf("%s%s %s 发生错误", fmt.Sprintf(wpconfig.Options.Value("siteurl")), c.FullPath(), time.Now().Format(time.RFC1123Z)), content)
|
fmt.Sprintf("%s%s %s 发生错误", fmt.Sprintf(wpconfig.Options.Value("siteurl")), c.FullPath(), time.Now().Format(time.RFC1123Z)), content)
|
||||||
|
|
||||||
if er != nil {
|
if er != nil {
|
||||||
|
|
|
@ -1,15 +1,26 @@
|
||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/fthvgb1/wp-go/helper/slice"
|
"fmt"
|
||||||
|
"github.com/fthvgb1/wp-go/internal/pkg/config"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var path = map[string]struct{}{
|
||||||
|
"wp-includes": {},
|
||||||
|
"wp-content": {},
|
||||||
|
"favicon.ico": {},
|
||||||
|
}
|
||||||
|
|
||||||
func SetStaticFileCache(c *gin.Context) {
|
func SetStaticFileCache(c *gin.Context) {
|
||||||
f := strings.Split(strings.TrimLeft(c.FullPath(), "/"), "/")
|
f := strings.Split(strings.TrimLeft(c.FullPath(), "/"), "/")
|
||||||
if len(f) > 0 && slice.IsContained(f[0], []string{"wp-includes", "wp-content", "favicon.ico"}) {
|
if _, ok := path[f[0]]; ok {
|
||||||
c.Header("Cache-Control", "private, max-age=86400")
|
t := config.GetConfig().CacheTime.CacheControl
|
||||||
|
if t > 0 {
|
||||||
|
c.Header("Cache-Control", fmt.Sprintf("private, max-age=%d", int(t.Seconds())))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
func ValidateServerNames() (func(ctx *gin.Context), func()) {
|
func ValidateServerNames() (func(ctx *gin.Context), func()) {
|
||||||
var serverName safety.Map[string, struct{}]
|
var serverName safety.Map[string, struct{}]
|
||||||
fn := func() {
|
fn := func() {
|
||||||
r := config.Conf.Load().TrustServerNames
|
r := config.GetConfig().TrustServerNames
|
||||||
if len(r) > 0 {
|
if len(r) > 0 {
|
||||||
for _, name := range r {
|
for _, name := range r {
|
||||||
serverName.Store(name, struct{}{})
|
serverName.Store(name, struct{}{})
|
||||||
|
|
104
internal/pkg/cache/cache.go
vendored
104
internal/pkg/cache/cache.go
vendored
|
@ -3,11 +3,13 @@ package cache
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/fthvgb1/wp-go/cache"
|
"github.com/fthvgb1/wp-go/cache"
|
||||||
|
"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/internal/pkg/config"
|
"github.com/fthvgb1/wp-go/internal/pkg/config"
|
||||||
"github.com/fthvgb1/wp-go/internal/pkg/dao"
|
"github.com/fthvgb1/wp-go/internal/pkg/dao"
|
||||||
"github.com/fthvgb1/wp-go/internal/pkg/logs"
|
"github.com/fthvgb1/wp-go/internal/pkg/logs"
|
||||||
"github.com/fthvgb1/wp-go/internal/pkg/models"
|
"github.com/fthvgb1/wp-go/internal/pkg/models"
|
||||||
|
"github.com/fthvgb1/wp-go/internal/plugins"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -46,39 +48,43 @@ var headerImagesCache *cache.MapCache[string, []models.PostThumbnail]
|
||||||
var ctx context.Context
|
var ctx context.Context
|
||||||
|
|
||||||
func InitActionsCommonCache() {
|
func InitActionsCommonCache() {
|
||||||
c := config.Conf.Load()
|
c := config.GetConfig()
|
||||||
archivesCaches = &Arch{
|
archivesCaches = &Arch{
|
||||||
mutex: &sync.Mutex{},
|
mutex: &sync.Mutex{},
|
||||||
setCacheFunc: dao.Archives,
|
fn: dao.Archives,
|
||||||
}
|
}
|
||||||
|
|
||||||
searchPostIdsCache = cache.NewMemoryMapCacheByFn[string](dao.SearchPostIds, c.SearchPostCacheTime)
|
searchPostIdsCache = cache.NewMemoryMapCacheByFn[string](dao.SearchPostIds, c.CacheTime.SearchPostCacheTime)
|
||||||
|
|
||||||
postListIdsCache = cache.NewMemoryMapCacheByFn[string](dao.SearchPostIds, c.PostListCacheTime)
|
postListIdsCache = cache.NewMemoryMapCacheByFn[string](dao.SearchPostIds, c.CacheTime.PostListCacheTime)
|
||||||
|
|
||||||
monthPostsCache = cache.NewMemoryMapCacheByFn[string](dao.MonthPost, c.MonthPostCacheTime)
|
monthPostsCache = cache.NewMemoryMapCacheByFn[string](dao.MonthPost, c.CacheTime.MonthPostCacheTime)
|
||||||
|
|
||||||
postContextCache = cache.NewMemoryMapCacheByFn[uint64](dao.GetPostContext, c.ContextPostCacheTime)
|
postContextCache = cache.NewMemoryMapCacheByFn[uint64](dao.GetPostContext, c.CacheTime.ContextPostCacheTime)
|
||||||
|
|
||||||
postsCache = cache.NewMemoryMapCacheByBatchFn(dao.GetPostsByIds, c.PostDataCacheTime)
|
postsCache = cache.NewMemoryMapCacheByBatchFn(dao.GetPostsByIds, c.CacheTime.PostDataCacheTime)
|
||||||
|
|
||||||
postMetaCache = cache.NewMemoryMapCacheByBatchFn(dao.GetPostMetaByPostIds, c.PostDataCacheTime)
|
postMetaCache = cache.NewMemoryMapCacheByBatchFn(dao.GetPostMetaByPostIds, c.CacheTime.PostDataCacheTime)
|
||||||
|
|
||||||
categoryAndTagsCaches = cache.NewVarCache(dao.CategoriesAndTags, c.CategoryCacheTime)
|
categoryAndTagsCaches = cache.NewVarCache(dao.CategoriesAndTags, c.CacheTime.CategoryCacheTime)
|
||||||
|
|
||||||
recentPostsCaches = cache.NewVarCache(dao.RecentPosts, c.RecentPostCacheTime)
|
recentPostsCaches = cache.NewVarCache(dao.RecentPosts, c.CacheTime.RecentPostCacheTime)
|
||||||
|
|
||||||
recentCommentsCaches = cache.NewVarCache(dao.RecentComments, c.RecentCommentsCacheTime)
|
recentCommentsCaches = cache.NewVarCache(dao.RecentComments, c.CacheTime.RecentCommentsCacheTime)
|
||||||
|
|
||||||
postCommentCaches = cache.NewMemoryMapCacheByFn[uint64](dao.PostComments, c.PostCommentsCacheTime)
|
postCommentCaches = cache.NewMemoryMapCacheByFn[uint64](dao.PostComments, c.CacheTime.PostCommentsCacheTime)
|
||||||
|
|
||||||
maxPostIdCache = cache.NewVarCache(dao.GetMaxPostId, c.MaxPostIdCacheTime)
|
maxPostIdCache = cache.NewVarCache(dao.GetMaxPostId, c.CacheTime.MaxPostIdCacheTime)
|
||||||
|
|
||||||
usersCache = cache.NewMemoryMapCacheByFn[uint64](dao.GetUserById, c.UserInfoCacheTime)
|
usersCache = cache.NewMemoryMapCacheByFn[uint64](dao.GetUserById, c.CacheTime.UserInfoCacheTime)
|
||||||
|
|
||||||
usersNameCache = cache.NewMemoryMapCacheByFn[string](dao.GetUserByName, c.UserInfoCacheTime)
|
usersNameCache = cache.NewMemoryMapCacheByFn[string](dao.GetUserByName, c.CacheTime.UserInfoCacheTime)
|
||||||
|
|
||||||
commentsCache = cache.NewMemoryMapCacheByBatchFn(dao.GetCommentByIds, c.CommentsCacheTime)
|
commentsCache = cache.NewMemoryMapCacheByBatchFn(dao.GetCommentByIds, c.CacheTime.CommentsCacheTime)
|
||||||
|
|
||||||
|
allUsernameCache = cache.NewVarCache(dao.AllUsername, c.CacheTime.UserInfoCacheTime)
|
||||||
|
|
||||||
|
headerImagesCache = cache.NewMemoryMapCacheByFn[string](getHeaderImages, c.CacheTime.ThemeHeaderImagCacheTime)
|
||||||
|
|
||||||
feedCache = cache.NewVarCache(feed, time.Hour)
|
feedCache = cache.NewVarCache(feed, time.Hour)
|
||||||
|
|
||||||
|
@ -88,10 +94,6 @@ func InitActionsCommonCache() {
|
||||||
|
|
||||||
newCommentCache = cache.NewMemoryMapCacheByFn[string, string](nil, 15*time.Minute)
|
newCommentCache = cache.NewMemoryMapCacheByFn[string, string](nil, 15*time.Minute)
|
||||||
|
|
||||||
allUsernameCache = cache.NewVarCache(dao.AllUsername, c.UserInfoCacheTime)
|
|
||||||
|
|
||||||
headerImagesCache = cache.NewMemoryMapCacheByFn[string](getHeaderImages, c.ThemeHeaderImagCacheTime)
|
|
||||||
|
|
||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
|
|
||||||
InitFeed()
|
InitFeed()
|
||||||
|
@ -132,62 +134,44 @@ func Archives(ctx context.Context) (r []models.PostArchive) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Arch struct {
|
type Arch struct {
|
||||||
data []models.PostArchive
|
data []models.PostArchive
|
||||||
mutex *sync.Mutex
|
mutex *sync.Mutex
|
||||||
setCacheFunc func(context.Context) ([]models.PostArchive, error)
|
fn func(context.Context) ([]models.PostArchive, error)
|
||||||
month time.Month
|
month time.Month
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Arch) getArchiveCache(ctx context.Context) []models.PostArchive {
|
func (a *Arch) getArchiveCache(ctx context.Context) []models.PostArchive {
|
||||||
l := len(c.data)
|
l := len(a.data)
|
||||||
m := time.Now().Month()
|
m := time.Now().Month()
|
||||||
if l > 0 && c.month != m || l < 1 {
|
if l > 0 && a.month != m || l < 1 {
|
||||||
r, err := c.setCacheFunc(ctx)
|
r, err := a.fn(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.ErrPrintln(err, "set cache err[%s]")
|
logs.ErrPrintln(err, "set cache err[%s]")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
c.mutex.Lock()
|
a.mutex.Lock()
|
||||||
defer c.mutex.Unlock()
|
defer a.mutex.Unlock()
|
||||||
c.month = m
|
a.month = m
|
||||||
c.data = r
|
a.data = r
|
||||||
}
|
}
|
||||||
return c.data
|
return a.data
|
||||||
}
|
}
|
||||||
|
|
||||||
func Categories(ctx context.Context) []models.TermsMy {
|
func CategoriesTags(ctx context.Context, t ...int) []models.TermsMy {
|
||||||
r, err := categoryAndTagsCaches.GetCache(ctx, time.Second, ctx)
|
r, err := categoryAndTagsCaches.GetCache(ctx, time.Second, ctx)
|
||||||
logs.ErrPrintln(err, "get category err")
|
logs.ErrPrintln(err, "get category err")
|
||||||
r = slice.Filter(r, func(my models.TermsMy) bool {
|
if len(t) > 0 {
|
||||||
return my.Taxonomy == "category"
|
return slice.Filter(r, func(my models.TermsMy) bool {
|
||||||
})
|
return helper.Or(t[0] == plugins.Tag, "post_tag", "category") == my.Taxonomy
|
||||||
|
})
|
||||||
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
func AllCategoryTagsNames(ctx context.Context, c int) map[string]struct{} {
|
||||||
func Tags(ctx context.Context) []models.TermsMy {
|
|
||||||
r, err := categoryAndTagsCaches.GetCache(ctx, time.Second, ctx)
|
|
||||||
logs.ErrPrintln(err, "get category err")
|
|
||||||
r = slice.Filter(r, func(my models.TermsMy) bool {
|
|
||||||
return my.Taxonomy == "post_tag"
|
|
||||||
})
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
func AllTagsNames(ctx context.Context) map[string]struct{} {
|
|
||||||
r, err := categoryAndTagsCaches.GetCache(ctx, time.Second, ctx)
|
r, err := categoryAndTagsCaches.GetCache(ctx, time.Second, ctx)
|
||||||
logs.ErrPrintln(err, "get category err")
|
logs.ErrPrintln(err, "get category err")
|
||||||
return slice.FilterAndToMap(r, func(t models.TermsMy) (string, struct{}, bool) {
|
return slice.FilterAndToMap(r, func(t models.TermsMy) (string, struct{}, bool) {
|
||||||
if t.Taxonomy == "post_tag" {
|
if helper.Or(c == plugins.Tag, "post_tag", "category") == t.Taxonomy {
|
||||||
return t.Name, struct{}{}, true
|
|
||||||
}
|
|
||||||
return "", struct{}{}, false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func AllCategoryNames(ctx context.Context) map[string]struct{} {
|
|
||||||
r, err := categoryAndTagsCaches.GetCache(ctx, time.Second, ctx)
|
|
||||||
logs.ErrPrintln(err, "get category err")
|
|
||||||
return slice.FilterAndToMap(r, func(t models.TermsMy) (string, struct{}, bool) {
|
|
||||||
if t.Taxonomy == "category" {
|
|
||||||
return t.Name, struct{}{}, true
|
return t.Name, struct{}{}, true
|
||||||
}
|
}
|
||||||
return "", struct{}{}, false
|
return "", struct{}{}, false
|
||||||
|
|
46
internal/pkg/cache/feed.go
vendored
46
internal/pkg/cache/feed.go
vendored
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/fthvgb1/wp-go/cache"
|
"github.com/fthvgb1/wp-go/cache"
|
||||||
"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/internal/pkg/logs"
|
"github.com/fthvgb1/wp-go/internal/pkg/logs"
|
||||||
"github.com/fthvgb1/wp-go/internal/pkg/models"
|
"github.com/fthvgb1/wp-go/internal/pkg/models"
|
||||||
"github.com/fthvgb1/wp-go/internal/plugins"
|
"github.com/fthvgb1/wp-go/internal/plugins"
|
||||||
|
@ -11,7 +12,6 @@ import (
|
||||||
"github.com/fthvgb1/wp-go/plugin/digest"
|
"github.com/fthvgb1/wp-go/plugin/digest"
|
||||||
"github.com/fthvgb1/wp-go/rss2"
|
"github.com/fthvgb1/wp-go/rss2"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -46,7 +46,7 @@ func PostFeedCache() *cache.MapCache[string, string] {
|
||||||
|
|
||||||
func feed(arg ...any) (xml []string, err error) {
|
func feed(arg ...any) (xml []string, err error) {
|
||||||
c := arg[0].(*gin.Context)
|
c := arg[0].(*gin.Context)
|
||||||
r := RecentPosts(c, 10)
|
r := RecentPosts(c, 10, true)
|
||||||
ids := slice.Map(r, func(t models.Posts) uint64 {
|
ids := slice.Map(r, func(t models.Posts) uint64 {
|
||||||
return t.Id
|
return t.Id
|
||||||
})
|
})
|
||||||
|
@ -54,21 +54,22 @@ func feed(arg ...any) (xml []string, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
site := wpconfig.Options.Value("siteurl")
|
||||||
rs := templateRss
|
rs := templateRss
|
||||||
rs.LastBuildDate = time.Now().Format(timeFormat)
|
rs.LastBuildDate = time.Now().Format(timeFormat)
|
||||||
rs.Items = slice.Map(posts, func(t models.Posts) rss2.Item {
|
rs.Items = slice.Map(posts, func(t models.Posts) rss2.Item {
|
||||||
desc := "无法提供摘要。这是一篇受保护的文章。"
|
desc := "无法提供摘要。这是一篇受保护的文章。"
|
||||||
plugins.PasswordProjectTitle(&t)
|
|
||||||
if t.PostPassword != "" {
|
if t.PostPassword != "" {
|
||||||
|
plugins.PasswordProjectTitle(&t)
|
||||||
plugins.PasswdProjectContent(&t)
|
plugins.PasswdProjectContent(&t)
|
||||||
} else {
|
} else {
|
||||||
desc = digest.Raw(t.PostContent, 55, fmt.Sprintf("/p/%d", t.Id))
|
desc = digest.Raw(t.PostContent, 55, fmt.Sprintf("/p/%d", t.Id))
|
||||||
}
|
}
|
||||||
l := ""
|
l := ""
|
||||||
if t.CommentStatus == "open" && t.CommentCount > 0 {
|
if t.CommentStatus == "open" && t.CommentCount > 0 {
|
||||||
l = fmt.Sprintf("%s/p/%d#comments", wpconfig.Options.Value("siteurl"), t.Id)
|
l = fmt.Sprintf("%s/p/%d#comments", site, t.Id)
|
||||||
} else if t.CommentStatus == "open" && t.CommentCount == 0 {
|
} else if t.CommentStatus == "open" && t.CommentCount == 0 {
|
||||||
l = fmt.Sprintf("%s/p/%d#respond", wpconfig.Options.Value("siteurl"), t.Id)
|
l = fmt.Sprintf("%s/p/%d#respond", site, t.Id)
|
||||||
}
|
}
|
||||||
user := GetUserById(c, t.PostAuthor)
|
user := GetUserById(c, t.PostAuthor)
|
||||||
|
|
||||||
|
@ -80,8 +81,8 @@ func feed(arg ...any) (xml []string, err error) {
|
||||||
Content: t.PostContent,
|
Content: t.PostContent,
|
||||||
Category: strings.Join(t.Categories, "、"),
|
Category: strings.Join(t.Categories, "、"),
|
||||||
CommentLink: l,
|
CommentLink: l,
|
||||||
CommentRss: fmt.Sprintf("%s/p/%d/feed", wpconfig.Options.Value("siteurl"), t.Id),
|
CommentRss: fmt.Sprintf("%s/p/%d/feed", site, t.Id),
|
||||||
Link: fmt.Sprintf("%s/p/%d", wpconfig.Options.Value("siteurl"), t.Id),
|
Link: fmt.Sprintf("%s/p/%d", site, t.Id),
|
||||||
Description: desc,
|
Description: desc,
|
||||||
PubDate: t.PostDateGmt.Format(timeFormat),
|
PubDate: t.PostDateGmt.Format(timeFormat),
|
||||||
}
|
}
|
||||||
|
@ -93,42 +94,36 @@ func feed(arg ...any) (xml []string, err error) {
|
||||||
func postFeed(arg ...any) (x string, err error) {
|
func postFeed(arg ...any) (x string, err error) {
|
||||||
c := arg[0].(*gin.Context)
|
c := arg[0].(*gin.Context)
|
||||||
id := arg[1].(string)
|
id := arg[1].(string)
|
||||||
Id := 0
|
ID := str.ToInteger[uint64](id, 0)
|
||||||
if id != "" {
|
|
||||||
Id, err = strconv.Atoi(id)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ID := uint64(Id)
|
|
||||||
maxId, err := GetMaxPostId(c)
|
maxId, err := GetMaxPostId(c)
|
||||||
logs.ErrPrintln(err, "get max post id")
|
logs.ErrPrintln(err, "get max post id")
|
||||||
if ID > maxId || err != nil {
|
if ID < 1 || ID > maxId || err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
post, err := GetPostById(c, ID)
|
post, err := GetPostById(c, ID)
|
||||||
if post.Id == 0 || err != nil {
|
if post.Id == 0 || err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
plugins.PasswordProjectTitle(&post)
|
|
||||||
comments, err := PostComments(c, post.Id)
|
comments, err := PostComments(c, post.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rs := templateRss
|
rs := templateRss
|
||||||
|
site := wpconfig.Options.Value("siteurl")
|
||||||
|
|
||||||
rs.Title = fmt.Sprintf("《%s》的评论", post.PostTitle)
|
rs.Title = fmt.Sprintf("《%s》的评论", post.PostTitle)
|
||||||
rs.AtomLink = fmt.Sprintf("%s/p/%d/feed", wpconfig.Options.Value("siteurl"), post.Id)
|
rs.AtomLink = fmt.Sprintf("%s/p/%d/feed", site, post.Id)
|
||||||
rs.Link = fmt.Sprintf("%s/p/%d", wpconfig.Options.Value("siteurl"), post.Id)
|
rs.Link = fmt.Sprintf("%s/p/%d", site, post.Id)
|
||||||
rs.LastBuildDate = time.Now().Format(timeFormat)
|
rs.LastBuildDate = time.Now().Format(timeFormat)
|
||||||
if post.PostPassword != "" {
|
if post.PostPassword != "" {
|
||||||
|
plugins.PasswordProjectTitle(&post)
|
||||||
|
plugins.PasswdProjectContent(&post)
|
||||||
if len(comments) > 0 {
|
if len(comments) > 0 {
|
||||||
plugins.PasswdProjectContent(&post)
|
|
||||||
t := comments[len(comments)-1]
|
t := comments[len(comments)-1]
|
||||||
rs.Items = []rss2.Item{
|
rs.Items = []rss2.Item{
|
||||||
{
|
{
|
||||||
Title: fmt.Sprintf("评价者:%s", t.CommentAuthor),
|
Title: fmt.Sprintf("评价者:%s", t.CommentAuthor),
|
||||||
Link: fmt.Sprintf("%s/p/%d#comment-%d", wpconfig.Options.Value("siteurl"), post.Id, t.CommentId),
|
Link: fmt.Sprintf("%s/p/%d#comment-%d", site, post.Id, t.CommentId),
|
||||||
Creator: t.CommentAuthor,
|
Creator: t.CommentAuthor,
|
||||||
PubDate: t.CommentDateGmt.Format(timeFormat),
|
PubDate: t.CommentDateGmt.Format(timeFormat),
|
||||||
Guid: fmt.Sprintf("%s#comment-%d", post.Guid, t.CommentId),
|
Guid: fmt.Sprintf("%s#comment-%d", post.Guid, t.CommentId),
|
||||||
|
@ -141,7 +136,7 @@ func postFeed(arg ...any) (x string, err error) {
|
||||||
rs.Items = slice.Map(comments, func(t models.Comments) rss2.Item {
|
rs.Items = slice.Map(comments, func(t models.Comments) 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", wpconfig.Options.Value("siteurl"), post.Id, t.CommentId),
|
Link: fmt.Sprintf("%s/p/%d#comment-%d", site, post.Id, t.CommentId),
|
||||||
Creator: t.CommentAuthor,
|
Creator: t.CommentAuthor,
|
||||||
PubDate: t.CommentDateGmt.Format(timeFormat),
|
PubDate: t.CommentDateGmt.Format(timeFormat),
|
||||||
Guid: fmt.Sprintf("%s#comment-%d", post.Guid, t.CommentId),
|
Guid: fmt.Sprintf("%s#comment-%d", post.Guid, t.CommentId),
|
||||||
|
@ -160,7 +155,8 @@ func commentsFeed(args ...any) (r []string, err error) {
|
||||||
rs := templateRss
|
rs := templateRss
|
||||||
rs.Title = fmt.Sprintf("\"%s\"的评论", wpconfig.Options.Value("blogname"))
|
rs.Title = fmt.Sprintf("\"%s\"的评论", wpconfig.Options.Value("blogname"))
|
||||||
rs.LastBuildDate = time.Now().Format(timeFormat)
|
rs.LastBuildDate = time.Now().Format(timeFormat)
|
||||||
rs.AtomLink = fmt.Sprintf("%s/comments/feed", wpconfig.Options.Value("siteurl"))
|
site := wpconfig.Options.Value("siteurl")
|
||||||
|
rs.AtomLink = fmt.Sprintf("%s/comments/feed", site)
|
||||||
com, err := GetCommentByIds(c, slice.Map(commens, func(t models.Comments) uint64 {
|
com, err := GetCommentByIds(c, slice.Map(commens, func(t models.Comments) uint64 {
|
||||||
return t.CommentId
|
return t.CommentId
|
||||||
}))
|
}))
|
||||||
|
@ -169,10 +165,10 @@ func commentsFeed(args ...any) (r []string, err error) {
|
||||||
}
|
}
|
||||||
rs.Items = slice.Map(com, func(t models.Comments) rss2.Item {
|
rs.Items = slice.Map(com, func(t models.Comments) rss2.Item {
|
||||||
post, _ := GetPostById(c, t.CommentPostId)
|
post, _ := GetPostById(c, t.CommentPostId)
|
||||||
plugins.PasswordProjectTitle(&post)
|
|
||||||
desc := "评论受保护:要查看请输入密码。"
|
desc := "评论受保护:要查看请输入密码。"
|
||||||
content := t.CommentContent
|
content := t.CommentContent
|
||||||
if post.PostPassword != "" {
|
if post.PostPassword != "" {
|
||||||
|
plugins.PasswordProjectTitle(&post)
|
||||||
plugins.PasswdProjectContent(&post)
|
plugins.PasswdProjectContent(&post)
|
||||||
content = post.PostContent
|
content = post.PostContent
|
||||||
} else {
|
} else {
|
||||||
|
@ -181,7 +177,7 @@ func commentsFeed(args ...any) (r []string, err error) {
|
||||||
}
|
}
|
||||||
return rss2.Item{
|
return rss2.Item{
|
||||||
Title: fmt.Sprintf("%s对《%s》的评论", t.CommentAuthor, post.PostTitle),
|
Title: fmt.Sprintf("%s对《%s》的评论", t.CommentAuthor, post.PostTitle),
|
||||||
Link: fmt.Sprintf("%s/p/%d#comment-%d", wpconfig.Options.Value("siteurl"), post.Id, t.CommentId),
|
Link: fmt.Sprintf("%s/p/%d#comment-%d", site, post.Id, t.CommentId),
|
||||||
Creator: t.CommentAuthor,
|
Creator: t.CommentAuthor,
|
||||||
Description: desc,
|
Description: desc,
|
||||||
PubDate: t.CommentDateGmt.Format(timeFormat),
|
PubDate: t.CommentDateGmt.Format(timeFormat),
|
||||||
|
|
17
internal/pkg/cache/posts.go
vendored
17
internal/pkg/cache/posts.go
vendored
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/fthvgb1/wp-go/helper/slice"
|
"github.com/fthvgb1/wp-go/helper/slice"
|
||||||
"github.com/fthvgb1/wp-go/internal/pkg/logs"
|
"github.com/fthvgb1/wp-go/internal/pkg/logs"
|
||||||
"github.com/fthvgb1/wp-go/internal/pkg/models"
|
"github.com/fthvgb1/wp-go/internal/pkg/models"
|
||||||
|
"github.com/fthvgb1/wp-go/internal/plugins"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -42,11 +43,23 @@ func GetMaxPostId(ctx *gin.Context) (uint64, error) {
|
||||||
return maxPostIdCache.GetCache(ctx, time.Second, ctx)
|
return maxPostIdCache.GetCache(ctx, time.Second, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RecentPosts(ctx context.Context, n int) (r []models.Posts) {
|
func RecentPosts(ctx context.Context, n int, project bool) (r []models.Posts) {
|
||||||
r, err := recentPostsCaches.GetCache(ctx, time.Second, ctx)
|
nn := n
|
||||||
|
if nn <= 5 {
|
||||||
|
nn = 10
|
||||||
|
}
|
||||||
|
r, err := recentPostsCaches.GetCache(ctx, time.Second, ctx, nn)
|
||||||
if n < len(r) {
|
if n < len(r) {
|
||||||
r = r[:n]
|
r = r[:n]
|
||||||
}
|
}
|
||||||
|
if project {
|
||||||
|
r = slice.Map(r, func(t models.Posts) models.Posts {
|
||||||
|
if t.PostPassword != "" {
|
||||||
|
plugins.PasswordProjectTitle(&t)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
})
|
||||||
|
}
|
||||||
logs.ErrPrintln(err, "get recent post")
|
logs.ErrPrintln(err, "get recent post")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,41 +8,50 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Conf safety.Var[Config]
|
var config safety.Var[Config]
|
||||||
|
|
||||||
|
func GetConfig() Config {
|
||||||
|
return config.Load()
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Ssl Ssl `yaml:"ssl"`
|
Ssl Ssl `yaml:"ssl"`
|
||||||
Mysql Mysql `yaml:"mysql"`
|
Mysql Mysql `yaml:"mysql"`
|
||||||
Mail Mail `yaml:"mail"`
|
Mail Mail `yaml:"mail"`
|
||||||
|
CacheTime CacheTime `yaml:"cacheTime"`
|
||||||
|
DigestWordCount int `yaml:"digestWordCount"`
|
||||||
|
MaxRequestSleepNum int64 `yaml:"maxRequestSleepNum"`
|
||||||
|
MaxRequestNum int64 `yaml:"maxRequestNum"`
|
||||||
|
SingleIpSearchNum int64 `yaml:"singleIpSearchNum"`
|
||||||
|
Gzip bool `yaml:"gzip"`
|
||||||
|
PostCommentUrl string `yaml:"postCommentUrl"`
|
||||||
|
TrustIps []string `yaml:"trustIps"`
|
||||||
|
TrustServerNames []string `yaml:"trustServerNames"`
|
||||||
|
Theme string `yaml:"theme"`
|
||||||
|
PostOrder string `yaml:"postOrder"`
|
||||||
|
UploadDir string `yaml:"uploadDir"`
|
||||||
|
Pprof string `yaml:"pprof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CacheTime struct {
|
||||||
|
CacheControl time.Duration `yaml:"cacheControl"`
|
||||||
RecentPostCacheTime time.Duration `yaml:"recentPostCacheTime"`
|
RecentPostCacheTime time.Duration `yaml:"recentPostCacheTime"`
|
||||||
CategoryCacheTime time.Duration `yaml:"categoryCacheTime"`
|
CategoryCacheTime time.Duration `yaml:"categoryCacheTime"`
|
||||||
ArchiveCacheTime time.Duration `yaml:"archiveCacheTime"`
|
ArchiveCacheTime time.Duration `yaml:"archiveCacheTime"`
|
||||||
ContextPostCacheTime time.Duration `yaml:"contextPostCacheTime"`
|
ContextPostCacheTime time.Duration `yaml:"contextPostCacheTime"`
|
||||||
RecentCommentsCacheTime time.Duration `yaml:"recentCommentsCacheTime"`
|
RecentCommentsCacheTime time.Duration `yaml:"recentCommentsCacheTime"`
|
||||||
DigestCacheTime time.Duration `yaml:"digestCacheTime"`
|
DigestCacheTime time.Duration `yaml:"digestCacheTime"`
|
||||||
DigestWordCount int `yaml:"digestWordCount"`
|
|
||||||
PostListCacheTime time.Duration `yaml:"postListCacheTime"`
|
PostListCacheTime time.Duration `yaml:"postListCacheTime"`
|
||||||
SearchPostCacheTime time.Duration `yaml:"searchPostCacheTime"`
|
SearchPostCacheTime time.Duration `yaml:"searchPostCacheTime"`
|
||||||
MonthPostCacheTime time.Duration `yaml:"monthPostCacheTime"`
|
MonthPostCacheTime time.Duration `yaml:"monthPostCacheTime"`
|
||||||
PostDataCacheTime time.Duration `yaml:"postDataCacheTime"`
|
PostDataCacheTime time.Duration `yaml:"postDataCacheTime"`
|
||||||
PostCommentsCacheTime time.Duration `yaml:"postCommentsCacheTime"`
|
PostCommentsCacheTime time.Duration `yaml:"postCommentsCacheTime"`
|
||||||
CrontabClearCacheTime time.Duration `yaml:"crontabClearCacheTime"`
|
CrontabClearCacheTime time.Duration `yaml:"crontabClearCacheTime"`
|
||||||
MaxRequestSleepNum int64 `yaml:"maxRequestSleepNum"`
|
|
||||||
SleepTime []time.Duration `yaml:"sleepTime"`
|
|
||||||
MaxRequestNum int64 `yaml:"maxRequestNum"`
|
|
||||||
SingleIpSearchNum int64 `yaml:"singleIpSearchNum"`
|
|
||||||
MaxPostIdCacheTime time.Duration `yaml:"maxPostIdCacheTime"`
|
MaxPostIdCacheTime time.Duration `yaml:"maxPostIdCacheTime"`
|
||||||
UserInfoCacheTime time.Duration `yaml:"userInfoCacheTime"`
|
UserInfoCacheTime time.Duration `yaml:"userInfoCacheTime"`
|
||||||
CommentsCacheTime time.Duration `yaml:"commentsCacheTime"`
|
CommentsCacheTime time.Duration `yaml:"commentsCacheTime"`
|
||||||
ThemeHeaderImagCacheTime time.Duration `yaml:"themeHeaderImagCacheTime"`
|
ThemeHeaderImagCacheTime time.Duration `yaml:"themeHeaderImagCacheTime"`
|
||||||
Gzip bool `yaml:"gzip"`
|
SleepTime []time.Duration `yaml:"sleepTime"`
|
||||||
PostCommentUrl string `yaml:"postCommentUrl"`
|
|
||||||
TrustIps []string `yaml:"trustIps"`
|
|
||||||
TrustServerNames []string `yaml:"trustServerNames"`
|
|
||||||
Theme string `yaml:"theme"`
|
|
||||||
PostOrder string `yaml:"postOrder"`
|
|
||||||
UploadDir string `yaml:"uploadDir"`
|
|
||||||
Pprof string `yaml:"pprof"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Ssl struct {
|
type Ssl struct {
|
||||||
|
@ -77,7 +86,7 @@ func InitConfig(conf string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
Conf.Store(c)
|
config.Store(c)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,22 +2,26 @@ package dao
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/number"
|
||||||
"github.com/fthvgb1/wp-go/helper/slice"
|
"github.com/fthvgb1/wp-go/helper/slice"
|
||||||
"github.com/fthvgb1/wp-go/internal/pkg/models"
|
"github.com/fthvgb1/wp-go/internal/pkg/models"
|
||||||
"github.com/fthvgb1/wp-go/model"
|
"github.com/fthvgb1/wp-go/model"
|
||||||
"strconv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// RecentComments
|
// RecentComments
|
||||||
// param context.Context
|
// param context.Context
|
||||||
func RecentComments(a ...any) (r []models.Comments, err error) {
|
func RecentComments(a ...any) (r []models.Comments, err error) {
|
||||||
ctx := a[0].(context.Context)
|
ctx := a[0].(context.Context)
|
||||||
return model.Find[models.Comments](ctx, model.SqlBuilder{
|
return model.Finds[models.Comments](ctx, model.Conditions(
|
||||||
{"comment_approved", "1"},
|
model.Where(model.SqlBuilder{
|
||||||
{"post_status", "publish"},
|
{"comment_approved", "1"},
|
||||||
}, "comment_ID,comment_author,comment_post_ID,post_title", "", model.SqlBuilder{{"comment_date_gmt", "desc"}}, model.SqlBuilder{
|
{"post_status", "publish"},
|
||||||
{"a", "left join", "wp_posts b", "a.comment_post_ID=b.ID"},
|
}),
|
||||||
}, nil, 10)
|
model.Fields("comment_ID,comment_author,comment_post_ID,post_title"),
|
||||||
|
model.Order(model.SqlBuilder{{"comment_date_gmt", "desc"}}),
|
||||||
|
model.Join(model.SqlBuilder{{"a", "left join", "wp_posts b", "a.comment_post_ID=b.ID"}}),
|
||||||
|
model.Limit(10),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostComments
|
// PostComments
|
||||||
|
@ -26,13 +30,17 @@ func RecentComments(a ...any) (r []models.Comments, err error) {
|
||||||
func PostComments(args ...any) ([]uint64, error) {
|
func PostComments(args ...any) ([]uint64, error) {
|
||||||
ctx := args[0].(context.Context)
|
ctx := args[0].(context.Context)
|
||||||
postId := args[1].(uint64)
|
postId := args[1].(uint64)
|
||||||
r, err := model.Find[models.Comments](ctx, model.SqlBuilder{
|
r, err := model.Finds[models.Comments](ctx, model.Conditions(
|
||||||
{"comment_approved", "1"},
|
model.Where(model.SqlBuilder{
|
||||||
{"comment_post_ID", "=", strconv.FormatUint(postId, 10), "int"},
|
{"comment_approved", "1"},
|
||||||
}, "comment_ID", "", model.SqlBuilder{
|
{"comment_post_ID", "=", number.ToString(postId), "int"},
|
||||||
{"comment_date_gmt", "asc"},
|
}),
|
||||||
{"comment_ID", "asc"},
|
model.Fields("comment_ID"),
|
||||||
}, nil, nil, 0)
|
model.Order(model.SqlBuilder{
|
||||||
|
{"comment_date_gmt", "asc"},
|
||||||
|
{"comment_ID", "asc"},
|
||||||
|
})),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package dao
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"github.com/fthvgb1/wp-go/internal/pkg/models"
|
"github.com/fthvgb1/wp-go/internal/pkg/models"
|
||||||
"github.com/fthvgb1/wp-go/internal/wpconfig"
|
"github.com/fthvgb1/wp-go/internal/wpconfig"
|
||||||
"github.com/fthvgb1/wp-go/model"
|
"github.com/fthvgb1/wp-go/model"
|
||||||
|
@ -20,23 +19,21 @@ type PostContext struct {
|
||||||
Next models.Posts
|
Next models.Posts
|
||||||
}
|
}
|
||||||
|
|
||||||
func PasswordProjectTitle(post *models.Posts) {
|
|
||||||
if post.PostPassword != "" {
|
|
||||||
post.PostTitle = fmt.Sprintf("密码保护:%s", post.PostTitle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func CategoriesAndTags(a ...any) (terms []models.TermsMy, err error) {
|
func CategoriesAndTags(a ...any) (terms []models.TermsMy, err error) {
|
||||||
ctx := a[0].(context.Context)
|
ctx := a[0].(context.Context)
|
||||||
var in = []any{"category", "post_tag"}
|
var in = []any{"category", "post_tag"}
|
||||||
terms, err = model.Find[models.TermsMy](ctx, model.SqlBuilder{
|
terms, err = model.Finds[models.TermsMy](ctx, model.Conditions(
|
||||||
{"tt.count", ">", "0", "int"},
|
model.Where(model.SqlBuilder{
|
||||||
{"tt.taxonomy", "in", ""},
|
{"tt.count", ">", "0", "int"},
|
||||||
}, "t.term_id", "", model.SqlBuilder{
|
{"tt.taxonomy", "in", ""},
|
||||||
{"t.name", "asc"},
|
}),
|
||||||
}, model.SqlBuilder{
|
model.Fields("t.term_id"),
|
||||||
{"t", "inner join", "wp_term_taxonomy tt", "t.term_id = tt.term_id"},
|
model.Order(model.SqlBuilder{{"t.name", "asc"}}),
|
||||||
}, nil, 0, in)
|
model.Join(model.SqlBuilder{
|
||||||
|
{"t", "inner join", "wp_term_taxonomy tt", "t.term_id = tt.term_id"},
|
||||||
|
}),
|
||||||
|
model.In(in),
|
||||||
|
))
|
||||||
for i := 0; i < len(terms); i++ {
|
for i := 0; i < len(terms); i++ {
|
||||||
if v, ok := wpconfig.Terms.Load(terms[i].Terms.TermId); ok {
|
if v, ok := wpconfig.Terms.Load(terms[i].Terms.TermId); ok {
|
||||||
terms[i].Terms = v
|
terms[i].Terms = v
|
||||||
|
@ -49,7 +46,13 @@ func CategoriesAndTags(a ...any) (terms []models.TermsMy, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Archives(ctx context.Context) ([]models.PostArchive, error) {
|
func Archives(ctx context.Context) ([]models.PostArchive, error) {
|
||||||
return model.Find[models.PostArchive](ctx, model.SqlBuilder{
|
return model.Finds[models.PostArchive](ctx, model.Conditions(
|
||||||
{"post_type", "post"}, {"post_status", "publish"},
|
model.Where(model.SqlBuilder{
|
||||||
}, "YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, count(ID) as posts", "year,month", model.SqlBuilder{{"year", "desc"}, {"month", "desc"}}, nil, nil, 0)
|
{"post_type", "post"},
|
||||||
|
{"post_status", "publish"},
|
||||||
|
}),
|
||||||
|
model.Fields("YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, count(ID) as posts"),
|
||||||
|
model.Group("year,month"),
|
||||||
|
model.Order(model.SqlBuilder{{"year", "desc"}, {"month", "desc"}}),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,10 @@ func GetPostMetaByPostIds(args ...any) (r map[uint64]map[string]any, err error)
|
||||||
r = make(map[uint64]map[string]any)
|
r = make(map[uint64]map[string]any)
|
||||||
ctx := args[0].(context.Context)
|
ctx := args[0].(context.Context)
|
||||||
ids := args[1].([]uint64)
|
ids := args[1].([]uint64)
|
||||||
rr, err := model.Find[models.PostMeta](ctx, model.SqlBuilder{
|
rr, err := model.Finds[models.PostMeta](ctx, model.Conditions(
|
||||||
{"post_id", "in", ""},
|
model.Where(model.SqlBuilder{{"post_id", "in", ""}}),
|
||||||
}, "*", "", nil, nil, nil, 0, slice.ToAnySlice(ids))
|
model.In(slice.ToAnySlice(ids)),
|
||||||
|
))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -24,6 +25,7 @@ func GetPostMetaByPostIds(args ...any) (r map[uint64]map[string]any, err error)
|
||||||
if _, ok := r[postmeta.PostId]; !ok {
|
if _, ok := r[postmeta.PostId]; !ok {
|
||||||
r[postmeta.PostId] = make(map[string]any)
|
r[postmeta.PostId] = make(map[string]any)
|
||||||
}
|
}
|
||||||
|
r[postmeta.PostId][postmeta.MetaKey] = postmeta.MetaValue
|
||||||
if postmeta.MetaKey == "_wp_attachment_metadata" {
|
if postmeta.MetaKey == "_wp_attachment_metadata" {
|
||||||
metadata, err := plugins.UnPHPSerialize[models.WpAttachmentMetadata](postmeta.MetaValue)
|
metadata, err := plugins.UnPHPSerialize[models.WpAttachmentMetadata](postmeta.MetaValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -31,11 +33,7 @@ func GetPostMetaByPostIds(args ...any) (r map[uint64]map[string]any, err error)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
r[postmeta.PostId][postmeta.MetaKey] = metadata
|
r[postmeta.PostId][postmeta.MetaKey] = metadata
|
||||||
|
|
||||||
} else {
|
|
||||||
r[postmeta.PostId][postmeta.MetaKey] = postmeta.MetaValue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,20 +13,21 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetPostsByIds(ids ...any) (m map[uint64]models.Posts, err error) {
|
func GetPostsByIds(a ...any) (m map[uint64]models.Posts, err error) {
|
||||||
ctx := ids[0].(context.Context)
|
ctx := a[0].(context.Context)
|
||||||
m = make(map[uint64]models.Posts)
|
m = make(map[uint64]models.Posts)
|
||||||
id := ids[1].([]uint64)
|
ids := a[1].([]uint64)
|
||||||
arg := slice.ToAnySlice(id)
|
rawPosts, err := model.Finds[models.Posts](ctx, model.Conditions(
|
||||||
rawPosts, err := model.Find[models.Posts](ctx, model.SqlBuilder{{
|
model.Where(model.SqlBuilder{{"Id", "in", ""}}),
|
||||||
"Id", "in", "",
|
model.Join(model.SqlBuilder{
|
||||||
}}, "a.*,ifnull(d.name,'') category_name,ifnull(taxonomy,'') `taxonomy`", "", nil, model.SqlBuilder{{
|
{"a", "left join", "wp_term_relationships b", "a.Id=b.object_id"},
|
||||||
"a", "left join", "wp_term_relationships b", "a.Id=b.object_id",
|
{"left join", "wp_term_taxonomy c", "b.term_taxonomy_id=c.term_taxonomy_id"},
|
||||||
}, {
|
{"left join", "wp_terms d", "c.term_id=d.term_id"},
|
||||||
"left join", "wp_term_taxonomy c", "b.term_taxonomy_id=c.term_taxonomy_id",
|
}),
|
||||||
}, {
|
model.Fields("a.*,ifnull(d.name,'') category_name,ifnull(taxonomy,'') `taxonomy`"),
|
||||||
"left join", "wp_terms d", "c.term_id=d.term_id",
|
model.In(slice.ToAnySlice(ids)),
|
||||||
}}, nil, 0, arg)
|
))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
|
@ -45,7 +46,7 @@ func GetPostsByIds(ids ...any) (m map[uint64]models.Posts, err error) {
|
||||||
}
|
}
|
||||||
//host, _ := wpconfig.Options.Load("siteurl")
|
//host, _ := wpconfig.Options.Load("siteurl")
|
||||||
host := ""
|
host := ""
|
||||||
meta, _ := GetPostMetaByPostIds(ctx, id)
|
meta, _ := GetPostMetaByPostIds(ctx, ids)
|
||||||
for k, pp := range postsMap {
|
for k, pp := range postsMap {
|
||||||
if len(pp.Categories) > 0 {
|
if len(pp.Categories) > 0 {
|
||||||
t := make([]string, 0, len(pp.Categories))
|
t := make([]string, 0, len(pp.Categories))
|
||||||
|
@ -97,7 +98,11 @@ func SearchPostIds(args ...any) (ids PostIds, err error) {
|
||||||
join := args[5].(model.SqlBuilder)
|
join := args[5].(model.SqlBuilder)
|
||||||
postType := args[6].([]any)
|
postType := args[6].([]any)
|
||||||
postStatus := args[7].([]any)
|
postStatus := args[7].([]any)
|
||||||
res, total, err := model.SimplePagination[models.Posts](ctx, where, "ID", "", page, limit, order, join, nil, postType, postStatus)
|
res, total, err := model.SimplePagination[models.Posts](
|
||||||
|
ctx, where, "ID",
|
||||||
|
"", page, limit, order,
|
||||||
|
join, nil, postType, postStatus,
|
||||||
|
)
|
||||||
for _, posts := range res {
|
for _, posts := range res {
|
||||||
ids.Ids = append(ids.Ids, posts.Id)
|
ids.Ids = append(ids.Ids, posts.Id)
|
||||||
}
|
}
|
||||||
|
@ -112,7 +117,10 @@ func SearchPostIds(args ...any) (ids PostIds, err error) {
|
||||||
|
|
||||||
func GetMaxPostId(a ...any) (uint64, error) {
|
func GetMaxPostId(a ...any) (uint64, error) {
|
||||||
ctx := a[0].(context.Context)
|
ctx := a[0].(context.Context)
|
||||||
r, err := model.SimpleFind[models.Posts](ctx, model.SqlBuilder{{"post_type", "post"}, {"post_status", "publish"}}, "max(ID) ID")
|
r, err := model.SimpleFind[models.Posts](ctx,
|
||||||
|
model.SqlBuilder{{"post_type", "post"}, {"post_status", "publish"}},
|
||||||
|
"max(ID) ID",
|
||||||
|
)
|
||||||
var id uint64
|
var id uint64
|
||||||
if len(r) > 0 {
|
if len(r) > 0 {
|
||||||
id = r[0].Id
|
id = r[0].Id
|
||||||
|
@ -122,14 +130,16 @@ func GetMaxPostId(a ...any) (uint64, error) {
|
||||||
|
|
||||||
func RecentPosts(a ...any) (r []models.Posts, err error) {
|
func RecentPosts(a ...any) (r []models.Posts, err error) {
|
||||||
ctx := a[0].(context.Context)
|
ctx := a[0].(context.Context)
|
||||||
r, err = model.Find[models.Posts](ctx, model.SqlBuilder{{
|
num := a[1].(int)
|
||||||
"post_type", "post",
|
r, err = model.Finds[models.Posts](ctx, model.Conditions(
|
||||||
}, {"post_status", "publish"}}, "ID,post_title,post_password", "", model.SqlBuilder{{"post_date", "desc"}}, nil, nil, 10)
|
model.Where(model.SqlBuilder{
|
||||||
for i, post := range r {
|
{"post_type", "post"},
|
||||||
if post.PostPassword != "" {
|
{"post_status", "publish"},
|
||||||
PasswordProjectTitle(&r[i])
|
}),
|
||||||
}
|
model.Fields("ID,post_title,post_password"),
|
||||||
}
|
model.Order(model.SqlBuilder{{"post_date", "desc"}}),
|
||||||
|
model.Limit(num),
|
||||||
|
))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,19 +179,15 @@ func MonthPost(args ...any) (r []uint64, err error) {
|
||||||
ctx := args[0].(context.Context)
|
ctx := args[0].(context.Context)
|
||||||
year, month := args[1].(string), args[2].(string)
|
year, month := args[1].(string), args[2].(string)
|
||||||
where := model.SqlBuilder{
|
where := model.SqlBuilder{
|
||||||
{"post_type", "in", ""},
|
{"post_type", "post"},
|
||||||
{"post_status", "in", ""},
|
{"post_status", "publish"},
|
||||||
{"year(post_date)", year},
|
{"year(post_date)", year},
|
||||||
{"month(post_date)", month},
|
{"month(post_date)", month},
|
||||||
}
|
}
|
||||||
postType := []any{"post"}
|
return model.Column[models.Posts, uint64](ctx, func(v models.Posts) (uint64, bool) {
|
||||||
status := []any{"publish"}
|
return v.Id, true
|
||||||
ids, err := model.Find[models.Posts](ctx, where, "ID", "", model.SqlBuilder{{"Id", "asc"}}, nil, nil, 0, postType, status)
|
}, model.Conditions(
|
||||||
if err != nil {
|
model.Fields("ID"),
|
||||||
return
|
model.Where(where),
|
||||||
}
|
))
|
||||||
for _, post := range ids {
|
|
||||||
r = append(r, post.Id)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,78 +1,32 @@
|
||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"github.com/fthvgb1/wp-go/internal/pkg/config"
|
"github.com/fthvgb1/wp-go/internal/pkg/config"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var Db *sqlx.DB
|
var db *sqlx.DB
|
||||||
|
|
||||||
type SqlxDb struct {
|
func InitDb() (*sqlx.DB, error) {
|
||||||
sqlx *sqlx.DB
|
c := config.GetConfig()
|
||||||
}
|
|
||||||
|
|
||||||
func NewSqlxDb(sqlx *sqlx.DB) *SqlxDb {
|
|
||||||
return &SqlxDb{sqlx: sqlx}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r SqlxDb) Select(ctx context.Context, dest any, sql string, params ...any) error {
|
|
||||||
if os.Getenv("SHOW_SQL") == "true" {
|
|
||||||
go log.Println(formatSql(sql, params))
|
|
||||||
}
|
|
||||||
return r.sqlx.Select(dest, sql, params...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r SqlxDb) Get(ctx context.Context, dest any, sql string, params ...any) error {
|
|
||||||
if os.Getenv("SHOW_SQL") == "true" {
|
|
||||||
go log.Println(formatSql(sql, params))
|
|
||||||
}
|
|
||||||
return r.sqlx.Get(dest, sql, params...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatSql(sql string, params []any) string {
|
|
||||||
for _, param := range params {
|
|
||||||
switch param.(type) {
|
|
||||||
case string:
|
|
||||||
sql = strings.Replace(sql, "?", fmt.Sprintf("'%s'", param.(string)), 1)
|
|
||||||
case int64:
|
|
||||||
sql = strings.Replace(sql, "?", strconv.FormatInt(param.(int64), 10), 1)
|
|
||||||
case int:
|
|
||||||
sql = strings.Replace(sql, "?", strconv.Itoa(param.(int)), 1)
|
|
||||||
case uint64:
|
|
||||||
sql = strings.Replace(sql, "?", strconv.FormatUint(param.(uint64), 10), 1)
|
|
||||||
case float64:
|
|
||||||
sql = strings.Replace(sql, "?", fmt.Sprintf("%f", param.(float64)), 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sql
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitDb() error {
|
|
||||||
c := config.Conf.Load()
|
|
||||||
dsn := c.Mysql.Dsn.GetDsn()
|
dsn := c.Mysql.Dsn.GetDsn()
|
||||||
var err error
|
var err error
|
||||||
Db, err = sqlx.Open("mysql", dsn)
|
db, err = sqlx.Open("mysql", dsn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
if c.Mysql.Pool.ConnMaxIdleTime != 0 {
|
if c.Mysql.Pool.ConnMaxIdleTime != 0 {
|
||||||
Db.SetConnMaxIdleTime(c.Mysql.Pool.ConnMaxLifetime)
|
db.SetConnMaxIdleTime(c.Mysql.Pool.ConnMaxLifetime)
|
||||||
}
|
}
|
||||||
if c.Mysql.Pool.MaxIdleConn != 0 {
|
if c.Mysql.Pool.MaxIdleConn != 0 {
|
||||||
Db.SetMaxIdleConns(c.Mysql.Pool.MaxIdleConn)
|
db.SetMaxIdleConns(c.Mysql.Pool.MaxIdleConn)
|
||||||
}
|
}
|
||||||
if c.Mysql.Pool.MaxOpenConn != 0 {
|
if c.Mysql.Pool.MaxOpenConn != 0 {
|
||||||
Db.SetMaxOpenConns(c.Mysql.Pool.MaxOpenConn)
|
db.SetMaxOpenConns(c.Mysql.Pool.MaxOpenConn)
|
||||||
}
|
}
|
||||||
if c.Mysql.Pool.ConnMaxLifetime != 0 {
|
if c.Mysql.Pool.ConnMaxLifetime != 0 {
|
||||||
Db.SetConnMaxLifetime(c.Mysql.Pool.ConnMaxLifetime)
|
db.SetConnMaxLifetime(c.Mysql.Pool.ConnMaxLifetime)
|
||||||
}
|
}
|
||||||
return err
|
return db, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package models
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type Posts struct {
|
type Posts struct {
|
||||||
|
post
|
||||||
Id uint64 `gorm:"column:ID" db:"ID" json:"ID" form:"ID"`
|
Id uint64 `gorm:"column:ID" db:"ID" json:"ID" form:"ID"`
|
||||||
PostAuthor uint64 `gorm:"column:post_author" db:"post_author" json:"post_author" form:"post_author"`
|
PostAuthor uint64 `gorm:"column:post_author" db:"post_author" json:"post_author" form:"post_author"`
|
||||||
PostDate time.Time `gorm:"column:post_date" db:"post_date" json:"post_date" form:"post_date"`
|
PostDate time.Time `gorm:"column:post_date" db:"post_date" json:"post_date" form:"post_date"`
|
||||||
|
@ -47,23 +48,19 @@ type PostThumbnail struct {
|
||||||
OriginAttachmentData WpAttachmentMetadata
|
OriginAttachmentData WpAttachmentMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w Posts) PrimaryKey() string {
|
type post struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w post) PrimaryKey() string {
|
||||||
return "ID"
|
return "ID"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w Posts) Table() string {
|
func (w post) Table() string {
|
||||||
return "wp_posts"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w PostArchive) PrimaryKey() string {
|
|
||||||
return "ID"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w PostArchive) Table() string {
|
|
||||||
return "wp_posts"
|
return "wp_posts"
|
||||||
}
|
}
|
||||||
|
|
||||||
type PostArchive struct {
|
type PostArchive struct {
|
||||||
|
post
|
||||||
Year string `db:"year"`
|
Year string `db:"year"`
|
||||||
Month string `db:"month"`
|
Month string `db:"month"`
|
||||||
Posts int `db:"posts"`
|
Posts int `db:"posts"`
|
||||||
|
|
|
@ -17,7 +17,7 @@ var ctx context.Context
|
||||||
|
|
||||||
func InitDigestCache() {
|
func InitDigestCache() {
|
||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
digestCache = cache.NewMemoryMapCacheByFn[uint64](digestRaw, config.Conf.Load().DigestCacheTime)
|
digestCache = cache.NewMemoryMapCacheByFn[uint64](digestRaw, config.GetConfig().CacheTime.DigestCacheTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ClearDigestCache() {
|
func ClearDigestCache() {
|
||||||
|
@ -30,7 +30,7 @@ func FlushCache() {
|
||||||
func digestRaw(arg ...any) (string, error) {
|
func digestRaw(arg ...any) (string, error) {
|
||||||
str := arg[0].(string)
|
str := arg[0].(string)
|
||||||
id := arg[1].(uint64)
|
id := arg[1].(uint64)
|
||||||
limit := config.Conf.Load().DigestWordCount
|
limit := config.GetConfig().DigestWordCount
|
||||||
if limit < 0 {
|
if limit < 0 {
|
||||||
return str, nil
|
return str, nil
|
||||||
} else if limit == 0 {
|
} else if limit == 0 {
|
||||||
|
|
|
@ -19,18 +19,14 @@ func ApplyPlugin(p *Plugin[models.Posts], post *models.Posts) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func PasswordProjectTitle(post *models.Posts) {
|
func PasswordProjectTitle(post *models.Posts) {
|
||||||
if post.PostPassword != "" {
|
post.PostTitle = fmt.Sprintf("密码保护:%s", post.PostTitle)
|
||||||
post.PostTitle = fmt.Sprintf("密码保护:%s", post.PostTitle)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func PasswdProjectContent(post *models.Posts) {
|
func PasswdProjectContent(post *models.Posts) {
|
||||||
if post.PostContent != "" {
|
format := `
|
||||||
format := `
|
|
||||||
<form action="/login" class="post-password-form" method="post">
|
<form action="/login" class="post-password-form" method="post">
|
||||||
<p>此内容受密码保护。如需查阅,请在下列字段中输入您的密码。</p>
|
<p>此内容受密码保护。如需查阅,请在下列字段中输入您的密码。</p>
|
||||||
<p><label for="pwbox-%d">密码: <input name="post_password" id="pwbox-%d" type="password" size="20"></label> <input type="submit" name="Submit" value="提交"></p>
|
<p><label for="pwbox-%d">密码: <input name="post_password" id="pwbox-%d" type="password" size="20"></label> <input type="submit" name="Submit" value="提交"></p>
|
||||||
</form>`
|
</form>`
|
||||||
post.PostContent = fmt.Sprintf(format, post.Id, post.Id)
|
post.PostContent = fmt.Sprintf(format, post.Id, post.Id)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ func InitThemeAndTemplateFuncMap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTemplateName() string {
|
func GetTemplateName() string {
|
||||||
tmlp := config.Conf.Load().Theme
|
tmlp := config.GetConfig().Theme
|
||||||
if tmlp == "" {
|
if tmlp == "" {
|
||||||
tmlp = wpconfig.Options.Value("template")
|
tmlp = wpconfig.Options.Value("template")
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,23 +139,16 @@ func (h handle) bodyClass() string {
|
||||||
s := ""
|
s := ""
|
||||||
switch h.scene {
|
switch h.scene {
|
||||||
case plugins.Search:
|
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"
|
s = "search-results"
|
||||||
} else {
|
|
||||||
s = "search-no-results"
|
|
||||||
}
|
}
|
||||||
case plugins.Category:
|
case plugins.Category, plugins.Tag:
|
||||||
cat := h.c.Param("category")
|
cat := h.c.Param("category")
|
||||||
_, cate := slice.SearchFirst(cache.Categories(h.c), func(my models.TermsMy) bool {
|
if cat == "" {
|
||||||
return my.Name == cat
|
cat = h.c.Param("tag")
|
||||||
})
|
|
||||||
if cate.Slug[0] != '%' {
|
|
||||||
s = cate.Slug
|
|
||||||
}
|
}
|
||||||
s = fmt.Sprintf("category-%d %v", cate.Terms.TermId, s)
|
_, cate := slice.SearchFirst(cache.CategoriesTags(h.c, h.scene), func(my models.TermsMy) bool {
|
||||||
case plugins.Tag:
|
|
||||||
cat := h.c.Param("tag")
|
|
||||||
_, cate := slice.SearchFirst(cache.Tags(h.c), func(my models.TermsMy) bool {
|
|
||||||
return my.Name == cat
|
return my.Name == cat
|
||||||
})
|
})
|
||||||
if cate.Slug[0] != '%' {
|
if cate.Slug[0] != '%' {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SimplePagination[T Model](ctx context.Context, where ParseWhere, fields, group string, page, pageSize int, order SqlBuilder, join SqlBuilder, having SqlBuilder, in ...[]any) (r []T, total int, err error) {
|
func pagination[T Model](db dbQuery, ctx context.Context, where ParseWhere, fields, group string, page, pageSize int, order SqlBuilder, join SqlBuilder, having SqlBuilder, in ...[]any) (r []T, total int, err error) {
|
||||||
var rr T
|
var rr T
|
||||||
var w string
|
var w string
|
||||||
var args []any
|
var args []any
|
||||||
|
@ -55,11 +55,11 @@ func SimplePagination[T Model](ctx context.Context, where ParseWhere, fields, gr
|
||||||
if group == "" {
|
if group == "" {
|
||||||
tpx := "select count(*) n from %s %s %s limit 1"
|
tpx := "select count(*) n from %s %s %s limit 1"
|
||||||
sq := fmt.Sprintf(tpx, rr.Table(), j, w)
|
sq := fmt.Sprintf(tpx, rr.Table(), j, w)
|
||||||
err = globalBb.Get(ctx, &n, sq, args...)
|
err = db.Get(ctx, &n, sq, args...)
|
||||||
} else {
|
} else {
|
||||||
tpx := "select count(*) n from (select %s from %s %s %s %s %s ) %s"
|
tpx := "select count(*) n from (select %s from %s %s %s %s %s ) %s"
|
||||||
sq := fmt.Sprintf(tpx, group, rr.Table(), j, w, groupBy, h, fmt.Sprintf("table%d", rand.Int()))
|
sq := fmt.Sprintf(tpx, group, rr.Table(), j, w, groupBy, h, fmt.Sprintf("table%d", rand.Int()))
|
||||||
err = globalBb.Get(ctx, &n, sq, args...)
|
err = db.Get(ctx, &n, sq, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -78,13 +78,18 @@ func SimplePagination[T Model](ctx context.Context, where ParseWhere, fields, gr
|
||||||
}
|
}
|
||||||
tp := "select %s from %s %s %s %s %s %s limit %d,%d"
|
tp := "select %s from %s %s %s %s %s %s limit %d,%d"
|
||||||
sq := fmt.Sprintf(tp, fields, rr.Table(), j, w, groupBy, h, order.parseOrderBy(), offset, pageSize)
|
sq := fmt.Sprintf(tp, fields, rr.Table(), j, w, groupBy, h, order.parseOrderBy(), offset, pageSize)
|
||||||
err = globalBb.Select(ctx, &r, sq, args...)
|
err = db.Select(ctx, &r, sq, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SimplePagination[T Model](ctx context.Context, where ParseWhere, fields, group string, page, pageSize int, order SqlBuilder, join SqlBuilder, having SqlBuilder, in ...[]any) (r []T, total int, err error) {
|
||||||
|
r, total, err = pagination[T](globalBb, ctx, where, fields, group, page, pageSize, order, join, having, in...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func FindOneById[T Model, I constraints.Integer](ctx context.Context, id I) (T, error) {
|
func FindOneById[T Model, I constraints.Integer](ctx context.Context, id I) (T, error) {
|
||||||
var r T
|
var r T
|
||||||
sq := fmt.Sprintf("select * from `%s` where `%s`=?", r.Table(), r.PrimaryKey())
|
sq := fmt.Sprintf("select * from `%s` where `%s`=?", r.Table(), r.PrimaryKey())
|
||||||
|
|
|
@ -3,15 +3,11 @@ package model
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
|
||||||
"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"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"log"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -102,40 +98,6 @@ func (p post) Table() string {
|
||||||
return "wp_posts"
|
return "wp_posts"
|
||||||
}
|
}
|
||||||
|
|
||||||
type SqlxDb struct {
|
|
||||||
sqlx *sqlx.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
var Db *SqlxDb
|
|
||||||
|
|
||||||
func (r SqlxDb) Select(_ context.Context, dest any, sql string, params ...any) error {
|
|
||||||
log.Println(formatSql(sql, params))
|
|
||||||
return r.sqlx.Select(dest, sql, params...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r SqlxDb) Get(_ context.Context, dest any, sql string, params ...any) error {
|
|
||||||
log.Println(formatSql(sql, params))
|
|
||||||
return r.sqlx.Get(dest, sql, params...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatSql(sql string, params []any) string {
|
|
||||||
for _, param := range params {
|
|
||||||
switch param.(type) {
|
|
||||||
case string:
|
|
||||||
sql = strings.Replace(sql, "?", fmt.Sprintf("'%s'", param.(string)), 1)
|
|
||||||
case int64:
|
|
||||||
sql = strings.Replace(sql, "?", strconv.FormatInt(param.(int64), 10), 1)
|
|
||||||
case int:
|
|
||||||
sql = strings.Replace(sql, "?", strconv.Itoa(param.(int)), 1)
|
|
||||||
case uint64:
|
|
||||||
sql = strings.Replace(sql, "?", strconv.FormatUint(param.(uint64), 10), 1)
|
|
||||||
case float64:
|
|
||||||
sql = strings.Replace(sql, "?", fmt.Sprintf("%f", param.(float64)), 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sql
|
|
||||||
}
|
|
||||||
|
|
||||||
var ctx = context.Background()
|
var ctx = context.Background()
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -143,8 +105,7 @@ func init() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
Db = &SqlxDb{db}
|
InitDB(NewSqlxQuery(db))
|
||||||
InitDB(Db)
|
|
||||||
}
|
}
|
||||||
func TestFind(t *testing.T) {
|
func TestFind(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/slice"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -11,6 +12,19 @@ import (
|
||||||
//
|
//
|
||||||
// Conditions 中可用 Where Fields Group Having Join Order Offset Limit In 函数
|
// Conditions 中可用 Where Fields Group Having Join Order Offset Limit In 函数
|
||||||
func Finds[T Model](ctx context.Context, q *QueryCondition) (r []T, err error) {
|
func Finds[T Model](ctx context.Context, q *QueryCondition) (r []T, err error) {
|
||||||
|
r, err = finds[T](globalBb, ctx, q)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DBFind 同 Finds 使用指定 db 查询
|
||||||
|
//
|
||||||
|
// Conditions 中可用 Where Fields Group Having Join Order Offset Limit In 函数
|
||||||
|
func DBFind[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r []T, err error) {
|
||||||
|
r, err = finds[T](db, ctx, q)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func finds[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r []T, err error) {
|
||||||
var rr T
|
var rr T
|
||||||
w := ""
|
w := ""
|
||||||
var args []any
|
var args []any
|
||||||
|
@ -48,25 +62,22 @@ func Finds[T Model](ctx context.Context, q *QueryCondition) (r []T, err error) {
|
||||||
l = fmt.Sprintf(" %s offset %d", l, q.offset)
|
l = fmt.Sprintf(" %s offset %d", l, q.offset)
|
||||||
}
|
}
|
||||||
sq := fmt.Sprintf(tp, q.fields, rr.Table(), j, w, groupBy, h, q.order.parseOrderBy(), l)
|
sq := fmt.Sprintf(tp, q.fields, rr.Table(), j, w, groupBy, h, q.order.parseOrderBy(), l)
|
||||||
err = globalBb.Select(ctx, &r, sq, args...)
|
err = db.Select(ctx, &r, sq, args...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChunkFind 分片查询并直接返回所有结果
|
func chunkFind[T Model](db dbQuery, ctx context.Context, perLimit int, q *QueryCondition) (r []T, err error) {
|
||||||
//
|
|
||||||
// Conditions 中可用 Where Fields Group Having Join Order Limit In 函数
|
|
||||||
func ChunkFind[T Model](ctx context.Context, perLimit int, q *QueryCondition) (r []T, err error) {
|
|
||||||
i := 1
|
i := 1
|
||||||
var rr []T
|
var rr []T
|
||||||
var total int
|
var total int
|
||||||
var offset int
|
var offset int
|
||||||
for {
|
for {
|
||||||
if 1 == i {
|
if 1 == i {
|
||||||
rr, total, err = SimplePagination[T](ctx, q.where, q.fields, q.group, i, perLimit, q.order, q.join, q.having, q.in...)
|
rr, total, err = pagination[T](db, ctx, q.where, q.fields, q.group, i, perLimit, q.order, q.join, q.having, q.in...)
|
||||||
} else {
|
} else {
|
||||||
q.offset = offset
|
q.offset = offset
|
||||||
q.limit = perLimit
|
q.limit = perLimit
|
||||||
rr, err = Finds[T](ctx, q)
|
rr, err = finds[T](db, ctx, q)
|
||||||
}
|
}
|
||||||
offset += perLimit
|
offset += perLimit
|
||||||
if (err != nil && err != sql.ErrNoRows) || len(rr) < 1 {
|
if (err != nil && err != sql.ErrNoRows) || len(rr) < 1 {
|
||||||
|
@ -81,10 +92,39 @@ func ChunkFind[T Model](ctx context.Context, perLimit int, q *QueryCondition) (r
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChunkFind 分片查询并直接返回所有结果
|
||||||
|
//
|
||||||
|
// Conditions 中可用 Where Fields Group Having Join Order Limit In 函数
|
||||||
|
func ChunkFind[T Model](ctx context.Context, perLimit int, q *QueryCondition) (r []T, err error) {
|
||||||
|
r, err = chunkFind[T](globalBb, ctx, perLimit, q)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DBChunkFind 同 ChunkFind
|
||||||
|
//
|
||||||
|
// Conditions 中可用 Where Fields Group Having Join Order Limit In 函数
|
||||||
|
func DBChunkFind[T Model](db dbQuery, ctx context.Context, perLimit int, q *QueryCondition) (r []T, err error) {
|
||||||
|
r, err = chunkFind[T](db, ctx, perLimit, q)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Chunk 分片查询并函数过虑返回新类型的切片
|
// Chunk 分片查询并函数过虑返回新类型的切片
|
||||||
//
|
//
|
||||||
// Conditions 中可用 Where Fields Group Having Join Order Limit In 函数
|
// Conditions 中可用 Where Fields Group Having Join Order Limit In 函数
|
||||||
func Chunk[T Model, R any](ctx context.Context, perLimit int, fn func(rows T) (R, bool), q *QueryCondition) (r []R, err error) {
|
func Chunk[T Model, R any](ctx context.Context, perLimit int, fn func(rows T) (R, bool), q *QueryCondition) (r []R, err error) {
|
||||||
|
r, err = chunk(globalBb, ctx, perLimit, fn, q)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DBChunk 同 Chunk
|
||||||
|
//
|
||||||
|
// Conditions 中可用 Where Fields Group Having Join Order Limit In 函数
|
||||||
|
func DBChunk[T Model, R any](db dbQuery, ctx context.Context, perLimit int, fn func(rows T) (R, bool), q *QueryCondition) (r []R, err error) {
|
||||||
|
r, err = chunk(db, ctx, perLimit, fn, q)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func chunk[T Model, R any](db dbQuery, ctx context.Context, perLimit int, fn func(rows T) (R, bool), q *QueryCondition) (r []R, err error) {
|
||||||
i := 1
|
i := 1
|
||||||
var rr []T
|
var rr []T
|
||||||
var count int
|
var count int
|
||||||
|
@ -92,11 +132,11 @@ func Chunk[T Model, R any](ctx context.Context, perLimit int, fn func(rows T) (R
|
||||||
var offset int
|
var offset int
|
||||||
for {
|
for {
|
||||||
if 1 == i {
|
if 1 == i {
|
||||||
rr, total, err = SimplePagination[T](ctx, q.where, q.fields, q.group, i, perLimit, q.order, q.join, q.having, q.in...)
|
rr, total, err = pagination[T](db, ctx, q.where, q.fields, q.group, i, perLimit, q.order, q.join, q.having, q.in...)
|
||||||
} else {
|
} else {
|
||||||
q.offset = offset
|
q.offset = offset
|
||||||
q.limit = perLimit
|
q.limit = perLimit
|
||||||
rr, err = Finds[T](ctx, q)
|
rr, err = finds[T](db, ctx, q)
|
||||||
}
|
}
|
||||||
offset += perLimit
|
offset += perLimit
|
||||||
if (err != nil && err != sql.ErrNoRows) || len(rr) < 1 {
|
if (err != nil && err != sql.ErrNoRows) || len(rr) < 1 {
|
||||||
|
@ -123,3 +163,26 @@ func Chunk[T Model, R any](ctx context.Context, perLimit int, fn func(rows T) (R
|
||||||
func Pagination[T Model](ctx context.Context, q *QueryCondition) ([]T, int, error) {
|
func Pagination[T Model](ctx context.Context, q *QueryCondition) ([]T, int, error) {
|
||||||
return SimplePagination[T](ctx, q.where, q.fields, q.group, q.page, q.limit, q.order, q.join, q.having, q.in...)
|
return SimplePagination[T](ctx, q.where, q.fields, q.group, q.page, q.limit, q.order, q.join, q.having, q.in...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DBPagination 同 Pagination 方便多个db使用
|
||||||
|
//
|
||||||
|
// Condition 中可使用 Where Fields Group Having Join Order Page Limit In 函数
|
||||||
|
func DBPagination[T Model](db dbQuery, ctx context.Context, q *QueryCondition) ([]T, int, error) {
|
||||||
|
return pagination[T](db, ctx, q.where, q.fields, q.group, q.page, q.limit, q.order, q.join, q.having, q.in...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Column[V Model, T any](ctx context.Context, fn func(V) (T, bool), q *QueryCondition) ([]T, error) {
|
||||||
|
return column[V, T](globalBb, ctx, fn, q)
|
||||||
|
}
|
||||||
|
func DBColumn[V Model, T any](db dbQuery, ctx context.Context, fn func(V) (T, bool), q *QueryCondition) (r []T, err error) {
|
||||||
|
return column[V, T](db, ctx, fn, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
func column[V Model, T any](db dbQuery, ctx context.Context, fn func(V) (T, bool), q *QueryCondition) (r []T, err error) {
|
||||||
|
res, err := finds[V](db, ctx, q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r = slice.FilterAndMap(res, fn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -230,3 +230,46 @@ func TestPagination(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestColumn(t *testing.T) {
|
||||||
|
type args[V Model, T any] struct {
|
||||||
|
ctx context.Context
|
||||||
|
fn func(V) (T, bool)
|
||||||
|
q *QueryCondition
|
||||||
|
}
|
||||||
|
type testCase[V Model, T any] struct {
|
||||||
|
name string
|
||||||
|
args args[V, T]
|
||||||
|
wantR []T
|
||||||
|
wantErr bool
|
||||||
|
}
|
||||||
|
tests := []testCase[post, uint64]{
|
||||||
|
{
|
||||||
|
name: "t1",
|
||||||
|
args: args[post, uint64]{
|
||||||
|
ctx: ctx,
|
||||||
|
fn: func(t post) (uint64, bool) {
|
||||||
|
return t.Id, true
|
||||||
|
},
|
||||||
|
q: Conditions(
|
||||||
|
Where(SqlBuilder{
|
||||||
|
{"ID", "<", "200", "int"},
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
wantR: []uint64{63, 64, 190, 193},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotR, err := Column[post](tt.args.ctx, tt.args.fn, tt.args.q)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Column() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(gotR, tt.wantR) {
|
||||||
|
t.Errorf("Column() gotR = %v, want %v", gotR, tt.wantR)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
51
model/sqxquery.go
Normal file
51
model/sqxquery.go
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SqlxQuery struct {
|
||||||
|
sqlx *sqlx.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSqlxQuery(sqlx *sqlx.DB) SqlxQuery {
|
||||||
|
return SqlxQuery{sqlx: sqlx}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r SqlxQuery) Select(ctx context.Context, dest any, sql string, params ...any) error {
|
||||||
|
if os.Getenv("SHOW_SQL") == "true" {
|
||||||
|
go log.Println(formatSql(sql, params))
|
||||||
|
}
|
||||||
|
return r.sqlx.Select(dest, sql, params...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r SqlxQuery) Get(ctx context.Context, dest any, sql string, params ...any) error {
|
||||||
|
if os.Getenv("SHOW_SQL") == "true" {
|
||||||
|
go log.Println(formatSql(sql, params))
|
||||||
|
}
|
||||||
|
return r.sqlx.Get(dest, sql, params...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatSql(sql string, params []any) string {
|
||||||
|
for _, param := range params {
|
||||||
|
switch param.(type) {
|
||||||
|
case string:
|
||||||
|
sql = strings.Replace(sql, "?", fmt.Sprintf("'%s'", param.(string)), 1)
|
||||||
|
case int64:
|
||||||
|
sql = strings.Replace(sql, "?", strconv.FormatInt(param.(int64), 10), 1)
|
||||||
|
case int:
|
||||||
|
sql = strings.Replace(sql, "?", strconv.Itoa(param.(int)), 1)
|
||||||
|
case uint64:
|
||||||
|
sql = strings.Replace(sql, "?", strconv.FormatUint(param.(uint64), 10), 1)
|
||||||
|
case float64:
|
||||||
|
sql = strings.Replace(sql, "?", fmt.Sprintf("%f", param.(float64)), 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sql
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user