discourse/app/jobs/regular/export_csv_file.rb

162 lines
4.4 KiB
Ruby

require 'csv'
require_dependency 'system_message'
module Jobs
class ExportCsvFile < Jobs::Base
CSV_USER_ATTRS = ['id','name','username','email','title','created_at','trust_level','active','admin','moderator','ip_address']
CSV_USER_STATS = ['topics_entered','posts_read_count','time_read','topic_count','post_count','likes_given','likes_received']
CSV_USER_SSO_ATTRS = ['external_id','external_email', 'external_username', 'external_name', 'external_avatar_url']
SCREENED_IP_ATTRS = ['ip_address','action_type','match_count','last_match_at','created_at']
sidekiq_options retry: false
attr_accessor :current_user
def initialize
@file_name = ""
end
def execute(args)
entity = args[:entity]
@current_user = User.find_by(id: args[:user_id])
data =
if entity == 'user'
user_export
elsif entity == 'screened_ips'
screened_ips_export
else
raise Discourse::InvalidParameters.new(:entity) if entity.blank?
end
if data && data.length > 0
set_file_path
header = get_header(entity)
write_csv_file(data, header)
end
notify_user
end
def user_export
query = ::AdminUserIndexQuery.new
user_data = query.find_users_query.to_a
user_data.map do |user|
group_names = get_group_names(user).join(';')
user_array = get_user_fields(user)
user_array.push(group_names) if group_names != ''
user_array
end
end
def screened_ips_export
screened_ips_data = ScreenedIpAddress.order('id desc').to_a
screened_ips_data.map do |screened_ip|
get_screened_ip_fields(screened_ip)
end
end
def get_header(entity)
case entity
when 'user'
header_array = CSV_USER_ATTRS + CSV_USER_STATS
if SiteSetting.enable_sso
header_array.concat(CSV_USER_SSO_ATTRS)
end
user_custom_fields = UserField.all
if user_custom_fields.present?
user_custom_fields.each do |custom_field|
header_array.push("#{custom_field.name} (custom user field)")
end
end
header_array.push("group_names")
when 'screened_ips'
header_array = SCREENED_IP_ATTRS
end
header_array
end
private
def get_group_names(user)
group_names = []
groups = user.groups
groups.each do |group|
group_names.push(group.name)
end
return group_names
end
def get_user_fields(user)
user_array = []
CSV_USER_ATTRS.each do |attr|
user_array.push(user.attributes[attr])
end
CSV_USER_STATS.each do |stat|
user_array.push(user.user_stat.attributes[stat])
end
if SiteSetting.enable_sso
sso = user.single_sign_on_record
CSV_USER_SSO_ATTRS.each do |stat|
field = sso.attributes[stat] if sso
user_array.push(field)
end
end
if user.user_fields.present?
user.user_fields.each do |custom_field|
user_array.push(custom_field[1])
end
end
user_array
end
def get_screened_ip_fields(screened_ip)
screened_ip_array = []
SCREENED_IP_ATTRS.each do |attr|
screened_ip_array.push(screened_ip.attributes[attr])
end
screened_ip_array
end
def set_file_path
@file_name = "export_#{SecureRandom.hex(4)}.csv"
# ensure directory exists
dir = File.dirname("#{ExportCsv.base_directory}/#{@file_name}")
FileUtils.mkdir_p(dir) unless Dir.exists?(dir)
end
def write_csv_file(data, header)
# write to CSV file
CSV.open(File.expand_path("#{ExportCsv.base_directory}/#{@file_name}", __FILE__), "w") do |csv|
csv << header
data.each do |value|
csv << value
end
end
end
def notify_user
if @current_user
if @file_name != "" && File.exists?("#{ExportCsv.base_directory}/#{@file_name}")
SystemMessage.create_from_system_user(@current_user, :csv_export_succeeded, download_link: "#{Discourse.base_url}/admin/export_csv/#{@file_name}", file_name: @file_name)
else
SystemMessage.create_from_system_user(@current_user, :csv_export_failed)
end
end
end
end
end