diff --git a/app/models/badges/badge_famous_question.rb b/app/models/badges/badge_famous_question.rb index 91c11076abbec3cc21bf07ea6375c95dc61e9a3f..bbc3633f6a088e4fdaa58199a70e5b31daf99e5e 100644 --- a/app/models/badges/badge_famous_question.rb +++ b/app/models/badges/badge_famous_question.rb @@ -37,7 +37,22 @@ class BadgeFamousQuestion notify(content, recv_user, new_user_badge) true else - upgrade_badge(existing_badge, post, recv_user) + check_upgrade(existing_badge, post, recv_user) + end + end + + # @param [UserBadge] existing_badge + # @param [Post] post + # @param [User] recv_user + # @return + def self.check_upgrade(existing_badge, post, recv_user) + old_badge_type = UserBadge.badge_types[existing_badge.badge_type] + badge_type = upgrade_badge(existing_badge, post) + return false unless badge_type + + if old_badge_type != badge_type + content = "Your badge has been upgraded to #{badge_type}!" + notify(content, recv_user, existing_badge) end end @@ -45,23 +60,17 @@ class BadgeFamousQuestion # @param [Post] post # @param [User] recv_user # @return boolean - def self.upgrade_badge(user_badge, post, recv_user) - # Check if the badge should be turned into a golden badge + def self.upgrade_badge(user_badge, post) if post.views_count >= BADGE_AWARD_THRESHOLDS[2] user_badge.update(badge_type: :gold) return false if user_badge.errors.any? - content = 'Your badge has been upgraded to gold!' - notify(content, recv_user, user_badge) - true - # Check if the badge should be turned into a silver badge + return UserBadge.badge_types[:gold] elsif post.views_count >= BADGE_AWARD_THRESHOLDS[1] user_badge.update(badge_type: :silver) return false if user_badge.errors.any? - content = 'Your badge has been upgraded to silver!' - notify(content, recv_user, user_badge) - true + return UserBadge.badge_types[:silver] end false end diff --git a/app/models/badges/badge_great_answer.rb b/app/models/badges/badge_great_answer.rb index 3546ecf8476af3376b21e51aafe23b1e4999f858..2b278943f2531e3b9a740a9c364a8d35e6338a6f 100644 --- a/app/models/badges/badge_great_answer.rb +++ b/app/models/badges/badge_great_answer.rb @@ -34,7 +34,18 @@ class BadgeGreatAnswer notify(content, recv_user, new_user_badge) true else - upgrade_badge(existing_badge, post, recv_user) + check_upgrade(existing_badge, post, recv_user) + end + end + + def self.check_upgrade(existing_badge, post, recv_user) + old_badge_type = UserBadge.badge_types[existing_badge.badge_type] + badge_type = upgrade_badge(existing_badge, post) + return false unless badge_type + + if old_badge_type != badge_type + content = "Your badge has been upgraded to #{badge_type}!" + notify(content, recv_user, existing_badge) end end @@ -42,23 +53,18 @@ class BadgeGreatAnswer # @param [Post] post # @param [User] recv_user # @return boolean - def self.upgrade_badge(user_badge, post, recv_user) + def self.upgrade_badge(user_badge, post) # Check if the badge should be turned into a golden badge if post.score >= BADGE_AWARD_THRESHOLDS[2] user_badge.update(badge_type: :gold) return false if user_badge.errors.any? - content = 'Your badge has been upgraded to gold!' - notify(content, recv_user, user_badge) - true - # Check if the badge should be turned into a silver badge + return UserBadge.badge_types[:gold] elsif post.score >= BADGE_AWARD_THRESHOLDS[1] user_badge.update(badge_type: :silver) return false if user_badge.errors.any? - content = 'Your badge has been upgraded to silver!' - notify(content, recv_user, user_badge) - true + return UserBadge.badge_types[:silver] end false end diff --git a/app/models/badges/badge_great_question.rb b/app/models/badges/badge_great_question.rb index d3f443760160c69c3753cb9d452be426e1f455c7..59fd6e821457060b8ec916ebbc603f94446984ee 100644 --- a/app/models/badges/badge_great_question.rb +++ b/app/models/badges/badge_great_question.rb @@ -35,33 +35,42 @@ class BadgeGreatQuestion content = "You have been awarded the badge '#{new_user_badge.badge.title}' for your question '#{post.title}'" notify(content, recv_user, new_user_badge) - true else - upgrade_badge(existing_badge, post, recv_user) + check_upgrade(existing_badge, post, recv_user) + end + true + end + + # @param [UserBadge] existing_badge + # @param [Post] post + # @param [User] recv_user + # @return + def self.check_upgrade(existing_badge, post, recv_user) + old_badge_type = UserBadge.badge_types[existing_badge.badge_type] + badge_type = upgrade_badge(existing_badge, post) + return false unless badge_type + + if old_badge_type != badge_type + content = "Your badge has been upgraded to #{badge_type}!" + notify(content, recv_user, existing_badge) end end # @param [UserBadge] user_badge # @param [Post] post # @param [User] recv_user - # @return boolean - def self.upgrade_badge(user_badge, post, recv_user) - # Check if the badge should be turned into a golden badge + # @return boolean OR string + def self.upgrade_badge(user_badge, post) if post.score >= BADGE_AWARD_THRESHOLDS[2] user_badge.update(badge_type: :gold) return false if user_badge.errors.any? - content = 'Your badge has been upgraded to gold!' - notify(content, recv_user, user_badge) - true - # Check if the badge should be turned into a silver badge + return UserBadge.badge_types[:gold] elsif post.score >= BADGE_AWARD_THRESHOLDS[1] user_badge.update(badge_type: :silver) return false if user_badge.errors.any? - content = 'Your badge has been upgraded to silver!' - notify(content, recv_user, user_badge) - true + return UserBadge.badge_types[:silver] end false end @@ -71,8 +80,6 @@ class BadgeGreatQuestion def self.eligible?(post) post.reload post.question? && post.score >= BADGE_AWARD_THRESHOLDS[0] - - # !recv_user.user_badges.exists?(badge_id: badge_id, badge_source: post) end # @param string message diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml index e2a91b308fd54b7fc2cf4eb3c4b3eed50650ea65..fb5d54c06337990c1215171f5e47e97238c723fc 100644 --- a/test/fixtures/users.yml +++ b/test/fixtures/users.yml @@ -122,7 +122,7 @@ enabled_2fa: two_factor_token: WT65ANYXBB2SBR7III7IVWNJDS4PQF2T backup_2fa_code: M8lENyehyCvo9F9MbyTl1aOL -<% (1..200).each do |i| %> +<% (1..210).each do |i| %> user_test_<%= i %>: email: user_test_<%= i %>@qpixel-test.net encrypted_password: '$2a$11$roUHXKxecjyQ72Qn7DWs3.9eRCCoRn176kX/UNb/xiue3aGqf7xEW' diff --git a/test/models/badges/badge_famous_question_test.rb b/test/models/badges/badge_famous_question_test.rb index 9a2dfd6ac4b7492f90c472a6618b01d013ecba07..17112f4780409ebd66c3595604118aabc088e173 100644 --- a/test/models/badges/badge_famous_question_test.rb +++ b/test/models/badges/badge_famous_question_test.rb @@ -38,6 +38,22 @@ class BadgeFamousQuestionTest < ActionController::TestCase assert_equal @user.user_badges.where(badge_id: @badge.id, badge_source: @post).count, 0 end + test 'user receives only one notification per badge tier' do + assert_equal @user.notifications.count, 2 + + create_views(1, BadgeFamousQuestion.badge_award_thresholds[0], @post) + assert_equal @user.notifications.count, 3 + + create_views(BadgeFamousQuestion.badge_award_thresholds[0] + 1, BadgeFamousQuestion.badge_award_thresholds[1], @post) + assert_equal @user.notifications.count, 4 + + create_views(BadgeFamousQuestion.badge_award_thresholds[1] + 1, BadgeFamousQuestion.badge_award_thresholds[2], @post) + assert_equal @user.notifications.count, 5 + + create_views(BadgeFamousQuestion.badge_award_thresholds[2] + 1, BadgeFamousQuestion.badge_award_thresholds[2] + 2, @post) + assert_equal @user.notifications.count, 5 + end + def create_views(start, stop, post) (start..stop).each do |i| unique_user = users("user_test_#{i}") diff --git a/test/models/badges/badge_great_answer_test.rb b/test/models/badges/badge_great_answer_test.rb index 02fd0bb74a81c5a622b58ec997866a74382de04c..a3a1e8f48d1f71281e1c9278eb7737c91a5239fd 100644 --- a/test/models/badges/badge_great_answer_test.rb +++ b/test/models/badges/badge_great_answer_test.rb @@ -51,4 +51,36 @@ class BadgeGreatAnswerTest < ActionController::TestCase assert_equal expected_count, post.upvote_count assert UserBadge.exists?(user: author, badge_id: BadgeGreatAnswer.badge_id) end + + test 'user receives only one notification per badge tier' do + post = posts(:answer_one) + author = post.user + old_votes = post.upvote_count + + assert_equal author.notifications.count, 2 + + # Create a badge (bronze, initially) + post.score = BadgeGreatAnswer.badge_award_thresholds[0] + 0.01 + create_vote_and_check_badge(post, author, users(:standard_user), old_votes + 1) + assert_equal author.notifications.count, 3 + + # Create a vote and upgrade the badge to silver + post.score = BadgeGreatAnswer.badge_award_thresholds[1] + 0.01 + create_vote_and_check_badge(post, author, users(:editor), old_votes + 2) + assert_equal author.notifications.count, 4 + + # Create a vote and upgrade the badge to gold + post.score = BadgeGreatAnswer.badge_award_thresholds[2] + 0.01 + create_vote_and_check_badge(post, author, users(:closer), old_votes + 3) + assert_equal author.notifications.count, 5 + + # Create additional votes, for checking notifications + post.score = BadgeGreatAnswer.badge_award_thresholds[2] + 0.01 + create_vote_and_check_badge(post, author, users(:standard_user), old_votes + 4) + post.score = BadgeGreatAnswer.badge_award_thresholds[2] + 0.01 + create_vote_and_check_badge(post, author, users(:editor), old_votes + 5) + post.score = BadgeGreatAnswer.badge_award_thresholds[2] + 0.01 + create_vote_and_check_badge(post, author, users(:closer), old_votes + 6) + assert_equal author.notifications.count, 5 + end end diff --git a/test/models/badges/badge_great_question_test.rb b/test/models/badges/badge_great_question_test.rb index fe8bdbecd3c492f360060a72dde0a9871694d498..7f4b10b281803bcc722abff88fbbdf412c5d00d2 100644 --- a/test/models/badges/badge_great_question_test.rb +++ b/test/models/badges/badge_great_question_test.rb @@ -29,6 +29,22 @@ class BadgeGreatQuestionTest < ActionController::TestCase assert_equal @user.user_badges.where(badge_id: @badge.id, badge_source: @post).count, 0 end + test 'user receives only one notification per badge tier' do + assert_equal @user.notifications.count, 2 + + create_votes(1, BRONZE_VOTES, @post) + assert_equal @user.notifications.count, 3 + + create_votes(BRONZE_VOTES + 1, SILVER_VOTES, @post) + assert_equal @user.notifications.count, 4 + + create_votes(SILVER_VOTES + 1, GOLD_VOTES, @post) + assert_equal @user.notifications.count, 5 + + create_votes(GOLD_VOTES + 1, GOLD_VOTES + 2, @post) + assert_equal @user.notifications.count, 5 + end + def create_votes(start, stop, post) (start..stop).each do |i| unique_user = users("user_test_#{i}")