feat(badge): add event for the badge

This commit is contained in:
LinkinStars
2024-08-08 16:19:47 +08:00
parent 264f927433
commit 07e4f549b1
17 changed files with 611 additions and 14 deletions
+10 -8
View File
@@ -78,6 +78,7 @@ import (
config2 "github.com/apache/incubator-answer/internal/service/config"
"github.com/apache/incubator-answer/internal/service/content"
"github.com/apache/incubator-answer/internal/service/dashboard"
"github.com/apache/incubator-answer/internal/service/event_queue"
export2 "github.com/apache/incubator-answer/internal/service/export"
"github.com/apache/incubator-answer/internal/service/follow"
meta2 "github.com/apache/incubator-answer/internal/service/meta"
@@ -172,7 +173,8 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
metaRepo := meta.NewMetaRepo(dataData)
metaCommonService := metacommon.NewMetaCommonService(metaRepo)
questionCommon := questioncommon.NewQuestionCommon(questionRepo, answerRepo, voteRepo, followRepo, tagCommonService, userCommon, collectionCommon, answerCommon, metaCommonService, configService, activityQueueService, revisionRepo, dataData)
userService := content.NewUserService(userRepo, userActiveActivityRepo, activityRepo, emailService, authService, siteInfoCommonService, userRoleRelService, userCommon, userExternalLoginService, userNotificationConfigRepo, userNotificationConfigService, questionCommon)
eventQueueService := event_queue.NewEventQueueService()
userService := content.NewUserService(userRepo, userActiveActivityRepo, activityRepo, emailService, authService, siteInfoCommonService, userRoleRelService, userCommon, userExternalLoginService, userNotificationConfigRepo, userNotificationConfigService, questionCommon, eventQueueService)
captchaRepo := captcha.NewCaptchaRepo(dataData)
captchaService := action.NewCaptchaService(captchaRepo)
userController := controller.NewUserController(authService, userService, captchaService, emailService, siteInfoCommonService, userNotificationConfigService)
@@ -181,7 +183,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
objService := object_info.NewObjService(answerRepo, questionRepo, commentCommonRepo, tagCommonRepo, tagCommonService)
notificationQueueService := notice_queue.NewNotificationQueueService()
externalNotificationQueueService := notice_queue.NewNewQuestionNotificationQueueService()
commentService := comment2.NewCommentService(commentRepo, commentCommonRepo, userCommon, objService, voteRepo, emailService, userRepo, notificationQueueService, externalNotificationQueueService, activityQueueService)
commentService := comment2.NewCommentService(commentRepo, commentCommonRepo, userCommon, objService, voteRepo, emailService, userRepo, notificationQueueService, externalNotificationQueueService, activityQueueService, eventQueueService)
rolePowerRelRepo := role.NewRolePowerRelRepo(dataData)
rolePowerRelService := role2.NewRolePowerRelService(rolePowerRelRepo, userRoleRelService)
rankService := rank2.NewRankService(userCommon, userRankRepo, objService, userRoleRelService, rolePowerRelService, configService)
@@ -194,13 +196,13 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
externalNotificationService := notification.NewExternalNotificationService(dataData, userNotificationConfigRepo, followRepo, emailService, userRepo, externalNotificationQueueService, userExternalLoginRepo, siteInfoCommonService)
reviewRepo := review.NewReviewRepo(dataData)
reviewService := review2.NewReviewService(reviewRepo, objService, userCommon, userRepo, questionRepo, answerRepo, userRoleRelService, externalNotificationQueueService, tagCommonService, questionCommon, notificationQueueService, siteInfoCommonService)
questionService := content.NewQuestionService(questionRepo, answerRepo, tagCommonService, questionCommon, userCommon, userRepo, userRoleRelService, revisionService, metaCommonService, collectionCommon, answerActivityService, emailService, notificationQueueService, externalNotificationQueueService, activityQueueService, siteInfoCommonService, externalNotificationService, reviewService, configService)
answerService := content.NewAnswerService(answerRepo, questionRepo, questionCommon, userCommon, collectionCommon, userRepo, revisionService, answerActivityService, answerCommon, voteRepo, emailService, userRoleRelService, notificationQueueService, externalNotificationQueueService, activityQueueService, reviewService)
questionService := content.NewQuestionService(questionRepo, answerRepo, tagCommonService, questionCommon, userCommon, userRepo, userRoleRelService, revisionService, metaCommonService, collectionCommon, answerActivityService, emailService, notificationQueueService, externalNotificationQueueService, activityQueueService, siteInfoCommonService, externalNotificationService, reviewService, configService, eventQueueService)
answerService := content.NewAnswerService(answerRepo, questionRepo, questionCommon, userCommon, collectionCommon, userRepo, revisionService, answerActivityService, answerCommon, voteRepo, emailService, userRoleRelService, notificationQueueService, externalNotificationQueueService, activityQueueService, reviewService, eventQueueService)
reportHandle := report_handle.NewReportHandle(questionService, answerService, commentService)
reportService := report2.NewReportService(reportRepo, objService, userCommon, answerRepo, questionRepo, commentCommonRepo, reportHandle, configService)
reportService := report2.NewReportService(reportRepo, objService, userCommon, answerRepo, questionRepo, commentCommonRepo, reportHandle, configService, eventQueueService)
reportController := controller.NewReportController(reportService, rankService, captchaService)
contentVoteRepo := activity.NewVoteRepo(dataData, activityRepo, userRankRepo, notificationQueueService)
voteService := content.NewVoteService(contentVoteRepo, configService, questionRepo, answerRepo, commentCommonRepo, objService)
voteService := content.NewVoteService(contentVoteRepo, configService, questionRepo, answerRepo, commentCommonRepo, objService, eventQueueService)
voteController := controller.NewVoteController(voteService, rankService, captchaService)
tagService := tag2.NewTagService(tagRepo, tagCommonService, revisionService, followRepo, siteInfoCommonService, activityQueueService)
tagController := controller.NewTagController(tagService, tagCommonService, rankService)
@@ -251,7 +253,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
permissionController := controller.NewPermissionController(rankService)
userPluginController := controller.NewUserPluginController(pluginCommonService)
reviewController := controller.NewReviewController(reviewService, rankService, captchaService)
metaService := meta2.NewMetaService(metaCommonService, userCommon, answerRepo, questionRepo)
metaService := meta2.NewMetaService(metaCommonService, userCommon, answerRepo, questionRepo, eventQueueService)
metaController := controller.NewMetaController(metaService)
answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, userAdminController, reasonController, themeController, siteInfoController, controllerSiteInfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController, permissionController, userPluginController, reviewController, metaController)
swaggerRouter := router.NewSwaggerRouter(swaggerConf)
@@ -260,7 +262,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
avatarMiddleware := middleware.NewAvatarMiddleware(serviceConf, uploaderService)
shortIDMiddleware := middleware.NewShortIDMiddleware(siteInfoCommonService)
templateRenderController := templaterender.NewTemplateRenderController(questionService, userService, tagService, answerService, commentService, siteInfoCommonService, questionRepo)
templateController := controller.NewTemplateController(templateRenderController, siteInfoCommonService)
templateController := controller.NewTemplateController(templateRenderController, siteInfoCommonService, eventQueueService, userService)
templateRouter := router.NewTemplateRouter(templateController, templateRenderController, siteInfoController, authUserMiddleware)
connectorController := controller.NewConnectorController(siteInfoCommonService, emailService, userExternalLoginService)
userCenterLoginService := user_external_login2.NewUserCenterLoginService(userRepo, userCommon, userExternalLoginRepo, userActiveActivityRepo, siteInfoCommonService)
+75
View File
@@ -0,0 +1,75 @@
/*
* 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 constant
// EventType event type. It is used to define the type of event. Such as object.action
type EventType string
// event object
const (
eventQuestion = "question"
eventAnswer = "answer"
eventComment = "comment"
eventUser = "user"
)
// event action
const (
eventCreate = "create"
eventUpdate = "update"
eventDelete = "delete"
eventVote = "vote"
eventAccept = "accept" // only question have the accept event
eventShare = "share" // the object share link has been clicked
eventFlag = "flag"
eventReact = "react"
)
const (
EventUserUpdate EventType = eventUser + "." + eventUpdate
EventUserShare EventType = eventUser + "." + eventShare
)
const (
EventQuestionCreate EventType = eventQuestion + "." + eventCreate
EventQuestionUpdate EventType = eventQuestion + "." + eventUpdate
EventQuestionDelete EventType = eventQuestion + "." + eventDelete
EventQuestionVote EventType = eventQuestion + "." + eventVote
EventQuestionAccept EventType = eventQuestion + "." + eventAccept
EventQuestionFlag EventType = eventQuestion + "." + eventFlag
EventQuestionReact EventType = eventQuestion + "." + eventReact
)
const (
EventAnswerCreate EventType = eventAnswer + "." + eventCreate
EventAnswerUpdate EventType = eventAnswer + "." + eventUpdate
EventAnswerDelete EventType = eventAnswer + "." + eventDelete
EventAnswerVote EventType = eventAnswer + "." + eventVote
EventAnswerFlag EventType = eventAnswer + "." + eventFlag
EventAnswerReact EventType = eventAnswer + "." + eventReact
)
const (
EventCommentCreate EventType = eventComment + "." + eventCreate
EventCommentUpdate EventType = eventComment + "." + eventUpdate
EventCommentDelete EventType = eventComment + "." + eventDelete
EventCommentVote EventType = eventComment + "." + eventVote
EventCommentFlag EventType = eventComment + "." + eventFlag
)
@@ -22,6 +22,8 @@ package controller
import (
"encoding/json"
"fmt"
"github.com/apache/incubator-answer/internal/service/content"
"github.com/apache/incubator-answer/internal/service/event_queue"
"github.com/apache/incubator-answer/plugin"
"html/template"
"net/http"
@@ -54,12 +56,16 @@ type TemplateController struct {
cssPath string
templateRenderController *templaterender.TemplateRenderController
siteInfoService siteinfo_common.SiteInfoCommonService
eventQueueService event_queue.EventQueueService
userService *content.UserService
}
// NewTemplateController new controller
func NewTemplateController(
templateRenderController *templaterender.TemplateRenderController,
siteInfoService siteinfo_common.SiteInfoCommonService,
eventQueueService event_queue.EventQueueService,
userService *content.UserService,
) *TemplateController {
script, css := GetStyle()
return &TemplateController{
@@ -67,6 +73,8 @@ func NewTemplateController(
cssPath: css,
templateRenderController: templateRenderController,
siteInfoService: siteInfoService,
eventQueueService: eventQueueService,
userService: userService,
}
}
func GetStyle() (script []string, css string) {
@@ -271,6 +279,7 @@ func (tc *TemplateController) QuestionInfo(ctx *gin.Context) {
id := ctx.Param("id")
title := ctx.Param("title")
answerid := ctx.Param("answerid")
shareUsername := ctx.Query("share")
if checker.IsQuestionsIgnorePath(id) {
// if id == "ask" {
file, err := ui.Build.ReadFile("build/index.html")
@@ -291,6 +300,13 @@ func (tc *TemplateController) QuestionInfo(ctx *gin.Context) {
tc.Page404(ctx)
return
}
if len(shareUsername) > 0 {
userInfo, err := tc.userService.GetOtherUserInfoByUsername(
ctx, &schema.GetOtherUserInfoByUsernameReq{Username: shareUsername})
if err == nil {
tc.eventQueueService.Send(ctx, schema.NewEvent(constant.EventUserShare, userInfo.ID))
}
}
encodeTitle := htmltext.UrlTitle(detail.Title)
if encodeTitle == title {
correctTitle = true
@@ -0,0 +1,57 @@
/*
* 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 badge
import (
"context"
"github.com/apache/incubator-answer/internal/service/event_queue"
"github.com/segmentfault/pacman/log"
"github.com/apache/incubator-answer/internal/base/data"
"github.com/apache/incubator-answer/internal/schema"
)
type BadgeEventService struct {
data *data.Data
eventQueueService event_queue.EventQueueService
}
func NewBadgeEventService(
data *data.Data,
eventQueueService event_queue.EventQueueService,
) *BadgeEventService {
n := &BadgeEventService{
data: data,
eventQueueService: eventQueueService,
}
eventQueueService.RegisterHandler(n.Handler)
return n
}
func (ns *BadgeEventService) Handler(ctx context.Context, msg *schema.EventMsg) error {
log.Debugf("received badge event %+v", msg)
// TODO: Check if badge already exists
// TODO: Check rule
// TODO: Distribute badge
return nil
}
+95
View File
@@ -0,0 +1,95 @@
/*
* 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 badge
import (
"context"
"github.com/apache/incubator-answer/internal/base/data"
"github.com/apache/incubator-answer/internal/base/reason"
"github.com/apache/incubator-answer/internal/entity"
"github.com/apache/incubator-answer/internal/service/unique"
"github.com/segmentfault/pacman/errors"
)
// BadgeRuleRepo collection repository
type BadgeRuleRepo struct {
data *data.Data
uniqueIDRepo unique.UniqueIDRepo
}
// FilledPersonalProfile filled personal profile
func (br *BadgeRuleRepo) FilledPersonalProfile(ctx context.Context, userID string) (reach bool, err error) {
bean := &entity.User{ID: userID}
exist, err := br.data.DB.Context(ctx).Get(bean)
if err != nil {
return false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
if !exist {
return false, nil
}
if len(bean.Bio) > 0 {
return true, nil
}
return false, nil
}
// FirstPostEdit first post edit
func (br *BadgeRuleRepo) FirstPostEdit(ctx context.Context, userID string, objectID string) {
}
// FirstFlaggedPost first flagged post.
func (br *BadgeRuleRepo) FirstFlaggedPost(ctx context.Context, userID string, reportID string) {
}
// FirstVotedPost first voted post
func (br *BadgeRuleRepo) FirstVotedPost(ctx context.Context) {
}
// FirstReactedPost first reacted post
func (br *BadgeRuleRepo) FirstReactedPost(ctx context.Context) {
}
// FirstSharedPost first shared post
func (br *BadgeRuleRepo) FirstSharedPost(ctx context.Context) {
}
// AskQuestionAcceptAnswer ask question accept answer
func (br *BadgeRuleRepo) AskQuestionAcceptAnswer(ctx context.Context) {
}
// AnswerAccepted answer accepted
func (br *BadgeRuleRepo) AnswerAccepted(ctx context.Context) {
}
// ReachAnswerScore reach answer score
func (br *BadgeRuleRepo) ReachAnswerScore(ctx context.Context) {
}
// ReachQuestionScore reach question score
func (br *BadgeRuleRepo) ReachQuestionScore(ctx context.Context) {
}
+47
View File
@@ -0,0 +1,47 @@
/*
* 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 badge
import "github.com/apache/incubator-answer/internal/base/constant"
var (
EventRuleMapping = map[constant.EventType][]string{
constant.EventUserUpdate: {FilledPersonalProfile},
constant.EventUserShare: {FirstSharedPost},
constant.EventQuestionCreate: {""},
constant.EventQuestionUpdate: {FirstPostEdit},
constant.EventQuestionDelete: {""},
constant.EventQuestionVote: {FirstVotedPost, ReachQuestionScore},
constant.EventQuestionAccept: {AskQuestionAcceptAnswer, AnswerAccepted},
constant.EventQuestionFlag: {FirstFlaggedPost},
constant.EventQuestionReact: {FirstReactedPost},
constant.EventAnswerCreate: {""},
constant.EventAnswerUpdate: {FirstPostEdit},
constant.EventAnswerDelete: {""},
constant.EventAnswerVote: {FirstVotedPost, ReachAnswerScore},
constant.EventAnswerFlag: {FirstFlaggedPost},
constant.EventAnswerReact: {FirstReactedPost},
constant.EventCommentCreate: {""},
constant.EventCommentUpdate: {""},
constant.EventCommentDelete: {""},
constant.EventCommentVote: {FirstVotedPost},
constant.EventCommentFlag: {FirstFlaggedPost},
}
)
+43
View File
@@ -0,0 +1,43 @@
/*
* 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 badge
const (
// FilledPersonalProfile filled personal profile
FilledPersonalProfile = "filled_personal_profile"
// FirstPostEdit first post edit
FirstPostEdit = "first_post_edit"
// FirstFlaggedPost first flagged post.
FirstFlaggedPost = "first_flagged_post"
// FirstVotedPost first voted post
FirstVotedPost = "first_voted_post"
// FirstReactedPost first reacted post
FirstReactedPost = "first_reacted_post"
// FirstSharedPost first shared post
FirstSharedPost = "first_shared_post"
// AskQuestionAcceptAnswer ask question accept answer
AskQuestionAcceptAnswer = "ask_question_accept_answer"
// AnswerAccepted answer accepted
AnswerAccepted = "answer_accepted"
// ReachAnswerScore reach answer score
ReachAnswerScore = "reach_answer_score"
// ReachQuestionScore reach question score
ReachQuestionScore = "reach_question_score"
)
+70
View File
@@ -0,0 +1,70 @@
/*
* 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 schema
import "github.com/apache/incubator-answer/internal/base/constant"
// EventMsg event message
type EventMsg struct {
EventType constant.EventType
UserID string
QuestionID string
QuestionUserID string
AnswerID string
AnswerUserID string
CommentID string
CommentUserID string
ExtraInfo map[string]string
}
func NewEvent(e constant.EventType, userID string) *EventMsg {
return &EventMsg{
UserID: userID,
EventType: e,
ExtraInfo: make(map[string]string),
}
}
func (e *EventMsg) QID(questionID, userID string) *EventMsg {
e.QuestionID = questionID
e.QuestionUserID = userID
return e
}
func (e *EventMsg) AID(answerID, userID string) *EventMsg {
e.AnswerID = answerID
e.AnswerUserID = userID
return e
}
func (e *EventMsg) CID(comment, userID string) *EventMsg {
e.CommentID = comment
e.CommentUserID = userID
return e
}
func (e *EventMsg) AddExtra(key, value string) *EventMsg {
e.ExtraInfo[key] = value
return e
}
+18 -1
View File
@@ -21,6 +21,7 @@ package comment
import (
"context"
"github.com/apache/incubator-answer/internal/service/event_queue"
"time"
"github.com/apache/incubator-answer/internal/base/constant"
@@ -86,6 +87,7 @@ type CommentService struct {
notificationQueueService notice_queue.NotificationQueueService
externalNotificationQueueService notice_queue.ExternalNotificationQueueService
activityQueueService activity_queue.ActivityQueueService
eventQueueService event_queue.EventQueueService
}
// NewCommentService new comment service
@@ -100,6 +102,7 @@ func NewCommentService(
notificationQueueService notice_queue.NotificationQueueService,
externalNotificationQueueService notice_queue.ExternalNotificationQueueService,
activityQueueService activity_queue.ActivityQueueService,
eventQueueService event_queue.EventQueueService,
) *CommentService {
return &CommentService{
commentRepo: commentRepo,
@@ -112,6 +115,7 @@ func NewCommentService(
notificationQueueService: notificationQueueService,
externalNotificationQueueService: externalNotificationQueueService,
activityQueueService: activityQueueService,
eventQueueService: eventQueueService,
}
}
@@ -184,13 +188,19 @@ func (cs *CommentService) AddComment(ctx context.Context, req *schema.AddComment
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).
CID(comment.ID, comment.UserID).QID(objInfo.QuestionID, objInfo.ObjectCreatorUserID)
case constant.AnswerObjectType:
activityMsg.ActivityTypeKey = constant.ActAnswerCommented
event = schema.NewEvent(constant.EventCommentCreate, req.UserID).
CID(comment.ID, comment.UserID).AID(objInfo.AnswerID, objInfo.ObjectCreatorUserID)
}
cs.activityQueueService.Send(ctx, activityMsg)
cs.eventQueueService.Send(ctx, event)
return resp, nil
}
@@ -241,7 +251,12 @@ func (cs *CommentService) addCommentNotification(
// RemoveComment delete comment
func (cs *CommentService) RemoveComment(ctx context.Context, req *schema.RemoveCommentReq) (err error) {
return cs.commentRepo.RemoveComment(ctx, req.CommentID)
err = cs.commentRepo.RemoveComment(ctx, req.CommentID)
if err != nil {
return err
}
cs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventCommentDelete, req.UserID).CID(req.CommentID, req.UserID))
return nil
}
// UpdateComment update comment
@@ -273,6 +288,8 @@ func (cs *CommentService) UpdateComment(ctx context.Context, req *schema.UpdateC
OriginalText: req.OriginalText,
ParsedText: req.ParsedText,
}
cs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventCommentUpdate, req.UserID).
CID(old.ID, old.UserID))
return resp, nil
}
@@ -22,6 +22,7 @@ package content
import (
"context"
"encoding/json"
"github.com/apache/incubator-answer/internal/service/event_queue"
"time"
"github.com/apache/incubator-answer/internal/base/constant"
@@ -67,6 +68,7 @@ type AnswerService struct {
externalNotificationQueueService notice_queue.ExternalNotificationQueueService
activityQueueService activity_queue.ActivityQueueService
reviewService *review.ReviewService
eventQueueService event_queue.EventQueueService
}
func NewAnswerService(
@@ -86,6 +88,7 @@ func NewAnswerService(
externalNotificationQueueService notice_queue.ExternalNotificationQueueService,
activityQueueService activity_queue.ActivityQueueService,
reviewService *review.ReviewService,
eventQueueService event_queue.EventQueueService,
) *AnswerService {
return &AnswerService{
answerRepo: answerRepo,
@@ -104,6 +107,7 @@ func NewAnswerService(
externalNotificationQueueService: externalNotificationQueueService,
activityQueueService: activityQueueService,
reviewService: reviewService,
eventQueueService: eventQueueService,
}
}
@@ -175,6 +179,8 @@ func (as *AnswerService) RemoveAnswer(ctx context.Context, req *schema.RemoveAns
OriginalObjectID: answerInfo.ID,
ActivityTypeKey: constant.ActAnswerDeleted,
})
as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventAnswerDelete, req.UserID).
AID(answerInfo.ID, answerInfo.UserID))
return
}
@@ -295,6 +301,8 @@ func (as *AnswerService) Insert(ctx context.Context, req *schema.AnswerAddReq) (
OriginalObjectID: questionInfo.ID,
ActivityTypeKey: constant.ActQuestionAnswered,
})
as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventAnswerCreate, req.UserID).
AID(insertData.ID, insertData.UserID))
return insertData.ID, nil
}
@@ -383,6 +391,8 @@ func (as *AnswerService) Update(ctx context.Context, req *schema.AnswerUpdateReq
ActivityTypeKey: constant.ActAnswerEdited,
RevisionID: revisionID,
})
as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventAnswerUpdate, req.UserID).
AID(insertData.ID, insertData.UserID))
}
return insertData.ID, nil
@@ -436,6 +446,9 @@ func (as *AnswerService) AcceptAnswer(ctx context.Context, req *schema.AcceptAns
oldAnswerInfo.ID = uid.DeShortID(oldAnswerInfo.ID)
}
as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionAccept, req.UserID).
QID(questionInfo.ID, questionInfo.UserID).AID(req.AnswerID, req.UserID))
as.updateAnswerRank(ctx, req.UserID, questionInfo, acceptedAnswerInfo, oldAnswerInfo)
return nil
}
@@ -23,6 +23,7 @@ import (
"encoding/json"
"fmt"
answercommon "github.com/apache/incubator-answer/internal/service/answer_common"
"github.com/apache/incubator-answer/internal/service/event_queue"
"strings"
"time"
@@ -84,6 +85,7 @@ type QuestionService struct {
newQuestionNotificationService *notification.ExternalNotificationService
reviewService *review.ReviewService
configService *config.ConfigService
eventQueueService event_queue.EventQueueService
}
func NewQuestionService(
@@ -106,6 +108,7 @@ func NewQuestionService(
newQuestionNotificationService *notification.ExternalNotificationService,
reviewService *review.ReviewService,
configService *config.ConfigService,
eventQueueService event_queue.EventQueueService,
) *QuestionService {
return &QuestionService{
questionRepo: questionRepo,
@@ -127,6 +130,7 @@ func NewQuestionService(
newQuestionNotificationService: newQuestionNotificationService,
reviewService: reviewService,
configService: configService,
eventQueueService: eventQueueService,
}
}
@@ -385,6 +389,8 @@ func (qs *QuestionService) AddQuestion(ctx context.Context, req *schema.Question
qs.externalNotificationQueueService.Send(ctx,
schema.CreateNewQuestionNotificationMsg(question.ID, question.Title, question.UserID, tags))
}
qs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionCreate, req.UserID).
QID(question.ID, question.UserID))
questionInfo, err = qs.GetQuestion(ctx, question.ID, question.UserID, req.QuestionPermission)
return
@@ -546,6 +552,8 @@ func (qs *QuestionService) RemoveQuestion(ctx context.Context, req *schema.Remov
OriginalObjectID: questionInfo.ID,
ActivityTypeKey: constant.ActQuestionDeleted,
})
qs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionDelete, req.UserID).
QID(questionInfo.ID, questionInfo.UserID))
return nil
}
@@ -937,6 +945,8 @@ func (qs *QuestionService) UpdateQuestion(ctx context.Context, req *schema.Quest
RevisionID: revisionID,
OriginalObjectID: question.ID,
})
qs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionUpdate, req.UserID).
QID(question.ID, question.UserID))
}
questionInfo, err = qs.GetQuestion(ctx, question.ID, question.UserID, req.QuestionPermission)
+8
View File
@@ -23,6 +23,7 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/apache/incubator-answer/internal/service/event_queue"
"time"
"github.com/apache/incubator-answer/internal/base/constant"
@@ -65,6 +66,7 @@ type UserService struct {
userNotificationConfigRepo user_notification_config.UserNotificationConfigRepo
userNotificationConfigService *user_notification_config.UserNotificationConfigService
questionService *questioncommon.QuestionCommon
eventQueueService event_queue.EventQueueService
}
func NewUserService(userRepo usercommon.UserRepo,
@@ -79,6 +81,7 @@ func NewUserService(userRepo usercommon.UserRepo,
userNotificationConfigRepo user_notification_config.UserNotificationConfigRepo,
userNotificationConfigService *user_notification_config.UserNotificationConfigService,
questionService *questioncommon.QuestionCommon,
eventQueueService event_queue.EventQueueService,
) *UserService {
return &UserService{
userCommonService: userCommonService,
@@ -93,6 +96,7 @@ func NewUserService(userRepo usercommon.UserRepo,
userNotificationConfigRepo: userNotificationConfigRepo,
userNotificationConfigService: userNotificationConfigService,
questionService: questionService,
eventQueueService: eventQueueService,
}
}
@@ -352,6 +356,10 @@ func (us *UserService) UpdateInfo(ctx context.Context, req *schema.UpdateInfoReq
cond := us.formatUserInfoForUpdateInfo(oldUserInfo, req, siteUsers)
err = us.userRepo.UpdateInfo(ctx, cond)
if err != nil {
return nil, err
}
us.eventQueueService.Send(ctx, schema.NewEvent(constant.EventUserUpdate, req.UserID))
return nil, err
}
+31
View File
@@ -21,6 +21,8 @@ package content
import (
"context"
"fmt"
"github.com/apache/incubator-answer/internal/service/event_queue"
"strings"
"github.com/apache/incubator-answer/internal/service/activity_common"
@@ -62,6 +64,7 @@ type VoteService struct {
commentCommonRepo comment_common.CommentCommonRepo
objectService *object_info.ObjService
activityRepo activity_common.ActivityRepo
eventQueueService event_queue.EventQueueService
}
func NewVoteService(
@@ -71,6 +74,7 @@ func NewVoteService(
answerRepo answercommon.AnswerRepo,
commentCommonRepo comment_common.CommentCommonRepo,
objectService *object_info.ObjService,
eventQueueService event_queue.EventQueueService,
) *VoteService {
return &VoteService{
voteRepo: voteRepo,
@@ -79,6 +83,7 @@ func NewVoteService(
answerRepo: answerRepo,
commentCommonRepo: commentCommonRepo,
objectService: objectService,
eventQueueService: eventQueueService,
}
}
@@ -112,6 +117,9 @@ func (vs *VoteService) VoteUp(ctx context.Context, req *schema.VoteReq) (resp *s
return nil, err
}
err = vs.voteRepo.Vote(ctx, voteUpOperationInfo)
if err != nil {
return nil, err
}
}
if err != nil {
return nil, err
@@ -125,6 +133,7 @@ func (vs *VoteService) VoteUp(ctx context.Context, req *schema.VoteReq) (resp *s
resp.Votes = resp.UpVotes - resp.DownVotes
if !req.IsCancel {
resp.VoteStatus = constant.ActVoteUp
vs.sendEvent(ctx, req, objectInfo, resp)
}
return resp, nil
}
@@ -173,6 +182,7 @@ func (vs *VoteService) VoteDown(ctx context.Context, req *schema.VoteReq) (resp
resp.Votes = resp.UpVotes - resp.DownVotes
if !req.IsCancel {
resp.VoteStatus = constant.ActVoteDown
vs.sendEvent(ctx, req, objectInfo, resp)
}
return resp, nil
}
@@ -289,3 +299,24 @@ func (vs *VoteService) getActivities(ctx context.Context, op *schema.VoteOperati
}
return activities
}
func (vs *VoteService) sendEvent(ctx context.Context,
req *schema.VoteReq, objectInfo *schema.SimpleObjectInfo, resp *schema.VoteResp) {
var event *schema.EventMsg
switch objectInfo.ObjectType {
case constant.QuestionObjectType:
event = schema.NewEvent(constant.EventQuestionVote, req.UserID).
QID(objectInfo.QuestionID, objectInfo.ObjectCreatorUserID)
case constant.AnswerObjectType:
event = schema.NewEvent(constant.EventAnswerVote, req.UserID).
AID(objectInfo.AnswerID, objectInfo.ObjectCreatorUserID)
case constant.CommentObjectType:
event = schema.NewEvent(constant.EventCommentVote, req.UserID).
CID(objectInfo.CommentID, objectInfo.ObjectCreatorUserID)
default:
return
}
event.AddExtra("vote_up_amount", fmt.Sprintf("%d", resp.UpVotes))
event.AddExtra("vote_down_amount", fmt.Sprintf("%d", resp.DownVotes))
vs.eventQueueService.Send(ctx, event)
}
@@ -0,0 +1,69 @@
/*
* 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 event_queue
import (
"context"
"github.com/apache/incubator-answer/internal/schema"
"github.com/segmentfault/pacman/log"
)
type EventQueueService interface {
Send(ctx context.Context, msg *schema.EventMsg)
RegisterHandler(handler func(ctx context.Context, msg *schema.EventMsg) error)
}
type eventQueueService struct {
Queue chan *schema.EventMsg
Handler func(ctx context.Context, msg *schema.EventMsg) error
}
func (ns *eventQueueService) Send(ctx context.Context, msg *schema.EventMsg) {
ns.Queue <- msg
}
func (ns *eventQueueService) RegisterHandler(
handler func(ctx context.Context, msg *schema.EventMsg) error) {
ns.Handler = handler
}
func (ns *eventQueueService) working() {
go func() {
for msg := range ns.Queue {
log.Debugf("received badge %+v", msg)
if ns.Handler == nil {
log.Warnf("no handler for badge")
continue
}
if err := ns.Handler(context.Background(), msg); err != nil {
log.Error(err)
}
}
}()
}
// NewEventQueueService create a new badge queue service
func NewEventQueueService() EventQueueService {
ns := &eventQueueService{}
ns.Queue = make(chan *schema.EventMsg, 128)
ns.working()
return ns
}
+18 -4
View File
@@ -23,6 +23,7 @@ import (
"context"
"encoding/json"
"errors"
"github.com/apache/incubator-answer/internal/service/event_queue"
"strconv"
"strings"
@@ -46,14 +47,22 @@ type MetaService struct {
userCommon *usercommon.UserCommon
questionRepo questioncommon.QuestionRepo
answerRepo answercommon.AnswerRepo
eventQueueService event_queue.EventQueueService
}
func NewMetaService(metaCommonService *metacommon.MetaCommonService, userCommon *usercommon.UserCommon, answerRepo answercommon.AnswerRepo, questionRepo questioncommon.QuestionRepo) *MetaService {
func NewMetaService(
metaCommonService *metacommon.MetaCommonService,
userCommon *usercommon.UserCommon,
answerRepo answercommon.AnswerRepo,
questionRepo questioncommon.QuestionRepo,
eventQueueService event_queue.EventQueueService,
) *MetaService {
return &MetaService{
metaCommonService: metaCommonService,
questionRepo: questionRepo,
userCommon: userCommon,
answerRepo: answerRepo,
eventQueueService: eventQueueService,
}
}
@@ -86,22 +95,27 @@ func (ms *MetaService) AddOrUpdateReaction(ctx context.Context, req *schema.Upda
if err != nil {
return nil, err
}
var event *schema.EventMsg
if objectType == constant.AnswerObjectType {
_, exist, err := ms.answerRepo.GetAnswer(ctx, req.ObjectID)
answerInfo, exist, err := ms.answerRepo.GetAnswer(ctx, req.ObjectID)
if err != nil {
return nil, err
}
if !exist {
return nil, myErrors.BadRequest(reason.AnswerNotFound)
}
event = schema.NewEvent(constant.EventAnswerReact, req.UserID).
AID(answerInfo.ID, answerInfo.UserID)
} else if objectType == constant.QuestionObjectType {
_, exist, err := ms.questionRepo.GetQuestion(ctx, req.ObjectID)
questionInfo, exist, err := ms.questionRepo.GetQuestion(ctx, req.ObjectID)
if err != nil {
return nil, err
}
if !exist {
return nil, myErrors.BadRequest(reason.QuestionNotFound)
}
event = schema.NewEvent(constant.EventQuestionReact, req.UserID).
QID(questionInfo.ID, questionInfo.UserID)
} else {
return nil, myErrors.BadRequest(reason.ObjectNotFound)
}
@@ -138,7 +152,7 @@ func (ms *MetaService) AddOrUpdateReaction(ctx context.Context, req *schema.Upda
if err != nil {
return nil, err
}
ms.eventQueueService.Send(ctx, event)
return resp, nil
}
+2
View File
@@ -33,6 +33,7 @@ import (
"github.com/apache/incubator-answer/internal/service/config"
"github.com/apache/incubator-answer/internal/service/content"
"github.com/apache/incubator-answer/internal/service/dashboard"
"github.com/apache/incubator-answer/internal/service/event_queue"
"github.com/apache/incubator-answer/internal/service/export"
"github.com/apache/incubator-answer/internal/service/follow"
"github.com/apache/incubator-answer/internal/service/meta"
@@ -117,4 +118,5 @@ var ProviderSetService = wire.NewSet(
notice_queue.NewNewQuestionNotificationQueueService,
review.NewReviewService,
meta.NewMetaService,
event_queue.NewEventQueueService,
)
+29 -1
View File
@@ -21,6 +21,7 @@ package report
import (
"encoding/json"
"github.com/apache/incubator-answer/internal/service/event_queue"
"github.com/apache/incubator-answer/internal/base/constant"
"github.com/apache/incubator-answer/internal/base/handler"
@@ -55,6 +56,7 @@ type ReportService struct {
commentCommonRepo comment_common.CommentCommonRepo
reportHandle *report_handle.ReportHandle
configService *config.ConfigService
eventQueueService event_queue.EventQueueService
}
// NewReportService new report service
@@ -67,6 +69,7 @@ func NewReportService(
commentCommonRepo comment_common.CommentCommonRepo,
reportHandle *report_handle.ReportHandle,
configService *config.ConfigService,
eventQueueService event_queue.EventQueueService,
) *ReportService {
return &ReportService{
reportRepo: reportRepo,
@@ -77,6 +80,7 @@ func NewReportService(
commentCommonRepo: commentCommonRepo,
reportHandle: reportHandle,
configService: configService,
eventQueueService: eventQueueService,
}
}
@@ -112,7 +116,12 @@ func (rs *ReportService) AddReport(ctx context.Context, req *schema.AddReportReq
Content: req.Content,
Status: entity.ReportStatusPending,
}
return rs.reportRepo.AddReport(ctx, report)
err = rs.reportRepo.AddReport(ctx, report)
if err != nil {
return err
}
rs.sendEvent(ctx, report, objInfo)
return nil
}
// GetUnreviewedReportPostPage get unreviewed report post page
@@ -218,3 +227,22 @@ func (rs *ReportService) ReviewReport(ctx context.Context, req *schema.ReviewRep
return rs.reportRepo.UpdateStatus(ctx, report.ID, entity.ReportStatusCompleted)
}
func (rs *ReportService) sendEvent(ctx context.Context,
report *entity.Report, objectInfo *schema.SimpleObjectInfo) {
var event *schema.EventMsg
switch objectInfo.ObjectType {
case constant.QuestionObjectType:
event = schema.NewEvent(constant.EventQuestionFlag, report.UserID).
QID(objectInfo.QuestionID, objectInfo.ObjectCreatorUserID)
case constant.AnswerObjectType:
event = schema.NewEvent(constant.EventAnswerFlag, report.UserID).
AID(objectInfo.AnswerID, objectInfo.ObjectCreatorUserID)
case constant.CommentObjectType:
event = schema.NewEvent(constant.EventCommentFlag, report.UserID).
CID(objectInfo.CommentID, objectInfo.ObjectCreatorUserID)
default:
return
}
rs.eventQueueService.Send(ctx, event)
}