diff --git a/app/controllers/data_controller.rb b/app/controllers/data_controller.rb index 18e3bad2..dae553e4 100644 --- a/app/controllers/data_controller.rb +++ b/app/controllers/data_controller.rb @@ -16,16 +16,29 @@ class DataController < ApplicationController redirect_to :back else @import_to = params[:import_to] - - #get column headers and formart as [['name', column_number]...] - i = -1 - @headers = import_headers(params[:file].path).collect { |v| [v, i+=1] } - @headers.unshift ['',i] + + begin + #get column headers and format as [['name', column_number]...] + i = -1 + @headers = import_headers(params[:file].path).collect { |v| [v, i+=1] } + @headers.unshift ['',i] + rescue Exception => e + flash[:error] = "Invalid CVS: could not read headers: #{e}" + redirect_to :back + return + end #save file for later - directory = "public/uploads/csv" - @path = File.join(directory, params[:file].original_filename) - File.open(@path, "wb") { |f| f.write(params[:file].read) } + begin + uploaded_file = params[:file] + @filename = Tracks::Utils.sanitize_filename(uploaded_file.original_filename) + path_and_file = Rails.root.join('public', 'uploads', 'csv', @filename) + File.open(path_and_file, "wb") { |f| f.write(uploaded_file.read) } + rescue Exception => e + flash[:error] = "Could not save uploaded CSV (#{path_and_file}). Can Tracks write to the upload directory? #{e}" + redirect_to :back + return + end case @import_to when 'projects' @@ -44,12 +57,14 @@ class DataController < ApplicationController def csv_import begin + filename = Tracks::Utils.sanitize_filename(params[:file]) + path_and_file = Rails.root.join('public', 'uploads', 'csv', filename) case params[:import_to] when 'projects' - count = Project.import params, current_user + count = Project.import path_and_file, params, current_user flash[:notice] = "#{count} Projects imported" when 'todos' - count = Todo.import params, current_user + count = Todo.import path_and_file, params, current_user flash[:notice] = "#{count} Todos imported" else flash[:error] = t('data.invalid_import_destination') @@ -57,11 +72,11 @@ class DataController < ApplicationController rescue Exception => e flash[:error] = t('data.invalid_import_destination') + ": #{e}" end - File.delete(params[:file]) + File.delete(path_and_file) redirect_to import_data_path end - def import_headers file + def import_headers(file) CSV.foreach(file, headers: false) do |row| return row end @@ -105,13 +120,14 @@ class DataController < ApplicationController send_data(result, :filename => "tracks_backup.yml", :type => 'text/plain') end + # export all actions as csv def csv_actions content_type = 'text/csv' - CSV::Writer.generate(result = "") do |csv| + CSV.generate(result = "") do |csv| csv << ["id", "Context", "Project", "Description", "Notes", "Tags", "Created at", "Due", "Completed at", "User ID", "Show from", "state"] - current_user.todos.include(:context, :project).all.each do |todo| + current_user.todos.includes(:context, :project, :taggings, :tags).each do |todo| csv << [todo.id, todo.context.name, todo.project_id.nil? ? "" : todo.project.name, todo.description, @@ -127,7 +143,7 @@ class DataController < ApplicationController send_data(result, :filename => "todos.csv", :type => content_type) end - + # export all notes as csv def csv_notes content_type = 'text/csv' CSV.generate(result = "") do |csv| diff --git a/app/models/project.rb b/app/models/project.rb index cd106fd4..685c51c1 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -138,9 +138,9 @@ class Project < ActiveRecord::Base @age_in_days ||= ((Time.now.utc - created_at).to_i / 1.day) + 1 end - def self.import(params, user) + def self.import(filename, params, user) count = 0 - CSV.foreach(params[:file], headers: true) do |row| + CSV.foreach(filename, headers: true) do |row| unless find_by_name_and_user_id row[params[:name].to_i], user.id project = new project.name = row[params[:name].to_i] diff --git a/app/models/todo.rb b/app/models/todo.rb index b9720960..5bc2105d 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -393,11 +393,11 @@ class Todo < ActiveRecord::Base end end - def self.import(params, user) - default_context = Context.where(:user_id=>user.id).order('id').first + def self.import(filename, params, user) + default_context = user.contexts.order('id').first count = 0 - CSV.foreach(params[:file], headers: true) do |row| + CSV.foreach(filename, headers: true) do |row| unless find_by_description_and_user_id row[params[:description].to_i], user.id todo = new todo.user = user diff --git a/app/views/data/csv_map.html.erb b/app/views/data/csv_map.html.erb index 929faa1e..5a8b9d4c 100644 --- a/app/views/data/csv_map.html.erb +++ b/app/views/data/csv_map.html.erb @@ -5,7 +5,7 @@ <%= select_tag(l, options_for_select(@headers) ) %>
<% end %> - <%= hidden_field_tag :file, @path %> + <%= hidden_field_tag :file, @filename %> <%= hidden_field_tag :import_to, @import_to %> <%= submit_tag "Import" %> <% end %> \ No newline at end of file diff --git a/lib/tracks/utils.rb b/lib/tracks/utils.rb index 31ed7d32..262f01ee 100644 --- a/lib/tracks/utils.rb +++ b/lib/tracks/utils.rb @@ -38,6 +38,10 @@ module Tracks RedCloth.new(text).to_html end + def self.sanitize_filename(filename) + filename.gsub(/[^0-9A-z.\-]/, '_') + end + private def self.helpers