discourse/app/jobs/regular/bulk_invite.rb
Dan Ungureanu e704f0a541
FIX: Autocorrect values for dropdown imported user fields (#12572)
When bulk inviting, the uploaded CSV file may contain wrong values for
the user fields. This tries to automatically correct them by finding
the most similar option (by ignoring the case).
2021-03-31 19:19:57 +03:00

214 lines
5.2 KiB
Ruby

# frozen_string_literal: true
module Jobs
class BulkInvite < ::Jobs::Base
sidekiq_options retry: false
def initialize
super
@logs = []
@sent = 0
@failed = 0
@groups = {}
@user_fields = {}
@valid_groups = {}
end
def execute(args)
@invites = args[:invites]
raise Discourse::InvalidParameters.new(:invites) if @invites.blank?
@current_user = User.find_by(id: args[:current_user_id])
raise Discourse::InvalidParameters.new(:current_user_id) unless @current_user
@guardian = Guardian.new(@current_user)
process_invites(@invites)
if @invites.length > Invite::BULK_INVITE_EMAIL_LIMIT
::Jobs.enqueue(:process_bulk_invite_emails)
end
ensure
notify_user
end
private
def process_invites(invites)
invites.each do |invite|
if (EmailValidator.email_regex =~ invite[:email])
# email is valid
send_invite(invite)
@sent += 1
else
# invalid email
save_log "Invalid Email '#{invite[:email]}"
@failed += 1
end
end
rescue Exception => e
save_log "Bulk Invite Process Failed -- '#{e.message}'"
@failed += 1
end
def get_groups(group_names)
groups = []
if group_names
group_names = group_names.split(';')
group_names.each { |group_name|
group = fetch_group(group_name)
if group && can_edit_group?(group)
# valid group
groups.push(group)
else
# invalid group
save_log "Invalid Group '#{group_name}'"
@failed += 1
end
}
end
groups
end
def get_topic(topic_id)
topic = nil
if topic_id
topic = Topic.find_by_id(topic_id)
if topic.nil?
save_log "Invalid Topic ID '#{topic_id}'"
@failed += 1
end
end
topic
end
def get_user_fields(fields)
user_fields = {}
fields.each do |key, value|
@user_fields[key] ||= UserField.includes(:user_field_options).where('name ILIKE ?', key).first || :nil
next if @user_fields[key] == :nil
# Automatically correct user field value
if @user_fields[key].field_type == "dropdown"
value = @user_fields[key].user_field_options.find { |ufo| ufo.value.casecmp?(value) }&.value
end
user_fields[@user_fields[key].id] = value
end
user_fields
end
def send_invite(invite)
email = invite[:email]
groups = get_groups(invite[:groups])
topic = get_topic(invite[:topic_id])
user_fields = get_user_fields(invite.except(:email, :groups, :topic_id))
begin
if user = Invite.find_user_by_email(email)
if groups.present?
Group.transaction do
groups.each do |group|
group.add(user)
GroupActionLogger
.new(@current_user, group)
.log_add_user_to_group(user)
end
end
end
if user_fields.present?
user_fields.each do |user_field, value|
user.set_user_field(user_field, value)
end
user.save_custom_fields
end
else
if user_fields.present?
user = User.where(staged: true).find_by_email(email)
user ||= User.new(username: UserNameSuggester.suggest(email), email: email, staged: true)
user_fields.each do |user_field, value|
user.set_user_field(user_field, value)
end
user.save!
end
invite_opts = {
email: email,
topic: topic,
group_ids: groups.map(&:id),
}
if @invites.length > Invite::BULK_INVITE_EMAIL_LIMIT
invite_opts[:emailed_status] = Invite.emailed_status_types[:bulk_pending]
end
Invite.generate(@current_user, invite_opts)
end
rescue => e
save_log "Error inviting '#{email}' -- #{Rails::Html::FullSanitizer.new.sanitize(e.message)}"
@sent -= 1
@failed += 1
end
end
def save_log(message)
@logs << "[#{Time.now}] #{message}"
end
def notify_user
if @current_user
if (@sent > 0 && @failed == 0)
SystemMessage.create_from_system_user(
@current_user,
:bulk_invite_succeeded,
sent: @sent
)
else
SystemMessage.create_from_system_user(
@current_user,
:bulk_invite_failed,
sent: @sent,
failed: @failed,
logs: @logs.join("\n")
)
end
end
end
def fetch_group(group_name)
group_name = group_name.downcase
group = @groups[group_name]
unless group
group = Group.find_by('lower(name) = ?', group_name)
@groups[group_name] = group
end
group
end
def can_edit_group?(group)
group_name = group.name.downcase
result = @valid_groups[group_name]
unless result
result = @guardian.can_edit_group?(group)
@valid_groups[group_name] = result
end
result
end
end
end