2014-08-09 06:28:57 -04:00
require 'csv'
require_dependency 'system_message'
module Jobs
class ExportCsvFile < Jobs :: Base
2015-01-19 08:51:53 -05:00
include ActionView :: Helpers :: NumberHelper
2014-12-06 23:15:22 -05:00
HEADER_ATTRS_FOR = { }
2014-12-29 06:58:33 -05:00
HEADER_ATTRS_FOR [ 'user_archive' ] = [ 'topic_title' , 'category' , 'sub_category' , 'is_pm' , 'post' , 'like_count' , 'reply_count' , 'url' , 'created_at' ]
2015-07-15 01:58:02 -04:00
HEADER_ATTRS_FOR [ 'user_list' ] = [ 'id' , 'name' , 'username' , 'email' , 'title' , 'created_at' , 'last_seen_at' , 'last_posted_at' , 'last_emailed_at' , 'trust_level' , 'approved' , 'suspended_at' , 'suspended_till' , 'blocked' , 'active' , 'admin' , 'moderator' , 'ip_address' ]
2014-12-06 23:15:22 -05:00
HEADER_ATTRS_FOR [ 'user_stats' ] = [ 'topics_entered' , 'posts_read_count' , 'time_read' , 'topic_count' , 'post_count' , 'likes_given' , 'likes_received' ]
HEADER_ATTRS_FOR [ 'user_sso' ] = [ 'external_id' , 'external_email' , 'external_username' , 'external_name' , 'external_avatar_url' ]
HEADER_ATTRS_FOR [ 'staff_action' ] = [ 'staff_user' , 'action' , 'subject' , 'created_at' , 'details' , 'context' ]
HEADER_ATTRS_FOR [ 'screened_email' ] = [ 'email' , 'action' , 'match_count' , 'last_match_at' , 'created_at' , 'ip_address' ]
HEADER_ATTRS_FOR [ 'screened_ip' ] = [ 'ip_address' , 'action' , 'match_count' , 'last_match_at' , 'created_at' ]
HEADER_ATTRS_FOR [ 'screened_url' ] = [ 'domain' , 'action' , 'match_count' , 'last_match_at' , 'created_at' ]
2015-09-15 16:45:01 -04:00
HEADER_ATTRS_FOR [ 'report' ] = [ 'date' , 'value' ]
2014-11-19 12:09:23 -05:00
2014-08-09 06:28:57 -04:00
sidekiq_options retry : false
attr_accessor :current_user
def execute ( args )
2015-01-14 11:00:51 -05:00
@entity = args [ :entity ]
2015-09-15 16:45:01 -04:00
@extra = HashWithIndifferentAccess . new ( args [ :args ] ) if args [ :args ]
2015-01-14 11:00:51 -05:00
@file_name = @entity
2014-08-09 06:28:57 -04:00
@current_user = User . find_by ( id : args [ :user_id ] )
2015-01-14 11:00:51 -05:00
export_method = " #{ @entity } _export " . to_sym
2014-11-25 17:43:17 -05:00
data =
2014-12-06 23:15:22 -05:00
if respond_to? ( export_method )
send ( export_method )
2014-11-25 17:43:17 -05:00
else
2014-12-06 23:15:22 -05:00
raise Discourse :: InvalidParameters . new ( :entity )
2014-11-25 17:43:17 -05:00
end
2014-08-09 06:28:57 -04:00
if data && data . length > 0
set_file_path
2015-01-14 11:00:51 -05:00
write_csv_file ( data )
2014-08-09 06:28:57 -04:00
end
2014-12-29 06:58:33 -05:00
ensure
2014-08-09 06:28:57 -04:00
notify_user
end
2014-12-22 11:17:04 -05:00
def user_archive_export
2016-02-05 10:16:33 -05:00
user_archive_data = Post . includes ( :topic = > :category ) . where ( user_id : @current_user . id ) . select ( :topic_id , :post_number , :raw , :like_count , :reply_count , :created_at ) . order ( :created_at ) . with_deleted . to_a
2014-12-22 11:17:04 -05:00
user_archive_data . map do | user_archive |
get_user_archive_fields ( user_archive )
end
end
2015-01-02 01:59:05 -05:00
def user_list_export
2015-11-02 00:31:08 -05:00
user_array = [ ]
user_field_ids = UserField . pluck ( :id )
2016-03-07 08:17:10 -05:00
condition = { }
if @extra && @extra [ :trust_level ] && trust_level = TrustLevel . levels [ @extra [ :trust_level ] . to_sym ]
condition = { trust_level : trust_level }
end
2015-11-02 00:31:08 -05:00
if SiteSetting . enable_sso
# SSO enabled
2016-03-07 08:17:10 -05:00
User . where ( condition ) . includes ( :user_stat , :single_sign_on_record , :groups ) . find_each do | user |
2016-02-05 10:16:33 -05:00
user_info_string = get_base_user_string ( user )
user_info_string = add_single_sign_on ( user , user_info_string )
user_info_string = add_custom_fields ( user , user_info_string , user_field_ids )
user_info_string = add_group_names ( user , user_info_string )
2015-11-02 00:31:08 -05:00
user_array . push ( user_info_string . split ( " , " ) )
user_info_string = nil
end
else
# SSO disabled
2016-03-07 08:17:10 -05:00
User . where ( condition ) . includes ( :user_stat , :groups ) . find_each do | user |
2016-02-05 10:16:33 -05:00
user_info_string = get_base_user_string ( user )
user_info_string = add_custom_fields ( user , user_info_string , user_field_ids )
user_info_string = add_group_names ( user , user_info_string )
2015-11-02 00:31:08 -05:00
user_array . push ( user_info_string . split ( " , " ) )
user_info_string = nil
end
2014-11-25 17:43:17 -05:00
end
2015-11-02 00:31:08 -05:00
user_field_ids = nil
user_array
2014-11-25 17:43:17 -05:00
end
2014-12-06 23:15:22 -05:00
def staff_action_export
2015-01-02 00:33:14 -05:00
if @current_user . admin?
staff_action_data = UserHistory . only_staff_actions . order ( 'id DESC' ) . to_a
else
# moderator
staff_action_data = UserHistory . where ( admin_only : false ) . only_staff_actions . order ( 'id DESC' ) . to_a
end
2014-12-06 23:15:22 -05:00
staff_action_data . map do | staff_action |
get_staff_action_fields ( staff_action )
end
end
2014-11-25 17:43:17 -05:00
2014-12-06 23:15:22 -05:00
def screened_email_export
screened_email_data = ScreenedEmail . order ( 'last_match_at desc' ) . to_a
screened_email_data . map do | screened_email |
get_screened_email_fields ( screened_email )
end
end
def screened_ip_export
screened_ip_data = ScreenedIpAddress . order ( 'id desc' ) . to_a
screened_ip_data . map do | screened_ip |
2014-11-25 17:43:17 -05:00
get_screened_ip_fields ( screened_ip )
end
end
2014-12-06 23:15:22 -05:00
def screened_url_export
screened_url_data = ScreenedUrl . select ( " domain, sum(match_count) as match_count, max(last_match_at) as last_match_at, min(created_at) as created_at " ) . group ( :domain ) . order ( 'last_match_at DESC' ) . to_a
screened_url_data . map do | screened_url |
get_screened_url_fields ( screened_url )
end
end
2015-09-15 16:45:01 -04:00
def report_export
@extra [ :start_date ] = @extra [ :start_date ] . to_date if @extra [ :start_date ] . is_a? ( String )
@extra [ :end_date ] = @extra [ :end_date ] . to_date if @extra [ :end_date ] . is_a? ( String )
@extra [ :category_id ] = @extra [ :category_id ] . to_i if @extra [ :category_id ]
2016-02-02 21:29:51 -05:00
@extra [ :group_id ] = @extra [ :group_id ] . to_i if @extra [ :group_id ]
2015-09-15 16:45:01 -04:00
r = Report . find ( @extra [ :name ] , @extra )
r . data . map do | row |
[ row [ :x ] . to_s ( :db ) , row [ :y ] . to_s ( :db ) ]
end
end
2015-01-14 11:00:51 -05:00
def get_header
2014-11-25 17:43:17 -05:00
2015-01-14 11:00:51 -05:00
case @entity
2015-01-14 05:47:22 -05:00
when 'user_list'
header_array = HEADER_ATTRS_FOR [ 'user_list' ] + HEADER_ATTRS_FOR [ 'user_stats' ]
2014-11-25 17:43:17 -05:00
if SiteSetting . enable_sso
2014-12-06 23:15:22 -05:00
header_array . concat ( HEADER_ATTRS_FOR [ 'user_sso' ] )
2014-11-25 17:43:17 -05:00
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 " )
2014-12-06 23:15:22 -05:00
else
2015-01-14 11:00:51 -05:00
header_array = HEADER_ATTRS_FOR [ @entity ]
2014-12-06 23:15:22 -05:00
end
2014-11-25 17:43:17 -05:00
header_array
end
2014-08-09 06:28:57 -04:00
private
2016-02-05 10:16:33 -05:00
def get_base_user_string ( user )
" #{ user . id } , #{ user . name } , #{ user . username } , #{ user . email } , #{ user . title } , #{ user . created_at } , #{ user . last_seen_at } , #{ user . last_posted_at } , #{ user . last_emailed_at } , #{ user . trust_level } , #{ user . approved } , #{ user . suspended_at } , #{ user . suspended_till } , #{ user . blocked } , #{ user . active } , #{ user . admin } , #{ user . moderator } , #{ user . ip_address } , #{ user . user_stat . topics_entered } , #{ user . user_stat . posts_read_count } , #{ user . user_stat . time_read } , #{ user . user_stat . topic_count } , #{ user . user_stat . post_count } , #{ user . user_stat . likes_given } , #{ user . user_stat . likes_received } "
end
def add_single_sign_on ( user , user_info_string )
if user . single_sign_on_record
user_info_string << " , #{ user . single_sign_on_record . external_id } , #{ user . single_sign_on_record . external_email } , #{ user . single_sign_on_record . external_username } , #{ user . single_sign_on_record . external_name } , #{ user . single_sign_on_record . external_avatar_url } "
else
user_info_string << " ,nil,nil,nil,nil,nil "
end
user_info_string
end
def add_custom_fields ( user , user_info_string , user_field_ids )
if user_field_ids . present?
user . user_fields . each do | custom_field |
user_info_string << " , #{ custom_field [ 1 ] } "
end
end
user_info_string
end
def add_group_names ( user , user_info_string )
group_names = user . groups . each_with_object ( " " ) do | group , names |
names << " #{ group . name } ; "
end
user_info_string << " , #{ group_names [ 0 .. - 2 ] } " unless group_names . blank?
group_names = nil
user_info_string
end
2014-12-22 11:17:04 -05:00
def get_user_archive_fields ( user_archive )
user_archive_array = [ ]
2014-12-29 06:58:33 -05:00
topic_data = user_archive . topic
user_archive = user_archive . as_json
2015-05-17 23:37:12 -04:00
topic_data = Topic . with_deleted . find_by ( id : user_archive [ 'topic_id' ] ) if topic_data . nil?
return user_archive_array if topic_data . nil?
category = topic_data . category
2014-12-29 06:58:33 -05:00
sub_category = " - "
if category
category_name = category . name
if ! category . parent_category_id . nil?
# sub category
category_name = Category . find_by ( id : category . parent_category_id ) . name
sub_category = category . name
end
else
# PM
category_name = " - "
end
is_pm = topic_data . archetype == " private_message " ? I18n . t ( " csv_export.boolean_yes " ) : I18n . t ( " csv_export.boolean_no " )
2015-11-25 04:43:15 -05:00
url = " #{ Discourse . base_url } /t/ #{ topic_data . slug } / #{ topic_data . id } / #{ user_archive [ 'post_number' ] } "
2014-12-29 06:58:33 -05:00
topic_hash = { " post " = > user_archive [ 'raw' ] , " topic_title " = > topic_data . title , " category " = > category_name , " sub_category " = > sub_category , " is_pm " = > is_pm , " url " = > url }
user_archive . merge! ( topic_hash )
2014-12-22 11:17:04 -05:00
HEADER_ATTRS_FOR [ 'user_archive' ] . each do | attr |
2014-12-29 06:58:33 -05:00
user_archive_array . push ( user_archive [ attr ] )
2014-12-22 11:17:04 -05:00
end
user_archive_array
end
2014-12-06 23:15:22 -05:00
def get_staff_action_fields ( staff_action )
staff_action_array = [ ]
HEADER_ATTRS_FOR [ 'staff_action' ] . each do | attr |
data =
if attr == 'action'
UserHistory . actions . key ( staff_action . attributes [ attr ] ) . to_s
elsif attr == 'staff_user'
user = User . find_by ( id : staff_action . attributes [ 'acting_user_id' ] )
user . username if ! user . nil?
2016-04-19 08:32:01 -04:00
elsif attr == 'subject'
user = User . find_by ( id : staff_action . attributes [ 'target_user_id' ] )
user . nil? ? staff_action . attributes [ attr ] : " #{ user . username } #{ staff_action . attributes [ attr ] } "
2014-12-06 23:15:22 -05:00
else
staff_action . attributes [ attr ]
end
staff_action_array . push ( data )
end
staff_action_array
end
def get_screened_email_fields ( screened_email )
screened_email_array = [ ]
HEADER_ATTRS_FOR [ 'screened_email' ] . each do | attr |
data =
if attr == 'action'
ScreenedEmail . actions . key ( screened_email . attributes [ 'action_type' ] ) . to_s
else
screened_email . attributes [ attr ]
end
screened_email_array . push ( data )
end
screened_email_array
end
2014-11-21 10:25:04 -05:00
def get_screened_ip_fields ( screened_ip )
screened_ip_array = [ ]
2014-11-12 03:42:50 -05:00
2014-12-06 23:15:22 -05:00
HEADER_ATTRS_FOR [ 'screened_ip' ] . each do | attr |
data =
if attr == 'action'
ScreenedIpAddress . actions . key ( screened_ip . attributes [ 'action_type' ] ) . to_s
else
screened_ip . attributes [ attr ]
end
screened_ip_array . push ( data )
2014-11-21 10:25:04 -05:00
end
2014-11-25 17:43:17 -05:00
screened_ip_array
2014-12-06 23:15:22 -05:00
end
def get_screened_url_fields ( screened_url )
screened_url_array = [ ]
HEADER_ATTRS_FOR [ 'screened_url' ] . each do | attr |
data =
if attr == 'action'
action = ScreenedUrl . actions . key ( screened_url . attributes [ 'action_type' ] ) . to_s
action = " do nothing " if action . blank?
else
screened_url . attributes [ attr ]
end
screened_url_array . push ( data )
end
screened_url_array
2014-11-21 10:25:04 -05:00
end
2014-11-12 03:42:50 -05:00
2014-08-09 06:28:57 -04:00
def set_file_path
2015-01-15 12:30:59 -05:00
if @entity == " user_archive "
file_name_prefix = " #{ @file_name . split ( '_' ) . join ( '-' ) } - #{ current_user . username } - #{ Time . now . strftime ( " %y%m%d-%H%M%S " ) } "
else
file_name_prefix = " #{ @file_name . split ( '_' ) . join ( '-' ) } - #{ Time . now . strftime ( " %y%m%d-%H%M%S " ) } "
end
@file = UserExport . create ( file_name : file_name_prefix , user_id : @current_user . id )
2015-01-02 01:59:05 -05:00
@file_name = " #{ file_name_prefix } - #{ @file . id } .csv "
2014-12-28 11:13:49 -05:00
2014-08-09 06:28:57 -04:00
# ensure directory exists
2014-12-28 11:13:49 -05:00
dir = File . dirname ( " #{ UserExport . base_directory } / #{ @file_name } " )
2014-08-09 06:28:57 -04:00
FileUtils . mkdir_p ( dir ) unless Dir . exists? ( dir )
end
2015-01-14 11:00:51 -05:00
def write_csv_file ( data )
2014-08-09 06:28:57 -04:00
# write to CSV file
2014-12-28 11:13:49 -05:00
CSV . open ( File . expand_path ( " #{ UserExport . base_directory } / #{ @file_name } " , __FILE__ ) , " w " ) do | csv |
2015-01-14 11:00:51 -05:00
csv << get_header
2014-08-09 06:28:57 -04:00
data . each do | value |
2014-08-15 13:53:17 -04:00
csv << value
2014-08-09 06:28:57 -04:00
end
end
2015-01-13 13:22:21 -05:00
# compress CSV file
2015-01-14 22:37:53 -05:00
` gzip -5 #{ File . expand_path ( " #{ UserExport . base_directory } / #{ @file_name } " , __FILE__ ) } `
2014-08-09 06:28:57 -04:00
end
def notify_user
if @current_user
2015-01-13 13:22:21 -05:00
if @file_name != " " && File . exists? ( " #{ UserExport . base_directory } / #{ @file_name } .gz " )
2015-07-06 18:19:31 -04:00
SystemMessage . create_from_system_user ( @current_user , :csv_export_succeeded , download_link : " #{ Discourse . base_uri } /export_csv/ #{ @file_name } .gz " , file_name : " #{ @file_name } .gz " , file_size : number_to_human_size ( File . size ( " #{ UserExport . base_directory } / #{ @file_name } .gz " ) ) )
2014-08-09 06:28:57 -04:00
else
SystemMessage . create_from_system_user ( @current_user , :csv_export_failed )
end
end
end
end
end