mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-23 15:48:43 -05:00
FEATURE: export user list
This commit is contained in:
parent
2850ce46b8
commit
d0736a06b6
11 changed files with 222 additions and 1 deletions
26
app/assets/javascripts/admin/models/export_csv.js
Normal file
26
app/assets/javascripts/admin/models/export_csv.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
Data model for representing an export
|
||||
|
||||
@class ExportCsv
|
||||
@extends Discourse.Model
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.ExportCsv = Discourse.Model.extend({});
|
||||
|
||||
Discourse.ExportCsv.reopenClass({
|
||||
/**
|
||||
Exports user list
|
||||
|
||||
@method export_user_list
|
||||
**/
|
||||
exportUserList: function() {
|
||||
return Discourse.ajax("/admin/export_csv/users.json").then(function(result) {
|
||||
if (result.success) {
|
||||
bootbox.alert(I18n.t("admin.export_csv.success"));
|
||||
} else {
|
||||
bootbox.alert(I18n.t("admin.export_csv.failed"));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
|
@ -9,6 +9,12 @@
|
|||
Discourse.AdminUsersListRoute = Discourse.Route.extend({
|
||||
renderTemplate: function() {
|
||||
this.render('admin/templates/users_list', {into: 'admin/templates/admin'});
|
||||
},
|
||||
|
||||
actions: {
|
||||
exportUsers: function() {
|
||||
Discourse.ExportCsv.exportUserList();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -57,7 +63,7 @@ Discourse.AdminUsersListNewRoute = Discourse.Route.extend({
|
|||
/**
|
||||
Handles the route that lists pending users.
|
||||
|
||||
@class AdminUsersListNewRoute
|
||||
@class AdminUsersListPendingRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
<div class='username controls'>
|
||||
{{text-field value=username placeholderKey="search_hint"}}
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<button {{action exportUsers}} class="btn" title="{{i18n admin.export_csv.users.title}}"><i class="fa fa-download"></i>{{i18n admin.export_csv.users.text}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-container">
|
||||
|
|
20
app/controllers/admin/export_csv_controller.rb
Normal file
20
app/controllers/admin/export_csv_controller.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
class Admin::ExportCsvController < Admin::AdminController
|
||||
|
||||
skip_before_filter :check_xhr, only: [:download]
|
||||
|
||||
def export_user_list
|
||||
# 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 download
|
||||
filename = params.fetch(:id)
|
||||
if export_csv_path = ExportCsv.get_download_path(filename)
|
||||
send_file export_csv_path
|
||||
else
|
||||
render nothing: true, status: 404
|
||||
end
|
||||
end
|
||||
|
||||
end
|
75
app/jobs/regular/export_csv_file.rb
Normal file
75
app/jobs/regular/export_csv_file.rb
Normal file
|
@ -0,0 +1,75 @@
|
|||
require 'csv'
|
||||
require_dependency 'system_message'
|
||||
|
||||
module Jobs
|
||||
|
||||
class ExportCsvFile < Jobs::Base
|
||||
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])
|
||||
|
||||
raise Discourse::InvalidParameters.new(:entity) if entity.blank?
|
||||
|
||||
case entity
|
||||
when 'user'
|
||||
query = ::AdminUserIndexQuery.new
|
||||
user_data = query.find_users_query.to_a
|
||||
|
||||
data = Hash.new do |hash, key|
|
||||
hash[key] = {}
|
||||
end
|
||||
|
||||
user_data.each do |user|
|
||||
id = user['id']
|
||||
email = user['email']
|
||||
data[id] = email
|
||||
end
|
||||
data = data.to_a
|
||||
end
|
||||
|
||||
if data && data.length > 0
|
||||
set_file_path
|
||||
write_csv_file(data)
|
||||
end
|
||||
|
||||
notify_user
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
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)
|
||||
# write to CSV file
|
||||
CSV.open(File.expand_path("#{ExportCsv.base_directory}/#{@file_name}", __FILE__), "w") do |csv|
|
||||
data.each do |value|
|
||||
csv << [value[1]]
|
||||
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}/download", file_name: @file_name)
|
||||
else
|
||||
SystemMessage.create_from_system_user(@current_user, :csv_export_failed)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
16
app/models/export_csv.rb
Normal file
16
app/models/export_csv.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
class ExportCsv
|
||||
|
||||
def self.get_download_path(filename)
|
||||
path = File.join(ExportCsv.base_directory, filename)
|
||||
if File.exists?(path)
|
||||
return path
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def self.base_directory
|
||||
File.join(Rails.root, "public", "uploads", "csv_exports", RailsMultisite::ConnectionManagement.current_db)
|
||||
end
|
||||
|
||||
end
|
|
@ -1603,6 +1603,13 @@ en:
|
|||
title: "Rollback the database to previous working state"
|
||||
confirm: "Are your sure you want to rollback the database to the previous working state?"
|
||||
|
||||
export_csv:
|
||||
users:
|
||||
text: "Export Users"
|
||||
title: "Export user list in a CSV file."
|
||||
success: "Export has been initiated, you will be notified shortly with progress."
|
||||
failed: "Export failed. Please check the logs."
|
||||
|
||||
customize:
|
||||
title: "Customize"
|
||||
long_title: "Site Customizations"
|
||||
|
|
|
@ -1387,6 +1387,17 @@ en:
|
|||
%{logs}
|
||||
```
|
||||
|
||||
csv_export_succeeded:
|
||||
subject_template: "Data Export completed successfully"
|
||||
text_body_template: |
|
||||
The data export was successful.
|
||||
|
||||
Download CSV file: <a class="attachment" href="%{download_link}">%{file_name}</a>
|
||||
|
||||
csv_export_failed:
|
||||
subject_template: "Export failed"
|
||||
text_body_template: "The export has failed. Please check the logs."
|
||||
|
||||
email_reject_trust_level:
|
||||
subject_template: "Email issue -- Insufficient Trust Level"
|
||||
text_body_template: |
|
||||
|
|
|
@ -145,6 +145,15 @@ Discourse::Application.routes.draw do
|
|||
end
|
||||
end
|
||||
|
||||
resources :export_csv, constraints: AdminConstraint.new do
|
||||
member do
|
||||
get "download" => "export_csv#download", constraints: { id: /[^\/]+/ }
|
||||
end
|
||||
collection do
|
||||
get "users" => "export_csv#export_user_list"
|
||||
end
|
||||
end
|
||||
|
||||
resources :badges, constraints: AdminConstraint.new do
|
||||
collection do
|
||||
get "types" => "badges#badge_types"
|
||||
|
|
35
spec/controllers/admin/export_csv_controller_spec.rb
Normal file
35
spec/controllers/admin/export_csv_controller_spec.rb
Normal file
|
@ -0,0 +1,35 @@
|
|||
require "spec_helper"
|
||||
|
||||
describe Admin::ExportCsvController do
|
||||
|
||||
it "is a subclass of AdminController" do
|
||||
(Admin::ExportCsvController < Admin::AdminController).should be_true
|
||||
end
|
||||
|
||||
let(:export_filename) { "export_b6a2bc87.csv" }
|
||||
|
||||
context "while logged in as an admin" do
|
||||
|
||||
before { @admin = log_in(:admin) }
|
||||
|
||||
describe ".download" do
|
||||
|
||||
it "uses send_file to transmit the export file" do
|
||||
controller.stubs(:render)
|
||||
export = ExportCsv.new()
|
||||
ExportCsv.expects(:get_download_path).with(export_filename).returns(export)
|
||||
subject.expects(:send_file).with(export)
|
||||
get :download, id: export_filename
|
||||
end
|
||||
|
||||
it "returns 404 when the export file does not exist" do
|
||||
ExportCsv.expects(:get_download_path).returns(nil)
|
||||
get :download, id: export_filename
|
||||
response.should be_not_found
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
13
spec/jobs/export_csv_file_spec.rb
Normal file
13
spec/jobs/export_csv_file_spec.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Jobs::ExportCsvFile do
|
||||
|
||||
context '.execute' do
|
||||
|
||||
it 'raises an error when the entity is missing' do
|
||||
lambda { Jobs::ExportCsvFile.new.execute(user_id: "1") }.should raise_error(Discourse::InvalidParameters)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in a new issue