diff --git a/tracks/app/controllers/data_controller.rb b/tracks/app/controllers/data_controller.rb new file mode 100644 index 00000000..7e911b28 --- /dev/null +++ b/tracks/app/controllers/data_controller.rb @@ -0,0 +1,87 @@ +class DataController < ApplicationController + + require 'csv' + + def index + end + + def import + end + + def export + # Show list of formats for export + end + + # Thanks to a tip by Gleb Arshinov + # + def yaml_export + all_tables = {} + + all_tables['todos'] = @user.todos.find(:all) + all_tables['contexts'] = @user.contexts.find(:all) + all_tables['projects'] = @user.projects.find(:all) + all_tables['notes'] = @user.notes.find(:all) + + result = all_tables.to_yaml + result.gsub!(/\n/, "\r\n") # TODO: general functionality for line endings + send_data(result, :filename => "tracks_backup.yml", :type => 'text/plain') + end + + def csv_actions + content_type = 'text/csv' + CSV::Writer.generate(result = "") do |csv| + csv << ["ID", "Context", "Project", "Description", "Notes", + "Created at", "Due", "Completed at", "User ID", "Show from", + "state"] + @user.todos.find(:all, :include => [:context, :project]).each do |todo| + # Format dates in ISO format for easy sorting in spreadsheet + # Print context and project names for easy viewing + csv << [todo.id, todo.context.name, + todo.project_id = todo.project_id.nil? ? "" : todo.project.name, + todo.description, + todo.notes, todo.created_at.to_formatted_s(:db), + todo.due = todo.due? ? todo.due.to_formatted_s(:db) : "", + todo.completed_at = todo.completed_at? ? todo.completed_at.to_formatted_s(:db) : "", + todo.user_id, + todo.show_from = todo.show_from? ? todo.show_from.to_formatted_s(:db) : "", + todo.state] + end + end + send_data(result, :filename => "todos.csv", :type => content_type) + end + + def csv_notes + content_type = 'text/csv' + CSV::Writer.generate(result = "") do |csv| + csv << ["ID", "User ID", "Project", "Note", + "Created at", "Updated at"] + @user.notes.find(:all, :include => [:project]).each do |note| + # Format dates in ISO format for easy sorting in spreadsheet + # Print context and project names for easy viewing + csv << [note.id, note.user_id, + note.project_id = note.project_id.nil? ? "" : note.project.name, + note.body, note.created_at.to_formatted_s(:db), + note.updated_at.to_formatted_s(:db)] + end + end + send_data(result, :filename => "notes.csv", :type => content_type) + end + + def xml_export + result = "" + result << @user.todos.find(:all).to_xml + result << @user.contexts.find(:all).to_xml(:skip_instruct => true) + result << @user.projects.find(:all).to_xml(:skip_instruct => true) + result << @user.notes.find(:all).to_xml(:skip_instruct => true) + send_data(result, :filename => "tracks_backup.xml", :type => 'text/xml') + end + + def yaml_form + # Draw the form to input the YAML text data + end + + def yaml_import + # Logic to load the YAML text file and create new records from data + end + +end diff --git a/tracks/app/helpers/data_helper.rb b/tracks/app/helpers/data_helper.rb new file mode 100644 index 00000000..e68f25eb --- /dev/null +++ b/tracks/app/helpers/data_helper.rb @@ -0,0 +1,2 @@ +module DataHelper +end diff --git a/tracks/app/views/data/export.rhtml b/tracks/app/views/data/export.rhtml new file mode 100644 index 00000000..024b6b91 --- /dev/null +++ b/tracks/app/views/data/export.rhtml @@ -0,0 +1,37 @@ +
+
+

Exporting data

+

You can choose between the following formats:

+
    +
  • YAML: Best for porting data between Tracks installations
  • +
  • CSV: Best for importing into spreadsheet or data analysis software
  • +
  • XML: Best for importing or repurposing the data
  • +
+ +

+ + + + + + + + + + + + + + + + + + + + + +
DescriptionDownload link
YAML file containing all your actions, contexts, projects and notes<%= link_to "YAML file", :controller => 'data', :action => 'yaml_export' %>
CSV file containing all of your actions, with named contexts and projects<%= link_to "CSV file (actions, contexts and projects)", :controller => 'data', :action => 'csv_actions' %>
CSV file containing all your notes<%= link_to "CSV file (notes only)", :controller => 'data', :action => 'csv_notes' %>
XML file containing all your actions, contexts, projects and notes<%= link_to "XML file (actions only)", :controller => 'data', :action => 'xml_export' %>
+

+ +
\ No newline at end of file diff --git a/tracks/app/views/data/import.rhtml b/tracks/app/views/data/import.rhtml new file mode 100644 index 00000000..36b67651 --- /dev/null +++ b/tracks/app/views/data/import.rhtml @@ -0,0 +1,18 @@ +
+
+
+

Importing data

+

You can choose between the following formats:

+
    +
  • YAML: Best for porting data between Tracks installations
  • +
  • CSV: Best for importing into spreadsheet or data analysis software
  • +
+ +
    +
  • YAML
  • +
  • CSV
  • +
+ +
+
\ No newline at end of file diff --git a/tracks/app/views/data/index.rhtml b/tracks/app/views/data/index.rhtml new file mode 100644 index 00000000..10d15e6d --- /dev/null +++ b/tracks/app/views/data/index.rhtml @@ -0,0 +1,15 @@ +
+
+
+

Importing and exporting data into Tracks

+

You can export your data in a number of different forms. Note: you can only export/import your own data (i.e. the data available when you are logged in).

+
+ +
    +
  • Import
  • +
  • + <%= link_to "Export", :controller => 'data', :action => 'export' %> +
  • +
+
+
\ No newline at end of file diff --git a/tracks/app/views/data/yaml_export.rhtml b/tracks/app/views/data/yaml_export.rhtml new file mode 100644 index 00000000..e69de29b diff --git a/tracks/app/views/data/yaml_form.rhtml b/tracks/app/views/data/yaml_form.rhtml new file mode 100644 index 00000000..444613d7 --- /dev/null +++ b/tracks/app/views/data/yaml_form.rhtml @@ -0,0 +1,19 @@ +
+
+
+

Paste the contents of the YAML file you exported into the text box below:

+
+ +

+<% form_for :import, @import, :url => {:controller => 'data', :action => 'yaml_import'} do |f| %> + <%= f.text_area :yaml %>
+ +<% end %> +

+ +
+
+ +
+ +
\ No newline at end of file diff --git a/tracks/app/views/data/yaml_import.rhtml b/tracks/app/views/data/yaml_import.rhtml new file mode 100644 index 00000000..cf79230b --- /dev/null +++ b/tracks/app/views/data/yaml_import.rhtml @@ -0,0 +1 @@ +

Import was successful

\ No newline at end of file diff --git a/tracks/app/views/layouts/standard.rhtml b/tracks/app/views/layouts/standard.rhtml index 370ce912..dee99240 100644 --- a/tracks/app/views/layouts/standard.rhtml +++ b/tracks/app/views/layouts/standard.rhtml @@ -2,9 +2,9 @@ - <% if @prefs.refresh != 0 -%> - ;url=<%= request.request_uri %>"> - <% end -%> + <% if @prefs.refresh != 0 -%> + ;url=<%= request.request_uri %>"> + <% end -%> <%= stylesheet_link_tag "standard" %> <%= stylesheet_link_tag "print", :media => "print" %> <%= javascript_include_tag :defaults %> @@ -47,6 +47,7 @@
  • <%= navigation_link( "Done", {:controller => "todo", :action => "completed"}, {:accesskey=>"d", :title=>"Completed"} ) %>
  • <%= navigation_link( "Notes", {:controller => "note", :action => "index"}, {:accesskey => "o", :title => "Show all notes"} ) %>
  • <%= navigation_link( "Preferences", {:controller => "preferences", :action => "index"}, {:accesskey => "u", :title => "Show my preferences"} ) %>
  • +
  • <%= navigation_link( "Import/Export", {:controller => "data", :action => "index"}, {:accesskey => "i", :title => "Import and export data"} ) %>
  • <% if @user.is_admin? -%>
  • <%= navigation_link("Admin", {:controller => "admin", :action => "index"}, {:accesskey => "a", :title => "Add or delete users"} ) %>
  • <% end -%> diff --git a/tracks/test/functional/data_controller_test.rb b/tracks/test/functional/data_controller_test.rb new file mode 100644 index 00000000..408edff0 --- /dev/null +++ b/tracks/test/functional/data_controller_test.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../test_helper' +require 'data_controller' + +# Re-raise errors caught by the controller. +class DataController; def rescue_action(e) raise e end; end + +class DataControllerTest < Test::Unit::TestCase + def setup + @controller = DataController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + # Replace this with your real tests. + def test_truth + assert true + end +end