diff --git a/app/assets/javascripts/admin/controllers/admin-logs-screened-emails.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-screened-emails.js.es6 index 2b4bd0e29cd..745a172d2ec 100644 --- a/app/assets/javascripts/admin/controllers/admin-logs-screened-emails.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-logs-screened-emails.js.es6 @@ -1,3 +1,5 @@ +import { outputExportResult } from 'admin/lib/export-result'; + export default Ember.ArrayController.extend(Discourse.Presence, { loading: false, @@ -7,12 +9,16 @@ export default Ember.ArrayController.extend(Discourse.Presence, { // feeling lazy window.location.reload(); }); + }, + + exportScreenedEmailList: function(subject) { + Discourse.ExportCsv.exportScreenedEmailList().then(outputExportResult); } }, show: function() { var self = this; - this.set('loading', true); + self.set('loading', true); Discourse.ScreenedEmail.findAll().then(function(result) { self.set('model', result); self.set('loading', false); diff --git a/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6 index 414461edacb..b06c74d04ea 100644 --- a/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6 @@ -1,10 +1,12 @@ +import { outputExportResult } from 'admin/lib/export-result'; + export default Ember.ArrayController.extend(Discourse.Presence, { loading: false, itemController: 'admin-log-screened-ip-address', show: function() { var self = this; - this.set('loading', true); + self.set('loading', true); Discourse.ScreenedIpAddress.findAll().then(function(result) { self.set('model', result); self.set('loading', false); @@ -34,6 +36,10 @@ export default Ember.ArrayController.extend(Discourse.Presence, { }); } }); + }, + + exportScreenedIpList: function(subject) { + Discourse.ExportCsv.exportScreenedIpList().then(outputExportResult); } } }); diff --git a/app/assets/javascripts/admin/controllers/admin-logs-screened-urls.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-screened-urls.js.es6 index 92cb40e4962..49637494c82 100644 --- a/app/assets/javascripts/admin/controllers/admin-logs-screened-urls.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-logs-screened-urls.js.es6 @@ -1,12 +1,20 @@ +import { outputExportResult } from 'admin/lib/export-result'; + export default Ember.ArrayController.extend(Discourse.Presence, { loading: false, show: function() { var self = this; - this.set('loading', true); + self.set('loading', true); Discourse.ScreenedUrl.findAll().then(function(result) { self.set('model', result); self.set('loading', false); }); + }, + + actions: { + exportScreenedUrlList: function(subject) { + Discourse.ExportCsv.exportScreenedUrlList().then(outputExportResult); + } } }); diff --git a/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 index 76df4a3b60d..9d043749316 100644 --- a/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 @@ -6,6 +6,8 @@ @namespace Discourse @module Discourse **/ +import { outputExportResult } from 'admin/lib/export-result'; + export default Ember.ArrayController.extend(Discourse.Presence, { loading: false, filters: {}, @@ -60,6 +62,10 @@ export default Ember.ArrayController.extend(Discourse.Presence, { filterBySubject: function(subject) { this.set('filters.subject', subject); + }, + + exportStaffActionLogs: function(subject) { + Discourse.ExportCsv.exportStaffActionLogs().then(outputExportResult); } } }); diff --git a/app/assets/javascripts/admin/lib/export-result.js.es6 b/app/assets/javascripts/admin/lib/export-result.js.es6 new file mode 100644 index 00000000000..da1058d5640 --- /dev/null +++ b/app/assets/javascripts/admin/lib/export-result.js.es6 @@ -0,0 +1,7 @@ +export function outputExportResult(result) { + if (result.success) { + bootbox.alert(I18n.t("admin.export_csv.success")); + } else { + bootbox.alert(I18n.t("admin.export_csv.failed")); + } +} diff --git a/app/assets/javascripts/admin/models/export_csv.js b/app/assets/javascripts/admin/models/export_csv.js index b747cd449be..082ddeb0014 100644 --- a/app/assets/javascripts/admin/models/export_csv.js +++ b/app/assets/javascripts/admin/models/export_csv.js @@ -15,15 +15,42 @@ Discourse.ExportCsv.reopenClass({ @method export_user_list **/ exportUserList: function() { - return Discourse.ajax("/admin/export_csv/users.json"); + return Discourse.ajax("/admin/export_csv/export_entity.json", {data: {entity: 'user'}}); }, /** - Exports screened IPs list + Exports staff action logs - @method export_screened_ips_list + @method export_staff_action_logs **/ - exportScreenedIpsList: function() { - return Discourse.ajax("/admin/export_csv/screened_ips.json"); + exportStaffActionLogs: function() { + return Discourse.ajax("/admin/export_csv/export_entity.json", {data: {entity: 'staff_action'}}); + }, + + /** + Exports screened email list + + @method export_screened_email_list + **/ + exportScreenedEmailList: function() { + return Discourse.ajax("/admin/export_csv/export_entity.json", {data: {entity: 'screened_email'}}); + }, + + /** + Exports screened IP list + + @method export_screened_ip_list + **/ + exportScreenedIpList: function() { + return Discourse.ajax("/admin/export_csv/export_entity.json", {data: {entity: 'screened_ip'}}); + }, + + /** + Exports screened URL list + + @method export_screened_url_list + **/ + exportScreenedUrlList: function() { + return Discourse.ajax("/admin/export_csv/export_entity.json", {data: {entity: 'screened_url'}}); } }); diff --git a/app/assets/javascripts/admin/routes/admin-logs.js.es6 b/app/assets/javascripts/admin/routes/admin-logs.js.es6 deleted file mode 100644 index a16a9f1a6bf..00000000000 --- a/app/assets/javascripts/admin/routes/admin-logs.js.es6 +++ /dev/null @@ -1,15 +0,0 @@ -export default Discourse.Route.extend({ - - actions: { - exportScreenedIps: function() { - Discourse.ExportCsv.exportScreenedIpsList().then(function(result) { - if (result.success) { - bootbox.alert(I18n.t("admin.export_csv.success")); - } else { - bootbox.alert(I18n.t("admin.export_csv.failed")); - } - }); - } - } - -}); diff --git a/app/assets/javascripts/admin/templates/logs.hbs b/app/assets/javascripts/admin/templates/logs.hbs index 0e4f8b4a61a..c85bb02d7cb 100644 --- a/app/assets/javascripts/admin/templates/logs.hbs +++ b/app/assets/javascripts/admin/templates/logs.hbs @@ -8,9 +8,6 @@
  • {{i18n 'admin.logs.logster.title'}}
  • -
    - -
    diff --git a/app/assets/javascripts/admin/templates/logs/screened_emails.hbs b/app/assets/javascripts/admin/templates/logs/screened_emails.hbs index 3a426459a49..f231c391943 100644 --- a/app/assets/javascripts/admin/templates/logs/screened_emails.hbs +++ b/app/assets/javascripts/admin/templates/logs/screened_emails.hbs @@ -1,4 +1,8 @@ -

    {{i18n 'admin.logs.screened_emails.description'}}

    +

    + {{i18n 'admin.logs.screened_emails.description'}} + +

    +
    {{#loading-spinner condition=loading}} {{#if model.length}} diff --git a/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.hbs b/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.hbs index f26fc2b0c8b..c1b27eb88fb 100644 --- a/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.hbs +++ b/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.hbs @@ -1,5 +1,8 @@

    {{i18n 'admin.logs.screened_ips.description'}}

    - +
    + + +
    {{screened-ip-address-form action="recordAdded"}}
    diff --git a/app/assets/javascripts/admin/templates/logs/screened_urls.hbs b/app/assets/javascripts/admin/templates/logs/screened_urls.hbs index ded1bba2472..701909ff564 100644 --- a/app/assets/javascripts/admin/templates/logs/screened_urls.hbs +++ b/app/assets/javascripts/admin/templates/logs/screened_urls.hbs @@ -1,4 +1,8 @@ -

    {{i18n 'admin.logs.screened_urls.description'}}

    +

    + {{i18n 'admin.logs.screened_urls.description'}} + +

    +
    {{#loading-spinner condition=loading}} {{#if model.length}} diff --git a/app/assets/javascripts/admin/templates/logs/staff_action_logs.hbs b/app/assets/javascripts/admin/templates/logs/staff_action_logs.hbs index 66fa817fd01..10ae1750533 100644 --- a/app/assets/javascripts/admin/templates/logs/staff_action_logs.hbs +++ b/app/assets/javascripts/admin/templates/logs/staff_action_logs.hbs @@ -28,6 +28,11 @@ {{/if}}
    +
    + +
    +
    +
    {{i18n 'admin.logs.staff_actions.instructions'}}
    diff --git a/app/assets/javascripts/admin/templates/users_list.hbs b/app/assets/javascripts/admin/templates/users_list.hbs index 9f857dec436..14032b4e203 100644 --- a/app/assets/javascripts/admin/templates/users_list.hbs +++ b/app/assets/javascripts/admin/templates/users_list.hbs @@ -13,7 +13,7 @@
    - +
    diff --git a/app/assets/javascripts/main_include_admin.js b/app/assets/javascripts/main_include_admin.js index 2cd37f1596c..00050ed3d9c 100644 --- a/app/assets/javascripts/main_include_admin.js +++ b/app/assets/javascripts/main_include_admin.js @@ -1,4 +1,5 @@ //= require list-view +//= require admin/lib/export-result //= require admin/models/user-field //= require admin/controllers/admin-email-skipped //= require admin/controllers/change-site-customization-details diff --git a/app/controllers/admin/export_csv_controller.rb b/app/controllers/admin/export_csv_controller.rb index 2a5d53a00f6..0ab4aefe068 100644 --- a/app/controllers/admin/export_csv_controller.rb +++ b/app/controllers/admin/export_csv_controller.rb @@ -2,15 +2,10 @@ class Admin::ExportCsvController < Admin::AdminController skip_before_filter :check_xhr, only: [:show] - def export_user_list + def export_entity + params.require(:entity) # export csv file in a background thread - Jobs.enqueue(:export_csv_file, entity: 'user', user_id: current_user.id) - render json: success_json - end - - def export_screened_ips_list - # export csv file in a background thread - Jobs.enqueue(:export_csv_file, entity: 'screened_ips', user_id: current_user.id) + Jobs.enqueue(:export_csv_file, entity: params[:entity], user_id: current_user.id) render json: success_json end diff --git a/app/jobs/regular/export_csv_file.rb b/app/jobs/regular/export_csv_file.rb index 926aee562d7..f8c2a2f79f9 100644 --- a/app/jobs/regular/export_csv_file.rb +++ b/app/jobs/regular/export_csv_file.rb @@ -4,10 +4,14 @@ 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'] + HEADER_ATTRS_FOR = {} + HEADER_ATTRS_FOR['user'] = ['id','name','username','email','title','created_at','trust_level','active','admin','moderator','ip_address'] + 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'] sidekiq_options retry: false attr_accessor :current_user @@ -20,14 +24,12 @@ module Jobs entity = args[:entity] @current_user = User.find_by(id: args[:user_id]) - + export_method = "#{entity}_export".to_sym data = - if entity == 'user' - user_export - elsif entity == 'screened_ips' - screened_ips_export + if respond_to?(export_method) + send(export_method) else - raise Discourse::InvalidParameters.new(:entity) if entity.blank? + raise Discourse::InvalidParameters.new(:entity) end if data && data.length > 0 @@ -50,21 +52,41 @@ module Jobs end end + def staff_action_export + staff_action_data = UserHistory.order('id DESC').to_a + staff_action_data.map do |staff_action| + get_staff_action_fields(staff_action) + end + end - def screened_ips_export - screened_ips_data = ScreenedIpAddress.order('id desc').to_a - screened_ips_data.map do |screened_ip| + 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| get_screened_ip_fields(screened_ip) end end + 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 + def get_header(entity) case entity when 'user' - header_array = CSV_USER_ATTRS + CSV_USER_STATS + header_array = HEADER_ATTRS_FOR['user'] + HEADER_ATTRS_FOR['user_stats'] if SiteSetting.enable_sso - header_array.concat(CSV_USER_SSO_ATTRS) + header_array.concat(HEADER_ATTRS_FOR['user_sso']) end user_custom_fields = UserField.all if user_custom_fields.present? @@ -73,9 +95,9 @@ module Jobs end end header_array.push("group_names") - when 'screened_ips' - header_array = SCREENED_IP_ATTRS - end + else + header_array = HEADER_ATTRS_FOR[entity] + end header_array end @@ -94,17 +116,17 @@ module Jobs def get_user_fields(user) user_array = [] - CSV_USER_ATTRS.each do |attr| + HEADER_ATTRS_FOR['user'].each do |attr| user_array.push(user.attributes[attr]) end - CSV_USER_STATS.each do |stat| + HEADER_ATTRS_FOR['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| + HEADER_ATTRS_FOR['user_sso'].each do |stat| field = sso.attributes[stat] if sso user_array.push(field) end @@ -119,16 +141,78 @@ module Jobs user_array end + 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? + 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 + def get_screened_ip_fields(screened_ip) screened_ip_array = [] - SCREENED_IP_ATTRS.each do |attr| - screened_ip_array.push(screened_ip.attributes[attr]) + 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) end screened_ip_array 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 + end + def set_file_path @file_name = "export_#{SecureRandom.hex(4)}.csv" diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index b0f2ecf3a7c..c3290d52f61 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1688,13 +1688,15 @@ en: confirm: "Are your sure you want to rollback the database to the previous working state?" export_csv: - users: - title: "Export full user list in CSV format." - screened_ips: - title: "Export full screened IPs list in CSV format." success: "Export initiated, you will be notified shortly with progress." failed: "Export failed. Please check the logs." button_text: "Export" + button_title: + user: "Export full user list in CSV format." + staff_action: "Export full staff action log in CSV format." + screened_email: "Export full screened email list in CSV format." + screened_ip: "Export full screened IP list in CSV format." + screened_url: "Export full screened URL list in CSV format." customize: title: "Customize" diff --git a/config/routes.rb b/config/routes.rb index 4c716ed7222..7846e50830a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -164,8 +164,7 @@ Discourse::Application.routes.draw do resources :export_csv, constraints: AdminConstraint.new do collection do - get "users" => "export_csv#export_user_list" - get "screened_ips" => "export_csv#export_screened_ips_list" + get "export_entity" => "export_csv#export_entity" end member do get "" => "export_csv#show", constraints: { id: /[^\/]+/ }