internal/repo/badge/badge_event_rule.go (195 lines of code) (raw):

/* * 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/answer/internal/base/constant" "github.com/apache/answer/internal/base/data" "github.com/apache/answer/internal/base/reason" "github.com/apache/answer/internal/entity" "github.com/apache/answer/internal/schema" "github.com/apache/answer/internal/service/badge" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" "strconv" ) // 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 _, handler := range handlers { t, err := handler(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) { badges := br.getBadgesByHandler(ctx, "FirstUpdateUserProfile") for _, b := range badges { 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 { continue } if len(bean.Bio) > 0 { awards = append(awards, br.createBadgeAward(event.UserID, entity.BadgeEmptyAwardKey, b)) } } return awards, nil } // FirstPostEdit first post edit func (br *eventRuleRepo) FirstPostEdit(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { badges := br.getBadgesByHandler(ctx, "FirstPostEdit") for _, b := range badges { awards = append(awards, br.createBadgeAward(event.UserID, event.GetObjectID(), b)) } return awards, nil } // FirstFlaggedPost first flagged post. func (br *eventRuleRepo) FirstFlaggedPost(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { badges := br.getBadgesByHandler(ctx, "FirstFlaggedPost") for _, b := range badges { awards = append(awards, br.createBadgeAward(event.UserID, event.GetObjectID(), b)) } return awards, nil } // FirstVotedPost first voted post func (br *eventRuleRepo) FirstVotedPost(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { badges := br.getBadgesByHandler(ctx, "FirstVotedPost") for _, b := range badges { awards = append(awards, br.createBadgeAward(event.UserID, event.GetObjectID(), b)) } return awards, nil } // FirstReactedPost first reacted post func (br *eventRuleRepo) FirstReactedPost(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { badges := br.getBadgesByHandler(ctx, "FirstReactedPost") for _, b := range badges { awards = append(awards, br.createBadgeAward(event.UserID, event.GetObjectID(), b)) } return awards, nil } // FirstSharedPost first shared post func (br *eventRuleRepo) FirstSharedPost(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { badges := br.getBadgesByHandler(ctx, "FirstSharedPost") for _, b := range badges { awards = append(awards, br.createBadgeAward(event.UserID, event.GetObjectID(), b)) } return awards, nil } // FirstAcceptAnswer user first accept answer func (br *eventRuleRepo) FirstAcceptAnswer(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { badges := br.getBadgesByHandler(ctx, "FirstAcceptAnswer") for _, b := range badges { awards = append(awards, br.createBadgeAward(event.UserID, event.GetObjectID(), b)) } return awards, nil } // ReachAnswerAcceptedAmount reach answer accepted amount func (br *eventRuleRepo) ReachAnswerAcceptedAmount(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { badges := br.getBadgesByHandler(ctx, "ReachAnswerAcceptedAmount") if len(event.AnswerUserID) == 0 { return nil, nil } // count user's accepted answer amount amount, err := br.data.DB.Context(ctx).Count(&entity.Answer{ UserID: event.AnswerUserID, Accepted: schema.AnswerAcceptedEnable, Status: entity.AnswerStatusAvailable, }) if err != nil { return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() } for _, b := range badges { // get badge requirement requirement := b.GetIntParam("amount") if requirement == 0 || amount < requirement { continue } awards = append(awards, br.createBadgeAward(event.AnswerUserID, event.AnswerID, b)) } return awards, nil } // ReachAnswerVote reach answer vote func (br *eventRuleRepo) ReachAnswerVote(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { badges := br.getBadgesByHandler(ctx, "ReachAnswerVote") // get vote amount amount, _ := strconv.Atoi(event.GetExtra("vote_up_amount")) if amount == 0 { return nil, nil } for _, b := range badges { // get badge requirement requirement := b.GetIntParam("amount") if requirement == 0 || int64(amount) < requirement { continue } awards = append(awards, br.createBadgeAward(event.AnswerUserID, event.AnswerID, b)) } return awards, nil } // ReachQuestionVote reach question vote func (br *eventRuleRepo) ReachQuestionVote(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { badges := br.getBadgesByHandler(ctx, "ReachQuestionVote") // get vote amount amount, _ := strconv.Atoi(event.GetExtra("vote_up_amount")) if amount == 0 { return nil, nil } for _, b := range badges { // get badge requirement requirement := b.GetIntParam("amount") if requirement == 0 || int64(amount) < requirement { continue } awards = append(awards, br.createBadgeAward(event.QuestionUserID, event.QuestionID, b)) } return awards, nil } func (br *eventRuleRepo) getBadgesByHandler(ctx context.Context, handler string) (badges []*entity.Badge) { badges = make([]*entity.Badge, 0) err := br.data.DB.Context(ctx).Where("handler = ?", handler).Find(&badges) if err != nil { log.Errorf("error getting badge by handler %s: %v", handler, err) return nil } return badges } func (br *eventRuleRepo) createBadgeAward(userID, awardKey string, badge *entity.Badge) (awards *entity.BadgeAward) { return &entity.BadgeAward{ UserID: userID, BadgeID: badge.ID, AwardKey: awardKey, } }