Initial commit

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 13:57:10 +08:00
co-authored by Claude Opus 5
commit 8679200f41
1897 changed files with 257900 additions and 0 deletions
+71
View File
@@ -0,0 +1,71 @@
package commentser
import (
"91porn-server/common/stderr"
"91porn-server/models/commod"
"91porn-server/models/v/cmtmod"
"time"
)
// GetChildCmtList 获取子评论列表
func GetChildCmtList(uid uint64, objID ObjectID, cid ObjectID, fstID ObjectID, curTime time.Time, page commod.Page) (code stderr.Code, data []cmtmod.ChildRespList, err error) {
// 获取作者
//videoInfo, err := vidmod.GetVideoInfo(objID.Hex())
//if err != nil {
// code = stderr.CommentErrGetDataFail
// return
//}
skip, limit := getNewPageInfo(0, int64(page.PageNumber), int64(page.PageSize))
aTotal, aList, err := getAuthorChildCmtList(objID, cid, fstID, skip, limit, curTime)
if err != nil {
code = stderr.CommentErrGetDataFail
return
}
if len(aList) > int(page.PageSize) {
data, err = getChildCommentTackInfo(uid, aList)
code = stderr.Success
return
}
// 获取热评及其回复
skip, limit = getNewPageInfo(aTotal, int64(page.PageNumber), int64(page.PageSize))
_, hList, err := getHotChildCmtList(objID, cid, fstID, skip, limit, curTime)
if err != nil {
code = stderr.CommentErrGetDataFail
return
}
aList = append(aList, hList...)
//if len(aList) > page.PageSize {
data, err = getChildCommentTackInfo(uid, aList)
code = stderr.Success
return
//}
// 获取普通评论
//skip, limit = getNewPageInfo(aTotal+hTotal, int64(page.PageNumber), int64(page.PageSize))
//cList, err := getChildCmtList(objID, cid, fstID, skip, limit, curTime)
//if err != nil {
// return
//}
//aList = append(aList, cList...)
//data, err = getChildCommentTackInfo(uid, aList)
//if err != nil {
// code = stderr.CommentErrGetDataFail
// return
//}
//code = stderr.Success
//return
}
// 获取作者的子评论及其回复和数量
func getAuthorChildCmtList(objID ObjectID, cid ObjectID, fstId ObjectID, skip int64, limit int64, curTime time.Time) (total int64, data []cmtmod.Comment, err error) {
return cmtmod.GetAuthorChildCmtList(objID, cid, fstId, skip, limit, curTime)
}
// 获取热门的子评论及其回复和数量
func getHotChildCmtList(objID ObjectID, cid ObjectID, fstId ObjectID, skip int64, limit int64, curTime time.Time) (total int64, data []cmtmod.Comment, err error) {
return cmtmod.GetHotChildCmtList(objID, cid, fstId, skip, limit, curTime)
}
// 获取普通子评论
func getChildCmtList(objID ObjectID, cid ObjectID, fstId ObjectID, skip int64, limit int64, curTime time.Time) (data []cmtmod.Comment, err error) {
return cmtmod.GetChildCmtList(objID, cid, fstId, skip, limit, curTime)
}
+328
View File
@@ -0,0 +1,328 @@
package commentser
import (
"91porn-server/app/service/userser"
"91porn-server/common"
"91porn-server/common/constant"
"91porn-server/models/v/cmtmod"
"91porn-server/models/v/followmod"
"91porn-server/models/v/likemod"
"91porn-server/models/v/usermod"
"go.mongodb.org/mongo-driver/bson/primitive"
"sync"
"time"
)
type ObjectID = primitive.ObjectID
// 获取父评论的附加信息--用户头像/是否点赞/是否是关注
func getParentCommentTackInfo(uid uint64, cModList []cmtmod.Comment) (data []cmtmod.ParentRespList, err error) {
now := time.Now()
if cModList == nil {
return []cmtmod.ParentRespList{}, err
}
var CIDs []ObjectID
var UIDs []uint64
for _, value := range cModList {
if uid != value.UserID && value.IsAdvertiser {
continue
}
tmp := cmtmod.ParentRespList{
ID: value.ID.Hex(),
ObjID: value.ObjID.Hex(),
UserID: value.UserID,
LikeCount: value.LikeCount,
LinkStr: value.LinkStr,
IsFollow: false,
IsAuthor: value.IsAuthor,
IsLike: false,
IsDelete: value.IsDelete,
IsGodComment: value.IsGodComment,
CommCount: value.CommentCount,
CommCountBurden: value.CommentCount,
Content: value.Content,
Image: value.Image,
Status: value.Status,
City: value.City,
QuoteType: value.QuoteType,
QuoteID: value.QuoteID,
QuoteTitle: value.QuoteTitle,
QuoteImg: value.QuoteImg,
CreatedAt: value.CreatedAt,
Info: []cmtmod.ChildRespList{}, // 空值处理
}
CIDs = append(CIDs, value.ID)
UIDs = append(UIDs, value.UserID)
data = append(data, tmp)
}
var wg = sync.WaitGroup{}
var errs []error
wg.Add(3)
// 获取点赞记录信息
common.Go(func() {
defer wg.Done()
likedList, err1 := likemod.FindLikesByObjIDS(constant.LikeTypeComment, uid, CIDs)
if err1 != nil {
errs = append(errs, err1)
return
}
for k, v := range data {
for _, ls := range likedList {
if v.ID == ls.ObjID.Hex() {
data[k].IsLike = true
break
}
}
}
})
// 获取用户昵称/性别/头像地址
common.Go(func() {
defer wg.Done()
users, err1 := usermod.FindUsersByUID(UIDs)
if err1 != nil {
errs = append(errs, err1)
return
}
for k, v := range data {
for _, u := range users {
if v.UserID == u.UID {
data[k].UserName = u.Name
data[k].UserPortrait = u.Portrait
data[k].Gender = u.Gender
data[k].Age = u.Age()
data[k].Level = u.VipLevel
data[k].VipLevel = u.VipLevel
data[k].SuperUser = u.GetSuperUser(now)
data[k].Awards = u.Awards
data[k].AwardsExpire = userser.HandleUserAwardsExpire(u)
data[k].VipExpireDate = u.VipExpireDate
break
}
}
}
})
// 是否关注
common.Go(func() {
defer wg.Done()
fMap, err1 := followmod.IsFollowUsers(uid, UIDs)
if err1 != nil {
errs = append(errs, err1)
return
}
for k, v := range data {
if fMap[v.UserID] {
data[k].IsFollow = true
} else {
data[k].IsFollow = false
}
}
})
wg.Wait()
if len(errs) > 0 {
err = errs[0]
return
}
return
}
// 获取父评论的作者或者热门的首条子评论
func getFstChildCmtOfParent(isAdvertiser bool, objID ObjectID, list []cmtmod.ParentRespList, ids []ObjectID, uid uint64, author uint64, curTime time.Time) (data []cmtmod.ParentRespList, err error) {
if list == nil || ids == nil {
return
}
// 先获取作者的子评论
aList, err := cmtmod.GetFstAuthorCmtOfParentCmt(isAdvertiser, objID, ids, author, curTime)
if err != nil {
return
}
var cmtMap = make(map[ObjectID]*cmtmod.Comment)
for _, v := range aList {
_v := v
cmtMap[v.CID] = &_v
}
// 获取其余的子评论
cList, err := cmtmod.GetFstCmtOfParentCmt(isAdvertiser, objID, ids, curTime)
for _, v := range cList {
_v := v
if cmtMap[v.CID] == nil {
cmtMap[v.CID] = &_v
}
}
var childList []cmtmod.Comment
for _, v := range cmtMap {
childList = append(childList, *v)
}
cResList, err := getChildCommentTackInfo(uid, childList)
var childMap = make(map[string]*cmtmod.ChildRespList)
for _, v := range cResList {
_v := v
childMap[v.CID] = &_v
}
for _, v := range list {
if childMap[v.ID] != nil {
v.Info = []cmtmod.ChildRespList{*childMap[v.ID]}
data = append(data, v)
} else {
data = append(data, v)
}
}
return
}
// 获取子评论的附加信息--用户头像/是否点赞/是否是关注
func getChildCommentTackInfo(uid uint64, cModList []cmtmod.Comment) (data []cmtmod.ChildRespList, err error) {
now := time.Now()
if len(cModList) == 0 {
return
}
var CIDs []ObjectID
var UIDs []uint64
var toUIDs []uint64
for _, value := range cModList {
if uid != value.UserID && value.IsAdvertiser {
continue
}
tmp := cmtmod.ChildRespList{
ID: value.ID.Hex(),
ObjID: value.ObjID.Hex(),
CID: value.CID.Hex(),
UserID: value.UserID,
ToUserID: value.ToUserID,
LikeCount: value.LikeCount,
LinkStr: value.LinkStr,
Level: value.Level,
IsFollow: false,
IsAuthor: value.IsAuthor,
IsLike: false,
IsDelete: value.IsDelete,
Content: value.Content,
Image: value.Image,
Status: value.Status,
City: value.City,
QuoteType: value.QuoteType,
QuoteID: value.QuoteID,
QuoteTitle: value.QuoteTitle,
QuoteImg: value.QuoteImg,
CreatedAt: value.CreatedAt,
}
CIDs = append(CIDs, value.ID)
UIDs = append(UIDs, value.UserID)
data = append(data, tmp)
if value.ToUserID != 0 {
toUIDs = append(UIDs, value.ToUserID)
}
}
var wg = sync.WaitGroup{}
var errs []error
wg.Add(4)
// 是否点赞
common.Go(func() {
defer wg.Done()
likedList, err1 := likemod.FindLikesByObjIDS(constant.LikeTypeComment, uid, CIDs)
if err1 != nil {
errs = append(errs, err1)
return
}
for k, v := range data {
for _, ls := range likedList {
if v.ID == ls.ObjID.Hex() {
data[k].IsLike = true
break
}
}
}
})
// 获取用户昵称/性别/头像地址
common.Go(func() {
defer wg.Done()
users, err1 := usermod.FindUsersByUID(UIDs)
if err1 != nil {
errs = append(errs, err1)
return
}
for k, v := range data {
for _, u := range users {
if v.UserID == u.UID {
data[k].UserName = u.Name
data[k].UserPortrait = u.Portrait
data[k].Gender = u.Gender
data[k].Age = u.Age()
data[k].VipLevel = u.VipLevel
data[k].Awards = u.Awards
data[k].AwardsExpire = userser.HandleUserAwardsExpire(u)
data[k].SuperUser = u.GetSuperUser(now)
data[k].VipExpireDate = u.VipExpireDate
break
}
}
}
})
// 获取回复用户
common.Go(func() {
defer wg.Done()
if toUIDs == nil || len(toUIDs) == 0 {
return
}
toUsers, err1 := usermod.FindUsersByUID(toUIDs)
if err1 != nil {
errs = append(errs, err1)
return
}
for k, v := range data {
for _, u := range toUsers {
if v.ToUserID == u.UID {
data[k].ToUserName = u.Name
break
}
}
}
return
})
// 是否关注
common.Go(func() {
defer wg.Done()
followers, err1 := followmod.IsFollowUsers(uid, UIDs)
if err1 != nil {
errs = append(errs, err1)
return
}
for k, v := range data {
data[k].IsFollow = followers[v.UserID]
}
})
wg.Wait()
if len(errs) > 0 {
err = errs[0]
return
}
return
}
// 计算分页信息
func getNewPageInfo(total int64, pageNumber int64, pageSize int64) (int64, int64) {
var curPage = pageNumber - total/pageSize
var skip, limit int64
if curPage == 1 {
skip = 0
limit = (pageSize - total%pageSize) + 1
} else {
skip = pageSize - total%pageSize + (curPage-2)*pageSize
limit = (pageSize) + 1
}
return skip, limit
}
// 排序
func sortCmtList(ids []ObjectID, cmtList []cmtmod.Comment) (list []cmtmod.Comment) {
var cMap = make(map[ObjectID]cmtmod.Comment)
for _, v := range cmtList {
cMap[v.ID] = v
}
for _, v := range ids {
list = append(list, cMap[v])
}
return
}
+32
View File
@@ -0,0 +1,32 @@
package commentser
import (
"91porn-server/app/appg"
"91porn-server/common/constant"
"91porn-server/common/constant/redisconst"
"time"
)
// 评论发表限制
func canPublishComment(uid uint64) (isCan bool, err error) {
var LimitExpire = time.Second * time.Duration(appg.Conf.CmtLimit.CmtLimitExpire)
var key = redisconst.AutoBlockKey(constant.FrequencyComment, uid)
cnt := appg.Redis.Incr(key)
if cnt == 1 {
_, _ = appg.Redis.ExpireKey(key, LimitExpire)
}
if cnt > appg.Conf.CmtLimit.CommentCount {
// err = usermod.UpdateById(nil, uid, time.Now().Add(12*time.Hour))
// if err != nil {
// return
// }
return
}
//code := CheckCountLimit(uid)
//if code != stderr.Success {
// return
//}
isCan = true
return
}
+251
View File
@@ -0,0 +1,251 @@
package commentser
import (
"91porn-server/common"
"91porn-server/common/log"
"91porn-server/common/stderr"
"91porn-server/models/cache/quicksearchdata"
"91porn-server/models/commod"
"91porn-server/models/v/cmtmod"
"91porn-server/models/v/mediamod"
"91porn-server/models/v/usermod"
"91porn-server/models/v/vidmod"
"fmt"
"math/rand"
"sync"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// GetParentCmtList 获取父评论列表
func GetParentCmtList(uid uint64, objID ObjectID, objType cmtmod.OType, curTime time.Time, page commod.Page) (code stderr.Code, data []cmtmod.ParentRespList, hasNext bool, err error) {
user, err := usermod.FindUserByUID(uid)
if err != nil {
code = stderr.ErrDbQueryError
return
}
if user == nil || user.ID.IsZero() || user.HasBanned || user.HasLocked {
code = stderr.UserIsNotExists
return
}
var publisherID uint64
if objType == cmtmod.OTypeCartoon || objType == cmtmod.OTypeDrama {
media, mediaErr := mediamod.GetInfo(objID)
if mediaErr != nil || media.ID.IsZero() || media.Status != 1 || media.IsDelete ||
(objType == cmtmod.OTypeDrama && media.MediaType != mediamod.MediaTypeDrama) {
code = stderr.CommentErrGetDataFail
err = mediaErr
return
}
} else {
// 获取视频作者
videoInfo, videoErr := vidmod.GetVideoInfo(objID.Hex())
if videoErr != nil {
code = stderr.CommentErrGetDataFail
err = videoErr
return
}
publisherID = videoInfo.PublisherID
}
skip, limit := getNewPageInfo(0, int64(page.PageNumber), int64(page.PageSize))
var (
isGodList = make([]cmtmod.Comment, 0)
aList = make([]cmtmod.Comment, 0)
hLikeList = make([]cmtmod.Comment, 0)
hReplyList = make([]cmtmod.Comment, 0)
)
wg := sync.WaitGroup{}
wg.Add(3)
common.Go(func() {
defer wg.Done()
// 获神评论
isGodList, err = getIsGodCommentParentCmtList(user.IsAdvertiser, objID, curTime)
if err != nil {
code = stderr.CommentErrGetDataFail
return
}
})
common.Go(func() {
defer wg.Done()
// 获取作者的评论
aList, err = getAuthorParentCmtList(user.IsAdvertiser, objID, publisherID, curTime)
if err != nil {
code = stderr.CommentErrGetDataFail
return
}
})
common.Go(func() {
defer wg.Done()
// 获取热门评论(回复数)
hReplyList, err = getHotReplyParentCmeList(user.UID, user.IsAdvertiser, objID, 0, 3, curTime)
if err != nil {
code = stderr.CommentErrGetDataFail
return
}
noIds := []primitive.ObjectID{}
for _, v := range hReplyList {
noIds = append(noIds, v.ID)
}
// 获取热门评论(点赞数)
hLikeList, err = getHotParentCmeList(user.UID, user.IsAdvertiser, noIds, objID, 0, 5, curTime)
if err != nil {
code = stderr.CommentErrGetDataFail
return
}
})
wg.Wait()
aList = append(isGodList, aList...) // 神评论+作者评论
aList = append(aList, hLikeList...)
aList = append(aList, hReplyList...)
var mList []cmtmod.Comment
if len(aList) > int(page.PageNumber*page.PageSize) {
mList = aList[skip : skip+limit]
} else if len(aList) > int((page.PageNumber-1)*page.PageSize) && len(aList) < int(page.PageNumber*page.PageSize) {
mList = aList[skip:]
}
var aIds []ObjectID // 作者+热评的id
for _, v := range aList {
aIds = append(aIds, v.ID)
}
if aIds == nil {
aIds = []ObjectID{}
}
if len(mList) <= int(page.PageSize) {
skip, limit = getNewPageInfo(int64(len(aList)), int64(page.PageNumber), int64(page.PageSize))
//获取普通评论
cList, err := getParentCmtList(user.IsAdvertiser, objID, aIds, skip, limit, curTime)
if err != nil {
code = stderr.CommentErrGetDataFail
return code, data, false, err
}
mList = append(mList, cList...)
}
list, err := getParentCommentTackInfo(uid, mList)
if err != nil {
code = stderr.CommentErrGetDataFail
return
}
var ids []ObjectID
for _, v := range mList {
ids = append(ids, v.ID)
}
// 获取首条子评论
data, err = getFstChildCmtOfParent(user.IsAdvertiser, objID, list, ids, uid, publisherID, curTime)
if err != nil {
code = stderr.CommentErrGetDataFail
return
}
if len(data) > int(page.PageSize) {
hasNext = true
data = data[:page.PageSize]
}
code = stderr.Success
return
}
func QuickSearch(objID string, data []cmtmod.ParentRespList) []cmtmod.ParentRespList {
//获取置顶评论,走缓存
quickSearches, err := quicksearchdata.GetAllFromCache(bson.M{"enabled": true, "type": 1})
if err != nil {
return data
}
count := len(quickSearches)
if count > 0 {
var (
info = make([]cmtmod.ChildRespList, 0)
s = rand.Intn(count)
q = quickSearches[s]
)
cmts := []cmtmod.ParentRespList{
cmtmod.ParentRespList{
Info: info,
ID: q.ID.Hex(),
ObjID: objID,
UserID: 100001,
UserName: "91PORN运营",
UserPortrait: "cf230705/image/cg/227/fg/1bw/a86065d7ab4cbb11ebbebaefc0ee4444.png",
Content: q.Title,
LinkStr: q.Link,
LinkType: q.LinkType,
SearchKeyword: q.SearchKeyword,
Level: 1,
Status: 1,
City: "香港",
CreatedAt: time.Now(),
}}
user, err := usermod.FindUserByUID(100001)
if err == nil && user != nil {
cmts[0].UserName = user.Name
cmts[0].UserPortrait = user.Portrait
}
data = append(cmts, data...)
}
return data
}
// 获取作者的父评论及其数量
func getAuthorParentCmtList(isAdvertiser bool, objID ObjectID, author uint64, curTime time.Time) (data []cmtmod.Comment, err error) {
return cmtmod.GetAuthorParentCmt(isAdvertiser, objID, author, curTime)
}
// 获取神评论及其数量
func getIsGodCommentParentCmtList(isAdvertiser bool, objID ObjectID, curTime time.Time) (data []cmtmod.Comment, err error) {
return cmtmod.GetIsGodCommentParentCmt(isAdvertiser, objID, curTime)
}
// 获取热门评论(点赞数)
func getHotParentCmeList(uid uint64, isAdvertiser bool, noIds []primitive.ObjectID, objID ObjectID, skip int64, limit int64, cutTime time.Time) (data []cmtmod.Comment, err error) {
return cmtmod.GetHotParentCmtList(uid, isAdvertiser, noIds, objID, skip, limit, cutTime)
}
// 获取热门评论(回复数)
func getHotReplyParentCmeList(uid uint64, isAdvertiser bool, objID ObjectID, skip int64, limit int64, cutTime time.Time) (data []cmtmod.Comment, err error) {
return cmtmod.GetHotReplyParentCmtList(uid, isAdvertiser, objID, skip, limit, cutTime)
}
// 获取其余评论
func getParentCmtList(isAdvertiser bool, objID ObjectID, ids []ObjectID, skip int64, limit int64, cutTime time.Time) (data []cmtmod.Comment, err error) {
// 获取作者+热评
return cmtmod.GetParentCmtList(isAdvertiser, objID, ids, skip, limit, cutTime)
}
// GetMyCmtList 获取我的评论列表
func GetMyCmtList(uid uint64, page commod.Page) (list []cmtmod.MyCmt, hasNext bool, err error) {
skip := int64(page.Skip())
list, hasNext, err = cmtmod.GetMyCmtList(uid, skip, int64(page.PageSize))
if err != nil {
log.Error(fmt.Sprintf("cmtmod.GetMyCmtList err:%v", err))
return
}
if len(list) == 0 {
list = []cmtmod.MyCmt{}
return
}
vids := []primitive.ObjectID{}
for _, v := range list {
vids = append(vids, v.ObjID)
}
vidList, err := vidmod.GetVideoListByIDsNoStatus(vids)
if err != nil {
log.Error(fmt.Sprintf("vidmod.GetVideoListByIDsNoStatus err:%v", err))
return
}
videoMap := make(map[primitive.ObjectID]*vidmod.VideoModel)
for _, v := range vidList {
videoMap[v.ID] = v
}
for i, v := range list {
// 从map中取出video对象
vid, ok := videoMap[v.ObjID]
if !ok {
continue
}
v.VidTitle = vid.Title
v.VidCover = vid.Cover
list[i] = v
}
return
}
+276
View File
@@ -0,0 +1,276 @@
package commentser
import (
"91porn-server/app/appg"
"91porn-server/app/service/vidhelpser"
"91porn-server/common/constant"
"91porn-server/common/constant/redisconst"
"91porn-server/common/log"
"91porn-server/common/stderr"
"91porn-server/models/v/aiplazamod"
"91porn-server/models/v/cmtmod"
"91porn-server/models/v/mediamod"
"91porn-server/models/v/usermod"
"91porn-server/models/v/vidmod"
"time"
"unicode"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// 发布评论后获取返回结果
func getRespInfoAfterPublish(uid uint64, id ObjectID, level int) (code stderr.Code, data interface{}, err error) {
var cmt cmtmod.Comment
if cmt, err = cmtmod.CmtFindOneByID(id); err != nil {
code = stderr.CommentErrGetDataFail
return
}
if level == 1 {
var info []cmtmod.ParentRespList
if info, err = getParentCommentTackInfo(uid, []cmtmod.Comment{cmt}); err != nil {
code = stderr.CommentErrSendFail
return
}
data = info[0]
} else {
var info []cmtmod.ChildRespList
info, err = getChildCommentTackInfo(uid, []cmtmod.Comment{cmt})
if code = stderr.CommentErrSendFail; err != nil {
return
}
data = info[0]
}
code = stderr.Success
return
}
// 检查用户状态
func checkUserStatus(uid uint64) (code stderr.Code, data *usermod.User, err error) {
// 获取用户状态
data, err = usermod.FindUserByUID(uid)
if err != nil || data == nil {
code = stderr.CommentUserInfoErr
return code, data, err
}
if data.HasBanned {
code = stderr.CommentUserHasBanned
return
}
if data.BannedTime.After(time.Now()) {
code = stderr.CommentUserHasBanned
return
}
// if data.Mobile == "" {
// code = stderr.CommentUserNotBind
// return code, data, nil
// }
code = stderr.Success
return
}
// 检查视频状态
func checkVideoStatus(videoID string) (code stderr.Code, videoInfo vidmod.VideoModel, err error) {
videoInfo, err = vidmod.GetVideoInfo(videoID)
if err != nil {
code = stderr.CommentVideoInfoErr
return code, videoInfo, err
}
if videoInfo.ID.IsZero() {
code = stderr.CommentErrVideoIsInvalid
return code, videoInfo, err
}
// 视频未通过审核/未审核
if videoInfo.Status != 1 && videoInfo.Status != 3 {
code = stderr.CommentErrVideoIsInvalid
return code, videoInfo, err
}
code = stderr.Success
return code, videoInfo, err
}
// 获取相关信息
func getTrackInfo(uid uint64, publisher uint64, isAuthor bool, ip string, param cmtmod.PublishReqInfo, cmtType cmtmod.CmtType) (code stderr.Code, data cmtmod.Comment, err error) {
//var waitGroup sync.WaitGroup
var city = "-"
//var replacedContent string
var replacedContent = param.Content
var cid ObjectID
var err1 error
if param.CID != "" {
if cid, err = primitive.ObjectIDFromHex(param.CID); err != nil {
code = stderr.CommentErrSendFail
return code, data, err
}
}
//waitGroup.Add(1)
//// 过滤评论
//common.Go(func() {
// defer waitGroup.Done()
// replacedContent, err1 = filterser.TextFilter(param.Content)
//})
// 获取城市城市
// common.Go(func() {
// defer waitGroup.Done()
// city = vidhelpser.GetLocationByIP(ip)
// })
//waitGroup.Wait()
if err = err1; err1 != nil {
code = stderr.CommentErrSendFail
return
}
isRobot := false
if uid < constant.RobotUIDLimit {
isRobot = true
}
now := time.Now()
data = cmtmod.Comment{
ObjType: param.ObjType,
ObjID: param.ObjID,
CID: cid,
PublisherID: publisher,
UserID: uid,
SortCnt: 0,
ToUserID: param.ToUserID,
Content: replacedContent,
OrgContent: param.Content,
Image: param.Image,
Status: 2,
Level: param.Level,
AuthorMark: isAuthor,
IsAuthor: isAuthor,
IsDelete: false,
CommentCount: 0,
LikeCount: 0,
IPAddr: ip,
City: city,
IsRobot: isRobot,
QuoteType: param.QuoteType,
QuoteID: param.QuoteID,
QuoteImg: param.QuoteImg,
QuoteTitle: param.QuoteTitle,
CreatedAt: now,
}
if param.RID != "" {
rid, err := primitive.ObjectIDFromHex(param.RID)
if err != nil {
code = stderr.CommentErrSendFail
return code, data, err
}
rCmt, err := cmtmod.CmtFindOneByID(rid)
if err != nil {
code = stderr.CommentErrSendFail
return code, data, err
}
user, err := usermod.FindUserByUID(rCmt.UserID)
if err != nil {
code = stderr.CommentErrSendFail
return code, data, err
}
data.RID = rid
data.GID = rCmt.GID
data.AuthorMark = rCmt.AuthorMark
data.SortCnt = rCmt.SortCnt
data.Type = cmtmod.CmtTypeReply
data.PublisherID = rCmt.UserID
data.ToUserName = user.Name
data.ToUserID = rCmt.UserID
data.CID = rCmt.CID
} else if param.RID == "" && !cid.IsZero() {
data.Type = cmtmod.CmtTypeComment
cCmt, err := cmtmod.CmtFindOneByID(cid)
if err != nil {
code = stderr.CommentErrSendFail
return code, data, err
}
data.PublisherID = cCmt.UserID
} else {
data.PublisherID = publisher
data.Type = cmtType
}
code = stderr.Success
return
}
// 设置分组id
func setGid(cid string, rid string, id ObjectID) (err error) {
if cid != "" && rid == "" {
return cmtmod.SetGid(id)
}
return
}
// 增加评论数
func incCommentCount(cid string, oType cmtmod.OType, objID ObjectID) (code stderr.Code, err error) {
if cid != "" {
var objCid ObjectID
if objCid, err = primitive.ObjectIDFromHex(cid); err != nil {
code = stderr.CommentErrSendFail
return code, err
}
// 根据cid获取评论信息
if toComment, err := cmtmod.CmtFindOneByID(objCid); err != nil || (toComment.Level != 1 && toComment.Level != 2) {
code = stderr.CommentErrSendFail
log.Error("app service comment CmtFindOneByID err", log.E(err), log.Any("toComment level", toComment.Level))
return code, err
}
if err = cmtmod.CmtIncreaseCommentCountByID(objCid); err != nil {
code = stderr.CommentErrIncCountFailed
return code, err
}
}
if oType == cmtmod.OTypeCartoon || oType == cmtmod.OTypeDrama {
if err = mediamod.IncrCommentCountByID(objID, 1); err != nil {
code = stderr.CommentErrIncCountFailed
return
}
} else if oType == cmtmod.OTypeAiPlaza {
aiplazamod.IncCommentCount(objID)
} else {
// 增加视频评论数
if err = vidhelpser.IncCommentCount(objID); err != nil {
code = stderr.CommentErrIncCountFailed
return
}
}
code = stderr.Success
return
}
// 检查是否为vip,非vip用户只能发表5个字
func checkVip(vipLevel int, content string) stderr.Code {
var charCnt int
for _, v := range content {
if unicode.Is(unicode.Scripts["Han"], v) {
charCnt++
} else {
charCnt++
}
if charCnt > 5 {
break
}
}
if vipLevel == 0 && charCnt > 5 {
return stderr.CommentNotVip
}
return stderr.Success
}
func CheckCountLimit(uid uint64) stderr.Code {
var key = redisconst.AutoBlockKey(constant.BlockComment, uid)
cnt := appg.Redis.Incr(key)
if cnt == 1 {
_, _ = appg.Redis.ExpireKey(key, 12*time.Hour)
}
if cnt > appg.Conf.CmtLimit.CommentCount {
err := usermod.UpdateById(nil, uid, time.Now().Add(12*time.Hour))
if err != nil {
return stderr.ErrDbUpdateError
}
return stderr.CommentCountOverLimit
}
return stderr.Success
}
+355
View File
@@ -0,0 +1,355 @@
package commentser
import (
"91porn-server/app/service/messageser"
"91porn-server/app/service/taskser"
"91porn-server/common"
"91porn-server/common/log"
"91porn-server/common/stderr"
"91porn-server/common/truthutil"
"91porn-server/middleware/ua"
"91porn-server/models/commod"
"91porn-server/models/v/cmtmod"
"91porn-server/models/v/dailytaskmod"
"91porn-server/models/v/mediamod"
"91porn-server/models/v/messagemod"
"91porn-server/models/v/usermod"
"91porn-server/models/v/vidmod"
"errors"
"fmt"
"time"
"unicode/utf8"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// GetVideoTotalComments 获取视频的评论数
func GetVideoTotalComments(objID primitive.ObjectID) (code stderr.Code, data int64, err error) {
return GetTotalComments(objID, cmtmod.OTypeVideo)
}
func GetTotalComments(objID primitive.ObjectID, objType cmtmod.OType) (code stderr.Code, data int64, err error) {
if objType == "" {
objType = cmtmod.OTypeVideo
}
params := bson.M{
"objID": objID,
"objType": objType,
"level": 1,
"status": 1,
"isDelete": false,
"isAdvertiser": bson.M{"$in": []any{nil, false}},
}
data, err = cmtmod.GetCount(params)
if err != nil {
code = stderr.ErrNetWorkBusy
return code, 0, err
}
code = stderr.Success
return code, data, err
}
// 获取二级评论列表
func GetSndCommentsList(uid uint64, objID primitive.ObjectID, cid primitive.ObjectID, fstID primitive.ObjectID, curTime time.Time, page commod.Page) (code stderr.Code, data []cmtmod.ChildRespList, err error) {
// 获取评论信息
stdQuery := commod.StdQuery{Page: &commod.PageBy{Num: page.PageNumber, Size: page.PageSize, CheckNext: true}, Order: &[]commod.OrderBy{}}
modList, err := cmtmod.CmtFindSecondLevelComments(objID, cid, fstID, curTime, stdQuery)
if err != nil {
code = stderr.ErrNetWorkBusy
log.Error("app service comment GetSndCommentsList CmtFindSecondLevelComments err", log.E(err))
return
}
// 空值直接返回
if modList == nil || len(modList) <= 0 {
code = stderr.Success
data = []cmtmod.ChildRespList{}
return
}
// 获取评论附加信息
cList, err := getChildCommentTackInfo(uid, modList)
if err != nil {
code = stderr.ErrNetWorkBusy
log.Error("app service comment GetSndCommentsList getSndCommentTackInfo err", log.E(err))
return
}
code = stderr.Success
data = cList
return
}
// PublishComment 发表评论
func PublishComment(uid uint64, ua ua.UA, ip string, param cmtmod.PublishReqInfo) (code stderr.Code, data interface{}, err error) {
// 获取用户状态
var user, publisher *usermod.User
if code, user, err = checkUserStatus(uid); err != nil || code != stderr.Success || user == nil {
return code, data, err
}
// 评论限制
if isCan, err := canPublishComment(uid); err != nil {
code = stderr.CommentErrSendFail
return code, data, err
} else if !isCan {
code = stderr.CommentPublishTooFrequent
return code, data, err
}
//检测评论是否包含网址,包含网址则发布不予处理
if uid > 200000 && !truthutil.CheckIsValid(param.Content, 1) {
log.Warn("comment send CheckIsValid fail", log.Any("uid", uid), log.Any("content", param.Content))
return stderr.Success, stderr.Success.Msg(), nil
}
// 校验视频是否通过审核
var videoInfo vidmod.VideoModel
var mediaInfo mediamod.Media
var isAuthor bool
var isOneself bool
if param.ObjType == "" || param.ObjType == cmtmod.OTypeVideo {
if code, videoInfo, err = checkVideoStatus(param.ObjID.Hex()); err != nil || code != stderr.Success || videoInfo.ID.IsZero() {
return code, data, err
}
// 获取视频作者信息
if publisher, err = usermod.FindUserByUID(videoInfo.PublisherID); err != nil {
log.Error("获取评论视频作者信息", log.Any("uid", uid), log.Any("ip", ip), log.Any("param", param), log.E(err))
return stderr.CommentErrSendFail, nil, err
}
if publisher == nil || publisher.ID.IsZero() {
return stderr.UserIsNotExists, nil, err
}
if uid == videoInfo.PublisherID {
isAuthor = true
}
}
if param.ObjType == cmtmod.OTypeCartoon || param.ObjType == cmtmod.OTypeDrama {
mediaInfo, err = mediamod.GetInfo(param.ObjID)
if err != nil || mediaInfo.ID.IsZero() || mediaInfo.IsDelete || mediaInfo.Status != 1 {
return stderr.CommentErrVideoIsInvalid, nil, err
}
if param.ObjType == cmtmod.OTypeDrama && mediaInfo.MediaType != mediamod.MediaTypeDrama {
return stderr.CommentErrVideoIsInvalid, nil, errors.New("invalid drama")
}
}
var cmtMod cmtmod.Comment
if code, cmtMod, err = getTrackInfo(uid, videoInfo.PublisherID, isAuthor, ip, param, cmtmod.CmtTypeVideo); code != stderr.Success || err != nil {
return code, data, err
}
cmtMod.IsAdvertiser = user.IsAdvertiser
if !mediaInfo.ID.IsZero() {
cmtMod.Title = mediaInfo.Title
}
var sUid uint64
if param.CID != "" {
// 根据回复ID获取用户信息
oid, _ := primitive.ObjectIDFromHex(param.CID)
cmt, err := cmtmod.CmtFindOneByID(oid)
if err != nil {
code = stderr.ErrDbQueryError
return code, data, err
}
// 校验是否是回复自己的评论
if cmt.UserID != uid {
sUid = cmt.UserID
}
if cmt.UserID == uid {
isOneself = true
}
}
// 保存到数据库
id, err := cmtmod.CmtInsertOne(&cmtMod)
fmt.Println(id.Hex())
if err != nil {
code = stderr.CommentErrSendFail
return code, data, err
}
if err = setGid(param.CID, param.RID, id); err != nil {
code = stderr.CommentErrSendFail
return code, data, err
}
// 推荐互动不按用户/账号身份过滤;运营后台直接配置的 fake* 展示值
// 不经过该真实评论落库链路,因此仍不会进入推荐累计分。
if param.ObjType == "" || param.ObjType == cmtmod.OTypeVideo {
if incErr := vidmod.IncrementRecommendInteraction(param.ObjID, vidmod.RecommendInteractionComment); incErr != nil {
// 评论已落库,推荐累计失败只记录,不能向客户端返回发布失败。
log.Error("increment recommend comment failed", log.E(incErr), log.Any("objID", param.ObjID))
}
}
if param.ObjType == cmtmod.OTypeDrama {
if incErr := mediamod.IncrCommentCountByID(param.ObjID, 1); incErr != nil {
log.Error("increment drama comment count failed", log.E(incErr), log.Any("objID", param.ObjID))
}
}
// 增加评论数(审核只统计已审核通过的评论)
//if code, err = incCommentCount(param.CID, param.ObjType, param.ObjID); code != stderr.Success || err != nil {
// return code, data, err
//}
//存动态
common.Go(func() {
if param.Content != "" && utf8.RuneCountInString(param.Content) >= 10 {
_ = taskser.CompleteDailyTask(nil, uid, dailytaskmod.DailyComment)
}
if !isAuthor && videoInfo.Title != "" {
dynamicContent := fmt.Sprintf("%s 于 %s 评论了你的作品", user.Name, time.Now().Format("15:04:05"))
messageser.PublicAddMsg(messagemod.PublicAddMsg{
SendUid: uid,
TakeUid: videoInfo.PublisherID,
MsgType: messagemod.CommentMsg,
ObjId: videoInfo.ID,
ObjName: videoInfo.Title,
ObjCover: videoInfo.Cover,
Content: dynamicContent, //param.Content,
})
}
if !isOneself && videoInfo.Title != "" && param.CID != "" && sUid != 0 {
dynamicContent := fmt.Sprintf("%s 于 %s 回复了你的评论", user.Name, time.Now().Format("15:04:05"))
messageser.PublicAddMsg(messagemod.PublicAddMsg{
SendUid: uid,
TakeUid: sUid,
MsgType: messagemod.ReplyCommentMsg,
ObjId: videoInfo.ID,
ObjName: videoInfo.Title,
ObjCover: videoInfo.Cover,
Content: dynamicContent, //param.Content,
})
}
})
//if (user.VipLevel == 0 || user.VipExpireDate.Before(now)) && !user.GetSuperUser(now) {
// if err = appg.Redis.Set(redisconst.CommentCacheKey(uid), data, 1*time.Minute); err != nil {
// log.Warn(fmt.Sprintf("用户ID:%d;IP:%s;保存缓存数据异常:%v", uid, ip, err))
// }
//}
// 获取该评论
return getRespInfoAfterPublish(uid, id, param.Level)
}
//func DailyComment(uid uint64) {
// key := redisconst.DailyTaskCacheKey(uid, dailytaskmod.DailyComment, timeutil.BeginOfToday())
// if appg.Redis.Exists(key) {
// return
// }
// tasks, err := dailytaskmod.GetUserDailyTaskByType(nil, dailytaskmod.DailyComment)
// if err != nil {
// return
// }
//
// if tasks == nil || tasks.ID.IsZero() {
// return
// }
//
// // 获取任务记录
// today := timeutil.BeginningOfDay(time.Now())
// item, err := taskrecordmod.GetUserRecordByTime(uid, tasks.ID, today)
// if item == nil || item.ID.IsZero() {
// now := time.Now()
// // 更新今日登录记录
// filter := bson.M{"uid": uid, "recordTime": today, "taskId": tasks.ID}
// cond := bson.M{
// "uid": uid,
// "recordTime": today,
// "taskId": tasks.ID,
// "type": taskrecordmod.DailyTask,
// "taskType": taskrecordmod.DailyComment,
// "status": taskrecordmod.UnReceived,
// "count": 1,
// "updateTime": now,
// "createTime": now,
// }
// if err := taskrecordmod.InsertTask(nil, filter, cond); err != nil {
// return
// }
// }
// // 判断每日评论只可三次
// if item != nil && !item.ID.IsZero() && item.Count < 3 {
// filter := bson.M{"uid": uid, "recordTime": today, "taskId": tasks.ID}
// if err := taskrecordmod.CurrentCountUpdate(nil, filter); err != nil {
// return
// }
// }
// // 每日超过三次评论放入缓存
// if item != nil && !item.ID.IsZero() && item.Count > 2 {
// err = appg.Redis.Set(key, "_", time.Hour*24)
// if err != nil {
// return
// }
// }
// return
//}
// NoVidPublishComment 非视频帖子发表评论
func NoVidPublishComment(uid uint64, ip, cmtType string, param cmtmod.PublishReqInfo) (code stderr.Code, data interface{}, err error) {
var publisherID uint64
// 获取用户状态
var user *usermod.User
if code, user, err = checkUserStatus(uid); err != nil || code != stderr.Success || user == nil {
return code, data, err
}
// 评论限制
if isCan, err := canPublishComment(uid); err != nil {
code = stderr.CommentErrSendFail
return code, data, err
} else if !isCan {
code = stderr.CommentPublishTooFrequent
return code, data, err
}
//检测评论是否包含网址,包含网址则发布不予处理
if uid > 200000 && !truthutil.CheckIsValid(param.Content, 1) {
log.Warn("comment send CheckIsValid fail", log.Any("uid", uid), log.Any("content", param.Content))
return stderr.Success, stderr.Success.Msg(), nil
}
var isAuthor bool
if uid == publisherID {
isAuthor = true
}
var cmtMod cmtmod.Comment
if code, cmtMod, err = getTrackInfo(uid, publisherID, isAuthor, ip, param, cmtmod.CmtNoVideo); code != stderr.Success || err != nil {
return code, data, err
}
cmtMod.IsAdvertiser = user.IsAdvertiser
// 保存到数据库
id, err := cmtmod.CmtInsertOne(&cmtMod)
if err != nil {
code = stderr.CommentErrSendFail
return code, data, err
}
if err = setGid(param.CID, param.RID, id); err != nil {
code = stderr.CommentErrSendFail
return code, data, err
}
common.Go(func() {
// 增加评论数
if param.Level == 2 {
_id, err := primitive.ObjectIDFromHex(param.CID)
if err != nil {
log.Warn("NoVidPublishComment primitive.ObjectIDFromHex err,", log.Any("CID", param.CID), log.Any("ToUserID", param.ToUserID))
}
if err = cmtmod.CmtIncreaseCommentCountByID(_id); err != nil {
log.Warn("NoVidPublishComment cmtmod.CmtIncreaseCommentCountByID err,", log.Any("err", err.Error()), log.Any("CID", param.CID), log.Any("ToUserID", param.ToUserID))
}
}
})
//存动态
//common.Go(func() {
// if objName != "" {
//messageser.PublicAddMsg(messagemod.PublicAddMsg{
// SendUid: uid,
// TakeUid: publisherID,
// MsgType: messagemod.DesireMsg,
// ObjId: objID,
// ObjName: objName,
//})
// }
//})
// 获取该评论
return getRespInfoAfterPublish(uid, id, param.Level)
}
+118
View File
@@ -0,0 +1,118 @@
package commentser
import (
"91porn-server/app/service/searcher"
"91porn-server/common"
"91porn-server/common/log"
"91porn-server/models/v/cmtmod"
"91porn-server/models/v/usermod"
"sync"
"time"
)
type VideoRes = searcher.VideoRes
type UserBInfo = usermod.BaseInfo
type Comment = cmtmod.Comment
type ReplyInfo struct {
RUID uint64 `json:"rUID"` //回复者UID
RName string `json:"rName"` //回复者名字
RPortrait string `json:"rPortrait"` //回复者头像
RContent string `json:"rContent"` //回复内容
RTime time.Time `json:"rTime"` //回复时间
RType cmtmod.CmtType `json:"rType"` //回复类型
Video VideoRes `json:"video"` //视屏信息
}
type ReplyPage struct {
HasNext bool `json:"hasNext"`
List []ReplyInfo `json:"list"`
}
func ReplyPages(uid uint64, skip, limit int64) (ReplyPage, error) {
limitEx := limit + 1
cmtList, err := cmtmod.ListByPublisherID(skip, limitEx, uid)
if err != nil {
return ReplyPage{}, err
}
hasNext := false
if len(cmtList) > int(limit) {
hasNext = true
cmtList = cmtList[:limit]
}
vids := make([]ObjectID, 0, len(cmtList))
uids := make([]uint64, 0, len(cmtList))
for _, v := range cmtList {
vids = append(vids, v.ObjID) //视屏ID
uids = append(uids, v.UserID)
}
var (
wg = sync.WaitGroup{}
videoResList []VideoRes
userInfos []*UserBInfo
)
wg.Add(2)
common.Go(func() {
defer wg.Done()
list, err := searcher.GetVideoResList(uid, vids)
if err != nil {
log.Error("commentser GetVideoResList faild", log.E(err))
}
videoResList = list
})
common.Go(func() {
defer wg.Done()
list, err := usermod.GetUsersBaseInfo(uids)
if err != nil {
log.Error("commentser GetUsersBaseInfo faild", log.E(err))
}
userInfos = list
})
wg.Wait()
videoResMap := make(map[ObjectID]VideoRes, len(videoResList))
for _, v := range videoResList {
vidp := v.VideoInfo.ID
if vidp != nil {
videoResMap[*vidp] = v
}
}
userInfoMap := make(map[uint64]*usermod.BaseInfo, len(userInfos))
for _, v := range userInfos {
userInfoMap[v.UID] = v
}
replyInfos := toReplyInfoList(cmtList, videoResMap, userInfoMap)
return ReplyPage{
hasNext,
replyInfos,
}, nil
}
func toReplyInfoList(cmtList []Comment,
videoResMap map[ObjectID]VideoRes,
userInfoMap map[uint64]*usermod.BaseInfo,
) []ReplyInfo {
replyInfos := make([]ReplyInfo, 0, len(cmtList))
for _, v := range cmtList {
userInfo, ok := userInfoMap[v.UserID]
if !ok {
continue
}
videoRes, ok := videoResMap[v.ObjID]
if !ok {
continue
}
replyInfo := ReplyInfo{
RUID: userInfo.UID,
RName: userInfo.Name,
RPortrait: userInfo.Portrait,
RContent: v.Content,
RType: v.Type,
RTime: v.CreatedAt,
Video: videoRes,
}
replyInfos = append(replyInfos, replyInfo)
}
return replyInfos
}