mirror of
https://github.com/snowykami/neo-blog.git
synced 2025-09-26 02:56:22 +00:00
feat: 更新评论功能,优化代码格式,添加位置格式化功能
All checks were successful
Push to Helm Chart Repository / build (push) Successful in 52s
All checks were successful
Push to Helm Chart Repository / build (push) Successful in 52s
This commit is contained in:
@ -1,50 +1,50 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
type CommentDto struct {
|
type CommentDto struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
TargetID uint `json:"target_id"`
|
TargetID uint `json:"target_id"`
|
||||||
TargetType string `json:"target_type"` // 目标类型,如 "post", "page"
|
TargetType string `json:"target_type"` // 目标类型,如 "post", "page"
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
ReplyID uint `json:"reply_id"` // 回复的评论ID
|
ReplyID uint `json:"reply_id"` // 回复的评论ID
|
||||||
Depth int `json:"depth"` // 评论的层级深度
|
Depth int `json:"depth"` // 评论的层级深度
|
||||||
CreatedAt string `json:"created_at"`
|
CreatedAt string `json:"created_at"`
|
||||||
UpdatedAt string `json:"updated_at"`
|
UpdatedAt string `json:"updated_at"`
|
||||||
User UserDto `json:"user"` // 评论的
|
User UserDto `json:"user"` // 评论的
|
||||||
ReplyCount uint64 `json:"reply_count"` // 回复数量
|
ReplyCount uint64 `json:"reply_count"` // 回复数量
|
||||||
LikeCount uint64 `json:"like_count"` // 点赞数量
|
LikeCount uint64 `json:"like_count"` // 点赞数量
|
||||||
IsLiked bool `json:"is_liked"` // 当前用户是否点赞
|
IsLiked bool `json:"is_liked"` // 当前用户是否点赞
|
||||||
IsPrivate bool `json:"is_private"`
|
IsPrivate bool `json:"is_private"`
|
||||||
Location string `json:"location"` // 用户位置,基于IP
|
Location string `json:"location"` // 用户位置,基于IP
|
||||||
OS string `json:"os"` // 用户操作系统,基于User-Agent
|
OS string `json:"os"` // 用户操作系统,基于User-Agent
|
||||||
Browser string `json:"browser"` // 用户浏览器,基于User-Agent
|
Browser string `json:"browser"` // 用户浏览器,基于User-Agent
|
||||||
ShowClientInfo bool `json:"show_client_info"`
|
ShowClientInfo bool `json:"show_client_info"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateCommentReq struct {
|
type CreateCommentReq struct {
|
||||||
TargetID uint `json:"target_id" binding:"required"` // 目标ID
|
TargetID uint `json:"target_id" binding:"required"` // 目标ID
|
||||||
TargetType string `json:"target_type" binding:"required"` // 目标类型,如 "post", "page"
|
TargetType string `json:"target_type" binding:"required"` // 目标类型,如 "post", "page"
|
||||||
Content string `json:"content" binding:"required"` // 评论内容
|
Content string `json:"content" binding:"required"` // 评论内容
|
||||||
ReplyID uint `json:"reply_id"` // 回复的评论ID
|
ReplyID uint `json:"reply_id"` // 回复的评论ID
|
||||||
IsPrivate bool `json:"is_private"` // 是否私密评论,默认false
|
IsPrivate bool `json:"is_private"` // 是否私密评论,默认false
|
||||||
RemoteAddr string `json:"remote_addr"` // 远程地址
|
RemoteAddr string `json:"remote_addr"` // 远程地址
|
||||||
UserAgent string `json:"user_agent"` // 用户代理
|
UserAgent string `json:"user_agent"` // 用户代理
|
||||||
ShowClientInfo bool `json:"show_client_info"` // 是否显示客户端信息
|
ShowClientInfo bool `json:"show_client_info"` // 是否显示客户端信息
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateCommentReq struct {
|
type UpdateCommentReq struct {
|
||||||
CommentID uint `json:"comment_id" binding:"required"` // 评论ID
|
CommentID uint `json:"comment_id" binding:"required"` // 评论ID
|
||||||
Content string `json:"content" binding:"required"` // 评论内容
|
Content string `json:"content" binding:"required"` // 评论内容
|
||||||
IsPrivate bool `json:"is_private"` // 是否私密
|
IsPrivate bool `json:"is_private"` // 是否私密
|
||||||
ShowClientInfo bool `json:"show_client_info"` // 是否显示客户端信息
|
ShowClientInfo bool `json:"show_client_info"` // 是否显示客户端信息
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetCommentListReq struct {
|
type GetCommentListReq struct {
|
||||||
TargetID uint `json:"target_id" binding:"required"`
|
TargetID uint `json:"target_id" binding:"required"`
|
||||||
TargetType string `json:"target_type" binding:"required"`
|
TargetType string `json:"target_type" binding:"required"`
|
||||||
CommentID uint `json:"comment_id"` // 获取某条评论的所有子评论
|
CommentID uint `json:"comment_id"` // 获取某条评论的所有子评论
|
||||||
OrderBy string `json:"order_by"` // 排序方式
|
OrderBy string `json:"order_by"` // 排序方式
|
||||||
Page uint64 `json:"page"` // 页码
|
Page uint64 `json:"page"` // 页码
|
||||||
Size uint64 `json:"size"`
|
Size uint64 `json:"size"`
|
||||||
Desc bool `json:"desc"`
|
Desc bool `json:"desc"`
|
||||||
Depth int `json:"depth"` // 评论的层级深度
|
Depth int `json:"depth"` // 评论的层级深度
|
||||||
}
|
}
|
||||||
|
@ -1,188 +1,188 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/snowykami/neo-blog/pkg/constant"
|
"github.com/snowykami/neo-blog/pkg/constant"
|
||||||
"github.com/snowykami/neo-blog/pkg/utils"
|
"github.com/snowykami/neo-blog/pkg/utils"
|
||||||
|
|
||||||
"github.com/snowykami/neo-blog/internal/ctxutils"
|
"github.com/snowykami/neo-blog/internal/ctxutils"
|
||||||
"github.com/snowykami/neo-blog/internal/dto"
|
"github.com/snowykami/neo-blog/internal/dto"
|
||||||
"github.com/snowykami/neo-blog/internal/model"
|
"github.com/snowykami/neo-blog/internal/model"
|
||||||
"github.com/snowykami/neo-blog/internal/repo"
|
"github.com/snowykami/neo-blog/internal/repo"
|
||||||
"github.com/snowykami/neo-blog/pkg/errs"
|
"github.com/snowykami/neo-blog/pkg/errs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CommentService struct{}
|
type CommentService struct{}
|
||||||
|
|
||||||
func NewCommentService() *CommentService {
|
func NewCommentService() *CommentService {
|
||||||
return &CommentService{}
|
return &CommentService{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *CommentService) CreateComment(ctx context.Context, req *dto.CreateCommentReq) (uint, error) {
|
func (cs *CommentService) CreateComment(ctx context.Context, req *dto.CreateCommentReq) (uint, error) {
|
||||||
currentUser, ok := ctxutils.GetCurrentUser(ctx)
|
currentUser, ok := ctxutils.GetCurrentUser(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, errs.ErrUnauthorized
|
return 0, errs.ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
if ok, err := cs.checkTargetExists(req.TargetID, req.TargetType); !ok {
|
if ok, err := cs.checkTargetExists(req.TargetID, req.TargetType); !ok {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, errs.New(errs.ErrBadRequest.Code, "target not found", err)
|
return 0, errs.New(errs.ErrBadRequest.Code, "target not found", err)
|
||||||
}
|
}
|
||||||
return 0, errs.ErrBadRequest
|
return 0, errs.ErrBadRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
comment := &model.Comment{
|
comment := &model.Comment{
|
||||||
Content: req.Content,
|
Content: req.Content,
|
||||||
ReplyID: req.ReplyID,
|
ReplyID: req.ReplyID,
|
||||||
TargetID: req.TargetID,
|
TargetID: req.TargetID,
|
||||||
TargetType: req.TargetType,
|
TargetType: req.TargetType,
|
||||||
UserID: currentUser.ID,
|
UserID: currentUser.ID,
|
||||||
IsPrivate: req.IsPrivate,
|
IsPrivate: req.IsPrivate,
|
||||||
RemoteAddr: req.RemoteAddr,
|
RemoteAddr: req.RemoteAddr,
|
||||||
UserAgent: req.UserAgent,
|
UserAgent: req.UserAgent,
|
||||||
ShowClientInfo: req.ShowClientInfo,
|
ShowClientInfo: req.ShowClientInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
commentID, err := repo.Comment.CreateComment(comment)
|
commentID, err := repo.Comment.CreateComment(comment)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return commentID, nil
|
return commentID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *CommentService) UpdateComment(ctx context.Context, req *dto.UpdateCommentReq) error {
|
func (cs *CommentService) UpdateComment(ctx context.Context, req *dto.UpdateCommentReq) error {
|
||||||
currentUser, ok := ctxutils.GetCurrentUser(ctx)
|
currentUser, ok := ctxutils.GetCurrentUser(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errs.ErrUnauthorized
|
return errs.ErrUnauthorized
|
||||||
}
|
}
|
||||||
logrus.Infof("UpdateComment: currentUser ID %d, req.CommentID %d", currentUser.ID, req.CommentID)
|
logrus.Infof("UpdateComment: currentUser ID %d, req.CommentID %d", currentUser.ID, req.CommentID)
|
||||||
|
|
||||||
comment, err := repo.Comment.GetComment(strconv.Itoa(int(req.CommentID)))
|
comment, err := repo.Comment.GetComment(strconv.Itoa(int(req.CommentID)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentUser.ID != comment.UserID {
|
if currentUser.ID != comment.UserID {
|
||||||
return errs.ErrForbidden
|
return errs.ErrForbidden
|
||||||
}
|
}
|
||||||
|
|
||||||
comment.Content = req.Content
|
comment.Content = req.Content
|
||||||
comment.IsPrivate = req.IsPrivate
|
comment.IsPrivate = req.IsPrivate
|
||||||
comment.ShowClientInfo = req.ShowClientInfo
|
comment.ShowClientInfo = req.ShowClientInfo
|
||||||
err = repo.Comment.UpdateComment(comment)
|
err = repo.Comment.UpdateComment(comment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *CommentService) DeleteComment(ctx context.Context, commentID string) error {
|
func (cs *CommentService) DeleteComment(ctx context.Context, commentID string) error {
|
||||||
currentUser, ok := ctxutils.GetCurrentUser(ctx)
|
currentUser, ok := ctxutils.GetCurrentUser(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errs.ErrUnauthorized
|
return errs.ErrUnauthorized
|
||||||
}
|
}
|
||||||
if commentID == "" {
|
if commentID == "" {
|
||||||
return errs.ErrBadRequest
|
return errs.ErrBadRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
comment, err := repo.Comment.GetComment(commentID)
|
comment, err := repo.Comment.GetComment(commentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errs.New(errs.ErrNotFound.Code, "comment not found", err)
|
return errs.New(errs.ErrNotFound.Code, "comment not found", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if comment.UserID != currentUser.ID {
|
if comment.UserID != currentUser.ID {
|
||||||
return errs.ErrForbidden
|
return errs.ErrForbidden
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := repo.Comment.DeleteComment(commentID); err != nil {
|
if err := repo.Comment.DeleteComment(commentID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *CommentService) GetComment(ctx context.Context, commentID string) (*dto.CommentDto, error) {
|
func (cs *CommentService) GetComment(ctx context.Context, commentID string) (*dto.CommentDto, error) {
|
||||||
comment, err := repo.Comment.GetComment(commentID)
|
comment, err := repo.Comment.GetComment(commentID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errs.New(errs.ErrNotFound.Code, "comment not found", err)
|
return nil, errs.New(errs.ErrNotFound.Code, "comment not found", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
currentUserID := uint(0)
|
currentUserID := uint(0)
|
||||||
if currentUser, ok := ctxutils.GetCurrentUser(ctx); ok {
|
if currentUser, ok := ctxutils.GetCurrentUser(ctx); ok {
|
||||||
currentUserID = currentUser.ID
|
currentUserID = currentUser.ID
|
||||||
}
|
}
|
||||||
if comment.IsPrivate && currentUserID != comment.UserID {
|
if comment.IsPrivate && currentUserID != comment.UserID {
|
||||||
return nil, errs.ErrForbidden
|
return nil, errs.ErrForbidden
|
||||||
}
|
}
|
||||||
commentDto := cs.toGetCommentDto(comment, currentUserID)
|
commentDto := cs.toGetCommentDto(comment, currentUserID)
|
||||||
return &commentDto, err
|
return &commentDto, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *CommentService) GetCommentList(ctx context.Context, req *dto.GetCommentListReq) ([]dto.CommentDto, error) {
|
func (cs *CommentService) GetCommentList(ctx context.Context, req *dto.GetCommentListReq) ([]dto.CommentDto, error) {
|
||||||
currentUserID := uint(0)
|
currentUserID := uint(0)
|
||||||
if currentUser, ok := ctxutils.GetCurrentUser(ctx); ok {
|
if currentUser, ok := ctxutils.GetCurrentUser(ctx); ok {
|
||||||
currentUserID = currentUser.ID
|
currentUserID = currentUser.ID
|
||||||
}
|
}
|
||||||
comments, err := repo.Comment.ListComments(currentUserID, req.TargetID, req.CommentID, req.TargetType, req.Page, req.Size, req.OrderBy, req.Desc, req.Depth)
|
comments, err := repo.Comment.ListComments(currentUserID, req.TargetID, req.CommentID, req.TargetType, req.Page, req.Size, req.OrderBy, req.Desc, req.Depth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errs.New(errs.ErrInternalServer.Code, "failed to list comments", err)
|
return nil, errs.New(errs.ErrInternalServer.Code, "failed to list comments", err)
|
||||||
}
|
}
|
||||||
commentDtos := make([]dto.CommentDto, 0)
|
commentDtos := make([]dto.CommentDto, 0)
|
||||||
for _, comment := range comments {
|
for _, comment := range comments {
|
||||||
//replyCount, _ := repo.Comment.CountReplyComments(currentUserID, comment.ID)
|
//replyCount, _ := repo.Comment.CountReplyComments(currentUserID, comment.ID)
|
||||||
commentDto := cs.toGetCommentDto(&comment, currentUserID)
|
commentDto := cs.toGetCommentDto(&comment, currentUserID)
|
||||||
commentDtos = append(commentDtos, commentDto)
|
commentDtos = append(commentDtos, commentDto)
|
||||||
}
|
}
|
||||||
return commentDtos, nil
|
return commentDtos, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *CommentService) toGetCommentDto(comment *model.Comment, currentUserID uint) dto.CommentDto {
|
func (cs *CommentService) toGetCommentDto(comment *model.Comment, currentUserID uint) dto.CommentDto {
|
||||||
isLiked := false
|
isLiked := false
|
||||||
if currentUserID != 0 {
|
if currentUserID != 0 {
|
||||||
isLiked, _ = repo.Like.IsLiked(currentUserID, comment.ID, constant.TargetTypeComment)
|
isLiked, _ = repo.Like.IsLiked(currentUserID, comment.ID, constant.TargetTypeComment)
|
||||||
}
|
}
|
||||||
ua := utils.ParseUA(comment.UserAgent)
|
ua := utils.ParseUA(comment.UserAgent)
|
||||||
if !comment.ShowClientInfo {
|
if !comment.ShowClientInfo {
|
||||||
comment.Location = ""
|
comment.Location = ""
|
||||||
ua.OS = ""
|
ua.OS = ""
|
||||||
ua.OSVersion = ""
|
ua.OSVersion = ""
|
||||||
ua.Browser = ""
|
ua.Browser = ""
|
||||||
ua.BrowserVer = ""
|
ua.BrowserVer = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return dto.CommentDto{
|
return dto.CommentDto{
|
||||||
ID: comment.ID,
|
ID: comment.ID,
|
||||||
Content: comment.Content,
|
Content: comment.Content,
|
||||||
TargetID: comment.TargetID,
|
TargetID: comment.TargetID,
|
||||||
TargetType: comment.TargetType,
|
TargetType: comment.TargetType,
|
||||||
ReplyID: comment.ReplyID,
|
ReplyID: comment.ReplyID,
|
||||||
CreatedAt: comment.CreatedAt.String(),
|
CreatedAt: comment.CreatedAt.String(),
|
||||||
UpdatedAt: comment.UpdatedAt.String(),
|
UpdatedAt: comment.UpdatedAt.String(),
|
||||||
Depth: comment.Depth,
|
Depth: comment.Depth,
|
||||||
User: comment.User.ToDto(),
|
User: comment.User.ToDto(),
|
||||||
ReplyCount: comment.CommentCount,
|
ReplyCount: comment.CommentCount,
|
||||||
LikeCount: comment.LikeCount,
|
LikeCount: comment.LikeCount,
|
||||||
IsLiked: isLiked,
|
IsLiked: isLiked,
|
||||||
IsPrivate: comment.IsPrivate,
|
IsPrivate: comment.IsPrivate,
|
||||||
OS: ua.OS + " " + ua.OSVersion,
|
OS: ua.OS + " " + ua.OSVersion,
|
||||||
Browser: ua.Browser + " " + ua.BrowserVer,
|
Browser: ua.Browser + " " + ua.BrowserVer,
|
||||||
Location: comment.Location,
|
Location: comment.Location,
|
||||||
ShowClientInfo: comment.ShowClientInfo,
|
ShowClientInfo: comment.ShowClientInfo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (cs *CommentService) checkTargetExists(targetID uint, targetType string) (bool, error) {
|
func (cs *CommentService) checkTargetExists(targetID uint, targetType string) (bool, error) {
|
||||||
switch targetType {
|
switch targetType {
|
||||||
case constant.TargetTypePost:
|
case constant.TargetTypePost:
|
||||||
if _, err := repo.Post.GetPostByID(strconv.Itoa(int(targetID))); err != nil {
|
if _, err := repo.Post.GetPostByID(strconv.Itoa(int(targetID))); err != nil {
|
||||||
return false, errs.New(errs.ErrNotFound.Code, "post not found", err)
|
return false, errs.New(errs.ErrNotFound.Code, "post not found", err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return false, errs.New(errs.ErrBadRequest.Code, "invalid target type", nil)
|
return false, errs.New(errs.ErrBadRequest.Code, "invalid target type", nil)
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
@ -1,53 +1,54 @@
|
|||||||
package constant
|
package constant
|
||||||
|
|
||||||
const (
|
const (
|
||||||
CaptchaTypeDisable = "disable" // 禁用验证码
|
CaptchaTypeDisable = "disable" // 禁用验证码
|
||||||
CaptchaTypeHCaptcha = "hcaptcha" // HCaptcha验证码
|
CaptchaTypeHCaptcha = "hcaptcha" // HCaptcha验证码
|
||||||
CaptchaTypeTurnstile = "turnstile" // Turnstile验证码
|
CaptchaTypeTurnstile = "turnstile" // Turnstile验证码
|
||||||
CaptchaTypeReCaptcha = "recaptcha" // ReCaptcha验证码
|
CaptchaTypeReCaptcha = "recaptcha" // ReCaptcha验证码
|
||||||
ContextKeyUserID = "user_id" // 上下文键:用户ID
|
ContextKeyUserID = "user_id" // 上下文键:用户ID
|
||||||
ModeDev = "dev"
|
ModeDev = "dev"
|
||||||
ModeProd = "prod"
|
ModeProd = "prod"
|
||||||
RoleUser = "user"
|
RoleUser = "user"
|
||||||
RoleAdmin = "admin"
|
RoleAdmin = "admin"
|
||||||
EnvKeyBaseUrl = "BASE_URL" // 环境变量:基础URL
|
EnvKeyBaseUrl = "BASE_URL" // 环境变量:基础URL
|
||||||
EnvKeyCaptchaProvider = "CAPTCHA_PROVIDER" // captcha提供者
|
EnvKeyCaptchaProvider = "CAPTCHA_PROVIDER" // captcha提供者
|
||||||
EnvKeyCaptchaSecreteKey = "CAPTCHA_SECRET_KEY" // captcha站点密钥
|
EnvKeyCaptchaSecreteKey = "CAPTCHA_SECRET_KEY" // captcha站点密钥
|
||||||
EnvKeyCaptchaUrl = "CAPTCHA_URL" // 某些自托管的captcha的url
|
EnvKeyCaptchaUrl = "CAPTCHA_URL" // 某些自托管的captcha的url
|
||||||
EnvKeyCaptchaSiteKey = "CAPTCHA_SITE_KEY" // captcha密钥key
|
EnvKeyCaptchaSiteKey = "CAPTCHA_SITE_KEY" // captcha密钥key
|
||||||
EnvKeyLogLevel = "LOG_LEVEL" // 环境变量:日志级别
|
EnvKeyLocationFormat = "LOCATION_FORMAT" // 环境变量:时区格式
|
||||||
EnvKeyMode = "MODE" // 环境变量:运行模式
|
EnvKeyLogLevel = "LOG_LEVEL" // 环境变量:日志级别
|
||||||
EnvKeyJwtSecrete = "JWT_SECRET" // 环境变量:JWT密钥
|
EnvKeyMode = "MODE" // 环境变量:运行模式
|
||||||
EnvKeyPasswordSalt = "PASSWORD_SALT" // 环境变量:密码盐
|
EnvKeyJwtSecrete = "JWT_SECRET" // 环境变量:JWT密钥
|
||||||
EnvKeyTokenDuration = "TOKEN_DURATION" // 环境变量:令牌有效期
|
EnvKeyPasswordSalt = "PASSWORD_SALT" // 环境变量:密码盐
|
||||||
EnvKeyMaxReplyDepth = "MAX_REPLY_DEPTH" // 环境变量:最大回复深度
|
EnvKeyTokenDuration = "TOKEN_DURATION" // 环境变量:令牌有效期
|
||||||
EnvKeyTokenDurationDefault = 300 // Token有效时长
|
EnvKeyMaxReplyDepth = "MAX_REPLY_DEPTH" // 环境变量:最大回复深度
|
||||||
EnvKeyRefreshTokenDurationDefault = 604800 // refresh token有效时长
|
EnvKeyTokenDurationDefault = 300 // Token有效时长
|
||||||
EnvKeyRefreshTokenDuration = "REFRESH_TOKEN_DURATION" // 环境变量:刷新令牌有效期
|
EnvKeyRefreshTokenDurationDefault = 604800 // refresh token有效时长
|
||||||
EnvKeyRefreshTokenDurationWithRemember = "REFRESH_TOKEN_DURATION_WITH_REMEMBER" // 环境变量:记住我刷新令牌有效期
|
EnvKeyRefreshTokenDuration = "REFRESH_TOKEN_DURATION" // 环境变量:刷新令牌有效期
|
||||||
KVKeyEmailVerificationCode = "email_verification_code:" // KV存储:邮箱验证码
|
EnvKeyRefreshTokenDurationWithRemember = "REFRESH_TOKEN_DURATION_WITH_REMEMBER" // 环境变量:记住我刷新令牌有效期
|
||||||
KVKeyOidcState = "oidc_state:" // KV存储:OIDC状态
|
KVKeyEmailVerificationCode = "email_verification_code:" // KV存储:邮箱验证码
|
||||||
ApiSuffix = "/api/v1" // API版本前缀
|
KVKeyOidcState = "oidc_state:" // KV存储:OIDC状态
|
||||||
OidcUri = "/user/oidc/login" // OIDC登录URI
|
ApiSuffix = "/api/v1" // API版本前缀
|
||||||
OidcProviderTypeMisskey = "misskey" // OIDC提供者类型:Misskey
|
OidcUri = "/user/oidc/login" // OIDC登录URI
|
||||||
OidcProviderTypeOauth2 = "oauth2" // OIDC提供者类型:GitHub
|
OidcProviderTypeMisskey = "misskey" // OIDC提供者类型:Misskey
|
||||||
DefaultBaseUrl = "http://localhost:3000" // 默认BaseUrl
|
OidcProviderTypeOauth2 = "oauth2" // OIDC提供者类型:GitHub
|
||||||
TargetTypePost = "post"
|
DefaultBaseUrl = "http://localhost:3000" // 默认BaseUrl
|
||||||
TargetTypeComment = "comment"
|
TargetTypePost = "post"
|
||||||
OrderByCreatedAt = "created_at" // 按创建时间排序
|
TargetTypeComment = "comment"
|
||||||
OrderByUpdatedAt = "updated_at" // 按更新时间排序
|
OrderByCreatedAt = "created_at" // 按创建时间排序
|
||||||
OrderByLikeCount = "like_count" // 按点赞数排序
|
OrderByUpdatedAt = "updated_at" // 按更新时间排序
|
||||||
OrderByCommentCount = "comment_count" // 按评论数排序
|
OrderByLikeCount = "like_count" // 按点赞数排序
|
||||||
OrderByViewCount = "view_count" // 按浏览量排序
|
OrderByCommentCount = "comment_count" // 按评论数排序
|
||||||
OrderByHeat = "heat"
|
OrderByViewCount = "view_count" // 按浏览量排序
|
||||||
MaxReplyDepthDefault = 3 // 默认最大回复深度
|
OrderByHeat = "heat"
|
||||||
HeatFactorViewWeight = 1 // 热度因子:浏览量权重
|
MaxReplyDepthDefault = 3 // 默认最大回复深度
|
||||||
HeatFactorLikeWeight = 5 // 热度因子:点赞权重
|
HeatFactorViewWeight = 1 // 热度因子:浏览量权重
|
||||||
HeatFactorCommentWeight = 10 // 热度因子:评论权重
|
HeatFactorLikeWeight = 5 // 热度因子:点赞权重
|
||||||
PageLimitDefault = 20 // 默认分页大小
|
HeatFactorCommentWeight = 10 // 热度因子:评论权重
|
||||||
|
PageLimitDefault = 20 // 默认分页大小
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
OrderByEnumPost = []string{OrderByCreatedAt, OrderByUpdatedAt, OrderByLikeCount, OrderByCommentCount, OrderByViewCount, OrderByHeat} // 帖子可用的排序方式
|
OrderByEnumPost = []string{OrderByCreatedAt, OrderByUpdatedAt, OrderByLikeCount, OrderByCommentCount, OrderByViewCount, OrderByHeat} // 帖子可用的排序方式
|
||||||
OrderByEnumComment = []string{OrderByCreatedAt, OrderByUpdatedAt, OrderByCommentCount} // 评论可用的排序方式
|
OrderByEnumComment = []string{OrderByCreatedAt, OrderByUpdatedAt, OrderByCommentCount} // 评论可用的排序方式
|
||||||
)
|
)
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/snowykami/neo-blog/pkg/constant"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IPData struct {
|
type IPData struct {
|
||||||
@ -56,5 +59,18 @@ func GetLocationString(ip string) string {
|
|||||||
if ipInfo == nil {
|
if ipInfo == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s %s %s %s", ipInfo.Country, ipInfo.Province, ipInfo.City, ipInfo.ISP)
|
|
||||||
|
tpl := Env.Get(constant.EnvKeyLocationFormat, "{{.Country}} {{.Province}} {{.City}} {{.ISP}}")
|
||||||
|
t, err := template.New("location").Parse(tpl)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Error(err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := t.Execute(&buf, ipInfo); err != nil {
|
||||||
|
logrus.Error(err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user