✨ update comment
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
package comment_api
|
package comment_api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"schisandra-cloud-album/model"
|
|
||||||
"schisandra-cloud-album/service"
|
"schisandra-cloud-album/service"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CommentAPI struct{}
|
type CommentAPI struct{}
|
||||||
@@ -13,18 +13,36 @@ type CommentImages struct {
|
|||||||
TopicId string `json:"topic_id" bson:"topic_id" required:"true"`
|
TopicId string `json:"topic_id" bson:"topic_id" required:"true"`
|
||||||
CommentId int64 `json:"comment_id" bson:"comment_id" required:"true"`
|
CommentId int64 `json:"comment_id" bson:"comment_id" required:"true"`
|
||||||
UserId string `json:"user_id" bson:"user_id" required:"true"`
|
UserId string `json:"user_id" bson:"user_id" required:"true"`
|
||||||
Images []string `json:"image_url" bson:"images" required:"true"`
|
Images [][]byte `json:"images" bson:"images" required:"true"`
|
||||||
CreatedAt string `json:"created_at" bson:"created_at" required:"true"`
|
CreatedAt string `json:"created_at" bson:"created_at" required:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommentData struct {
|
type CommentContent struct {
|
||||||
Comment model.ScaCommentReply `json:"comment"`
|
NickName string `json:"nickname"`
|
||||||
Images []string `json:"images,omitempty"`
|
Avatar string `json:"avatar"`
|
||||||
|
Level int `json:"level,omitempty"`
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
UserId string `json:"user_id"`
|
||||||
|
TopicId string `json:"topic_id"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
ReplyTo int64 `json:"reply_to,omitempty"`
|
||||||
|
ReplyId int64 `json:"reply_id,omitempty"`
|
||||||
|
ReplyUser string `json:"reply_user,omitempty"`
|
||||||
|
ReplyUsername string `json:"reply_username,omitempty"`
|
||||||
|
Author int `json:"author"`
|
||||||
|
Likes int64 `json:"likes"`
|
||||||
|
ReplyCount int64 `json:"reply_count"`
|
||||||
|
CreatedTime time.Time `json:"created_time"`
|
||||||
|
Dislikes int64 `json:"dislikes"`
|
||||||
|
Location string `json:"location"`
|
||||||
|
Browser string `json:"browser"`
|
||||||
|
OperatingSystem string `json:"operating_system"`
|
||||||
|
Images []string `json:"images,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommentResponse struct {
|
type CommentResponse struct {
|
||||||
Size int `json:"size"`
|
Size int `json:"size"`
|
||||||
Total int64 `json:"total"`
|
Total int64 `json:"total"`
|
||||||
Current int `json:"current"`
|
Current int `json:"current"`
|
||||||
Comments []CommentData `json:"comments"`
|
Comments []CommentContent `json:"comments"`
|
||||||
}
|
}
|
||||||
|
@@ -2,19 +2,25 @@ package comment_api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"github.com/acmestack/gorm-plus/gplus"
|
"github.com/acmestack/gorm-plus/gplus"
|
||||||
ginI18n "github.com/gin-contrib/i18n"
|
ginI18n "github.com/gin-contrib/i18n"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/mssola/useragent"
|
"github.com/mssola/useragent"
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"io"
|
||||||
|
"regexp"
|
||||||
"schisandra-cloud-album/api/comment_api/dto"
|
"schisandra-cloud-album/api/comment_api/dto"
|
||||||
"schisandra-cloud-album/common/enum"
|
"schisandra-cloud-album/common/enum"
|
||||||
"schisandra-cloud-album/common/result"
|
"schisandra-cloud-album/common/result"
|
||||||
"schisandra-cloud-album/global"
|
"schisandra-cloud-album/global"
|
||||||
"schisandra-cloud-album/model"
|
"schisandra-cloud-album/model"
|
||||||
"schisandra-cloud-album/utils"
|
"schisandra-cloud-album/utils"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -63,6 +69,12 @@ func (CommentAPI) CommentSubmit(c *gin.Context) {
|
|||||||
if commentRequest.UserID == commentRequest.Author {
|
if commentRequest.UserID == commentRequest.Author {
|
||||||
isAuthor = 1
|
isAuthor = 1
|
||||||
}
|
}
|
||||||
|
tx := global.DB.Begin()
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
}
|
||||||
|
}()
|
||||||
commentReply := model.ScaCommentReply{
|
commentReply := model.ScaCommentReply{
|
||||||
Content: commentRequest.Content,
|
Content: commentRequest.Content,
|
||||||
UserId: commentRequest.UserID,
|
UserId: commentRequest.UserID,
|
||||||
@@ -74,31 +86,59 @@ func (CommentAPI) CommentSubmit(c *gin.Context) {
|
|||||||
Location: location,
|
Location: location,
|
||||||
Browser: browser,
|
Browser: browser,
|
||||||
OperatingSystem: operatingSystem,
|
OperatingSystem: operatingSystem,
|
||||||
|
Agent: userAgent,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = commentReplyService.CreateCommentReply(&commentReply); err != nil {
|
if err = commentReplyService.CreateCommentReply(&commentReply); err != nil {
|
||||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||||
|
tx.Rollback()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(commentRequest.Images) > 0 {
|
if len(commentRequest.Images) > 0 {
|
||||||
|
|
||||||
|
var imagesData [][]byte
|
||||||
|
for _, img := range commentRequest.Images {
|
||||||
|
re := regexp.MustCompile(`^data:image/\w+;base64,`)
|
||||||
|
imgWithoutPrefix := re.ReplaceAllString(img, "")
|
||||||
|
data, err := base64ToBytes(imgWithoutPrefix)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorln(err)
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
imagesData = append(imagesData, data)
|
||||||
|
}
|
||||||
|
|
||||||
commentImages := CommentImages{
|
commentImages := CommentImages{
|
||||||
TopicId: commentRequest.TopicId,
|
TopicId: commentRequest.TopicId,
|
||||||
CommentId: commentReply.Id,
|
CommentId: commentReply.Id,
|
||||||
UserId: commentRequest.UserID,
|
UserId: commentRequest.UserID,
|
||||||
Images: commentRequest.Images,
|
Images: imagesData,
|
||||||
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
|
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
|
||||||
}
|
}
|
||||||
if _, err = global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").InsertOne(context.Background(), commentImages); err != nil {
|
if _, err = global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").InsertOne(context.Background(), commentImages); err != nil {
|
||||||
global.LOG.Errorln(err)
|
global.LOG.Errorln(err)
|
||||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||||
|
tx.Rollback()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tx.Commit()
|
||||||
result.OkWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitSuccess"), c)
|
result.OkWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitSuccess"), c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// base64ToBytes 将base64字符串转换为字节数组
|
||||||
|
func base64ToBytes(base64Str string) ([]byte, error) {
|
||||||
|
reader := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64Str))
|
||||||
|
data, err := io.ReadAll(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to decode base64 string")
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ReplySubmit 提交回复
|
// ReplySubmit 提交回复
|
||||||
// @Summary 提交回复
|
// @Summary 提交回复
|
||||||
// @Description 提交回复
|
// @Description 提交回复
|
||||||
@@ -117,7 +157,7 @@ func (CommentAPI) ReplySubmit(c *gin.Context) {
|
|||||||
if replyCommentRequest.Content == "" ||
|
if replyCommentRequest.Content == "" ||
|
||||||
replyCommentRequest.UserID == "" ||
|
replyCommentRequest.UserID == "" ||
|
||||||
replyCommentRequest.TopicId == "" ||
|
replyCommentRequest.TopicId == "" ||
|
||||||
replyCommentRequest.ReplyId == "" ||
|
strconv.FormatInt(replyCommentRequest.ReplyId, 10) == "" ||
|
||||||
replyCommentRequest.ReplyUser == "" {
|
replyCommentRequest.ReplyUser == "" {
|
||||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||||
return
|
return
|
||||||
@@ -148,6 +188,12 @@ func (CommentAPI) ReplySubmit(c *gin.Context) {
|
|||||||
if replyCommentRequest.UserID == replyCommentRequest.Author {
|
if replyCommentRequest.UserID == replyCommentRequest.Author {
|
||||||
isAuthor = 1
|
isAuthor = 1
|
||||||
}
|
}
|
||||||
|
tx := global.DB.Begin()
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
}
|
||||||
|
}()
|
||||||
commentReply := model.ScaCommentReply{
|
commentReply := model.ScaCommentReply{
|
||||||
Content: replyCommentRequest.Content,
|
Content: replyCommentRequest.Content,
|
||||||
UserId: replyCommentRequest.UserID,
|
UserId: replyCommentRequest.UserID,
|
||||||
@@ -161,27 +207,168 @@ func (CommentAPI) ReplySubmit(c *gin.Context) {
|
|||||||
Location: location,
|
Location: location,
|
||||||
Browser: browser,
|
Browser: browser,
|
||||||
OperatingSystem: operatingSystem,
|
OperatingSystem: operatingSystem,
|
||||||
|
Agent: userAgent,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = commentReplyService.CreateCommentReply(&commentReply); err != nil {
|
if err = commentReplyService.CreateCommentReply(&commentReply); err != nil {
|
||||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = commentReplyService.UpdateCommentReplyCount(replyCommentRequest.ReplyId)
|
||||||
|
if err != nil {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||||
|
tx.Rollback()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(replyCommentRequest.Images) > 0 {
|
if len(replyCommentRequest.Images) > 0 {
|
||||||
|
|
||||||
|
var imagesData [][]byte
|
||||||
|
for _, img := range replyCommentRequest.Images {
|
||||||
|
re := regexp.MustCompile(`^data:image/\w+;base64,`)
|
||||||
|
imgWithoutPrefix := re.ReplaceAllString(img, "")
|
||||||
|
data, err := base64ToBytes(imgWithoutPrefix)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorln(err)
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
imagesData = append(imagesData, data)
|
||||||
|
}
|
||||||
commentImages := CommentImages{
|
commentImages := CommentImages{
|
||||||
TopicId: replyCommentRequest.TopicId,
|
TopicId: replyCommentRequest.TopicId,
|
||||||
CommentId: commentReply.Id,
|
CommentId: commentReply.Id,
|
||||||
UserId: replyCommentRequest.UserID,
|
UserId: replyCommentRequest.UserID,
|
||||||
Images: replyCommentRequest.Images,
|
Images: imagesData,
|
||||||
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
|
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
|
||||||
}
|
}
|
||||||
if _, err = global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").InsertOne(context.Background(), commentImages); err != nil {
|
if _, err = global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").InsertOne(context.Background(), commentImages); err != nil {
|
||||||
global.LOG.Errorln(err)
|
global.LOG.Errorln(err)
|
||||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||||
|
tx.Rollback()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tx.Commit()
|
||||||
|
result.OkWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitSuccess"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReplyReplySubmit 提交回复的回复
|
||||||
|
// @Summary 提交回复的回复
|
||||||
|
// @Description 提交回复的回复
|
||||||
|
// @Tags 评论
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param reply_reply_request body dto.ReplyReplyRequest true "回复回复请求"
|
||||||
|
// @Router /auth/reply/reply/submit [post]
|
||||||
|
func (CommentAPI) ReplyReplySubmit(c *gin.Context) {
|
||||||
|
replyReplyRequest := dto.ReplyReplyRequest{}
|
||||||
|
if err := c.ShouldBindJSON(&replyReplyRequest); err != nil {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if replyReplyRequest.Content == "" ||
|
||||||
|
replyReplyRequest.UserID == "" ||
|
||||||
|
replyReplyRequest.TopicId == "" ||
|
||||||
|
replyReplyRequest.ReplyTo == 0 ||
|
||||||
|
replyReplyRequest.ReplyId == 0 ||
|
||||||
|
replyReplyRequest.ReplyUser == "" {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(replyReplyRequest.Images) > 3 {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "TooManyImages"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userAgent := c.GetHeader("User-Agent")
|
||||||
|
if userAgent == "" {
|
||||||
|
global.LOG.Errorln("user-agent is empty")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ua := useragent.New(userAgent)
|
||||||
|
|
||||||
|
ip := utils.GetClientIP(c)
|
||||||
|
location, err := global.IP2Location.SearchByStr(ip)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorln(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
location = utils.RemoveZeroAndAdjust(location)
|
||||||
|
|
||||||
|
browser, _ := ua.Browser()
|
||||||
|
operatingSystem := ua.OS()
|
||||||
|
isAuthor := 0
|
||||||
|
if replyReplyRequest.UserID == replyReplyRequest.Author {
|
||||||
|
isAuthor = 1
|
||||||
|
}
|
||||||
|
tx := global.DB.Begin()
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
commentReply := model.ScaCommentReply{
|
||||||
|
Content: replyReplyRequest.Content,
|
||||||
|
UserId: replyReplyRequest.UserID,
|
||||||
|
TopicId: replyReplyRequest.TopicId,
|
||||||
|
TopicType: enum.CommentTopicType,
|
||||||
|
CommentType: enum.REPLY,
|
||||||
|
ReplyTo: replyReplyRequest.ReplyTo,
|
||||||
|
ReplyId: replyReplyRequest.ReplyId,
|
||||||
|
ReplyUser: replyReplyRequest.ReplyUser,
|
||||||
|
Author: isAuthor,
|
||||||
|
CommentIp: ip,
|
||||||
|
Location: location,
|
||||||
|
Browser: browser,
|
||||||
|
OperatingSystem: operatingSystem,
|
||||||
|
Agent: userAgent,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = commentReplyService.CreateCommentReply(&commentReply); err != nil {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = commentReplyService.UpdateCommentReplyCount(replyReplyRequest.ReplyId)
|
||||||
|
if err != nil {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(replyReplyRequest.Images) > 0 {
|
||||||
|
|
||||||
|
var imagesData [][]byte
|
||||||
|
for _, img := range replyReplyRequest.Images {
|
||||||
|
re := regexp.MustCompile(`^data:image/\w+;base64,`)
|
||||||
|
imgWithoutPrefix := re.ReplaceAllString(img, "")
|
||||||
|
data, err := base64ToBytes(imgWithoutPrefix)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorln(err)
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
imagesData = append(imagesData, data)
|
||||||
|
}
|
||||||
|
commentImages := CommentImages{
|
||||||
|
TopicId: replyReplyRequest.TopicId,
|
||||||
|
CommentId: commentReply.Id,
|
||||||
|
UserId: replyReplyRequest.UserID,
|
||||||
|
Images: imagesData,
|
||||||
|
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
|
||||||
|
}
|
||||||
|
if _, err = global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").InsertOne(context.Background(), commentImages); err != nil {
|
||||||
|
global.LOG.Errorln(err)
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tx.Commit()
|
||||||
result.OkWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitSuccess"), c)
|
result.OkWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitSuccess"), c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -207,22 +394,154 @@ func (CommentAPI) CommentList(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
query, u := gplus.NewQuery[model.ScaCommentReply]()
|
query, u := gplus.NewQuery[model.ScaCommentReply]()
|
||||||
page := gplus.NewPage[model.ScaCommentReply](commentListRequest.Page, commentListRequest.Size)
|
page := gplus.NewPage[model.ScaCommentReply](commentListRequest.Page, commentListRequest.Size)
|
||||||
query.Eq(&u.TopicId, commentListRequest.TopicId).OrderByDesc(&u.Likes)
|
query.Eq(&u.TopicId, commentListRequest.TopicId).Eq(&u.CommentType, enum.COMMENT).OrderByDesc(&u.Likes)
|
||||||
page, _ = gplus.SelectPage(page, query)
|
page, _ = gplus.SelectPage(page, query)
|
||||||
|
|
||||||
var commentsWithImages []CommentData
|
var commentsWithImages []CommentContent
|
||||||
|
|
||||||
for _, user := range page.Records {
|
for _, comment := range page.Records {
|
||||||
// 获取评论图片
|
// 获取评论图片
|
||||||
commentImages := CommentImages{}
|
commentImages := CommentImages{}
|
||||||
wrong := global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").FindOne(context.Background(), bson.M{"comment_id": user.Id}).Decode(&commentImages)
|
wrong := global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").FindOne(context.Background(), bson.M{"comment_id": comment.Id}).Decode(&commentImages)
|
||||||
if wrong != nil && !errors.Is(wrong, mongo.ErrNoDocuments) {
|
if wrong != nil && !errors.Is(wrong, mongo.ErrNoDocuments) {
|
||||||
global.LOG.Errorln(wrong)
|
global.LOG.Errorln(wrong)
|
||||||
}
|
}
|
||||||
commentsWithImages = append(commentsWithImages, CommentData{
|
// 将图片转换为base64
|
||||||
Comment: *user,
|
var imagesBase64 []string
|
||||||
Images: commentImages.Images,
|
for _, img := range commentImages.Images {
|
||||||
})
|
mimeType := getMimeType(img) // 动态获取 MIME 类型
|
||||||
|
base64Img := base64.StdEncoding.EncodeToString(img)
|
||||||
|
base64WithPrefix := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Img)
|
||||||
|
imagesBase64 = append(imagesBase64, base64WithPrefix)
|
||||||
|
}
|
||||||
|
// 组装评论数据
|
||||||
|
queryUser, n := gplus.NewQuery[model.ScaAuthUser]()
|
||||||
|
queryUser.Eq(&n.UID, comment.UserId)
|
||||||
|
userInfo, _ := gplus.SelectOne(queryUser)
|
||||||
|
commentsWithImages = append(commentsWithImages,
|
||||||
|
CommentContent{
|
||||||
|
Avatar: *userInfo.Avatar,
|
||||||
|
NickName: *userInfo.Nickname,
|
||||||
|
Id: comment.Id,
|
||||||
|
UserId: comment.UserId,
|
||||||
|
TopicId: comment.TopicId,
|
||||||
|
Dislikes: comment.Dislikes,
|
||||||
|
Content: comment.Content,
|
||||||
|
ReplyCount: comment.ReplyCount,
|
||||||
|
Likes: comment.Likes,
|
||||||
|
CreatedTime: comment.CreatedTime,
|
||||||
|
Author: comment.Author,
|
||||||
|
Location: comment.Location,
|
||||||
|
Browser: comment.Browser,
|
||||||
|
OperatingSystem: comment.OperatingSystem,
|
||||||
|
Images: imagesBase64,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
response := CommentResponse{
|
||||||
|
Comments: commentsWithImages,
|
||||||
|
Size: page.Size,
|
||||||
|
Current: page.Current,
|
||||||
|
Total: page.Total,
|
||||||
|
}
|
||||||
|
result.OkWithData(response, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMimeType(data []byte) string {
|
||||||
|
if len(data) < 4 {
|
||||||
|
return "application/octet-stream" // 默认类型
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断 JPEG
|
||||||
|
if data[0] == 0xFF && data[1] == 0xD8 {
|
||||||
|
return "image/jpeg"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断 PNG
|
||||||
|
if len(data) >= 8 && data[0] == 0x89 && data[1] == 0x50 && data[2] == 0x4E && data[3] == 0x47 &&
|
||||||
|
data[4] == 0x0D && data[5] == 0x0A && data[6] == 0x1A && data[7] == 0x0A {
|
||||||
|
return "image/png"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断 GIF
|
||||||
|
if len(data) >= 6 && data[0] == 'G' && data[1] == 'I' && data[2] == 'F' {
|
||||||
|
return "image/gif"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "application/octet-stream" // 默认类型
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReplyList 获取回复列表
|
||||||
|
// @Summary 获取回复列表
|
||||||
|
// @Description 获取回复列表
|
||||||
|
// @Tags 评论
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param reply_list_request body dto.ReplyListRequest true "回复列表请求"
|
||||||
|
// @Router /auth/reply/list [post]
|
||||||
|
func (CommentAPI) ReplyList(c *gin.Context) {
|
||||||
|
replyListRequest := dto.ReplyListRequest{}
|
||||||
|
err := c.ShouldBindJSON(&replyListRequest)
|
||||||
|
if err != nil {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if replyListRequest.TopicId == "" || strconv.FormatInt(replyListRequest.CommentId, 10) == "" {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
query, u := gplus.NewQuery[model.ScaCommentReply]()
|
||||||
|
page := gplus.NewPage[model.ScaCommentReply](replyListRequest.Page, replyListRequest.Size)
|
||||||
|
query.Eq(&u.TopicId, replyListRequest.TopicId).Eq(&u.ReplyId, replyListRequest.CommentId).Eq(&u.CommentType, enum.REPLY).OrderByDesc(&u.Likes)
|
||||||
|
page, _ = gplus.SelectPage(page, query)
|
||||||
|
|
||||||
|
var commentsWithImages []CommentContent
|
||||||
|
|
||||||
|
for _, comment := range page.Records {
|
||||||
|
// 获取评论图片
|
||||||
|
commentImages := CommentImages{}
|
||||||
|
wrong := global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").FindOne(context.Background(), bson.M{"comment_id": comment.Id}).Decode(&commentImages)
|
||||||
|
if wrong != nil && !errors.Is(wrong, mongo.ErrNoDocuments) {
|
||||||
|
global.LOG.Errorln(wrong)
|
||||||
|
}
|
||||||
|
// 将图片转换为base64
|
||||||
|
var imagesBase64 []string
|
||||||
|
for _, img := range commentImages.Images {
|
||||||
|
mimeType := getMimeType(img) // 动态获取 MIME 类型
|
||||||
|
base64Img := base64.StdEncoding.EncodeToString(img)
|
||||||
|
base64WithPrefix := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Img)
|
||||||
|
imagesBase64 = append(imagesBase64, base64WithPrefix)
|
||||||
|
}
|
||||||
|
// 查询评论用户信息
|
||||||
|
queryUser, n := gplus.NewQuery[model.ScaAuthUser]()
|
||||||
|
queryUser.Eq(&n.UID, comment.UserId)
|
||||||
|
userInfo, _ := gplus.SelectOne(queryUser)
|
||||||
|
// 查询回复用户信息
|
||||||
|
queryReplyUser, m := gplus.NewQuery[model.ScaAuthUser]()
|
||||||
|
queryReplyUser.Eq(&m.UID, comment.ReplyUser)
|
||||||
|
replyUserInfo, _ := gplus.SelectOne(queryReplyUser)
|
||||||
|
commentsWithImages = append(commentsWithImages,
|
||||||
|
CommentContent{
|
||||||
|
Avatar: *userInfo.Avatar,
|
||||||
|
NickName: *userInfo.Nickname,
|
||||||
|
Id: comment.Id,
|
||||||
|
UserId: comment.UserId,
|
||||||
|
TopicId: comment.TopicId,
|
||||||
|
Dislikes: comment.Dislikes,
|
||||||
|
Content: comment.Content,
|
||||||
|
ReplyUsername: *replyUserInfo.Nickname,
|
||||||
|
ReplyCount: comment.ReplyCount,
|
||||||
|
Likes: comment.Likes,
|
||||||
|
CreatedTime: comment.CreatedTime,
|
||||||
|
ReplyUser: comment.ReplyUser,
|
||||||
|
ReplyId: comment.ReplyId,
|
||||||
|
ReplyTo: comment.ReplyTo,
|
||||||
|
Author: comment.Author,
|
||||||
|
Location: comment.Location,
|
||||||
|
Browser: comment.Browser,
|
||||||
|
OperatingSystem: comment.OperatingSystem,
|
||||||
|
Images: imagesBase64,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
response := CommentResponse{
|
response := CommentResponse{
|
||||||
Comments: commentsWithImages,
|
Comments: commentsWithImages,
|
||||||
|
@@ -12,12 +12,30 @@ type ReplyCommentRequest struct {
|
|||||||
Images []string `json:"images"`
|
Images []string `json:"images"`
|
||||||
UserID string `json:"user_id"`
|
UserID string `json:"user_id"`
|
||||||
TopicId string `json:"topic_id"`
|
TopicId string `json:"topic_id"`
|
||||||
ReplyId string `json:"reply_id"`
|
ReplyId int64 `json:"reply_id"`
|
||||||
ReplyUser string `json:"reply_user"`
|
ReplyUser string `json:"reply_user"`
|
||||||
Author string `json:"author"`
|
Author string `json:"author"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ReplyReplyRequest struct {
|
||||||
|
Content string `json:"content"`
|
||||||
|
Images []string `json:"images"`
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
TopicId string `json:"topic_id"`
|
||||||
|
ReplyTo int64 `json:"reply_to"`
|
||||||
|
ReplyId int64 `json:"reply_id"`
|
||||||
|
ReplyUser string `json:"reply_user"`
|
||||||
|
Author string `json:"author"`
|
||||||
|
}
|
||||||
|
|
||||||
type CommentListRequest struct {
|
type CommentListRequest struct {
|
||||||
TopicId string `json:"topic_id"`
|
TopicId string `json:"topic_id"`
|
||||||
Page int `json:"page" default:"1"`
|
Page int `json:"page" default:"1"`
|
||||||
Size int `json:"size" default:"10"`
|
Size int `json:"size" default:"5"`
|
||||||
|
}
|
||||||
|
type ReplyListRequest struct {
|
||||||
|
TopicId string `json:"topic_id"`
|
||||||
|
CommentId int64 `json:"comment_id"`
|
||||||
|
Page int `json:"page" default:"1"`
|
||||||
|
Size int `json:"size" default:"5"`
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
"github.com/rbcervilla/redisstore/v9"
|
"github.com/rbcervilla/redisstore/v9"
|
||||||
"github.com/redis/go-redis/v9"
|
"github.com/redis/go-redis/v9"
|
||||||
|
"net/http"
|
||||||
"schisandra-cloud-album/common/constant"
|
"schisandra-cloud-album/common/constant"
|
||||||
"schisandra-cloud-album/global"
|
"schisandra-cloud-album/global"
|
||||||
)
|
)
|
||||||
@@ -20,7 +21,10 @@ func InitSession(client *redis.Client) {
|
|||||||
store.Options(sessions.Options{
|
store.Options(sessions.Options{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
//Domain: global.CONFIG.System.Web,
|
//Domain: global.CONFIG.System.Web,
|
||||||
MaxAge: 86400 * 7,
|
MaxAge: 86400 * 7,
|
||||||
|
HttpOnly: true,
|
||||||
|
Secure: true,
|
||||||
|
SameSite: http.SameSiteLaxMode,
|
||||||
})
|
})
|
||||||
global.Session = store
|
global.Session = store
|
||||||
}
|
}
|
||||||
|
@@ -12,25 +12,27 @@ type ScaCommentReply struct {
|
|||||||
Id int64 `gorm:"column:id;type:bigint(20);primary_key;AUTO_INCREMENT;comment:主键id" json:"id"`
|
Id int64 `gorm:"column:id;type:bigint(20);primary_key;AUTO_INCREMENT;comment:主键id" json:"id"`
|
||||||
UserId string `gorm:"column:user_id;type:varchar(20);comment:评论用户id" json:"user_id"`
|
UserId string `gorm:"column:user_id;type:varchar(20);comment:评论用户id" json:"user_id"`
|
||||||
TopicId string `gorm:"column:topic_id;type:varchar(20);comment:评论话题id" json:"topic_id"`
|
TopicId string `gorm:"column:topic_id;type:varchar(20);comment:评论话题id" json:"topic_id"`
|
||||||
TopicType int `gorm:"column:topic_type;type:int(11);comment:话题类型" json:"topic_type"`
|
TopicType int `gorm:"column:topic_type;type:int(11);comment:话题类型" json:"-"`
|
||||||
Content string `gorm:"column:content;type:longtext;comment:评论内容" json:"content"`
|
Content string `gorm:"column:content;type:longtext;comment:评论内容" json:"content"`
|
||||||
CommentType int `gorm:"column:comment_type;type:int(11);comment:评论类型 0评论 1 回复" json:"comment_type"`
|
CommentType int `gorm:"column:comment_type;type:int(11);comment:评论类型 0评论 1 回复" json:"-"`
|
||||||
ReplyId string `gorm:"column:reply_id;type:varchar(20);comment:回复目标id" json:"reply_id"`
|
ReplyTo int64 `gorm:"column:reply_to;type:bigint(20);comment:回复子评论id" json:"reply_to"`
|
||||||
ReplyUser string `gorm:"column:reply_user;type:varchar(20);comment:回复人id" json:"reply_user"`
|
ReplyId int64 `gorm:"column:reply_id;type:varchar(20);comment:回复目标id" json:"reply_id,omitempty"`
|
||||||
|
ReplyUser string `gorm:"column:reply_user;type:varchar(20);comment:回复人id" json:"reply_user,omitempty"`
|
||||||
Author int `gorm:"column:author;type:int(11);default:0;comment:评论回复是否作者 0否 1是" json:"author"`
|
Author int `gorm:"column:author;type:int(11);default:0;comment:评论回复是否作者 0否 1是" json:"author"`
|
||||||
Likes int64 `gorm:"column:likes;type:bigint(20);default:0;comment:点赞数" json:"likes"`
|
Likes int64 `gorm:"column:likes;type:bigint(20);default:0;comment:点赞数" json:"likes"`
|
||||||
ReplyCount int64 `gorm:"column:reply_count;type:bigint(20);default:0;comment:回复数量" json:"reply_count"`
|
ReplyCount int64 `gorm:"column:reply_count;type:bigint(20);default:0;comment:回复数量" json:"reply_count"`
|
||||||
CreatedTime time.Time `gorm:"column:created_time;type:datetime;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_time"`
|
CreatedTime time.Time `gorm:"column:created_time;type:datetime;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_time"`
|
||||||
UpdateTime time.Time `gorm:"column:update_time;type:datetime;default:CURRENT_TIMESTAMP;comment:更新时间" json:"update_time"`
|
UpdateTime time.Time `gorm:"column:update_time;type:datetime;default:CURRENT_TIMESTAMP;comment:更新时间" json:"-"`
|
||||||
Deleted int `gorm:"column:deleted;type:int(11);default:0;comment:是否删除 0未删除 1 已删除" json:"deleted"`
|
Deleted int `gorm:"column:deleted;type:int(11);default:0;comment:是否删除 0未删除 1 已删除" json:"-"`
|
||||||
CreatedBy string `gorm:"column:created_by;type:varchar(32);comment:创建人" json:"created_by"`
|
CreatedBy string `gorm:"column:created_by;type:varchar(32);comment:创建人" json:"-"`
|
||||||
UpdateBy string `gorm:"column:update_by;type:varchar(32);comment:更新人" json:"update_by"`
|
UpdateBy string `gorm:"column:update_by;type:varchar(32);comment:更新人" json:"-"`
|
||||||
Dislikes int64 `gorm:"column:dislikes;type:bigint(20);default:0;comment:踩数" json:"dislikes"`
|
Dislikes int64 `gorm:"column:dislikes;type:bigint(20);default:0;comment:踩数" json:"dislikes"`
|
||||||
CommentIp string `gorm:"column:comment_ip;type:varchar(20);comment:评论ip" json:"comment_ip"`
|
CommentIp string `gorm:"column:comment_ip;type:varchar(20);comment:评论ip" json:"-"`
|
||||||
Location string `gorm:"column:location;type:varchar(20);comment:评论地址" json:"location"`
|
Location string `gorm:"column:location;type:varchar(20);comment:评论地址" json:"location"`
|
||||||
Browser string `gorm:"column:browser;type:varchar(20);comment:评论浏览器" json:"browser"`
|
Browser string `gorm:"column:browser;type:varchar(20);comment:评论浏览器" json:"browser"`
|
||||||
OperatingSystem string `gorm:"column:operating_system;type:varchar(20);comment:评论操作系统" json:"operating_system"`
|
OperatingSystem string `gorm:"column:operating_system;type:varchar(20);comment:评论操作系统" json:"operating_system"`
|
||||||
CommentOrder int64 `gorm:"column:comment_order;type:bigint(20);default:0;comment:评论排序" json:"comment_order"`
|
CommentOrder int64 `gorm:"column:comment_order;type:bigint(20);default:0;comment:评论排序" json:"-"`
|
||||||
|
Agent string `gorm:"column:agent;type:varchar(255);comment:客户端设备信息" json:"agent"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (comment *ScaCommentReply) TableName() string {
|
func (comment *ScaCommentReply) TableName() string {
|
||||||
|
@@ -11,4 +11,6 @@ func CommentRouter(router *gin.RouterGroup) {
|
|||||||
router.POST("/auth/comment/submit", commonApi.CommentSubmit)
|
router.POST("/auth/comment/submit", commonApi.CommentSubmit)
|
||||||
router.POST("/auth/reply/submit", commonApi.ReplySubmit)
|
router.POST("/auth/reply/submit", commonApi.ReplySubmit)
|
||||||
router.POST("/auth/comment/list", commonApi.CommentList)
|
router.POST("/auth/comment/list", commonApi.CommentList)
|
||||||
|
router.POST("/auth/reply/list", commonApi.ReplyList)
|
||||||
|
router.POST("/auth/reply/reply/submit", commonApi.ReplyReplySubmit)
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
package comment_reply_service
|
package comment_reply_service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"gorm.io/gorm"
|
||||||
"schisandra-cloud-album/global"
|
"schisandra-cloud-album/global"
|
||||||
"schisandra-cloud-album/model"
|
"schisandra-cloud-album/model"
|
||||||
)
|
)
|
||||||
@@ -38,3 +40,19 @@ func (CommentReplyService) GetCommentListOrderByLikesDesc(topicID uint, page, pa
|
|||||||
}
|
}
|
||||||
return comments, nil
|
return comments, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateCommentReplyCount 更新评论
|
||||||
|
func (CommentReplyService) UpdateCommentReplyCount(commentID int64) error {
|
||||||
|
// 使用事务处理错误
|
||||||
|
err := global.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
|
result := tx.Model(&model.ScaCommentReply{}).Where("id = ?", commentID).Update("reply_count", gorm.Expr("reply_count + ?", 1))
|
||||||
|
if result.Error != nil {
|
||||||
|
return result.Error // 返回更新错误
|
||||||
|
}
|
||||||
|
if result.RowsAffected == 0 {
|
||||||
|
return fmt.Errorf("comment not found") // 处理评论不存在的情况
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/gob"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"schisandra-cloud-album/global"
|
"schisandra-cloud-album/global"
|
||||||
@@ -12,12 +13,8 @@ func SetSession(c *gin.Context, key string, data interface{}) error {
|
|||||||
global.LOG.Error("SetSession failed: ", err)
|
global.LOG.Error("SetSession failed: ", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
jsonData, err := json.Marshal(data)
|
gob.Register(data)
|
||||||
if err != nil {
|
session.Values[key] = data
|
||||||
global.LOG.Error("SetSession failed: ", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
session.Values[key] = jsonData
|
|
||||||
err = session.Save(c.Request, c.Writer)
|
err = session.Save(c.Request, c.Writer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Error("SetSession failed: ", err)
|
global.LOG.Error("SetSession failed: ", err)
|
||||||
@@ -25,3 +22,38 @@ func SetSession(c *gin.Context, key string, data interface{}) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetSession(c *gin.Context, key string) interface{} {
|
||||||
|
session, err := global.Session.Get(c.Request, key)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Error("GetSession failed: ", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
jsonData, ok := session.Values[key]
|
||||||
|
if !ok {
|
||||||
|
global.LOG.Error("GetSession failed: ", "key not found")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var data interface{}
|
||||||
|
err = json.Unmarshal(jsonData.([]byte), &data)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Error("GetSession failed: ", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func DelSession(c *gin.Context, key string) {
|
||||||
|
session, err := global.Session.Get(c.Request, key)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Error("DelSession failed: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(session.Values, key)
|
||||||
|
err = session.Save(c.Request, c.Writer)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Error("DelSession failed: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user