Automatically reward thumbs-up milestone badges (#20338)

* initial work on #20111

* initial work on #20111

* fix cron

* is this a good test

* add in initial check, fix test data

* Update spec

---------

Co-authored-by: Mac Siri <krairit.siri@gmail.com>
This commit is contained in:
Philip How 2023-11-14 16:47:24 +00:00 committed by GitHub
parent 9c268e3ca5
commit 779701d5f6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 93 additions and 0 deletions

View file

@ -0,0 +1,55 @@
module Badges
class AwardThumbsUp
THUMBS_UP_BADGES = {
100 => "100 Thumbs Up Milestone",
500 => "500 Thumbs Up Milestone",
1000 => "1,000 Thumbs Up Milestone",
5000 => "5,000 Thumbs Up Milestone",
10_000 => "10,000 Thumbs Up Milestone"
}.freeze
MIN_THRESHOLD = THUMBS_UP_BADGES.keys.min
def self.call
badge_ids = fetch_badge_ids
# Early return if any badge is not found
return if badge_ids.values.any?(&:nil?)
user_thumbsup_counts = get_user_thumbsup_counts
user_thumbsup_counts.each do |user_id, count|
THUMBS_UP_BADGES.each do |threshold, _|
break unless count >= threshold
badge_id = badge_ids[threshold]
next unless badge_id
next unless (user = User.find_by(id: user_id))
user.badge_achievements.create(
badge_id: badge_id,
rewarding_context_message_markdown: generate_message(threshold: threshold),
)
end
end
end
def self.get_user_thumbsup_counts
Reaction.where(category: "thumbsup", reactable_type: "Article")
.group(:user_id)
.having("COUNT(*) >= ?", MIN_THRESHOLD)
.order(Arel.sql("COUNT(*) DESC"))
.count
end
def self.fetch_badge_ids
THUMBS_UP_BADGES.transform_values do |title|
Badge.find_by(title: title)&.id
end
end
def self.generate_message(threshold:)
I18n.t("services.badges.thumbs_up", count: threshold)
end
end
end

View file

@ -31,6 +31,7 @@ en:
first: Thank you for participating in constructive conversation! You posted two or more comments this week. Keep it up to continue the streak!
longest: 32 weeks! You've achieved the longest streak possible for the Community Wellness badge. Amazing job engaging in the community and keep up your amazing contributions to our community!
other: Congrats on achieving a %{weeks} week streak for the Community Wellness Badge! Keep the constructive comments flowing to continue the streak!
thumbs_up: Thank you for your efforts reviewing posts on and reaching %{count} thumbs-up reactions!
broadcasts:
welcome_notification:
generator:

View file

@ -31,6 +31,7 @@ fr:
first: Merci de participer à une conversation constructive ! Vous avez posté deux commentaires ou plus cette semaine. Continuez comme ça pour poursuivre la série !
longest: 32 semaines ! Vous avez atteint la plus longue période possible pour l'insigne du bien-être communautaire. Vous avez fait un travail remarquable en vous engageant dans la communauté et continuez à apporter votre contribution à notre communauté !
other: Félicitations pour avoir atteint une série de %{weeks} semaines pour l'insigne du bien-être communautaire ! Continuez à envoyer des commentaires constructifs pour que la série continue !
thumbs_up: Merci pour vos efforts en examinant les messages et en obtenant %{count} réactions positives!
broadcasts:
welcome_notification:
generator:

View file

@ -86,6 +86,14 @@ award_community_wellness_badges:
- ""
- award_community_wellness
- ""
award_thumbs_up_badges:
description: "Awards Thumbs Up Milestone badge to users (runs daily at 01:00 UTC) "
cron: "0 1 * * *"
class: "BadgeAchievements::BadgeAwardWorker"
args:
- ""
- award_thumbs_up
- ""
resave_supported_tags:
description: "Resaves supported tags to recalculate scores (runs daily at 00:25 UTC)"
cron: "25 0 * * *"

View file

@ -0,0 +1,28 @@
require "rails_helper"
RSpec.describe Badges::AwardThumbsUp, type: :service do
let(:thumbs_up_tiers) { described_class::THUMBS_UP_BADGES.keys }
it "does nothing if there are no thumbsup badges" do
user = create(:user)
allow(described_class).to receive(:get_user_thumbsup_counts).and_return(user.id => thumbs_up_tiers.max)
expect { described_class.call }.not_to change { user.badges.count }
end
it "awards the correct badge to the correct user" do
all_badges = described_class::THUMBS_UP_BADGES.map do |_, badge_title|
create(:badge, title: badge_title)
end
ghost_user = create(:user)
user = create(:user)
prolific_user = create(:user)
allow(described_class).to receive(:get_user_thumbsup_counts)
.and_return(user.id => thumbs_up_tiers.min, prolific_user.id => thumbs_up_tiers.max)
described_class.call
expect(ghost_user.badges.count).to eq(0)
expect(user.badges).to eq([Badge.find_by(title: described_class::THUMBS_UP_BADGES[thumbs_up_tiers.min])])
expect(prolific_user.badges).to eq(all_badges)
end
end