chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,728 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package comment
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/apache/answer/internal/service/eventqueue"
|
||||
"github.com/apache/answer/internal/service/review"
|
||||
|
||||
"time"
|
||||
|
||||
"github.com/apache/answer/internal/base/constant"
|
||||
"github.com/apache/answer/internal/base/pager"
|
||||
"github.com/apache/answer/internal/base/reason"
|
||||
"github.com/apache/answer/internal/entity"
|
||||
"github.com/apache/answer/internal/schema"
|
||||
"github.com/apache/answer/internal/service/activity_common"
|
||||
"github.com/apache/answer/internal/service/activityqueue"
|
||||
"github.com/apache/answer/internal/service/comment_common"
|
||||
"github.com/apache/answer/internal/service/export"
|
||||
"github.com/apache/answer/internal/service/noticequeue"
|
||||
"github.com/apache/answer/internal/service/object_info"
|
||||
"github.com/apache/answer/internal/service/permission"
|
||||
usercommon "github.com/apache/answer/internal/service/user_common"
|
||||
"github.com/apache/answer/internal/service/vector_sync"
|
||||
"github.com/apache/answer/pkg/htmltext"
|
||||
"github.com/apache/answer/pkg/token"
|
||||
"github.com/apache/answer/pkg/uid"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/segmentfault/pacman/errors"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
)
|
||||
|
||||
// CommentRepo comment repository
|
||||
type CommentRepo interface {
|
||||
AddComment(ctx context.Context, comment *entity.Comment) (err error)
|
||||
RemoveComment(ctx context.Context, commentID string) (err error)
|
||||
UpdateCommentContent(ctx context.Context, commentID string, original string, parsedText string) (err error)
|
||||
UpdateCommentStatus(ctx context.Context, commentID string, status int) (err error)
|
||||
GetComment(ctx context.Context, commentID string) (comment *entity.Comment, exist bool, err error)
|
||||
GetCommentPage(ctx context.Context, commentQuery *CommentQuery) (
|
||||
comments []*entity.Comment, total int64, err error)
|
||||
}
|
||||
|
||||
type CommentQuery struct {
|
||||
pager.PageCond
|
||||
// object id
|
||||
ObjectID string
|
||||
// query condition
|
||||
QueryCond string
|
||||
// user id
|
||||
UserID string
|
||||
}
|
||||
|
||||
func (c *CommentQuery) GetOrderBy() string {
|
||||
if c.QueryCond == "vote" {
|
||||
return "vote_count DESC,created_at ASC"
|
||||
}
|
||||
if c.QueryCond == "created_at" {
|
||||
return "created_at DESC"
|
||||
}
|
||||
return "created_at ASC"
|
||||
}
|
||||
|
||||
// CommentService user service
|
||||
type CommentService struct {
|
||||
commentRepo CommentRepo
|
||||
commentCommonRepo comment_common.CommentCommonRepo
|
||||
userCommon *usercommon.UserCommon
|
||||
voteCommon activity_common.VoteRepo
|
||||
objectInfoService *object_info.ObjService
|
||||
emailService *export.EmailService
|
||||
userRepo usercommon.UserRepo
|
||||
notificationQueueService noticequeue.Service
|
||||
externalNotificationQueueService noticequeue.ExternalService
|
||||
activityQueueService activityqueue.Service
|
||||
eventQueueService eventqueue.Service
|
||||
reviewService *review.ReviewService
|
||||
vectorSyncService vector_sync.Service
|
||||
}
|
||||
|
||||
// NewCommentService new comment service
|
||||
func NewCommentService(
|
||||
commentRepo CommentRepo,
|
||||
commentCommonRepo comment_common.CommentCommonRepo,
|
||||
userCommon *usercommon.UserCommon,
|
||||
objectInfoService *object_info.ObjService,
|
||||
voteCommon activity_common.VoteRepo,
|
||||
emailService *export.EmailService,
|
||||
userRepo usercommon.UserRepo,
|
||||
notificationQueueService noticequeue.Service,
|
||||
externalNotificationQueueService noticequeue.ExternalService,
|
||||
activityQueueService activityqueue.Service,
|
||||
eventQueueService eventqueue.Service,
|
||||
reviewService *review.ReviewService,
|
||||
vectorSyncService vector_sync.Service,
|
||||
) *CommentService {
|
||||
return &CommentService{
|
||||
commentRepo: commentRepo,
|
||||
commentCommonRepo: commentCommonRepo,
|
||||
userCommon: userCommon,
|
||||
voteCommon: voteCommon,
|
||||
objectInfoService: objectInfoService,
|
||||
emailService: emailService,
|
||||
userRepo: userRepo,
|
||||
notificationQueueService: notificationQueueService,
|
||||
externalNotificationQueueService: externalNotificationQueueService,
|
||||
activityQueueService: activityQueueService,
|
||||
eventQueueService: eventQueueService,
|
||||
reviewService: reviewService,
|
||||
vectorSyncService: vectorSyncService,
|
||||
}
|
||||
}
|
||||
|
||||
// AddComment add comment
|
||||
func (cs *CommentService) AddComment(ctx context.Context, req *schema.AddCommentReq) (
|
||||
resp *schema.GetCommentResp, err error) {
|
||||
comment := &entity.Comment{}
|
||||
_ = copier.Copy(comment, req)
|
||||
comment.Status = entity.CommentStatusAvailable
|
||||
|
||||
objInfo, err := cs.objectInfoService.GetInfo(ctx, req.ObjectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if objInfo.IsDeleted() {
|
||||
return nil, errors.BadRequest(reason.NewObjectAlreadyDeleted)
|
||||
}
|
||||
objInfo.ObjectID = uid.DeShortID(objInfo.ObjectID)
|
||||
objInfo.QuestionID = uid.DeShortID(objInfo.QuestionID)
|
||||
objInfo.AnswerID = uid.DeShortID(objInfo.AnswerID)
|
||||
if objInfo.ObjectType == constant.QuestionObjectType || objInfo.ObjectType == constant.AnswerObjectType {
|
||||
comment.QuestionID = objInfo.QuestionID
|
||||
}
|
||||
|
||||
if len(req.ReplyCommentID) > 0 {
|
||||
replyComment, exist, err := cs.commentCommonRepo.GetComment(ctx, req.ReplyCommentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exist {
|
||||
return nil, errors.BadRequest(reason.CommentNotFound)
|
||||
}
|
||||
comment.SetReplyUserID(replyComment.UserID)
|
||||
comment.SetReplyCommentID(replyComment.ID)
|
||||
} else {
|
||||
comment.SetReplyUserID("")
|
||||
comment.SetReplyCommentID("")
|
||||
}
|
||||
|
||||
err = cs.commentRepo.AddComment(ctx, comment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
comment.Status = cs.reviewService.AddCommentReview(ctx, comment, req.IP, req.UserAgent)
|
||||
if err := cs.commentRepo.UpdateCommentStatus(ctx, comment.ID, comment.Status); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp = &schema.GetCommentResp{}
|
||||
resp.SetFromComment(comment)
|
||||
resp.MemberActions = permission.GetCommentPermission(ctx, req.UserID, resp.UserID,
|
||||
time.Now(), req.CanEdit, req.CanDelete)
|
||||
|
||||
if comment.Status == entity.CommentStatusAvailable {
|
||||
if err := cs.addCommentNotification(ctx, req, resp, comment, objInfo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// get user info
|
||||
userInfo, exist, err := cs.userCommon.GetUserBasicInfoByID(ctx, resp.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if exist {
|
||||
resp.Username = userInfo.Username
|
||||
resp.UserDisplayName = userInfo.DisplayName
|
||||
resp.UserAvatar = userInfo.Avatar
|
||||
resp.UserStatus = userInfo.Status
|
||||
}
|
||||
|
||||
activityMsg := &schema.ActivityMsg{
|
||||
UserID: comment.UserID,
|
||||
ObjectID: comment.ID,
|
||||
OriginalObjectID: req.ObjectID,
|
||||
ActivityTypeKey: constant.ActQuestionCommented,
|
||||
}
|
||||
var event *schema.EventMsg
|
||||
switch objInfo.ObjectType {
|
||||
case constant.QuestionObjectType:
|
||||
activityMsg.ActivityTypeKey = constant.ActQuestionCommented
|
||||
event = schema.NewEvent(constant.EventCommentCreate, req.UserID).TID(comment.ID).
|
||||
CID(comment.ID, comment.UserID).QID(objInfo.QuestionID, objInfo.ObjectCreatorUserID)
|
||||
case constant.AnswerObjectType:
|
||||
activityMsg.ActivityTypeKey = constant.ActAnswerCommented
|
||||
event = schema.NewEvent(constant.EventCommentCreate, req.UserID).TID(comment.ID).
|
||||
CID(comment.ID, comment.UserID).AID(objInfo.AnswerID, objInfo.ObjectCreatorUserID)
|
||||
}
|
||||
cs.activityQueueService.Send(ctx, activityMsg)
|
||||
cs.eventQueueService.Send(ctx, event)
|
||||
if comment.Status == entity.CommentStatusAvailable {
|
||||
switch objInfo.ObjectType {
|
||||
case constant.QuestionObjectType:
|
||||
cs.vectorSyncService.Send(ctx, &vector_sync.Task{Action: vector_sync.ActionUpsert, ObjectType: vector_sync.ObjectTypeQuestion, ObjectID: objInfo.QuestionID})
|
||||
case constant.AnswerObjectType:
|
||||
cs.vectorSyncService.Send(ctx, &vector_sync.Task{Action: vector_sync.ActionUpsert, ObjectType: vector_sync.ObjectTypeAnswer, ObjectID: objInfo.AnswerID})
|
||||
cs.vectorSyncService.Send(ctx, &vector_sync.Task{Action: vector_sync.ActionUpsert, ObjectType: vector_sync.ObjectTypeQuestion, ObjectID: objInfo.QuestionID})
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (cs *CommentService) addCommentNotification(
|
||||
ctx context.Context, req *schema.AddCommentReq, resp *schema.GetCommentResp,
|
||||
comment *entity.Comment, objInfo *schema.SimpleObjectInfo) error {
|
||||
// The priority of the notification
|
||||
// 1. reply to user
|
||||
// 2. comment mention to user
|
||||
// 3. answer or question was commented
|
||||
alreadyNotifiedUserID := make(map[string]bool)
|
||||
|
||||
// get reply user info
|
||||
if len(resp.ReplyUserID) > 0 && resp.ReplyUserID != req.UserID {
|
||||
replyUser, exist, err := cs.userCommon.GetUserBasicInfoByID(ctx, resp.ReplyUserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exist {
|
||||
resp.ReplyUsername = replyUser.Username
|
||||
resp.ReplyUserDisplayName = replyUser.DisplayName
|
||||
resp.ReplyUserStatus = replyUser.Status
|
||||
}
|
||||
cs.notificationCommentReply(ctx, replyUser.ID, comment.ID, req.UserID,
|
||||
objInfo.QuestionID, objInfo.Title, htmltext.FetchExcerpt(comment.ParsedText, "...", 240))
|
||||
alreadyNotifiedUserID[replyUser.ID] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(req.MentionUsernameList) > 0 {
|
||||
alreadyNotifiedUserIDs := cs.notificationMention(
|
||||
ctx, req.MentionUsernameList, comment.ID, req.UserID, alreadyNotifiedUserID)
|
||||
for _, userID := range alreadyNotifiedUserIDs {
|
||||
alreadyNotifiedUserID[userID] = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if objInfo.ObjectType == constant.QuestionObjectType && !alreadyNotifiedUserID[objInfo.ObjectCreatorUserID] {
|
||||
cs.notificationQuestionComment(ctx, objInfo.ObjectCreatorUserID,
|
||||
objInfo.QuestionID, objInfo.Title, comment.ID, req.UserID, htmltext.FetchExcerpt(comment.ParsedText, "...", 240))
|
||||
} else if objInfo.ObjectType == constant.AnswerObjectType && !alreadyNotifiedUserID[objInfo.ObjectCreatorUserID] {
|
||||
cs.notificationAnswerComment(ctx, objInfo.QuestionID, objInfo.Title, objInfo.AnswerID,
|
||||
objInfo.ObjectCreatorUserID, comment.ID, req.UserID, htmltext.FetchExcerpt(comment.ParsedText, "...", 240))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveComment delete comment
|
||||
func (cs *CommentService) RemoveComment(ctx context.Context, req *schema.RemoveCommentReq) (err error) {
|
||||
commentInfo, exist, err := cs.commentCommonRepo.GetComment(ctx, req.CommentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exist {
|
||||
return nil
|
||||
}
|
||||
err = cs.commentRepo.RemoveComment(ctx, req.CommentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventCommentDelete, req.UserID).
|
||||
TID(req.CommentID).CID(req.CommentID, req.UserID))
|
||||
if commentInfo.ObjectID == commentInfo.QuestionID {
|
||||
cs.vectorSyncService.Send(ctx, &vector_sync.Task{Action: vector_sync.ActionUpsert, ObjectType: vector_sync.ObjectTypeQuestion, ObjectID: commentInfo.QuestionID})
|
||||
} else {
|
||||
cs.vectorSyncService.Send(ctx, &vector_sync.Task{Action: vector_sync.ActionUpsert, ObjectType: vector_sync.ObjectTypeAnswer, ObjectID: commentInfo.ObjectID})
|
||||
cs.vectorSyncService.Send(ctx, &vector_sync.Task{Action: vector_sync.ActionUpsert, ObjectType: vector_sync.ObjectTypeQuestion, ObjectID: commentInfo.QuestionID})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateComment update comment
|
||||
func (cs *CommentService) UpdateComment(ctx context.Context, req *schema.UpdateCommentReq) (
|
||||
resp *schema.UpdateCommentResp, err error) {
|
||||
old, exist, err := cs.commentCommonRepo.GetComment(ctx, req.CommentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exist {
|
||||
return nil, errors.BadRequest(reason.CommentNotFound)
|
||||
}
|
||||
// user can't edit the comment that was posted by others except admin
|
||||
if !req.IsAdmin && req.UserID != old.UserID {
|
||||
return nil, errors.BadRequest(reason.CommentNotFound)
|
||||
}
|
||||
|
||||
// user can edit the comment that was posted by himself before deadline.
|
||||
// admin can edit it at any time
|
||||
if !req.IsAdmin && (time.Now().After(old.CreatedAt.Add(constant.CommentEditDeadline))) {
|
||||
return nil, errors.BadRequest(reason.CommentCannotEditAfterDeadline)
|
||||
}
|
||||
|
||||
if err = cs.commentRepo.UpdateCommentContent(ctx, old.ID, req.OriginalText, req.ParsedText); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp = &schema.UpdateCommentResp{
|
||||
CommentID: old.ID,
|
||||
OriginalText: req.OriginalText,
|
||||
ParsedText: req.ParsedText,
|
||||
}
|
||||
cs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventCommentUpdate, req.UserID).TID(old.ID).
|
||||
CID(old.ID, old.UserID))
|
||||
if old.ObjectID == old.QuestionID {
|
||||
cs.vectorSyncService.Send(ctx, &vector_sync.Task{Action: vector_sync.ActionUpsert, ObjectType: vector_sync.ObjectTypeQuestion, ObjectID: old.QuestionID})
|
||||
} else {
|
||||
cs.vectorSyncService.Send(ctx, &vector_sync.Task{Action: vector_sync.ActionUpsert, ObjectType: vector_sync.ObjectTypeAnswer, ObjectID: old.ObjectID})
|
||||
cs.vectorSyncService.Send(ctx, &vector_sync.Task{Action: vector_sync.ActionUpsert, ObjectType: vector_sync.ObjectTypeQuestion, ObjectID: old.QuestionID})
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetComment get comment one
|
||||
func (cs *CommentService) GetComment(ctx context.Context, req *schema.GetCommentReq) (resp *schema.GetCommentResp, err error) {
|
||||
comment, exist, err := cs.commentCommonRepo.GetComment(ctx, req.ID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !exist {
|
||||
return nil, errors.BadRequest(reason.CommentNotFound)
|
||||
}
|
||||
objInfo, err := cs.objectInfoService.GetInfo(ctx, comment.ObjectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := objInfo.CheckVisibility(req.UserID, req.IsAdminModerator); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp = &schema.GetCommentResp{
|
||||
CommentID: comment.ID,
|
||||
CreatedAt: comment.CreatedAt.Unix(),
|
||||
UserID: comment.UserID,
|
||||
ReplyUserID: comment.GetReplyUserID(),
|
||||
ReplyCommentID: comment.GetReplyCommentID(),
|
||||
ObjectID: comment.ObjectID,
|
||||
VoteCount: comment.VoteCount,
|
||||
OriginalText: comment.OriginalText,
|
||||
ParsedText: comment.ParsedText,
|
||||
}
|
||||
|
||||
// get comment user info
|
||||
if len(resp.UserID) > 0 {
|
||||
commentUser, exist, err := cs.userCommon.GetUserBasicInfoByID(ctx, resp.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if exist {
|
||||
resp.Username = commentUser.Username
|
||||
resp.UserDisplayName = commentUser.DisplayName
|
||||
resp.UserAvatar = commentUser.Avatar
|
||||
resp.UserStatus = commentUser.Status
|
||||
}
|
||||
}
|
||||
|
||||
// get reply user info
|
||||
if len(resp.ReplyUserID) > 0 {
|
||||
replyUser, exist, err := cs.userCommon.GetUserBasicInfoByID(ctx, resp.ReplyUserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if exist {
|
||||
resp.ReplyUsername = replyUser.Username
|
||||
resp.ReplyUserDisplayName = replyUser.DisplayName
|
||||
resp.ReplyUserStatus = replyUser.Status
|
||||
}
|
||||
}
|
||||
|
||||
// check if current user vote this comment
|
||||
resp.IsVote = cs.checkIsVote(ctx, req.UserID, resp.CommentID)
|
||||
|
||||
resp.MemberActions = permission.GetCommentPermission(ctx, req.UserID, resp.UserID,
|
||||
comment.CreatedAt, req.CanEdit, req.CanDelete)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetCommentWithPage get comment list page
|
||||
func (cs *CommentService) GetCommentWithPage(ctx context.Context, req *schema.GetCommentWithPageReq) (
|
||||
pageModel *pager.PageModel, err error) {
|
||||
objInfo, err := cs.objectInfoService.GetInfo(ctx, req.ObjectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := objInfo.CheckVisibility(req.UserID, req.IsAdminModerator); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dto := &CommentQuery{
|
||||
PageCond: pager.PageCond{Page: req.Page, PageSize: req.PageSize},
|
||||
ObjectID: req.ObjectID,
|
||||
QueryCond: req.QueryCond,
|
||||
}
|
||||
commentList, total, err := cs.commentRepo.GetCommentPage(ctx, dto)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp := make([]*schema.GetCommentResp, 0)
|
||||
for _, comment := range commentList {
|
||||
commentResp, err := cs.convertCommentEntity2Resp(ctx, req, comment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp = append(resp, commentResp)
|
||||
}
|
||||
|
||||
// if user request the specific comment, add it if not exist.
|
||||
if len(req.CommentID) > 0 {
|
||||
commentExist := false
|
||||
for _, t := range resp {
|
||||
if t.CommentID == req.CommentID {
|
||||
commentExist = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !commentExist {
|
||||
comment, exist, err := cs.commentCommonRepo.GetComment(ctx, req.CommentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if exist && comment.ObjectID == req.ObjectID {
|
||||
commentResp, err := cs.convertCommentEntity2Resp(ctx, req, comment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp = append(resp, commentResp)
|
||||
}
|
||||
}
|
||||
}
|
||||
return pager.NewPageModel(total, resp), nil
|
||||
}
|
||||
|
||||
func (cs *CommentService) convertCommentEntity2Resp(ctx context.Context, req *schema.GetCommentWithPageReq,
|
||||
comment *entity.Comment) (commentResp *schema.GetCommentResp, err error) {
|
||||
commentResp = &schema.GetCommentResp{
|
||||
CommentID: comment.ID,
|
||||
CreatedAt: comment.CreatedAt.Unix(),
|
||||
UserID: comment.UserID,
|
||||
ReplyUserID: comment.GetReplyUserID(),
|
||||
ReplyCommentID: comment.GetReplyCommentID(),
|
||||
ObjectID: comment.ObjectID,
|
||||
VoteCount: comment.VoteCount,
|
||||
OriginalText: comment.OriginalText,
|
||||
ParsedText: comment.ParsedText,
|
||||
}
|
||||
|
||||
// get comment user info
|
||||
if len(commentResp.UserID) > 0 {
|
||||
commentUser, exist, err := cs.userCommon.GetUserBasicInfoByID(ctx, commentResp.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if exist {
|
||||
commentResp.Username = commentUser.Username
|
||||
commentResp.UserDisplayName = commentUser.DisplayName
|
||||
commentResp.UserAvatar = commentUser.Avatar
|
||||
commentResp.UserStatus = commentUser.Status
|
||||
}
|
||||
}
|
||||
|
||||
// get reply user info
|
||||
if len(commentResp.ReplyUserID) > 0 {
|
||||
replyUser, exist, err := cs.userCommon.GetUserBasicInfoByID(ctx, commentResp.ReplyUserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if exist {
|
||||
commentResp.ReplyUsername = replyUser.Username
|
||||
commentResp.ReplyUserDisplayName = replyUser.DisplayName
|
||||
commentResp.ReplyUserStatus = replyUser.Status
|
||||
}
|
||||
}
|
||||
|
||||
// check if current user vote this comment
|
||||
commentResp.IsVote = cs.checkIsVote(ctx, req.UserID, commentResp.CommentID)
|
||||
|
||||
commentResp.MemberActions = permission.GetCommentPermission(ctx,
|
||||
req.UserID, commentResp.UserID, comment.CreatedAt, req.CanEdit, req.CanDelete)
|
||||
return commentResp, nil
|
||||
}
|
||||
|
||||
func (cs *CommentService) checkIsVote(ctx context.Context, userID, commentID string) (isVote bool) {
|
||||
status := cs.voteCommon.GetVoteStatus(ctx, commentID, userID)
|
||||
return len(status) > 0
|
||||
}
|
||||
|
||||
// GetCommentPersonalWithPage get personal comment list page
|
||||
func (cs *CommentService) GetCommentPersonalWithPage(ctx context.Context, req *schema.GetCommentPersonalWithPageReq) (
|
||||
pageModel *pager.PageModel, err error) {
|
||||
if len(req.Username) > 0 {
|
||||
userInfo, exist, err := cs.userCommon.GetUserBasicInfoByUserName(ctx, req.Username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exist {
|
||||
return nil, errors.BadRequest(reason.UserNotFound)
|
||||
}
|
||||
req.UserID = userInfo.ID
|
||||
}
|
||||
if len(req.UserID) == 0 {
|
||||
return nil, errors.BadRequest(reason.UserNotFound)
|
||||
}
|
||||
|
||||
dto := &CommentQuery{
|
||||
PageCond: pager.PageCond{Page: req.Page, PageSize: req.PageSize},
|
||||
UserID: req.UserID,
|
||||
QueryCond: "created_at",
|
||||
}
|
||||
commentList, total, err := cs.commentRepo.GetCommentPage(ctx, dto)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp := make([]*schema.GetCommentPersonalWithPageResp, 0)
|
||||
for _, comment := range commentList {
|
||||
commentResp := &schema.GetCommentPersonalWithPageResp{
|
||||
CommentID: comment.ID,
|
||||
CreatedAt: comment.CreatedAt.Unix(),
|
||||
ObjectID: comment.ObjectID,
|
||||
Content: comment.ParsedText, // todo trim
|
||||
}
|
||||
if len(comment.ObjectID) > 0 {
|
||||
objInfo, err := cs.objectInfoService.GetInfo(ctx, comment.ObjectID)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
} else {
|
||||
commentResp.ObjectType = objInfo.ObjectType
|
||||
commentResp.Title = objInfo.Title
|
||||
commentResp.UrlTitle = htmltext.UrlTitle(objInfo.Title)
|
||||
commentResp.QuestionID = objInfo.QuestionID
|
||||
commentResp.AnswerID = objInfo.AnswerID
|
||||
if objInfo.QuestionStatus == entity.QuestionStatusDeleted {
|
||||
commentResp.Title = "Deleted question"
|
||||
}
|
||||
}
|
||||
}
|
||||
resp = append(resp, commentResp)
|
||||
}
|
||||
return pager.NewPageModel(total, resp), nil
|
||||
}
|
||||
|
||||
func (cs *CommentService) notificationQuestionComment(ctx context.Context, questionUserID,
|
||||
questionID, questionTitle, commentID, commentUserID, commentSummary string) {
|
||||
if questionUserID == commentUserID {
|
||||
return
|
||||
}
|
||||
// send internal notification
|
||||
msg := &schema.NotificationMsg{
|
||||
ReceiverUserID: questionUserID,
|
||||
TriggerUserID: commentUserID,
|
||||
Type: schema.NotificationTypeInbox,
|
||||
ObjectID: commentID,
|
||||
}
|
||||
msg.ObjectType = constant.CommentObjectType
|
||||
msg.NotificationAction = constant.NotificationCommentQuestion
|
||||
cs.notificationQueueService.Send(ctx, msg)
|
||||
|
||||
// send external notification
|
||||
receiverUserInfo, exist, err := cs.userRepo.GetByUserID(ctx, questionUserID)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
if !exist {
|
||||
log.Warnf("user %s not found", questionUserID)
|
||||
return
|
||||
}
|
||||
|
||||
externalNotificationMsg := &schema.ExternalNotificationMsg{
|
||||
ReceiverUserID: receiverUserInfo.ID,
|
||||
ReceiverEmail: receiverUserInfo.EMail,
|
||||
ReceiverLang: receiverUserInfo.Language,
|
||||
}
|
||||
rawData := &schema.NewCommentTemplateRawData{
|
||||
QuestionTitle: questionTitle,
|
||||
QuestionID: questionID,
|
||||
CommentID: commentID,
|
||||
CommentSummary: commentSummary,
|
||||
UnsubscribeCode: token.GenerateToken(),
|
||||
}
|
||||
commentUser, _, _ := cs.userCommon.GetUserBasicInfoByID(ctx, commentUserID)
|
||||
if commentUser != nil {
|
||||
rawData.CommentUserDisplayName = commentUser.DisplayName
|
||||
}
|
||||
externalNotificationMsg.NewCommentTemplateRawData = rawData
|
||||
cs.externalNotificationQueueService.Send(ctx, externalNotificationMsg)
|
||||
}
|
||||
|
||||
func (cs *CommentService) notificationAnswerComment(ctx context.Context,
|
||||
questionID, questionTitle, answerID, answerUserID, commentID, commentUserID, commentSummary string) {
|
||||
if answerUserID == commentUserID {
|
||||
return
|
||||
}
|
||||
|
||||
// Send internal notification.
|
||||
msg := &schema.NotificationMsg{
|
||||
ReceiverUserID: answerUserID,
|
||||
TriggerUserID: commentUserID,
|
||||
Type: schema.NotificationTypeInbox,
|
||||
ObjectID: commentID,
|
||||
}
|
||||
msg.ObjectType = constant.CommentObjectType
|
||||
msg.NotificationAction = constant.NotificationCommentAnswer
|
||||
cs.notificationQueueService.Send(ctx, msg)
|
||||
|
||||
// Send external notification.
|
||||
receiverUserInfo, exist, err := cs.userRepo.GetByUserID(ctx, answerUserID)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
if !exist {
|
||||
log.Warnf("user %s not found", answerUserID)
|
||||
return
|
||||
}
|
||||
externalNotificationMsg := &schema.ExternalNotificationMsg{
|
||||
ReceiverUserID: receiverUserInfo.ID,
|
||||
ReceiverEmail: receiverUserInfo.EMail,
|
||||
ReceiverLang: receiverUserInfo.Language,
|
||||
}
|
||||
rawData := &schema.NewCommentTemplateRawData{
|
||||
QuestionTitle: questionTitle,
|
||||
QuestionID: questionID,
|
||||
AnswerID: answerID,
|
||||
CommentID: commentID,
|
||||
CommentSummary: commentSummary,
|
||||
UnsubscribeCode: token.GenerateToken(),
|
||||
}
|
||||
commentUser, _, _ := cs.userCommon.GetUserBasicInfoByID(ctx, commentUserID)
|
||||
if commentUser != nil {
|
||||
rawData.CommentUserDisplayName = commentUser.DisplayName
|
||||
}
|
||||
externalNotificationMsg.NewCommentTemplateRawData = rawData
|
||||
cs.externalNotificationQueueService.Send(ctx, externalNotificationMsg)
|
||||
}
|
||||
|
||||
func (cs *CommentService) notificationCommentReply(ctx context.Context, replyUserID, commentID, commentUserID,
|
||||
questionID, questionTitle, commentSummary string) {
|
||||
msg := &schema.NotificationMsg{
|
||||
ReceiverUserID: replyUserID,
|
||||
TriggerUserID: commentUserID,
|
||||
Type: schema.NotificationTypeInbox,
|
||||
ObjectID: commentID,
|
||||
}
|
||||
msg.ObjectType = constant.CommentObjectType
|
||||
msg.NotificationAction = constant.NotificationReplyToYou
|
||||
cs.notificationQueueService.Send(ctx, msg)
|
||||
|
||||
// Send external notification.
|
||||
receiverUserInfo, exist, err := cs.userRepo.GetByUserID(ctx, replyUserID)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
if !exist {
|
||||
log.Warnf("user %s not found", replyUserID)
|
||||
return
|
||||
}
|
||||
externalNotificationMsg := &schema.ExternalNotificationMsg{
|
||||
ReceiverUserID: receiverUserInfo.ID,
|
||||
ReceiverEmail: receiverUserInfo.EMail,
|
||||
ReceiverLang: receiverUserInfo.Language,
|
||||
}
|
||||
rawData := &schema.NewCommentTemplateRawData{
|
||||
QuestionTitle: questionTitle,
|
||||
QuestionID: questionID,
|
||||
CommentID: commentID,
|
||||
CommentSummary: commentSummary,
|
||||
UnsubscribeCode: token.GenerateToken(),
|
||||
}
|
||||
commentUser, _, _ := cs.userCommon.GetUserBasicInfoByID(ctx, commentUserID)
|
||||
if commentUser != nil {
|
||||
rawData.CommentUserDisplayName = commentUser.DisplayName
|
||||
}
|
||||
externalNotificationMsg.NewCommentTemplateRawData = rawData
|
||||
cs.externalNotificationQueueService.Send(ctx, externalNotificationMsg)
|
||||
}
|
||||
|
||||
func (cs *CommentService) notificationMention(
|
||||
ctx context.Context, mentionUsernameList []string, commentID, commentUserID string,
|
||||
alreadyNotifiedUserID map[string]bool) (alreadyNotifiedUserIDs []string) {
|
||||
for _, username := range mentionUsernameList {
|
||||
userInfo, exist, err := cs.userCommon.GetUserBasicInfoByUserName(ctx, username)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
continue
|
||||
}
|
||||
if exist && !alreadyNotifiedUserID[userInfo.ID] {
|
||||
msg := &schema.NotificationMsg{
|
||||
ReceiverUserID: userInfo.ID,
|
||||
TriggerUserID: commentUserID,
|
||||
Type: schema.NotificationTypeInbox,
|
||||
ObjectID: commentID,
|
||||
}
|
||||
msg.ObjectType = constant.CommentObjectType
|
||||
msg.NotificationAction = constant.NotificationMentionYou
|
||||
cs.notificationQueueService.Send(ctx, msg)
|
||||
alreadyNotifiedUserIDs = append(alreadyNotifiedUserIDs, userInfo.ID)
|
||||
}
|
||||
}
|
||||
return alreadyNotifiedUserIDs
|
||||
}
|
||||
Reference in New Issue
Block a user