diff --git a/app/assets/javascripts/admin/controllers/admin-badges-award.js.es6 b/app/assets/javascripts/admin/controllers/admin-badges-award.js.es6
index af3afd528b1..ef141ccac12 100644
--- a/app/assets/javascripts/admin/controllers/admin-badges-award.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-badges-award.js.es6
@@ -4,6 +4,7 @@ import { popupAjaxError } from "discourse/lib/ajax-error";
export default Controller.extend({
saving: false,
+ replaceBadgeOwners: false,
actions: {
massAward() {
@@ -18,6 +19,7 @@ export default Controller.extend({
};
options.data.append("file", file);
+ options.data.append("replace_badge_owners", this.replaceBadgeOwners);
this.set("saving", true);
diff --git a/app/assets/javascripts/admin/templates/badges-award.hbs b/app/assets/javascripts/admin/templates/badges-award.hbs
index 66ef70365a9..d7a24e0651c 100644
--- a/app/assets/javascripts/admin/templates/badges-award.hbs
+++ b/app/assets/javascripts/admin/templates/badges-award.hbs
@@ -16,6 +16,12 @@
{{I18n 'admin.badges.mass_award.upload_csv'}}
+
+
+
{{d-button
class="btn-primary"
action=(action 'massAward')
diff --git a/app/controllers/admin/badges_controller.rb b/app/controllers/admin/badges_controller.rb
index a63d33bda64..f494fb921ef 100644
--- a/app/controllers/admin/badges_controller.rb
+++ b/app/controllers/admin/badges_controller.rb
@@ -43,6 +43,9 @@ class Admin::BadgesController < Admin::AdminController
badge = Badge.find_by(id: params[:badge_id])
raise Discourse::InvalidParameters if csv_file.try(:tempfile).nil? || badge.nil?
+ replace_badge_owners = params[:replace_badge_owners] == 'true'
+ BadgeGranter.revoke_all(badge) if replace_badge_owners
+
batch_number = 1
line_number = 1
batch = []
diff --git a/app/services/badge_granter.rb b/app/services/badge_granter.rb
index 620e3cd0b17..18dc48493ff 100644
--- a/app/services/badge_granter.rb
+++ b/app/services/badge_granter.rb
@@ -104,6 +104,16 @@ class BadgeGranter
end
end
+ def self.revoke_all(badge)
+ custom_badge_names = TranslationOverride.where(translation_key: badge.translation_key).pluck(:value)
+
+ users = User.joins(:user_badges).where(user_badges: { badge_id: badge.id }).where(title: badge.name)
+ users = users.or(User.joins(:user_badges).where(title: custom_badge_names)) unless custom_badge_names.empty?
+ users.update_all(title: nil)
+
+ UserBadge.where(badge: badge).delete_all
+ end
+
def self.queue_badge_grant(type, opt)
return unless SiteSetting.enable_badges
payload = nil
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index b447c667577..e22d930491d 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -4505,6 +4505,7 @@ en:
upload_csv: Upload a CSV with user emails
aborted: Please upload a CSV containing user emails
success: Your CSV was received and users will receive their badge shortly.
+ replace_owners: Remove the badge from previous owners
emoji:
title: "Emoji"
diff --git a/spec/services/badge_granter_spec.rb b/spec/services/badge_granter_spec.rb
index e91b755e628..6bfd968e4ca 100644
--- a/spec/services/badge_granter_spec.rb
+++ b/spec/services/badge_granter_spec.rb
@@ -225,6 +225,39 @@ describe BadgeGranter do
end
end
+ describe 'revoke_all' do
+ it 'deletes every user_badge record associated with that badge' do
+ described_class.grant(badge, user)
+
+ described_class.revoke_all(badge)
+
+ expect(UserBadge.exists?(badge: badge, user: user)).to eq(false)
+ end
+
+ it 'removes titles' do
+ another_title = 'another title'
+ described_class.grant(badge, user)
+ user.update!(title: badge.name)
+ user2 = Fabricate(:user, title: another_title)
+
+ described_class.revoke_all(badge)
+
+ expect(user.reload.title).to be_nil
+ expect(user2.reload.title).to eq(another_title)
+ end
+
+ it 'removes custom badge titles' do
+ custom_badge_title = 'this is a badge title'
+ TranslationOverride.create!(translation_key: badge.translation_key, value: custom_badge_title, locale: 'en_US')
+ described_class.grant(badge, user)
+ user.update!(title: custom_badge_title)
+
+ described_class.revoke_all(badge)
+
+ expect(user.reload.title).to be_nil
+ end
+ end
+
context "update_badges" do
fab!(:user) { Fabricate(:user) }
fab!(:liker) { Fabricate(:user) }