update comment

This commit is contained in:
landaiqing
2024-09-24 01:15:21 +08:00
parent 5cc4294268
commit 5d86914cb7
8 changed files with 452 additions and 39 deletions

View File

@@ -1,8 +1,8 @@
package comment_api
import (
"schisandra-cloud-album/model"
"schisandra-cloud-album/service"
"time"
)
type CommentAPI struct{}
@@ -13,18 +13,36 @@ type CommentImages struct {
TopicId string `json:"topic_id" bson:"topic_id" required:"true"`
CommentId int64 `json:"comment_id" bson:"comment_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"`
}
type CommentData struct {
Comment model.ScaCommentReply `json:"comment"`
Images []string `json:"images,omitempty"`
type CommentContent struct {
NickName string `json:"nickname"`
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 {
Size int `json:"size"`
Total int64 `json:"total"`
Current int `json:"current"`
Comments []CommentData `json:"comments"`
Size int `json:"size"`
Total int64 `json:"total"`
Current int `json:"current"`
Comments []CommentContent `json:"comments"`
}

View File

@@ -2,19 +2,25 @@ package comment_api
import (
"context"
"encoding/base64"
"errors"
"fmt"
"github.com/acmestack/gorm-plus/gplus"
ginI18n "github.com/gin-contrib/i18n"
"github.com/gin-gonic/gin"
"github.com/mssola/useragent"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"io"
"regexp"
"schisandra-cloud-album/api/comment_api/dto"
"schisandra-cloud-album/common/enum"
"schisandra-cloud-album/common/result"
"schisandra-cloud-album/global"
"schisandra-cloud-album/model"
"schisandra-cloud-album/utils"
"strconv"
"strings"
"time"
)
@@ -63,6 +69,12 @@ func (CommentAPI) CommentSubmit(c *gin.Context) {
if commentRequest.UserID == commentRequest.Author {
isAuthor = 1
}
tx := global.DB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
commentReply := model.ScaCommentReply{
Content: commentRequest.Content,
UserId: commentRequest.UserID,
@@ -74,31 +86,59 @@ func (CommentAPI) CommentSubmit(c *gin.Context) {
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
}
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{
TopicId: commentRequest.TopicId,
CommentId: commentReply.Id,
UserId: commentRequest.UserID,
Images: commentRequest.Images,
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)
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 提交回复
// @Summary 提交回复
// @Description 提交回复
@@ -117,7 +157,7 @@ func (CommentAPI) ReplySubmit(c *gin.Context) {
if replyCommentRequest.Content == "" ||
replyCommentRequest.UserID == "" ||
replyCommentRequest.TopicId == "" ||
replyCommentRequest.ReplyId == "" ||
strconv.FormatInt(replyCommentRequest.ReplyId, 10) == "" ||
replyCommentRequest.ReplyUser == "" {
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
return
@@ -148,6 +188,12 @@ func (CommentAPI) ReplySubmit(c *gin.Context) {
if replyCommentRequest.UserID == replyCommentRequest.Author {
isAuthor = 1
}
tx := global.DB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
commentReply := model.ScaCommentReply{
Content: replyCommentRequest.Content,
UserId: replyCommentRequest.UserID,
@@ -161,27 +207,168 @@ func (CommentAPI) ReplySubmit(c *gin.Context) {
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(replyCommentRequest.ReplyId)
if err != nil {
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
tx.Rollback()
return
}
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{
TopicId: replyCommentRequest.TopicId,
CommentId: commentReply.Id,
UserId: replyCommentRequest.UserID,
Images: replyCommentRequest.Images,
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)
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)
return
}
@@ -207,22 +394,154 @@ func (CommentAPI) CommentList(c *gin.Context) {
}
query, u := gplus.NewQuery[model.ScaCommentReply]()
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)
var commentsWithImages []CommentData
var commentsWithImages []CommentContent
for _, user := range page.Records {
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": 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) {
global.LOG.Errorln(wrong)
}
commentsWithImages = append(commentsWithImages, CommentData{
Comment: *user,
Images: commentImages.Images,
})
// 将图片转换为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)
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{
Comments: commentsWithImages,

View File

@@ -12,12 +12,30 @@ type ReplyCommentRequest struct {
Images []string `json:"images"`
UserID string `json:"user_id"`
TopicId string `json:"topic_id"`
ReplyId string `json:"reply_id"`
ReplyId int64 `json:"reply_id"`
ReplyUser string `json:"reply_user"`
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 {
TopicId string `json:"topic_id"`
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"`
}