From 9441362c7272fc5ac5ac519f7d3fcb7e2acf3607 Mon Sep 17 00:00:00 2001 From: Roman Rizzi Date: Tue, 18 Feb 2020 10:53:12 -0300 Subject: [PATCH] FEATURE: Support uploading a csv with either user emails or usernames (#8971) --- app/controllers/admin/badges_controller.rb | 5 ++++- app/jobs/regular/mass_award_badge.rb | 10 +++++++++- config/locales/client.en.yml | 4 ++-- spec/fixtures/csv/usernames.csv | 3 +++ spec/jobs/mass_award_badge_spec.rb | 13 +++++++++---- spec/requests/admin/badges_controller_spec.rb | 13 ++++++++++++- 6 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 spec/fixtures/csv/usernames.csv diff --git a/app/controllers/admin/badges_controller.rb b/app/controllers/admin/badges_controller.rb index f494fb921ef..2c1846d3dae 100644 --- a/app/controllers/admin/badges_controller.rb +++ b/app/controllers/admin/badges_controller.rb @@ -51,6 +51,9 @@ class Admin::BadgesController < Admin::AdminController batch = [] File.open(csv_file) do |csv| + mode = Email.is_valid?(CSV.parse_line(csv.first).first) ? 'email' : 'username' + csv.rewind + csv.each_line do |email_line| batch.concat CSV.parse_line(email_line) line_number += 1 @@ -60,7 +63,7 @@ class Admin::BadgesController < Admin::AdminController last_batch_item = full_batch || csv.eof? if last_batch_item - Jobs.enqueue(:mass_award_badge, user_emails: batch, badge_id: badge.id) + Jobs.enqueue(:mass_award_badge, users_batch: batch, badge_id: badge.id, mode: mode) batch = [] batch_number += 1 end diff --git a/app/jobs/regular/mass_award_badge.rb b/app/jobs/regular/mass_award_badge.rb index ae6db5f6f51..ef512899177 100644 --- a/app/jobs/regular/mass_award_badge.rb +++ b/app/jobs/regular/mass_award_badge.rb @@ -3,8 +3,16 @@ module Jobs class MassAwardBadge < ::Jobs::Base def execute(args) + return unless mode = args[:mode] badge = Badge.find_by(id: args[:badge_id]) - users = User.select(:id, :username, :locale).with_email(args[:user_emails]) + + users = User.select(:id, :username, :locale) + + if mode == 'email' + users = users.with_email(args[:users_batch]) + else + users = users.where(username_lower: args[:users_batch].map!(&:downcase)) + end return if users.empty? || badge.nil? diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 408b32075d7..1211978b667 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -4502,8 +4502,8 @@ en: description: Award the same badge to many users at once. no_badge_selected: Please select a badge to get started. perform: "Award Badge to Users" - upload_csv: Upload a CSV with user emails - aborted: Please upload a CSV containing user emails + upload_csv: Upload a CSV with either user emails or usernames + aborted: Please upload a CSV containing either user emails or usernames success: Your CSV was received and users will receive their badge shortly. replace_owners: Remove the badge from previous owners diff --git a/spec/fixtures/csv/usernames.csv b/spec/fixtures/csv/usernames.csv new file mode 100644 index 00000000000..93c2848626a --- /dev/null +++ b/spec/fixtures/csv/usernames.csv @@ -0,0 +1,3 @@ +username1 +username2 +username3 \ No newline at end of file diff --git a/spec/jobs/mass_award_badge_spec.rb b/spec/jobs/mass_award_badge_spec.rb index b617a2e49b6..3fcff6faa9c 100644 --- a/spec/jobs/mass_award_badge_spec.rb +++ b/spec/jobs/mass_award_badge_spec.rb @@ -6,9 +6,10 @@ describe Jobs::MassAwardBadge do describe '#execute' do fab!(:badge) { Fabricate(:badge) } fab!(:user) { Fabricate(:user) } + let(:email_mode) { 'email' } it 'creates the badge for an existing user' do - subject.execute(user_emails: [user.email], badge_id: badge.id) + execute_job([user.email]) expect(UserBadge.where(user: user, badge: badge).exists?).to eq(true) end @@ -16,14 +17,14 @@ describe Jobs::MassAwardBadge do it 'works with multiple users' do user_2 = Fabricate(:user) - subject.execute(user_emails: [user.email, user_2.email], badge_id: badge.id) + execute_job([user.email, user_2.email]) expect(UserBadge.exists?(user: user, badge: badge)).to eq(true) expect(UserBadge.exists?(user: user_2, badge: badge)).to eq(true) end it 'also creates a notification for the user' do - subject.execute(user_emails: [user.email], badge_id: badge.id) + execute_job([user.email]) expect(Notification.exists?(user: user)).to eq(true) expect(UserBadge.where.not(notification_id: nil).exists?(user: user, badge: badge)).to eq(true) @@ -34,10 +35,14 @@ describe Jobs::MassAwardBadge do UserBadge.create!(badge_id: Badge::Member, user: user, granted_by: Discourse.system_user, granted_at: Time.now) - subject.execute(user_emails: [user.email, user_2.email], badge_id: badge.id) + execute_job([user.email, user_2.email]) expect(UserBadge.find_by(user: user, badge: badge).featured_rank).to eq(2) expect(UserBadge.find_by(user: user_2, badge: badge).featured_rank).to eq(1) end + + def execute_job(emails) + subject.execute(users_batch: emails, badge_id: badge.id, mode: 'email') + end end end diff --git a/spec/requests/admin/badges_controller_spec.rb b/spec/requests/admin/badges_controller_spec.rb index 15d27bf2fd1..06d294bcc0d 100644 --- a/spec/requests/admin/badges_controller_spec.rb +++ b/spec/requests/admin/badges_controller_spec.rb @@ -199,7 +199,7 @@ describe Admin::BadgesController do expect(response.status).to eq(400) end - it 'creates the badge for an existing user' do + it 'awards the badge using a list of user emails' do Jobs.run_immediately! user = Fabricate(:user, email: 'user1@test.com') @@ -209,6 +209,17 @@ describe Admin::BadgesController do expect(UserBadge.exists?(user: user, badge: badge)).to eq(true) end + + it 'awards the badge using a list of usernames' do + Jobs.run_immediately! + + user = Fabricate(:user, username: 'username1') + file = file_from_fixtures('usernames.csv', 'csv') + + post "/admin/badges/award/#{badge.id}.json", params: { file: fixture_file_upload(file) } + + expect(UserBadge.exists?(user: user, badge: badge)).to eq(true) + end end end end