244 lines
5.9 KiB
Go
244 lines
5.9 KiB
Go
package handler
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/ArtalkJS/Artalk/internal/core"
|
|
"github.com/ArtalkJS/Artalk/internal/entity"
|
|
"github.com/ArtalkJS/Artalk/server/common"
|
|
"github.com/gofiber/fiber/v2"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// 获取评论查询实例
|
|
func GetCommentQuery(app *core.App, c *fiber.Ctx, p ParamsGet, siteID uint, scopes ...func(*gorm.DB) *gorm.DB) *gorm.DB {
|
|
q := app.Dao().DB().Model(&entity.Comment{})
|
|
|
|
q.Scopes(SiteIsolationScope(app, c, p), AllowedComment(app, c, p))
|
|
q.Order(GetSortRuleSQL(p.SortBy, "created_at DESC")) // 排序规则
|
|
q.Scopes(scopes...)
|
|
|
|
switch {
|
|
case !p.IsMsgCenter:
|
|
// ==========
|
|
// 非通知中心
|
|
// ==========
|
|
|
|
// 只看管理员功能
|
|
if p.ViewOnlyAdmin {
|
|
adminIDs := app.Dao().GetAllAdminIDs() // 获取管理员列表
|
|
q.Where("user_id IN ?", adminIDs) // 只允许管理员 user_id
|
|
}
|
|
|
|
q.Where("page_key = ?", p.PageKey)
|
|
|
|
case p.IsMsgCenter:
|
|
// ==========
|
|
// 通知中心
|
|
// ==========
|
|
user := p.User
|
|
if user == nil || user.IsEmpty() {
|
|
return q.Where("id = 0") // user not found
|
|
}
|
|
|
|
// admin_only 检测
|
|
if strings.HasPrefix(p.Type, "admin_") {
|
|
if !p.IsAdminReq || !common.IsAdminHasSiteAccess(app, c, p.SiteName) {
|
|
return q.Where("id = 0")
|
|
}
|
|
}
|
|
|
|
switch p.Type {
|
|
case "all":
|
|
q.Where("rid IN (?) OR user_id = ?", app.Dao().GetUserAllCommentIDs(user.ID), user.ID)
|
|
case "mentions":
|
|
q.Where("rid IN (?) AND user_id != ?", app.Dao().GetUserAllCommentIDs(user.ID), user.ID)
|
|
case "mine":
|
|
q.Where("user_id = ?", user.ID)
|
|
case "pending":
|
|
q.Where("user_id = ? AND is_pending = ?", user.ID, true)
|
|
case "admin_all":
|
|
|
|
case "admin_pending":
|
|
q.Where("is_pending = ?", true)
|
|
default:
|
|
return q.Where("id = 0")
|
|
}
|
|
}
|
|
|
|
return q
|
|
}
|
|
|
|
// 根评论 Root comments
|
|
func RootComments() func(db *gorm.DB) *gorm.DB {
|
|
return func(db *gorm.DB) *gorm.DB {
|
|
return db.Where("rid = 0")
|
|
}
|
|
}
|
|
|
|
// 允许的评论
|
|
func AllowedComment(app *core.App, c *fiber.Ctx, p ParamsGet) func(db *gorm.DB) *gorm.DB {
|
|
return func(db *gorm.DB) *gorm.DB {
|
|
if common.CheckIsAdminReq(app, c) {
|
|
return db // 管理员显示全部
|
|
}
|
|
|
|
// 通知中心允许显示个人的待审状态的评论
|
|
if p.IsMsgCenter && !p.User.IsEmpty() {
|
|
return db.Where("is_pending = ? OR (is_pending = ? AND user_id = ?)", false, true, p.User.ID)
|
|
}
|
|
|
|
return db.Where("is_pending = ?", false) // 不允许待审评论
|
|
}
|
|
}
|
|
|
|
func AllowedCommentChecker(app *core.App, c *fiber.Ctx, p ParamsGet) func(*entity.Comment) bool {
|
|
return func(comment *entity.Comment) bool {
|
|
if common.CheckIsAdminReq(app, c) {
|
|
return true // 管理员显示全部
|
|
}
|
|
|
|
// 通知中心允许显示个人的待审状态的评论
|
|
if p.IsMsgCenter && p.User.ID == comment.UserID {
|
|
return true
|
|
}
|
|
|
|
// 不允许待审评论
|
|
if comment.IsPending {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
}
|
|
|
|
func SiteIsolationChecker(app *core.App, c *fiber.Ctx, p ParamsGet) func(*entity.Comment) bool {
|
|
return func(comment *entity.Comment) bool {
|
|
if common.CheckIsAdminReq(app, c) && p.SiteAll {
|
|
return true // 仅管理员支持取消站点隔离
|
|
}
|
|
|
|
if comment.SiteName != p.SiteName {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
}
|
|
|
|
// 站点隔离
|
|
func SiteIsolationScope(app *core.App, c *fiber.Ctx, p ParamsGet) func(db *gorm.DB) *gorm.DB {
|
|
return func(db *gorm.DB) *gorm.DB {
|
|
if common.CheckIsAdminReq(app, c) && p.SiteAll {
|
|
return db // 仅管理员支持取消站点隔离
|
|
}
|
|
|
|
return db.Where("site_name = ?", p.SiteName)
|
|
}
|
|
}
|
|
|
|
// 排序规则
|
|
func GetSortRuleSQL(sortBy string, defaultSQL string) string {
|
|
switch sortBy {
|
|
case "date_desc":
|
|
return "created_at DESC"
|
|
case "date_asc":
|
|
return "created_at ASC"
|
|
case "vote":
|
|
return "vote_up DESC, created_at DESC"
|
|
}
|
|
|
|
return defaultSQL
|
|
}
|
|
|
|
// 评论计数
|
|
func CountComments(db *gorm.DB) int64 {
|
|
var count int64
|
|
db.Count(&count)
|
|
return count
|
|
}
|
|
|
|
// 评论搜索
|
|
func CommentSearchScope(app *core.App, p ParamsGet) func(d *gorm.DB) *gorm.DB {
|
|
var userIds []uint
|
|
app.Dao().DB().Model(&entity.User{}).Where(
|
|
"LOWER(name) = LOWER(?) OR LOWER(email) = LOWER(?)", p.Search, p.Search,
|
|
).Pluck("id", &userIds)
|
|
|
|
return func(d *gorm.DB) *gorm.DB {
|
|
return d.Where("user_id IN (?) OR content LIKE ? OR page_key = ? OR ip = ? OR ua = ?",
|
|
userIds, "%"+p.Search+"%", p.Search, p.Search, p.Search)
|
|
}
|
|
}
|
|
|
|
// 分页
|
|
func Paginate(offset int, limit int) func(db *gorm.DB) *gorm.DB {
|
|
if offset < 0 {
|
|
offset = 0
|
|
}
|
|
|
|
if limit > 100 {
|
|
limit = 100
|
|
} else if limit <= 0 {
|
|
limit = 15
|
|
}
|
|
|
|
return func(db *gorm.DB) *gorm.DB {
|
|
return db.Offset(offset).Limit(limit)
|
|
}
|
|
}
|
|
|
|
// 插入置顶的评论
|
|
func prependPinnedComments(app *core.App, c *fiber.Ctx, p ParamsGet, comments *[]entity.Comment) {
|
|
if p.IsMsgCenter || p.Offset != 0 {
|
|
return // 通知中心关闭置顶 & 仅在分页的首页加入置顶评论
|
|
}
|
|
|
|
pinnedComments := []entity.Comment{}
|
|
GetCommentQuery(app, c, p, p.SiteID).Where("is_pinned = ?", true).Find(&pinnedComments)
|
|
if len(pinnedComments) == 0 {
|
|
return // 没有置顶评论
|
|
}
|
|
|
|
// 去掉已 pinned 且重复存在于原列表中的评论
|
|
filteredComments := []entity.Comment{}
|
|
for _, co := range *comments {
|
|
if !entity.ContainsComment(pinnedComments, co.ID) {
|
|
filteredComments = append(filteredComments, co)
|
|
}
|
|
}
|
|
|
|
// prepend
|
|
*comments = append(pinnedComments, filteredComments...)
|
|
}
|
|
|
|
// 处理来自配置文件的 fronted 配置项
|
|
func UseCfgFrontend(app *core.App, p *ParamsGet) {
|
|
feConf := app.Conf().Frontend
|
|
if feConf == nil || reflect.ValueOf(feConf).Kind() != reflect.Map {
|
|
return
|
|
}
|
|
|
|
// pagination
|
|
// TODO consider ignore pageSize configuration in sidebar
|
|
(func() {
|
|
pagination, isExist := feConf["pagination"]
|
|
if !isExist {
|
|
return
|
|
}
|
|
if reflect.ValueOf(pagination).Kind() != reflect.Map {
|
|
return
|
|
}
|
|
|
|
// pagination.pageSize
|
|
cfgPageSizeStr := fmt.Sprintf("%v", pagination.(common.Map)["pageSize"])
|
|
confPageSize, err := strconv.Atoi(cfgPageSizeStr)
|
|
if err == nil && confPageSize > 0 {
|
|
p.Limit = confPageSize
|
|
}
|
|
})()
|
|
}
|