mirror of https://gitee.com/answerdev/answer.git
feat(notification): add upvote and down vote notification
This commit is contained in:
parent
3952439d49
commit
c56d54b0fe
|
@ -5,14 +5,24 @@ const (
|
||||||
UpdateQuestion = "notification.action.update_question"
|
UpdateQuestion = "notification.action.update_question"
|
||||||
// AnswerTheQuestion answer the question
|
// AnswerTheQuestion answer the question
|
||||||
AnswerTheQuestion = "notification.action.answer_the_question"
|
AnswerTheQuestion = "notification.action.answer_the_question"
|
||||||
|
// UpVotedTheQuestion up voted the question
|
||||||
|
UpVotedTheQuestion = "notification.action.up_voted_question"
|
||||||
|
// DownVotedTheQuestion down voted the question
|
||||||
|
DownVotedTheQuestion = "notification.action.down_voted_question"
|
||||||
// UpdateAnswer update answer
|
// UpdateAnswer update answer
|
||||||
UpdateAnswer = "notification.action.update_answer"
|
UpdateAnswer = "notification.action.update_answer"
|
||||||
// AcceptAnswer accept answer
|
// AcceptAnswer accept answer
|
||||||
AcceptAnswer = "notification.action.accept_answer"
|
AcceptAnswer = "notification.action.accept_answer"
|
||||||
|
// UpVotedTheAnswer up voted the answer
|
||||||
|
UpVotedTheAnswer = "notification.action.up_voted_answer"
|
||||||
|
// DownVotedTheAnswer down voted the answer
|
||||||
|
DownVotedTheAnswer = "notification.action.down_voted_answer"
|
||||||
// CommentQuestion comment question
|
// CommentQuestion comment question
|
||||||
CommentQuestion = "notification.action.comment_question"
|
CommentQuestion = "notification.action.comment_question"
|
||||||
// CommentAnswer comment answer
|
// CommentAnswer comment answer
|
||||||
CommentAnswer = "notification.action.comment_answer"
|
CommentAnswer = "notification.action.comment_answer"
|
||||||
|
// UpVotedTheComment up voted the comment
|
||||||
|
UpVotedTheComment = "notification.action.up_voted_comment"
|
||||||
// ReplyToYou reply to you
|
// ReplyToYou reply to you
|
||||||
ReplyToYou = "notification.action.reply_to_you"
|
ReplyToYou = "notification.action.reply_to_you"
|
||||||
// MentionYou mention you
|
// MentionYou mention you
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/answerdev/answer/internal/base/constant"
|
||||||
"github.com/answerdev/answer/pkg/converter"
|
"github.com/answerdev/answer/pkg/converter"
|
||||||
|
|
||||||
"github.com/answerdev/answer/internal/base/pager"
|
"github.com/answerdev/answer/internal/base/pager"
|
||||||
|
@ -70,7 +71,9 @@ var LimitDownActions = map[string][]string{
|
||||||
|
|
||||||
func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUserID string, actions []string) (resp *schema.VoteResp, err error) {
|
func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUserID string, actions []string) (resp *schema.VoteResp, err error) {
|
||||||
resp = &schema.VoteResp{}
|
resp = &schema.VoteResp{}
|
||||||
notificationUserIDs := make([]string, 0)
|
achievementNotificationUserIDs := make([]string, 0)
|
||||||
|
sendInboxNotification := false
|
||||||
|
upVote := false
|
||||||
_, err = vr.data.DB.Transaction(func(session *xorm.Session) (result any, err error) {
|
_, err = vr.data.DB.Transaction(func(session *xorm.Session) (result any, err error) {
|
||||||
result = nil
|
result = nil
|
||||||
for _, action := range actions {
|
for _, action := range actions {
|
||||||
|
@ -127,7 +130,7 @@ func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUse
|
||||||
if isReachStandard {
|
if isReachStandard {
|
||||||
insertActivity.Rank = 0
|
insertActivity.Rank = 0
|
||||||
}
|
}
|
||||||
notificationUserIDs = append(notificationUserIDs, activityUserID)
|
achievementNotificationUserIDs = append(achievementNotificationUserIDs, activityUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if has {
|
if has {
|
||||||
|
@ -142,13 +145,17 @@ func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUse
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
sendInboxNotification = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// update votes
|
// update votes
|
||||||
if action == "vote_down" || action == "vote_up" {
|
if action == constant.ActVoteDown || action == constant.ActVoteUp {
|
||||||
votes := 1
|
votes := 1
|
||||||
if action == "vote_down" {
|
if action == constant.ActVoteDown {
|
||||||
|
upVote = false
|
||||||
votes = -1
|
votes = -1
|
||||||
|
} else {
|
||||||
|
upVote = true
|
||||||
}
|
}
|
||||||
err = vr.updateVotes(ctx, session, objectID, votes)
|
err = vr.updateVotes(ctx, session, objectID, votes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -165,9 +172,12 @@ func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUse
|
||||||
resp, err = vr.GetVoteResultByObjectId(ctx, objectID)
|
resp, err = vr.GetVoteResultByObjectId(ctx, objectID)
|
||||||
resp.VoteStatus = vr.voteCommon.GetVoteStatus(ctx, objectID, userID)
|
resp.VoteStatus = vr.voteCommon.GetVoteStatus(ctx, objectID, userID)
|
||||||
|
|
||||||
for _, activityUserID := range notificationUserIDs {
|
for _, activityUserID := range achievementNotificationUserIDs {
|
||||||
vr.sendNotification(ctx, activityUserID, objectUserID, objectID)
|
vr.sendNotification(ctx, activityUserID, objectUserID, objectID)
|
||||||
}
|
}
|
||||||
|
if sendInboxNotification {
|
||||||
|
vr.sendVoteInboxNotification(userID, objectUserID, objectID, upVote)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,3 +451,40 @@ func (vr *VoteRepo) sendNotification(ctx context.Context, activityUserID, object
|
||||||
}
|
}
|
||||||
notice_queue.AddNotification(msg)
|
notice_queue.AddNotification(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vr *VoteRepo) sendVoteInboxNotification(triggerUserID, receiverUserID, objectID string, upvote bool) {
|
||||||
|
if triggerUserID == receiverUserID {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
objectType, _ := obj.GetObjectTypeStrByObjectID(objectID)
|
||||||
|
|
||||||
|
msg := &schema.NotificationMsg{
|
||||||
|
TriggerUserID: triggerUserID,
|
||||||
|
ReceiverUserID: receiverUserID,
|
||||||
|
Type: schema.NotificationTypeInbox,
|
||||||
|
ObjectID: objectID,
|
||||||
|
ObjectType: objectType,
|
||||||
|
}
|
||||||
|
if objectType == constant.QuestionObjectType {
|
||||||
|
if upvote {
|
||||||
|
msg.NotificationAction = constant.UpVotedTheQuestion
|
||||||
|
} else {
|
||||||
|
msg.NotificationAction = constant.DownVotedTheQuestion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if objectType == constant.AnswerObjectType {
|
||||||
|
if upvote {
|
||||||
|
msg.NotificationAction = constant.UpVotedTheAnswer
|
||||||
|
} else {
|
||||||
|
msg.NotificationAction = constant.DownVotedTheAnswer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if objectType == constant.CommentObjectType {
|
||||||
|
if upvote {
|
||||||
|
msg.NotificationAction = constant.UpVotedTheComment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(msg.NotificationAction) > 0 {
|
||||||
|
notice_queue.AddNotification(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -63,9 +63,23 @@ func (g *GetPluginConfigResp) SetConfigFields(ctx *gin.Context, fields []plugin.
|
||||||
configField.UIOptions.Label = field.UIOptions.Label.Translate(ctx)
|
configField.UIOptions.Label = field.UIOptions.Label.Translate(ctx)
|
||||||
configField.UIOptions.Text = field.UIOptions.Text.Translate(ctx)
|
configField.UIOptions.Text = field.UIOptions.Text.Translate(ctx)
|
||||||
if field.UIOptions.Action != nil {
|
if field.UIOptions.Action != nil {
|
||||||
configField.UIOptions.Action = &ConfigFieldUIOptionAction{
|
uiOptionAction := &UIOptionAction{
|
||||||
Url: field.UIOptions.Action.Url,
|
Url: field.UIOptions.Action.Url,
|
||||||
|
Method: field.UIOptions.Action.Method,
|
||||||
}
|
}
|
||||||
|
if field.UIOptions.Action.Loading != nil {
|
||||||
|
uiOptionAction.Loading = &LoadingAction{
|
||||||
|
Text: field.UIOptions.Action.Loading.Text.Translate(ctx),
|
||||||
|
State: string(field.UIOptions.Action.Loading.State),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if field.UIOptions.Action.OnComplete != nil {
|
||||||
|
uiOptionAction.OnCompleteAction = &OnCompleteAction{
|
||||||
|
ToastReturnMessage: field.UIOptions.Action.OnComplete.ToastReturnMessage,
|
||||||
|
RefreshFormConfig: field.UIOptions.Action.OnComplete.RefreshFormConfig,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
configField.UIOptions.Action = uiOptionAction
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, option := range field.Options {
|
for _, option := range field.Options {
|
||||||
|
@ -90,13 +104,13 @@ type ConfigField struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigFieldUIOptions struct {
|
type ConfigFieldUIOptions struct {
|
||||||
Placeholder string `json:"placeholder,omitempty"`
|
Placeholder string `json:"placeholder,omitempty"`
|
||||||
Rows string `json:"rows,omitempty"`
|
Rows string `json:"rows,omitempty"`
|
||||||
InputType string `json:"input_type,omitempty"`
|
InputType string `json:"input_type,omitempty"`
|
||||||
Label string `json:"label,omitempty"`
|
Label string `json:"label,omitempty"`
|
||||||
Action *ConfigFieldUIOptionAction `json:"action,omitempty"`
|
Action *UIOptionAction `json:"action,omitempty"`
|
||||||
Variant string `json:"variant,omitempty"`
|
Variant string `json:"variant,omitempty"`
|
||||||
Text string `json:"text,omitempty"`
|
Text string `json:"text,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigFieldOption struct {
|
type ConfigFieldOption struct {
|
||||||
|
@ -104,8 +118,21 @@ type ConfigFieldOption struct {
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigFieldUIOptionAction struct {
|
type UIOptionAction struct {
|
||||||
Url string `json:"url"`
|
Url string `json:"url"`
|
||||||
|
Method string `json:"method,omitempty"`
|
||||||
|
Loading *LoadingAction `json:"loading,omitempty"`
|
||||||
|
OnCompleteAction *OnCompleteAction `json:"on_complete,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoadingAction struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
State string `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OnCompleteAction struct {
|
||||||
|
ToastReturnMessage bool `json:"toast_return_message"`
|
||||||
|
RefreshFormConfig bool `json:"refresh_form_config"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdatePluginConfigReq struct {
|
type UpdatePluginConfigReq struct {
|
||||||
|
|
|
@ -63,12 +63,12 @@ func NewVoteService(
|
||||||
}
|
}
|
||||||
|
|
||||||
// VoteUp vote up
|
// VoteUp vote up
|
||||||
func (as *VoteService) VoteUp(ctx context.Context, dto *schema.VoteDTO) (voteResp *schema.VoteResp, err error) {
|
func (vs *VoteService) VoteUp(ctx context.Context, dto *schema.VoteDTO) (voteResp *schema.VoteResp, err error) {
|
||||||
voteResp = &schema.VoteResp{}
|
voteResp = &schema.VoteResp{}
|
||||||
|
|
||||||
var objectUserID string
|
var objectUserID string
|
||||||
|
|
||||||
objectUserID, err = as.GetObjectUserID(ctx, dto.ObjectID)
|
objectUserID, err = vs.GetObjectUserID(ctx, dto.ObjectID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -80,19 +80,19 @@ func (as *VoteService) VoteUp(ctx context.Context, dto *schema.VoteDTO) (voteRes
|
||||||
}
|
}
|
||||||
|
|
||||||
if dto.IsCancel {
|
if dto.IsCancel {
|
||||||
return as.voteRepo.VoteUpCancel(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
return vs.voteRepo.VoteUpCancel(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
||||||
} else {
|
} else {
|
||||||
return as.voteRepo.VoteUp(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
return vs.voteRepo.VoteUp(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// VoteDown vote down
|
// VoteDown vote down
|
||||||
func (as *VoteService) VoteDown(ctx context.Context, dto *schema.VoteDTO) (voteResp *schema.VoteResp, err error) {
|
func (vs *VoteService) VoteDown(ctx context.Context, dto *schema.VoteDTO) (voteResp *schema.VoteResp, err error) {
|
||||||
voteResp = &schema.VoteResp{}
|
voteResp = &schema.VoteResp{}
|
||||||
|
|
||||||
var objectUserID string
|
var objectUserID string
|
||||||
|
|
||||||
objectUserID, err = as.GetObjectUserID(ctx, dto.ObjectID)
|
objectUserID, err = vs.GetObjectUserID(ctx, dto.ObjectID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -104,9 +104,9 @@ func (as *VoteService) VoteDown(ctx context.Context, dto *schema.VoteDTO) (voteR
|
||||||
}
|
}
|
||||||
|
|
||||||
if dto.IsCancel {
|
if dto.IsCancel {
|
||||||
return as.voteRepo.VoteDownCancel(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
return vs.voteRepo.VoteDownCancel(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
||||||
} else {
|
} else {
|
||||||
return as.voteRepo.VoteDown(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
return vs.voteRepo.VoteDown(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,13 +44,13 @@ type ConfigField struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigFieldUIOptions struct {
|
type ConfigFieldUIOptions struct {
|
||||||
Placeholder Translator `json:"placeholder,omitempty"`
|
Placeholder Translator `json:"placeholder,omitempty"`
|
||||||
Rows string `json:"rows,omitempty"`
|
Rows string `json:"rows,omitempty"`
|
||||||
InputType InputType `json:"input_type,omitempty"`
|
InputType InputType `json:"input_type,omitempty"`
|
||||||
Label Translator `json:"label,omitempty"`
|
Label Translator `json:"label,omitempty"`
|
||||||
Action *ConfigFieldUIOptionAction `json:"action,omitempty"`
|
Action *UIOptionAction `json:"action,omitempty"`
|
||||||
Variant string `json:"variant,omitempty"`
|
Variant string `json:"variant,omitempty"`
|
||||||
Text Translator `json:"text,omitempty"`
|
Text Translator `json:"text,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigFieldOption struct {
|
type ConfigFieldOption struct {
|
||||||
|
@ -58,8 +58,29 @@ type ConfigFieldOption struct {
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigFieldUIOptionAction struct {
|
type UIOptionAction struct {
|
||||||
Url string `json:"url"`
|
Url string `json:"url"`
|
||||||
|
Method string `json:"method,omitempty"`
|
||||||
|
Loading *LoadingAction `json:"loading,omitempty"`
|
||||||
|
OnComplete *OnCompleteAction `json:"on_complete,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
LoadingActionStateNone LoadingActionType = "none"
|
||||||
|
LoadingActionStatePending LoadingActionType = "pending"
|
||||||
|
LoadingActionStateComplete LoadingActionType = "completed"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LoadingActionType string
|
||||||
|
|
||||||
|
type LoadingAction struct {
|
||||||
|
Text Translator `json:"text"`
|
||||||
|
State LoadingActionType `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OnCompleteAction struct {
|
||||||
|
ToastReturnMessage bool `json:"toast_return_message"`
|
||||||
|
RefreshFormConfig bool `json:"refresh_form_config"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config interface {
|
type Config interface {
|
||||||
|
|
Loading…
Reference in New Issue