diff --git a/app/controllers/admin/badge_achievements_controller.rb b/app/controllers/admin/badge_achievements_controller.rb index 94ca4a49d..4c536b730 100644 --- a/app/controllers/admin/badge_achievements_controller.rb +++ b/app/controllers/admin/badge_achievements_controller.rb @@ -32,9 +32,14 @@ module Admin end usernames = permitted_params[:usernames].downcase.split(/\s*,\s*/) + include_default_description = permitted_params[:include_default_description] == "1" message = permitted_params[:message_markdown].presence || I18n.t("admin.badge_achievements_controller.congrats", community: ::Settings::Community.community_name) - BadgeAchievements::BadgeAwardWorker.perform_async(usernames, permitted_params[:badge], message) + BadgeAchievements::BadgeAwardWorker + .perform_async(usernames, + permitted_params[:badge], + message, + include_default_description) flash[:success] = I18n.t("admin.badge_achievements_controller.rewarded") redirect_to admin_badge_achievements_path @@ -46,7 +51,7 @@ module Admin private def permitted_params - params.permit(:usernames, :badge, :message_markdown) + params.permit(:usernames, :badge, :message_markdown, :include_default_description) end end end diff --git a/app/services/badges/award.rb b/app/services/badges/award.rb index afdb3d1a6..a1c92d478 100644 --- a/app/services/badges/award.rb +++ b/app/services/badges/award.rb @@ -1,6 +1,6 @@ module Badges class Award - def self.call(user_relation, slug, message_markdown) + def self.call(user_relation, slug, message_markdown, include_default_description: true) return unless (badge_id = Badge.id_for_slug(slug)) user_relation.find_each do |user| @@ -9,6 +9,7 @@ module Badges achievement = user.badge_achievements.create( badge_id: badge_id, rewarding_context_message_markdown: message_markdown, + include_default_description: include_default_description, ) user.touch if achievement.persisted? end diff --git a/app/services/badges/award_first_post.rb b/app/services/badges/award_first_post.rb index 8dc3ee4ac..55c9f2d71 100644 --- a/app/services/badges/award_first_post.rb +++ b/app/services/badges/award_first_post.rb @@ -6,6 +6,7 @@ module Badges return unless (badge_id = Badge.id_for_slug(BADGE_SLUG)) Article.joins(:user) + .published .where("articles.published_at > ?", 1.week.ago) .where("articles.published_at < ?", 1.hour.ago) .where("articles.score >= ?", 0) diff --git a/app/services/notifications/new_badge_achievement/send.rb b/app/services/notifications/new_badge_achievement/send.rb index 75ee7c5e1..7bacaccb1 100644 --- a/app/services/notifications/new_badge_achievement/send.rb +++ b/app/services/notifications/new_badge_achievement/send.rb @@ -27,6 +27,7 @@ module Notifications attr_reader :badge_achievement def json_data + description = badge_achievement.include_default_description ? badge_achievement.badge.description : nil { user: user_data(badge_achievement.user), badge_achievement: { @@ -34,7 +35,7 @@ module Notifications rewarding_context_message: badge_achievement.rewarding_context_message, badge: { title: badge_achievement.badge.title, - description: badge_achievement.badge.description, + description: description, badge_image_url: badge_achievement.badge.badge_image_url, credits_awarded: badge_achievement.badge.credits_awarded } diff --git a/app/views/admin/badge_achievements/award.html.erb b/app/views/admin/badge_achievements/award.html.erb index 6e5bb6796..8dfd68d18 100644 --- a/app/views/admin/badge_achievements/award.html.erb +++ b/app/views/admin/badge_achievements/award.html.erb @@ -19,10 +19,17 @@
<%= f.label :message_markdown, "Override Default Message", class: "crayons-field__label" %>

- Supports Markdown + Supports Markdown. This overrides the "message" sent in notifications and emails, it does not override the badge description.

<%= f.text_area :message_markdown, size: "40x3", class: "crayons-textfield" %>
+
+ <%= f.check_box :include_default_description, checked: true %> + <%= f.label :include_default_description, "Include Default Description", class: "crayons-field__label pt-2" %> +
+

+ If checked, the default badge description will be included above the message. If unchecked, only the message will be included. +

<%= f.submit "Award Badges", class: "c-btn c-btn--primary" %>
diff --git a/app/views/mailers/notify_mailer/new_badge_email.html.erb b/app/views/mailers/notify_mailer/new_badge_email.html.erb index 1f320eb0a..43f035546 100644 --- a/app/views/mailers/notify_mailer/new_badge_email.html.erb +++ b/app/views/mailers/notify_mailer/new_badge_email.html.erb @@ -5,9 +5,12 @@

<%= @badge.title %> badge

-

- <%= @badge.description %> -

+ + <% if @badge_achievement.include_default_description %> +

+ <%= @badge.description %> +

+ <% end %> <% if @badge_achievement.rewarding_context_message.present? %>

@@ -21,7 +24,7 @@

+ style="font-weight:bold;color:white;background:#4e57ef;padding: 12px 15px;border-radius:6px;text-decoration:none"> Check out your profile

diff --git a/app/views/mailers/notify_mailer/new_badge_email.text.erb b/app/views/mailers/notify_mailer/new_badge_email.text.erb index 71fcc72ea..7ec9369e2 100644 --- a/app/views/mailers/notify_mailer/new_badge_email.text.erb +++ b/app/views/mailers/notify_mailer/new_badge_email.text.erb @@ -1,6 +1,6 @@ Congratulations, <%= @user.name %>! You got the <%= @badge.title %> badge! Be sure to check out your profile. -<%= @badge.description %> +<%= @badge.description if @badge_achievement.include_default_description %> <%= strip_tags @badge_achievement.rewarding_context_message %> diff --git a/app/views/notifications/_badgeachievement.html.erb b/app/views/notifications/_badgeachievement.html.erb index 081ccc580..ec8fa2911 100644 --- a/app/views/notifications/_badgeachievement.html.erb +++ b/app/views/notifications/_badgeachievement.html.erb @@ -4,7 +4,9 @@

<%= t("views.notifications.badge.heading_html", badge: tag.strong(sanitize(json_data["badge_achievement"]["badge"]["title"]), class: "fw-bold")) %>

-

<%= json_data["badge_achievement"]["badge"]["description"] %>

+ <% if json_data["badge_achievement"]["badge"]["description"] %> +

<%= json_data["badge_achievement"]["badge"]["description"] %>

+ <% end %>
diff --git a/app/workers/badge_achievements/badge_award_worker.rb b/app/workers/badge_achievements/badge_award_worker.rb index fc97e338b..2cc92d353 100644 --- a/app/workers/badge_achievements/badge_award_worker.rb +++ b/app/workers/badge_achievements/badge_award_worker.rb @@ -4,7 +4,7 @@ module BadgeAchievements sidekiq_options queue: :high_priority, retry: 10 - def perform(usernames, badge_slug, message) + def perform(usernames, badge_slug, message, include_default_description = true) # rubocop:disable Style/OptionalBooleanParameter if (award_class = "Badges::#{badge_slug.classify}".safe_constantize) award_class.call else @@ -12,6 +12,7 @@ module BadgeAchievements User.where(username: usernames), badge_slug, message, + include_default_description: include_default_description, ) end end diff --git a/db/migrate/20240227181740_add_include_badge_description_in_email.rb b/db/migrate/20240227181740_add_include_badge_description_in_email.rb new file mode 100644 index 000000000..2b82cb2ea --- /dev/null +++ b/db/migrate/20240227181740_add_include_badge_description_in_email.rb @@ -0,0 +1,5 @@ +class AddIncludeBadgeDescriptionInEmail < ActiveRecord::Migration[7.0] + def change + add_column :badge_achievements, :include_default_description, :boolean, default: true, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 9983464bd..b4742e0e4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2024_02_12_142953) do +ActiveRecord::Schema[7.0].define(version: 2024_02_27_181740) do # These are extensions that must be enabled in order to support this database enable_extension "citext" enable_extension "ltree" @@ -200,6 +200,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_02_12_142953) do create_table "badge_achievements", force: :cascade do |t| t.bigint "badge_id", null: false t.datetime "created_at", precision: nil, null: false + t.boolean "include_default_description", default: true, null: false t.bigint "rewarder_id" t.text "rewarding_context_message" t.text "rewarding_context_message_markdown" diff --git a/spec/requests/admin/badge_achievements_spec.rb b/spec/requests/admin/badge_achievements_spec.rb index c031ca557..b87c9f090 100644 --- a/spec/requests/admin/badge_achievements_spec.rb +++ b/spec/requests/admin/badge_achievements_spec.rb @@ -46,7 +46,7 @@ RSpec.describe "/admin/content_manager/badge_achievements" do message_markdown: "you got a badge nice one" } expect(BadgeAchievements::BadgeAwardWorker).to have_received(:perform_async).with( - usernames_array, badge.slug, "you got a badge nice one" + usernames_array, badge.slug, "you got a badge nice one", false ) expect(request.flash[:success]).to include("Badges are being rewarded. The task will finish shortly.") end @@ -60,7 +60,10 @@ RSpec.describe "/admin/content_manager/badge_achievements" do message_markdown: "Hinder me? Thou fool. No living man may hinder me!" } expect(BadgeAchievements::BadgeAwardWorker).to have_received(:perform_async).with( - usernames_array, badge.slug, "Hinder me? Thou fool. No living man may hinder me!" + usernames_array, + badge.slug, + "Hinder me? Thou fool. No living man may hinder me!", + false, ) expect(request.flash[:success]).to include("Badges are being rewarded. The task will finish shortly.") end @@ -72,9 +75,43 @@ RSpec.describe "/admin/content_manager/badge_achievements" do usernames: usernames_string, message_markdown: "" } - expect(BadgeAchievements::BadgeAwardWorker).to have_received(:perform_async).with(usernames_array, - badge.slug, - expected_message) + expect(BadgeAchievements::BadgeAwardWorker) + .to have_received(:perform_async).with(usernames_array, + badge.slug, + expected_message, + false) + expect(request.flash[:success]).to include("Badges are being rewarded. The task will finish shortly.") + end + + it "includes default description if passed as true" do + allow(BadgeAchievements::BadgeAwardWorker).to receive(:perform_async) + post admin_badge_achievements_award_badges_path, params: { + badge: badge.slug, + usernames: usernames_string, + message_markdown: "", + include_default_description: "1" + } + expect(BadgeAchievements::BadgeAwardWorker) + .to have_received(:perform_async).with(usernames_array, + badge.slug, + expected_message, + true) + expect(request.flash[:success]).to include("Badges are being rewarded. The task will finish shortly.") + end + + it "does not include default description if passed as false" do + allow(BadgeAchievements::BadgeAwardWorker).to receive(:perform_async) + post admin_badge_achievements_award_badges_path, params: { + badge: badge.slug, + usernames: usernames_string, + message_markdown: "", + include_default_description: "0" + } + expect(BadgeAchievements::BadgeAwardWorker) + .to have_received(:perform_async).with(usernames_array, + badge.slug, + expected_message, + false) expect(request.flash[:success]).to include("Badges are being rewarded. The task will finish shortly.") end @@ -83,8 +120,11 @@ RSpec.describe "/admin/content_manager/badge_achievements" do usernames: usernames_string, message_markdown: "" } - expect(BadgeAchievements::BadgeAwardWorker).not_to have_received(:perform_async).with(usernames_array, - badge.slug, "") + expect(BadgeAchievements::BadgeAwardWorker) + .not_to have_received(:perform_async).with(usernames_array, + badge.slug, + "", + false) end it "does not award a badge if the username provided is not lowercase" do @@ -93,8 +133,11 @@ RSpec.describe "/admin/content_manager/badge_achievements" do usernames: user.username.upcase, message_markdown: "" } - expect(BadgeAchievements::BadgeAwardWorker).not_to have_received(:perform_async).with(user.username.upcase, - badge.slug, "") + expect(BadgeAchievements::BadgeAwardWorker) + .not_to have_received(:perform_async).with(user.username.upcase, + badge.slug, + "", + false) end end diff --git a/spec/services/badges/award_spec.rb b/spec/services/badges/award_spec.rb index 01b86fae4..248dcb6a1 100644 --- a/spec/services/badges/award_spec.rb +++ b/spec/services/badges/award_spec.rb @@ -8,21 +8,31 @@ RSpec.describe Badges::Award, type: :service do it "awards badges" do expect do - described_class.call(User.all, "one-year-club", "Congrats on a badge!") + described_class.call(User.all, "one-year-club", "Congrats on a badge!", include_default_description: true) end.to change(BadgeAchievement, :count).by(2) end it "creates correct badge achievements" do - described_class.call(User.all, "one-year-club", "Congrats on a badge!") + described_class.call(User.all, "one-year-club", "Congrats on a badge!", include_default_description: true) expect(user.badge_achievements.pluck(:badge_id)).to eq([badge.id]) expect(user2.badge_achievements.pluck(:rewarding_context_message_markdown)) .to eq(["Congrats on a badge!"]) end + it "creates correct badge achievements without default description" do + described_class.call(User.all, "one-year-club", "Congrats on a badge!", include_default_description: false) + expect(user.badge_achievements.pluck(:include_default_description)).to eq([false]) + end + + it "creates correct badge achievements with default description" do + described_class.call(User.all, "one-year-club", "Congrats on a badge!", include_default_description: true) + expect(user.badge_achievements.pluck(:include_default_description)).to eq([true]) + end + it "doesn't award badges to spam accounts" do spammer = create(:user, username: "spam_account") - described_class.call(User.all, "one-year-club", "Congrats on a badge!") + described_class.call(User.all, "one-year-club", "Congrats on a badge!", include_default_description: true) expect(user.badge_achievements.any?).to be true expect(spammer.badge_achievements.any?).to be false end diff --git a/spec/workers/badge_achievements/badge_award_worker_spec.rb b/spec/workers/badge_achievements/badge_award_worker_spec.rb index f2227c53e..6c351ec92 100644 --- a/spec/workers/badge_achievements/badge_award_worker_spec.rb +++ b/spec/workers/badge_achievements/badge_award_worker_spec.rb @@ -15,16 +15,16 @@ RSpec.describe BadgeAchievements::BadgeAwardWorker, type: :worker do it "sends badge email" do relation = User.none allow(User).to receive(:where).with(username: ["jess"]).and_return(relation) - worker.perform(["jess"], "test", "yo") + worker.perform(["jess"], "test", "yo", false) - expect(Badges::Award).to have_received(:call).with(relation, "test", "yo") + expect(Badges::Award).to have_received(:call).with(relation, "test", "yo", include_default_description: false) end end context "with predefined badge_slug" do it "sends badge email" do allow(Badges::AwardYearlyClub).to receive(:call) - worker.perform([], "award_yearly_club", "") + worker.perform([], "award_yearly_club", "", true) expect(Badges::AwardYearlyClub).to have_received(:call) expect(Badges::Award).not_to have_received(:call)