create a new table to maintain csv export log

This commit is contained in:
Arpit Jalan 2014-12-24 14:41:41 +05:30
parent bb152a5b3f
commit 7c7474aa10
9 changed files with 86 additions and 63 deletions

View file

@ -15,14 +15,14 @@ class ExportCsvController < ApplicationController
# download # download
def show def show
params.require(:entity) params.require(:id)
params.require(:file_id) filename = params.fetch(:id)
if params[:entity] == "system" export_id = filename.split('_')[1].split('.')[0]
guardian.ensure_can_export_admin_entity!(current_user) export_initiated_by_user_id = 0
end export_initiated_by_user_id = CsvExportLog.where(id: export_id)[0].user_id unless CsvExportLog.where(id: export_id).empty?
export_csv_path = CsvExportLog.get_download_path(filename)
filename = params.fetch(:file_id) if export_csv_path && export_initiated_by_user_id == current_user.id
if export_csv_path = ExportCsv.get_download_path(filename)
send_file export_csv_path send_file export_csv_path
else else
render nothing: true, status: 404 render nothing: true, status: 404

View file

@ -239,15 +239,17 @@ module Jobs
def set_file_path def set_file_path
@file_name = "export_#{SecureRandom.hex(4)}.csv" @file = CsvExportLog.create(export_type: @entity_type, user_id: @current_user.id)
@file_name = "export_#{@file.id}.csv"
# ensure directory exists # ensure directory exists
dir = File.dirname("#{ExportCsv.base_directory}/#{@file_name}") dir = File.dirname("#{CsvExportLog.base_directory}/#{@file_name}")
FileUtils.mkdir_p(dir) unless Dir.exists?(dir) FileUtils.mkdir_p(dir) unless Dir.exists?(dir)
end end
def write_csv_file(data, header) def write_csv_file(data, header)
# write to CSV file # write to CSV file
CSV.open(File.expand_path("#{ExportCsv.base_directory}/#{@file_name}", __FILE__), "w") do |csv| CSV.open(File.expand_path("#{CsvExportLog.base_directory}/#{@file_name}", __FILE__), "w") do |csv|
csv << header csv << header
data.each do |value| data.each do |value|
csv << value csv << value
@ -257,12 +259,8 @@ module Jobs
def notify_user def notify_user
if @current_user if @current_user
if @file_name != "" && File.exists?("#{ExportCsv.base_directory}/#{@file_name}") if @file_name != "" && File.exists?("#{CsvExportLog.base_directory}/#{@file_name}")
if @entity_type == "admin" SystemMessage.create_from_system_user(@current_user, :csv_export_succeeded, download_link: "#{Discourse.base_url}/export_csv/#{@file_name}", file_name: @file_name)
SystemMessage.create_from_system_user(@current_user, :csv_export_succeeded, download_link: "#{Discourse.base_url}/export_csv/system/#{@file_name}", file_name: @file_name)
else
SystemMessage.create_from_system_user(@current_user, :csv_export_succeeded, download_link: "#{Discourse.base_url}/export_csv/#{@current_user.username}/#{@file_name}", file_name: @file_name)
end
else else
SystemMessage.create_from_system_user(@current_user, :csv_export_failed) SystemMessage.create_from_system_user(@current_user, :csv_export_failed)
end end

View file

@ -3,7 +3,7 @@ module Jobs
every 2.day every 2.day
def execute(args) def execute(args)
ExportCsv.remove_old_exports # delete exported CSV files older than 2 days CsvExportLog.remove_old_exports # delete exported CSV files older than 2 days
end end
end end
end end

View file

@ -31,6 +31,7 @@ end
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# allowed_ips :inet is an Array # allowed_ips :inet is an Array
# hidden :boolean default(FALSE), not null
# #
# Indexes # Indexes
# #

View file

@ -0,0 +1,40 @@
class CsvExportLog < ActiveRecord::Base
def self.get_download_path(filename)
path = File.join(CsvExportLog.base_directory, filename)
if File.exists?(path)
return path
else
nil
end
end
def self.remove_old_exports
expired_exports = CsvExportLog.where('created_at < ?', 2.days.ago).to_a
expired_exports.map do |expired_export|
file_name = "export_#{expired_export.id}.csv"
file_path = "#{CsvExportLog.base_directory}/#{file_name}"
if File.exist?(file_path)
File.delete(file_path)
end
CsvExportLog.find(expired_export.id).destroy
end
end
def self.base_directory
File.join(Rails.root, "public", "uploads", "csv_exports", RailsMultisite::ConnectionManagement.current_db)
end
end
# == Schema Information
#
# Table name: csv_export_logs
#
# id :integer not null, primary key
# export_type :string(255) not null
# user_id :integer not null
# created_at :datetime
# updated_at :datetime
#

View file

@ -1,29 +0,0 @@
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.remove_old_exports
if Dir.exists?(ExportCsv.base_directory)
Dir.foreach(ExportCsv.base_directory) do |file|
path = File.join(ExportCsv.base_directory, file)
next if File.directory? path
if (File.mtime(path) < 2.days.ago)
File.delete(path)
end
end
end
end
def self.base_directory
File.join(Rails.root, "public", "uploads", "csv_exports", RailsMultisite::ConnectionManagement.current_db)
end
end

View file

@ -436,8 +436,10 @@ Discourse::Application.routes.draw do
collection do collection do
get "export_entity" => "export_csv#export_entity" get "export_entity" => "export_csv#export_entity"
end end
member do
get "" => "export_csv#show", constraints: { id: /[^\/]+/ }
end
end end
get "export_csv/:entity/:file_id" => "export_csv#show", constraints: {entity: USERNAME_ROUTE_FORMAT, file_id: /[^\/]+/}
get "onebox" => "onebox#show" get "onebox" => "onebox#show"

View file

@ -0,0 +1,9 @@
class CreateCsvExportLogs < ActiveRecord::Migration
def change
create_table :csv_export_logs do |t|
t.string :export_type, null: false
t.integer :user_id, null: false
t.timestamps
end
end
end

View file

@ -1,8 +1,7 @@
require "spec_helper" require "spec_helper"
describe ExportCsvController do describe ExportCsvController do
let(:export_filename) { "export_999.csv" }
let(:export_filename) { "export_b6a2bc87.csv" }
context "while logged in as normal user" do context "while logged in as normal user" do
@ -23,23 +22,24 @@ describe ExportCsvController do
describe ".download" do describe ".download" do
it "uses send_file to transmit the export file" do it "uses send_file to transmit the export file" do
file = CsvExportLog.create(export_type: "user", user_id: @user.id)
file_name = "export_#{file.id}.csv"
controller.stubs(:render) controller.stubs(:render)
export = ExportCsv.new() export = CsvExportLog.new()
ExportCsv.expects(:get_download_path).with(export_filename).returns(export) CsvExportLog.expects(:get_download_path).with(file_name).returns(export)
subject.expects(:send_file).with(export) subject.expects(:send_file).with(export)
get :show, entity: "username", file_id: export_filename get :show, id: file_name
response.should be_success response.should be_success
end end
it "returns 404 when the normal user tries to access admin export file" do it "returns 404 when the user tries to export another user's csv file" do
controller.stubs(:render) get :show, id: export_filename
get :show, entity: "system", file_id: export_filename response.should be_not_found
response.should_not be_success
end end
it "returns 404 when the export file does not exist" do it "returns 404 when the export file does not exist" do
ExportCsv.expects(:get_download_path).returns(nil) CsvExportLog.expects(:get_download_path).returns(nil)
get :show, entity: "username", file_id: export_filename get :show, id: export_filename
response.should be_not_found response.should be_not_found
end end
end end
@ -59,17 +59,19 @@ describe ExportCsvController do
describe ".download" do describe ".download" do
it "uses send_file to transmit the export file" do it "uses send_file to transmit the export file" do
file = CsvExportLog.create(export_type: "admin", user_id: @admin.id)
file_name = "export_#{file.id}.csv"
controller.stubs(:render) controller.stubs(:render)
export = ExportCsv.new() export = CsvExportLog.new()
ExportCsv.expects(:get_download_path).with(export_filename).returns(export) CsvExportLog.expects(:get_download_path).with(file_name).returns(export)
subject.expects(:send_file).with(export) subject.expects(:send_file).with(export)
get :show, entity: "system", file_id: export_filename get :show, id: file_name
response.should be_success response.should be_success
end end
it "returns 404 when the export file does not exist" do it "returns 404 when the export file does not exist" do
ExportCsv.expects(:get_download_path).returns(nil) CsvExportLog.expects(:get_download_path).returns(nil)
get :show, entity: "system", file_id: export_filename get :show, id: export_filename
response.should be_not_found response.should be_not_found
end end
end end