This is an automated email from the ASF dual-hosted git repository.

linkinstar pushed a commit to branch feat/1.4.0/badges
in repository https://gitbox.apache.org/repos/asf/incubator-answer.git

commit 07e4f549b13216f76a69a897fb73d2a8fcd55de4
Author: LinkinStars <[email protected]>
AuthorDate: Thu Aug 8 16:19:47 2024 +0800

    feat(badge): add event for the badge
---
 cmd/wire_gen.go                              | 18 +++---
 internal/base/constant/event.go              | 75 ++++++++++++++++++++++
 internal/controller/template_controller.go   | 16 +++++
 internal/repo/badge/badge_event_handler.go   | 57 +++++++++++++++++
 internal/repo/badge/badge_rule.go            | 95 ++++++++++++++++++++++++++++
 internal/repo/badge/event_rule_mapping.go    | 47 ++++++++++++++
 internal/repo/badge/rule.go                  | 43 +++++++++++++
 internal/schema/event_schema.go              | 70 ++++++++++++++++++++
 internal/service/comment/comment_service.go  | 19 +++++-
 internal/service/content/answer_service.go   | 13 ++++
 internal/service/content/question_service.go | 10 +++
 internal/service/content/user_service.go     |  8 +++
 internal/service/content/vote_service.go     | 31 +++++++++
 internal/service/event_queue/event_queue.go  | 69 ++++++++++++++++++++
 internal/service/meta/meta_service.go        | 22 +++++--
 internal/service/provider.go                 |  2 +
 internal/service/report/report_service.go    | 30 ++++++++-
 17 files changed, 611 insertions(+), 14 deletions(-)

diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go
index 4928a122..c6cdc021 100644
--- a/cmd/wire_gen.go
+++ b/cmd/wire_gen.go
@@ -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, pluginCon [...]
        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)
diff --git a/internal/base/constant/event.go b/internal/base/constant/event.go
new file mode 100644
index 00000000..f7fd8412
--- /dev/null
+++ b/internal/base/constant/event.go
@@ -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
+)
diff --git a/internal/controller/template_controller.go 
b/internal/controller/template_controller.go
index 09f5bffc..a786f646 100644
--- a/internal/controller/template_controller.go
+++ b/internal/controller/template_controller.go
@@ -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
diff --git a/internal/repo/badge/badge_event_handler.go 
b/internal/repo/badge/badge_event_handler.go
new file mode 100644
index 00000000..242778ec
--- /dev/null
+++ b/internal/repo/badge/badge_event_handler.go
@@ -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
+}
diff --git a/internal/repo/badge/badge_rule.go 
b/internal/repo/badge/badge_rule.go
new file mode 100644
index 00000000..3ae0b7b4
--- /dev/null
+++ b/internal/repo/badge/badge_rule.go
@@ -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) {
+
+}
diff --git a/internal/repo/badge/event_rule_mapping.go 
b/internal/repo/badge/event_rule_mapping.go
new file mode 100644
index 00000000..8f01fdef
--- /dev/null
+++ b/internal/repo/badge/event_rule_mapping.go
@@ -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},
+       }
+)
diff --git a/internal/repo/badge/rule.go b/internal/repo/badge/rule.go
new file mode 100644
index 00000000..635b30da
--- /dev/null
+++ b/internal/repo/badge/rule.go
@@ -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"
+)
diff --git a/internal/schema/event_schema.go b/internal/schema/event_schema.go
new file mode 100644
index 00000000..01f80fbb
--- /dev/null
+++ b/internal/schema/event_schema.go
@@ -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
+}
diff --git a/internal/service/comment/comment_service.go 
b/internal/service/comment/comment_service.go
index 9f2c45f1..75d30f9d 100644
--- a/internal/service/comment/comment_service.go
+++ b/internal/service/comment/comment_service.go
@@ -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
 }
 
diff --git a/internal/service/content/answer_service.go 
b/internal/service/content/answer_service.go
index f8feda8a..5674a79b 100644
--- a/internal/service/content/answer_service.go
+++ b/internal/service/content/answer_service.go
@@ -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
 }
diff --git a/internal/service/content/question_service.go 
b/internal/service/content/question_service.go
index 6d8b37ba..dfb778ea 100644
--- a/internal/service/content/question_service.go
+++ b/internal/service/content/question_service.go
@@ -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)
diff --git a/internal/service/content/user_service.go 
b/internal/service/content/user_service.go
index 11f3bb63..2a6122ae 100644
--- a/internal/service/content/user_service.go
+++ b/internal/service/content/user_service.go
@@ -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
 }
 
diff --git a/internal/service/content/vote_service.go 
b/internal/service/content/vote_service.go
index bfb403c9..c83011a9 100644
--- a/internal/service/content/vote_service.go
+++ b/internal/service/content/vote_service.go
@@ -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)
+}
diff --git a/internal/service/event_queue/event_queue.go 
b/internal/service/event_queue/event_queue.go
new file mode 100644
index 00000000..b89a3ccc
--- /dev/null
+++ b/internal/service/event_queue/event_queue.go
@@ -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
+}
diff --git a/internal/service/meta/meta_service.go 
b/internal/service/meta/meta_service.go
index 1026b173..778c6ca6 100644
--- a/internal/service/meta/meta_service.go
+++ b/internal/service/meta/meta_service.go
@@ -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
 }
 
diff --git a/internal/service/provider.go b/internal/service/provider.go
index e82d9316..a22a6ea9 100644
--- a/internal/service/provider.go
+++ b/internal/service/provider.go
@@ -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,
 )
diff --git a/internal/service/report/report_service.go 
b/internal/service/report/report_service.go
index 7f060a39..218423e1 100644
--- a/internal/service/report/report_service.go
+++ b/internal/service/report/report_service.go
@@ -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)
+}


Reply via email to