2022-09-27 17:59:05 +08:00
|
|
|
package notificationcommon
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
|
2022-10-24 16:51:05 +08:00
|
|
|
"github.com/answerdev/answer/internal/base/constant"
|
|
|
|
"github.com/answerdev/answer/internal/base/data"
|
|
|
|
"github.com/answerdev/answer/internal/base/reason"
|
|
|
|
"github.com/answerdev/answer/internal/entity"
|
|
|
|
"github.com/answerdev/answer/internal/schema"
|
|
|
|
"github.com/answerdev/answer/internal/service/activity_common"
|
|
|
|
"github.com/answerdev/answer/internal/service/notice_queue"
|
|
|
|
"github.com/answerdev/answer/internal/service/object_info"
|
|
|
|
usercommon "github.com/answerdev/answer/internal/service/user_common"
|
2022-09-27 17:59:05 +08:00
|
|
|
"github.com/goccy/go-json"
|
|
|
|
"github.com/jinzhu/copier"
|
|
|
|
"github.com/segmentfault/pacman/errors"
|
|
|
|
"github.com/segmentfault/pacman/log"
|
|
|
|
)
|
|
|
|
|
|
|
|
type NotificationRepo interface {
|
|
|
|
AddNotification(ctx context.Context, notification *entity.Notification) (err error)
|
2022-10-26 17:37:11 +08:00
|
|
|
GetNotificationPage(ctx context.Context, search *schema.NotificationSearch) ([]*entity.Notification, int64, error)
|
2022-09-27 17:59:05 +08:00
|
|
|
ClearUnRead(ctx context.Context, userID string, notificationType int) (err error)
|
|
|
|
ClearIDUnRead(ctx context.Context, userID string, id string) (err error)
|
|
|
|
GetByUserIdObjectIdTypeId(ctx context.Context, userID, objectID string, notificationType int) (*entity.Notification, bool, error)
|
|
|
|
UpdateNotificationContent(ctx context.Context, notification *entity.Notification) (err error)
|
|
|
|
GetById(ctx context.Context, id string) (*entity.Notification, bool, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
type NotificationCommon struct {
|
|
|
|
data *data.Data
|
|
|
|
notificationRepo NotificationRepo
|
|
|
|
activityRepo activity_common.ActivityRepo
|
|
|
|
followRepo activity_common.FollowRepo
|
|
|
|
userCommon *usercommon.UserCommon
|
|
|
|
objectInfoService *object_info.ObjService
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewNotificationCommon(
|
|
|
|
data *data.Data,
|
|
|
|
notificationRepo NotificationRepo,
|
|
|
|
userCommon *usercommon.UserCommon,
|
|
|
|
activityRepo activity_common.ActivityRepo,
|
|
|
|
followRepo activity_common.FollowRepo,
|
|
|
|
objectInfoService *object_info.ObjService,
|
|
|
|
) *NotificationCommon {
|
|
|
|
notification := &NotificationCommon{
|
|
|
|
data: data,
|
|
|
|
notificationRepo: notificationRepo,
|
|
|
|
activityRepo: activityRepo,
|
|
|
|
followRepo: followRepo,
|
|
|
|
userCommon: userCommon,
|
|
|
|
objectInfoService: objectInfoService,
|
|
|
|
}
|
|
|
|
notification.HandleNotification()
|
|
|
|
return notification
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ns *NotificationCommon) HandleNotification() {
|
|
|
|
go func() {
|
|
|
|
for msg := range notice_queue.NotificationQueue {
|
|
|
|
log.Debugf("received notification %+v", msg)
|
|
|
|
err := ns.AddNotification(context.TODO(), msg)
|
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddNotification
|
|
|
|
// need set
|
|
|
|
// UserID
|
|
|
|
// Type 1 inbox 2 achievement
|
|
|
|
// [inbox] Activity
|
|
|
|
// [achievement] Rank
|
|
|
|
// ObjectInfo.Title
|
|
|
|
// ObjectInfo.ObjectID
|
|
|
|
// ObjectInfo.ObjectType
|
|
|
|
func (ns *NotificationCommon) AddNotification(ctx context.Context, msg *schema.NotificationMsg) error {
|
|
|
|
req := &schema.NotificationContent{
|
|
|
|
TriggerUserID: msg.TriggerUserID,
|
|
|
|
ReceiverUserID: msg.ReceiverUserID,
|
|
|
|
ObjectInfo: schema.ObjectInfo{
|
|
|
|
Title: msg.Title,
|
|
|
|
ObjectID: msg.ObjectID,
|
|
|
|
ObjectType: msg.ObjectType,
|
|
|
|
},
|
|
|
|
NotificationAction: msg.NotificationAction,
|
|
|
|
Type: msg.Type,
|
|
|
|
}
|
|
|
|
var questionID string // just for notify all followers
|
|
|
|
objInfo, err := ns.objectInfoService.GetInfo(ctx, req.ObjectInfo.ObjectID)
|
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
} else {
|
|
|
|
req.ObjectInfo.Title = objInfo.Title
|
|
|
|
questionID = objInfo.QuestionID
|
|
|
|
objectMap := make(map[string]string)
|
|
|
|
objectMap["question"] = objInfo.QuestionID
|
|
|
|
objectMap["answer"] = objInfo.AnswerID
|
|
|
|
objectMap["comment"] = objInfo.CommentID
|
|
|
|
req.ObjectInfo.ObjectMap = objectMap
|
|
|
|
}
|
|
|
|
|
|
|
|
if msg.Type == schema.NotificationTypeAchievement {
|
|
|
|
notificationInfo, exist, err := ns.notificationRepo.GetByUserIdObjectIdTypeId(ctx, req.ReceiverUserID, req.ObjectInfo.ObjectID, req.Type)
|
|
|
|
if err != nil {
|
|
|
|
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
|
|
|
}
|
|
|
|
rank, err := ns.activityRepo.GetUserIDObjectIDActivitySum(ctx, req.ReceiverUserID, req.ObjectInfo.ObjectID)
|
|
|
|
if err != nil {
|
|
|
|
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
|
|
|
}
|
|
|
|
req.Rank = rank
|
|
|
|
if exist {
|
|
|
|
//modify notification
|
|
|
|
updateContent := &schema.NotificationContent{}
|
|
|
|
err := json.Unmarshal([]byte(notificationInfo.Content), updateContent)
|
|
|
|
if err != nil {
|
|
|
|
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
|
|
|
}
|
|
|
|
updateContent.Rank = rank
|
|
|
|
content, err := json.Marshal(updateContent)
|
|
|
|
if err != nil {
|
|
|
|
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
|
|
|
}
|
|
|
|
notificationInfo.Content = string(content)
|
|
|
|
err = ns.notificationRepo.UpdateNotificationContent(ctx, notificationInfo)
|
|
|
|
if err != nil {
|
|
|
|
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
info := &entity.Notification{}
|
|
|
|
now := time.Now()
|
|
|
|
info.UserID = req.ReceiverUserID
|
|
|
|
info.Type = req.Type
|
|
|
|
info.IsRead = schema.NotificationNotRead
|
|
|
|
info.Status = schema.NotificationStatusNormal
|
|
|
|
info.CreatedAt = now
|
|
|
|
info.UpdatedAt = now
|
|
|
|
info.ObjectID = req.ObjectInfo.ObjectID
|
|
|
|
|
|
|
|
userBasicInfo, exist, err := ns.userCommon.GetUserBasicInfoByID(ctx, req.TriggerUserID)
|
|
|
|
if err != nil {
|
|
|
|
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
|
|
|
}
|
|
|
|
if !exist {
|
|
|
|
return errors.InternalServer(reason.UserNotFound).WithError(err).WithStack()
|
|
|
|
}
|
|
|
|
req.UserInfo = userBasicInfo
|
|
|
|
content, err := json.Marshal(req)
|
|
|
|
if err != nil {
|
|
|
|
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
|
|
|
}
|
|
|
|
info.Content = string(content)
|
|
|
|
err = ns.notificationRepo.AddNotification(ctx, info)
|
|
|
|
if err != nil {
|
|
|
|
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
|
|
|
}
|
|
|
|
err = ns.addRedDot(ctx, info.UserID, info.Type)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("addRedDot Error", err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
go ns.SendNotificationToAllFollower(context.Background(), msg, questionID)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ns *NotificationCommon) addRedDot(ctx context.Context, userID string, botType int) error {
|
|
|
|
key := fmt.Sprintf("answer_RedDot_%d_%s", botType, userID)
|
|
|
|
err := ns.data.Cache.SetInt64(ctx, key, 1, 30*24*time.Hour) //Expiration time is one month.
|
|
|
|
if err != nil {
|
|
|
|
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SendNotificationToAllFollower send notification to all followers
|
|
|
|
func (ns *NotificationCommon) SendNotificationToAllFollower(ctx context.Context, msg *schema.NotificationMsg,
|
|
|
|
questionID string) {
|
|
|
|
if msg.NoNeedPushAllFollow {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if msg.NotificationAction != constant.UpdateQuestion &&
|
|
|
|
msg.NotificationAction != constant.AnswerTheQuestion &&
|
|
|
|
msg.NotificationAction != constant.UpdateAnswer &&
|
|
|
|
msg.NotificationAction != constant.AdoptAnswer {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
condObjectID := msg.ObjectID
|
|
|
|
if len(questionID) > 0 {
|
|
|
|
condObjectID = questionID
|
|
|
|
}
|
|
|
|
userIDs, err := ns.followRepo.GetFollowUserIDs(ctx, condObjectID)
|
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
log.Infof("send notification to all followers: %s %d", condObjectID, len(userIDs))
|
|
|
|
for _, userID := range userIDs {
|
|
|
|
t := &schema.NotificationMsg{}
|
|
|
|
_ = copier.Copy(t, msg)
|
|
|
|
t.ReceiverUserID = userID
|
|
|
|
t.TriggerUserID = msg.TriggerUserID
|
|
|
|
t.NoNeedPushAllFollow = true
|
|
|
|
notice_queue.AddNotification(t)
|
|
|
|
}
|
|
|
|
}
|