FEATURE: Replace existing badge owners when using the bulk award feature (#8770)

* FEATURE: Replace existing badge owners when using the bulk award feature

* Use ActiveRecord to sanitize title update query, Change replace checkbox text

Co-Authored-By: Robin Ward <robin.ward@gmail.com>

Co-authored-by: Robin Ward <robin.ward@gmail.com>
This commit is contained in:
Roman Rizzi 2020-01-23 14:14:58 -03:00 committed by GitHub
parent db5373a87c
commit 9eb622985a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 55 additions and 0 deletions

View File

@ -4,6 +4,7 @@ import { popupAjaxError } from "discourse/lib/ajax-error";
export default Controller.extend({ export default Controller.extend({
saving: false, saving: false,
replaceBadgeOwners: false,
actions: { actions: {
massAward() { massAward() {
@ -18,6 +19,7 @@ export default Controller.extend({
}; };
options.data.append("file", file); options.data.append("file", file);
options.data.append("replace_badge_owners", this.replaceBadgeOwners);
this.set("saving", true); this.set("saving", true);

View File

@ -16,6 +16,12 @@
<h4>{{I18n 'admin.badges.mass_award.upload_csv'}}</h4> <h4>{{I18n 'admin.badges.mass_award.upload_csv'}}</h4>
<input type='file' id='massAwardCSVUpload' accept='.csv' /> <input type='file' id='massAwardCSVUpload' accept='.csv' />
</div> </div>
<div>
<label>
{{input type="checkbox" checked=replaceBadgeOwners}}
{{i18n 'admin.badges.mass_award.replace_owners'}}
</label>
</div>
{{d-button {{d-button
class="btn-primary" class="btn-primary"
action=(action 'massAward') action=(action 'massAward')

View File

@ -43,6 +43,9 @@ class Admin::BadgesController < Admin::AdminController
badge = Badge.find_by(id: params[:badge_id]) badge = Badge.find_by(id: params[:badge_id])
raise Discourse::InvalidParameters if csv_file.try(:tempfile).nil? || badge.nil? 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 batch_number = 1
line_number = 1 line_number = 1
batch = [] batch = []

View File

@ -104,6 +104,16 @@ class BadgeGranter
end end
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) def self.queue_badge_grant(type, opt)
return unless SiteSetting.enable_badges return unless SiteSetting.enable_badges
payload = nil payload = nil

View File

@ -4505,6 +4505,7 @@ en:
upload_csv: Upload a CSV with user emails upload_csv: Upload a CSV with user emails
aborted: Please upload a CSV containing user emails aborted: Please upload a CSV containing user emails
success: Your CSV was received and users will receive their badge shortly. success: Your CSV was received and users will receive their badge shortly.
replace_owners: Remove the badge from previous owners
emoji: emoji:
title: "Emoji" title: "Emoji"

View File

@ -225,6 +225,39 @@ describe BadgeGranter do
end end
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 context "update_badges" do
fab!(:user) { Fabricate(:user) } fab!(:user) { Fabricate(:user) }
fab!(:liker) { Fabricate(:user) } fab!(:liker) { Fabricate(:user) }