first pass at csv import functionality for tracks

This commit is contained in:
Darren Cato 2013-07-21 13:37:35 -04:00
parent d093ba39bd
commit 3450c22e97
9 changed files with 144 additions and 4 deletions

View file

@ -7,6 +7,64 @@ class DataController < ApplicationController
end
def import
end
def csv_map
if params[:file].blank?
flash[:notice] = "File can't be blank"
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]
#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) }
case @import_to
when 'projects'
@labels = [:name, :description]
when 'todos'
@labels = [:description, :context, :project, :notes, :created_at, :due, :completed_at]
else
flash[:error] = "Ivalid import desitination"
redirect_to :back
end
respond_to do |format|
format.html
end
end
end
def csv_import
begin
case params[:import_to]
when 'projects'
count = Project.import params, current_user
flash[:notice] = "#{count} Projects imported"
when 'todos'
count = Todo.import params, current_user
flash[:notice] = "#{count} Todos imported"
else
flash[:error] = "Ivalid import desitination"
end
rescue Exception => e
flash[:error] = "Error importing CSV: #{e}"
end
File.delete(params[:file])
redirect_to import_data_path
end
def import_headers file
CSV.foreach(file, headers: false) do |row|
return row
end
end
def export

View file

@ -137,6 +137,22 @@ class Project < ActiveRecord::Base
@age_in_days ||= (Date.today - created_at.to_date + 1).to_i
end
def self.import params, user
count = 0
CSV.foreach(params[:file], 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]
project.user = user
project.description = row[params[:description].to_i] if row[params[:description].to_i].present?
project.state = 'active'
project.save!
count += 1
end
end
count
end
end
class NullProject

View file

@ -1,5 +1,8 @@
class Todo < ActiveRecord::Base
MAX_DESC_LENGTH = 300
MAX_NOTES_LENGTH = 60000
before_save :render_note
after_save :save_predecessors
@ -106,8 +109,8 @@ class Todo < ActiveRecord::Base
# Description field can't be empty, and must be < 100 bytes Notes must be <
# 60,000 bytes (65,000 actually, but I'm being cautious)
validates_presence_of :description
validates_length_of :description, :maximum => 100
validates_length_of :notes, :maximum => 60000, :allow_nil => true
validates_length_of :description, :maximum => MAX_DESC_LENGTH
validates_length_of :notes, :maximum => MAX_NOTES_LENGTH, :allow_nil => true
validates_presence_of :show_from, :if => :deferred?
validates_presence_of :context
validate :check_show_from_in_future
@ -431,4 +434,27 @@ class Todo < ActiveRecord::Base
end
end
def self.import params, user
default_context = Context.where(:user_id=>user.id).order('id').first
count = 0
CSV.foreach(params[:file], headers: true) do |row|
unless find_by_description_and_user_id row[params[:description].to_i], user.id
todo = new
todo.user = user
todo.description = row[params[:description].to_i].truncate MAX_DESC_LENGTH
todo.context = Context.find_by_name_and_user_id(row[params[:context].to_i], user.id) || default_context
todo.project = Project.find_by_name_and_user_id(row[params[:project].to_i], user.id) if row[params[:project].to_i].present?
todo.state = row[params[:completed_at].to_i].present? ? 'completed' : 'active'
todo.notes = row[params[:notes].to_i].truncate MAX_NOTES_LENGTH if row[params[:notes].to_i].present?
todo.created_at = row[params[:created_at].to_i] if row[params[:created_at].to_i].present?
todo.due = row[params[:due].to_i]
todo.completed_at = row[params[:completed_at].to_i] if row[params[:completed_at].to_i].present?
todo.save!
count += 1
end
end
count
end
end

View file

View file

@ -0,0 +1,11 @@
<h3>Map fields to be imported<h3>
<%= form_tag csv_import_data_path do %>
<% @labels.each do |l| %>
<%= label_tag l %>:
<%= select_tag(l, options_for_select(@headers) ) %>
<br>
<% end %>
<%= hidden_field_tag :file, @path %>
<%= hidden_field_tag :import_to, @import_to %>
<%= submit_tag "Import" %>
<% end %>

View file

@ -0,0 +1,18 @@
<div id="display_box">
<div id="feeds">
<div id="feedlegend">
<h2>Importing data</h2>
<div>
<h3>Please upload your CSV file</h3>
<%= form_tag csv_map_data_path, :id => 'upload_form', multipart: true do %>
<label for="import_to">Import to:</label>
<%= select_tag(:import_to, options_for_select([['Projects', 'projects'], ['Todos', 'todos']], 1) ) %>
<br><br>
<%= file_field_tag :file %>
<%= submit_tag "Upload", :id => "upload_form_submit" %>
<% end %>
</div>
</div>
</div>
</div>

View file

@ -77,7 +77,8 @@
<li><a href="#"><%= t('layouts.navigation.admin') %></a>
<ul>
<li><%= navigation_link( t('layouts.navigation.preferences'), preferences_path, {:accesskey => "u", :title => t('layouts.navigation.preferences_title')} ) %></li>
<li><%= navigation_link( t('layouts.navigation.export'), data_path, {:accesskey => "i", :title => t('layouts.navigation.export_title')} ) %></li>
<li><%= navigation_link( t('layouts.navigation.export'), data_path, {:accesskey => "e", :title => t('layouts.navigation.export_title')} ) %></li>
<li><%= navigation_link( t('layouts.navigation.import'), import_data_path, {:accesskey => "i", :title => t('layouts.navigation.import_title')} ) %></li>
<% if current_user.is_admin? -%>
<li><%= navigation_link(t('layouts.navigation.manage_users'), users_path, {:accesskey => "a", :title => t('layouts.navigation.manage_users_title')} ) %></li>
<% end -%>

View file

@ -386,7 +386,8 @@ en:
stats: Statistics
tickler_title: Tickler
manage_users: Manage users
export_title: Import and export data
export_title: Export data
import_title: Import data
preferences: Preferences
integrations_: Integrate Tracks
feeds_title: See a list of available feeds
@ -402,6 +403,7 @@ en:
completed_tasks_title: Completed
home: Home
export: Export
import: Import
contexts_title: Contexts
calendar: Calendar
projects_title: Projects

View file

@ -139,4 +139,12 @@ Tracksapp::Application.routes.draw do
resources :notes
resources :preferences
resources :data do
collection do
get :import
post :csv_map
post :csv_import
end
end
end