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

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

commit 9b0de85ed4f5d9b77506b4698cc87850baf89691
Author: LinkinStars <[email protected]>
AuthorDate: Thu Aug 8 18:09:27 2024 +0800

    feat(badge): add badge event handler
---
 cmd/wire_gen.go                                    |   4 +-
 internal/repo/badge/badge_event_rule.go            | 216 +++++++++++++++++++++
 internal/repo/badge/badge_repo.go                  |  31 ++-
 internal/repo/badge/badge_rule.go                  |  95 ---------
 internal/repo/badge/event_rule_mapping.go          |  47 -----
 internal/repo/badge/rule.go                        |  43 ----
 internal/repo/provider.go                          |   1 +
 internal/schema/event_schema.go                    |  10 +
 .../{repo => service}/badge/badge_event_handler.go |  34 +++-
 internal/service/badge/badge_service.go            |  19 +-
 internal/service/provider.go                       |   1 +
 11 files changed, 304 insertions(+), 197 deletions(-)

diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go
index 24cdb163..f49ef20e 100644
--- a/cmd/wire_gen.go
+++ b/cmd/wire_gen.go
@@ -263,7 +263,9 @@ func initApplication(debug bool, serverConf *conf.Server, 
dbConf *data.Database,
        badgeRepo := badge.NewBadgeRepo(dataData, uniqueIDRepo)
        badgeGroupRepo := badge_group.NewBadgeGroupRepo(dataData, uniqueIDRepo)
        badgeAwardRepo := badge_award.NewBadgeAwardRepo(dataData, uniqueIDRepo)
-       badgeService := badge2.NewBadgeService(badgeRepo, badgeGroupRepo, 
badgeAwardRepo)
+       eventRuleRepo := badge.NewEventRuleRepo(dataData)
+       badgeEventService := badge2.NewBadgeEventService(dataData, 
eventQueueService, badgeRepo, eventRuleRepo)
+       badgeService := badge2.NewBadgeService(badgeRepo, badgeGroupRepo, 
badgeAwardRepo, badgeEventService)
        badgeAwardService := badge_award2.NewBadgeAwardService(badgeAwardRepo, 
userCommon, objService, questionRepo, answerRepo)
        badgeController := controller.NewBadgeController(badgeService, 
badgeAwardService)
        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 [...]
diff --git a/internal/repo/badge/badge_event_rule.go 
b/internal/repo/badge/badge_event_rule.go
new file mode 100644
index 00000000..8f940720
--- /dev/null
+++ b/internal/repo/badge/badge_event_rule.go
@@ -0,0 +1,216 @@
+/*
+ * 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/constant"
+       "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/schema"
+       "github.com/apache/incubator-answer/internal/service/badge"
+       "github.com/segmentfault/pacman/errors"
+       "github.com/segmentfault/pacman/log"
+)
+
+// eventRuleRepo event rule repo
+type eventRuleRepo struct {
+       data             *data.Data
+       EventRuleMapping map[constant.EventType][]badge.EventRuleHandler
+}
+
+// NewEventRuleRepo creates a new badge repository
+func NewEventRuleRepo(data *data.Data) badge.EventRuleRepo {
+       b := &eventRuleRepo{
+               data: data,
+       }
+       b.EventRuleMapping = map[constant.EventType][]badge.EventRuleHandler{
+               constant.EventUserUpdate:     {b.FirstUpdateUserProfile},
+               constant.EventUserShare:      {b.FirstSharedPost},
+               constant.EventQuestionCreate: nil,
+               constant.EventQuestionUpdate: {b.FirstPostEdit},
+               constant.EventQuestionDelete: nil,
+               constant.EventQuestionVote:   {b.FirstVotedPost, 
b.ReachQuestionVote},
+               constant.EventQuestionAccept: {b.FirstAcceptAnswer, 
b.ReachAnswerAcceptedAmount},
+               constant.EventQuestionFlag:   {b.FirstFlaggedPost},
+               constant.EventQuestionReact:  {b.FirstReactedPost},
+               constant.EventAnswerCreate:   nil,
+               constant.EventAnswerUpdate:   {b.FirstPostEdit},
+               constant.EventAnswerDelete:   nil,
+               constant.EventAnswerVote:     {b.FirstVotedPost, 
b.ReachAnswerVote},
+               constant.EventAnswerFlag:     {b.FirstFlaggedPost},
+               constant.EventAnswerReact:    {b.FirstReactedPost},
+               constant.EventCommentCreate:  nil,
+               constant.EventCommentUpdate:  nil,
+               constant.EventCommentDelete:  nil,
+               constant.EventCommentVote:    {b.FirstVotedPost},
+               constant.EventCommentFlag:    {b.FirstFlaggedPost},
+       }
+       return b
+}
+
+// HandleEventWithRule handle event with rule
+func (br *eventRuleRepo) HandleEventWithRule(ctx context.Context, msg 
*schema.EventMsg) (
+       awards []*entity.BadgeAward) {
+       handlers := br.EventRuleMapping[msg.EventType]
+       for _, h := range handlers {
+               t, err := h(ctx, msg)
+               if err != nil {
+                       log.Errorf("error handling badge event %+v: %v", msg, 
err)
+               } else {
+                       awards = append(awards, t...)
+               }
+       }
+       return awards
+}
+
+// FirstUpdateUserProfile first update user profile
+func (br *eventRuleRepo) FirstUpdateUserProfile(ctx context.Context,
+       event *schema.EventMsg) (awards []*entity.BadgeAward, err error) {
+       b := br.getBadgeByHandler(ctx, "FirstUpdateUserProfile")
+       if b == nil {
+               return nil, nil
+       }
+       bean := &entity.User{ID: event.UserID}
+       exist, err := br.data.DB.Context(ctx).Get(bean)
+       if err != nil {
+               return nil, 
errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
+       }
+       if !exist {
+               return nil, nil
+       }
+       if len(bean.Bio) > 0 {
+               return append(awards, br.createBadgeAward(event.UserID, b.ID, 
"")), nil
+       }
+       return nil, nil
+}
+
+// FirstPostEdit first post edit
+func (br *eventRuleRepo) FirstPostEdit(ctx context.Context,
+       event *schema.EventMsg) (awards []*entity.BadgeAward, err error) {
+       b := br.getBadgeByHandler(ctx, "FirstPostEdit")
+       if b == nil {
+               return nil, nil
+       }
+       return append(awards, br.createBadgeAward(event.UserID, b.ID, 
event.GetObjectID())), nil
+}
+
+// FirstFlaggedPost first flagged post.
+func (br *eventRuleRepo) FirstFlaggedPost(ctx context.Context,
+       event *schema.EventMsg) (awards []*entity.BadgeAward, err error) {
+       b := br.getBadgeByHandler(ctx, "FirstFlaggedPost")
+       if b == nil {
+               return nil, nil
+       }
+       return append(awards, br.createBadgeAward(event.UserID, b.ID, 
event.GetObjectID())), nil
+}
+
+// FirstVotedPost first voted post
+func (br *eventRuleRepo) FirstVotedPost(ctx context.Context,
+       event *schema.EventMsg) (awards []*entity.BadgeAward, err error) {
+       b := br.getBadgeByHandler(ctx, "FirstVotedPost")
+       if b == nil {
+               return nil, nil
+       }
+       return append(awards, br.createBadgeAward(event.UserID, b.ID, 
event.GetObjectID())), nil
+}
+
+// FirstReactedPost first reacted post
+func (br *eventRuleRepo) FirstReactedPost(ctx context.Context,
+       event *schema.EventMsg) (awards []*entity.BadgeAward, err error) {
+       b := br.getBadgeByHandler(ctx, "FirstReactedPost")
+       if b == nil {
+               return nil, nil
+       }
+       return append(awards, br.createBadgeAward(event.UserID, b.ID, 
event.GetObjectID())), nil
+}
+
+// FirstSharedPost first shared post
+func (br *eventRuleRepo) FirstSharedPost(ctx context.Context,
+       event *schema.EventMsg) (awards []*entity.BadgeAward, err error) {
+       b := br.getBadgeByHandler(ctx, "FirstSharedPost")
+       if b == nil {
+               return nil, nil
+       }
+       return append(awards, br.createBadgeAward(event.UserID, b.ID, 
event.GetObjectID())), nil
+}
+
+// FirstAcceptAnswer user first accept answer
+func (br *eventRuleRepo) FirstAcceptAnswer(ctx context.Context,
+       event *schema.EventMsg) (awards []*entity.BadgeAward, err error) {
+       b := br.getBadgeByHandler(ctx, "FirstAcceptAnswer")
+       if b == nil {
+               return nil, nil
+       }
+       return append(awards, br.createBadgeAward(event.UserID, b.ID, 
event.GetObjectID())), nil
+}
+
+// ReachAnswerAcceptedAmount reach answer accepted amount
+func (br *eventRuleRepo) ReachAnswerAcceptedAmount(ctx context.Context,
+       event *schema.EventMsg) (awards []*entity.BadgeAward, err error) {
+       b := br.getBadgeByHandler(ctx, "ReachAnswerAcceptedAmount")
+       if b == nil {
+               return nil, nil
+       }
+       return append(awards, br.createBadgeAward(event.UserID, b.ID, 
event.GetObjectID())), nil
+}
+
+// ReachAnswerVote reach answer vote
+func (br *eventRuleRepo) ReachAnswerVote(ctx context.Context,
+       event *schema.EventMsg) (awards []*entity.BadgeAward, err error) {
+       b := br.getBadgeByHandler(ctx, "ReachAnswerVote")
+       if b == nil {
+               return nil, nil
+       }
+       return append(awards, br.createBadgeAward(event.UserID, b.ID, 
event.GetObjectID())), nil
+}
+
+// ReachQuestionVote reach question vote
+func (br *eventRuleRepo) ReachQuestionVote(ctx context.Context,
+       event *schema.EventMsg) (awards []*entity.BadgeAward, err error) {
+       b := br.getBadgeByHandler(ctx, "ReachQuestionVote")
+       if b == nil {
+               return nil, nil
+       }
+       return append(awards, br.createBadgeAward(event.UserID, b.ID, 
event.GetObjectID())), nil
+}
+
+func (br *eventRuleRepo) getBadgeByHandler(ctx context.Context, handler 
string) (b *entity.Badge) {
+       b = &entity.Badge{Handler: handler}
+       exist, err := br.data.DB.Context(ctx).Get(b)
+       if err != nil {
+               log.Errorf("error getting badge by handler %s: %v", handler, 
err)
+               return nil
+       }
+       if !exist {
+               log.Errorf("badge not found by handler %s", handler)
+               return nil
+       }
+       return b
+}
+
+func (br *eventRuleRepo) createBadgeAward(userID, badgeID, objectID string) 
(awards *entity.BadgeAward) {
+       return &entity.BadgeAward{
+               UserID:   userID,
+               BadgeID:  badgeID,
+               ObjectID: objectID,
+       }
+}
diff --git a/internal/repo/badge/badge_repo.go 
b/internal/repo/badge/badge_repo.go
index 7651f95b..5030f0da 100644
--- a/internal/repo/badge/badge_repo.go
+++ b/internal/repo/badge/badge_repo.go
@@ -22,9 +22,11 @@ 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/badge"
        "github.com/apache/incubator-answer/internal/service/unique"
+       "github.com/segmentfault/pacman/errors"
 )
 
 type badgeRepo struct {
@@ -40,9 +42,21 @@ func NewBadgeRepo(data *data.Data, uniqueIDRepo 
unique.UniqueIDRepo) badge.Badge
        }
 }
 
-func (r badgeRepo) GetByID(ctx context.Context, id string) (badge 
*entity.Badge, exists bool, err error) {
+func (r *badgeRepo) GetByID(ctx context.Context, id string) (badge 
*entity.Badge, exists bool, err error) {
        badge = &entity.Badge{}
        exists, err = r.data.DB.Context(ctx).Where("id = ?", id).Get(badge)
+       if err != nil {
+               err = 
errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
+       }
+       return
+}
+
+func (r *badgeRepo) GetByIDs(ctx context.Context, ids []string) (badges 
[]*entity.Badge, err error) {
+       badges = make([]*entity.Badge, 0)
+       err = r.data.DB.Context(ctx).In("id", ids).Find(&badges)
+       if err != nil {
+               err = 
errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
+       }
        return
 }
 
@@ -50,6 +64,9 @@ func (r badgeRepo) GetByID(ctx context.Context, id string) 
(badge *entity.Badge,
 func (r *badgeRepo) ListByLevel(ctx context.Context, level entity.BadgeLevel) 
(badges []*entity.Badge, err error) {
        badges = make([]*entity.Badge, 0)
        err = r.data.DB.Context(ctx).Where("level = ?", level).Find(&badges)
+       if err != nil {
+               err = 
errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
+       }
        return
 }
 
@@ -57,6 +74,9 @@ func (r *badgeRepo) ListByLevel(ctx context.Context, level 
entity.BadgeLevel) (b
 func (r *badgeRepo) ListByGroup(ctx context.Context, groupID int64) (badges 
[]*entity.Badge, err error) {
        badges = make([]*entity.Badge, 0)
        err = r.data.DB.Context(ctx).Where("group_id = ?", 
groupID).Find(&badges)
+       if err != nil {
+               err = 
errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
+       }
        return
 }
 
@@ -64,6 +84,9 @@ func (r *badgeRepo) ListByGroup(ctx context.Context, groupID 
int64) (badges []*e
 func (r *badgeRepo) ListByLevelAndGroup(ctx context.Context, level 
entity.BadgeLevel, groupID int64) (badges []*entity.Badge, err error) {
        badges = make([]*entity.Badge, 0)
        err = r.data.DB.Context(ctx).Where("level = ? AND group_id = ?", level, 
groupID).Find(&badges)
+       if err != nil {
+               err = 
errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
+       }
        return
 }
 
@@ -71,6 +94,9 @@ func (r *badgeRepo) ListByLevelAndGroup(ctx context.Context, 
level entity.BadgeL
 func (r *badgeRepo) ListActivated(ctx context.Context) (badges 
[]*entity.Badge, err error) {
        badges = make([]*entity.Badge, 0)
        err = r.data.DB.Context(ctx).Where("status = ?", 
entity.BadgeStatusActive).Find(&badges)
+       if err != nil {
+               err = 
errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
+       }
        return
 }
 
@@ -78,5 +104,8 @@ func (r *badgeRepo) ListActivated(ctx context.Context) 
(badges []*entity.Badge,
 func (r *badgeRepo) ListInactivated(ctx context.Context) (badges 
[]*entity.Badge, err error) {
        badges = make([]*entity.Badge, 0)
        err = r.data.DB.Context(ctx).Where("status = ?", 
entity.BadgeStatusInactive).Find(&badges)
+       if err != nil {
+               err = 
errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
+       }
        return
 }
diff --git a/internal/repo/badge/badge_rule.go 
b/internal/repo/badge/badge_rule.go
deleted file mode 100644
index 3ae0b7b4..00000000
--- a/internal/repo/badge/badge_rule.go
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 8f01fdef..00000000
--- a/internal/repo/badge/event_rule_mapping.go
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 635b30da..00000000
--- a/internal/repo/badge/rule.go
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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/repo/provider.go b/internal/repo/provider.go
index ee309e02..7f222a42 100644
--- a/internal/repo/provider.go
+++ b/internal/repo/provider.go
@@ -104,6 +104,7 @@ var ProviderSetRepo = wire.NewSet(
        plugin_config.NewPluginUserConfigRepo,
        review.NewReviewRepo,
        badge.NewBadgeRepo,
+       badge.NewEventRuleRepo,
        badge_group.NewBadgeGroupRepo,
        badge_award.NewBadgeAwardRepo,
 )
diff --git a/internal/schema/event_schema.go b/internal/schema/event_schema.go
index 01f80fbb..17be9627 100644
--- a/internal/schema/event_schema.go
+++ b/internal/schema/event_schema.go
@@ -68,3 +68,13 @@ func (e *EventMsg) AddExtra(key, value string) *EventMsg {
        e.ExtraInfo[key] = value
        return e
 }
+
+func (e *EventMsg) GetObjectID() string {
+       if len(e.CommentID) > 0 {
+               return e.CommentID
+       }
+       if len(e.AnswerID) > 0 {
+               return e.AnswerID
+       }
+       return e.QuestionID
+}
diff --git a/internal/repo/badge/badge_event_handler.go 
b/internal/service/badge/badge_event_handler.go
similarity index 60%
rename from internal/repo/badge/badge_event_handler.go
rename to internal/service/badge/badge_event_handler.go
index 242778ec..587ee77d 100644
--- a/internal/repo/badge/badge_event_handler.go
+++ b/internal/service/badge/badge_event_handler.go
@@ -21,6 +21,8 @@ package badge
 
 import (
        "context"
+       "github.com/apache/incubator-answer/internal/entity"
+       "github.com/apache/incubator-answer/internal/service/badge_award"
        "github.com/apache/incubator-answer/internal/service/event_queue"
        "github.com/segmentfault/pacman/log"
 
@@ -31,15 +33,28 @@ import (
 type BadgeEventService struct {
        data              *data.Data
        eventQueueService event_queue.EventQueueService
+       badgeAwardRepo    badge_award.BadgeAwardRepo
+       badgeRepo         BadgeRepo
+       eventRuleRepo     EventRuleRepo
+}
+
+type EventRuleHandler func(ctx context.Context, event *schema.EventMsg) 
(awards []*entity.BadgeAward, err error)
+
+type EventRuleRepo interface {
+       HandleEventWithRule(ctx context.Context, msg *schema.EventMsg) (awards 
[]*entity.BadgeAward)
 }
 
 func NewBadgeEventService(
        data *data.Data,
        eventQueueService event_queue.EventQueueService,
+       badgeRepo BadgeRepo,
+       eventRuleRepo EventRuleRepo,
 ) *BadgeEventService {
        n := &BadgeEventService{
                data:              data,
                eventQueueService: eventQueueService,
+               badgeRepo:         badgeRepo,
+               eventRuleRepo:     eventRuleRepo,
        }
        eventQueueService.RegisterHandler(n.Handler)
        return n
@@ -47,11 +62,24 @@ func NewBadgeEventService(
 
 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
+       awards := ns.eventRuleRepo.HandleEventWithRule(ctx, msg)
+       if len(awards) == 0 {
+               return nil
+       }
 
-       // TODO: Distribute badge
+       badgeIDs := make([]string, 0)
+       for _, award := range awards {
+               badgeIDs = append(badgeIDs, award.BadgeID)
+       }
+
+       badges, err := ns.badgeRepo.GetByIDs(ctx, badgeIDs)
+       if err != nil {
+               log.Errorf("error getting badges %+v: %v", badgeIDs, err)
+               return err
+       }
 
+       // TODO: award badges to user
+       log.Debugf("awarding badges %+v to user", badges)
        return nil
 }
diff --git a/internal/service/badge/badge_service.go 
b/internal/service/badge/badge_service.go
index 94ba5b64..16087f9c 100644
--- a/internal/service/badge/badge_service.go
+++ b/internal/service/badge/badge_service.go
@@ -36,6 +36,7 @@ import (
 
 type BadgeRepo interface {
        GetByID(ctx context.Context, id string) (badge *entity.Badge, exists 
bool, err error)
+       GetByIDs(ctx context.Context, ids []string) (badges []*entity.Badge, 
err error)
        ListByLevel(ctx context.Context, level entity.BadgeLevel) 
([]*entity.Badge, error)
        ListByGroup(ctx context.Context, groupID int64) ([]*entity.Badge, error)
        ListByLevelAndGroup(ctx context.Context, level entity.BadgeLevel, 
groupID int64) ([]*entity.Badge, error)
@@ -44,19 +45,23 @@ type BadgeRepo interface {
 }
 
 type BadgeService struct {
-       badgeRepo      BadgeRepo
-       badgeGroupRepo badge_group.BadgeGroupRepo
-       badgeAwardRepo badge_award.BadgeAwardRepo
+       badgeRepo         BadgeRepo
+       badgeGroupRepo    badge_group.BadgeGroupRepo
+       badgeAwardRepo    badge_award.BadgeAwardRepo
+       badgeEventService *BadgeEventService
 }
 
 func NewBadgeService(
        badgeRepo BadgeRepo,
        badgeGroupRepo badge_group.BadgeGroupRepo,
-       badgeAwardRepo badge_award.BadgeAwardRepo) *BadgeService {
+       badgeAwardRepo badge_award.BadgeAwardRepo,
+       badgeEventService *BadgeEventService,
+) *BadgeService {
        return &BadgeService{
-               badgeRepo:      badgeRepo,
-               badgeGroupRepo: badgeGroupRepo,
-               badgeAwardRepo: badgeAwardRepo,
+               badgeRepo:         badgeRepo,
+               badgeGroupRepo:    badgeGroupRepo,
+               badgeAwardRepo:    badgeAwardRepo,
+               badgeEventService: badgeEventService,
        }
 }
 
diff --git a/internal/service/provider.go b/internal/service/provider.go
index bf1528b8..7a6b1340 100644
--- a/internal/service/provider.go
+++ b/internal/service/provider.go
@@ -123,6 +123,7 @@ var ProviderSetService = wire.NewSet(
        meta.NewMetaService,
        event_queue.NewEventQueueService,
        badge.NewBadgeService,
+       badge.NewBadgeEventService,
        badge_award.NewBadgeAwardService,
        badge_group.NewBadgeGroupService,
 )

Reply via email to