From d093ba39bd06818f520b4bae2f308ab0f36949fe Mon Sep 17 00:00:00 2001 From: Darren Cato Date: Sun, 14 Jul 2013 20:56:35 -0400 Subject: [PATCH 01/19] modified gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 81d54e3e..b418ad46 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*.DS_Store *.tmproj *~ .dotest From 9073fa1237ef54f16978454d687daf976220ee17 Mon Sep 17 00:00:00 2001 From: Don Cruse Date: Thu, 18 Jul 2013 22:32:44 -0500 Subject: [PATCH 02/19] Removing some intermediate values This removes some intermediate steps that were ultimately not necessary to the math. It also consolidates some of the methods for counting events so that fewer intermediate values are necessary. To that end, a new scope is added to the ToDo model for events that are *either* created_at or completed_at after a certain date. This scope allows the StatsController to pull out the largest possible responsive set of values, and then filter just the particular slices that it needs for various steps in the calculation. --- app/controllers/stats_controller.rb | 73 +++++++++++++++-------------- app/models/todo.rb | 1 + 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index 008bc3bc..f2d628bb 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -13,39 +13,36 @@ class StatsController < ApplicationController def actions_done_last12months_data # get actions created and completed in the past 12+3 months. +3 for running - # average - actions_done_last12months = current_user.todos.completed_after(@cut_off_year).select("completed_at" ) - actions_created_last12months = current_user.todos.created_after(@cut_off_year).select("created_at") + # - outermost set of entries needed for these calculations + actions_last12months = current_user.todos.created_or_completed_after(@cut_off_year_plus3).select("completed_at,created_at") # convert to array and fill in non-existing months - @actions_done_last12months_array = convert_to_months_from_today_array(actions_done_last12months, 13, :completed_at) - @actions_created_last12months_array = convert_to_months_from_today_array(actions_created_last12months, 13, :created_at) + @actions_done_last12months_array = put_events_into_month_buckets(actions_last12months, 13, :completed_at) + @actions_created_last12months_array = put_events_into_month_buckets(actions_last12months, 13, :created_at) # find max for graph in both arrays - @max = [@actions_done_last12months_array.max, @actions_created_last12months_array.max].max + @max = (@actions_done_last12months_array + @actions_created_last12months_array).max # find running avg - actions_done_last12monthsPlus3 = current_user.todos.completed_after(@cut_off_year_plus3).select("completed_at" ) - actions_created_last12monthsPlus3 = current_user.todos.created_after(@cut_off_year_plus3).select("created_at") - actions_done_last12monthsPlus3_array = convert_to_months_from_today_array(actions_done_last12monthsPlus3, 16, :completed_at) - actions_created_last12monthsPlus3_array = convert_to_months_from_today_array(actions_created_last12monthsPlus3, 16, :created_at) + done_in_last_15_months = put_events_into_month_buckets(actions_last12months, 16, :completed_at) + created_in_last_15_months = put_events_into_month_buckets(actions_last12months, 16, :created_at) - @actions_done_avg_last12months_array, @actions_created_avg_last12months_array = - find_running_avg_array(actions_done_last12monthsPlus3_array, actions_created_last12monthsPlus3_array, 13) + @actions_done_avg_last12months_array = make_running_avg_array(done_in_last_15_months, 13) + @actions_created_avg_last12months_array = make_running_avg_array(created_in_last_15_months, 13) # interpolate avg for current month. - interpolate_avg_for_current_month(@actions_created_last12months_array, @actions_done_last12months_array) + @interpolated_actions_created_this_month = interpolate_avg_for_current_month(@actions_created_last12months_array) + @interpolated_actions_done_this_month = interpolate_avg_for_current_month(@actions_done_last12months_array) - @created_count_array = Array.new(13, actions_created_last12months.size/12.0) - @done_count_array = Array.new(13, actions_done_last12months.size/12.0) + @created_count_array = Array.new(13, actions_last12months.created_after(@cut_off_year).count/12.0) + @done_count_array = Array.new(13, actions_last12months.completed_after(@cut_off_year).count/12.0) @month_names = Array.new(13){ |i| t('date.month_names')[ (Time.now.mon - i -1 ) % 12 + 1 ]} render :layout => false end - def interpolate_avg_for_current_month(created_set, done_set) + def interpolate_avg_for_current_month(set) percent_of_month = Time.zone.now.day.to_f / Time.zone.now.end_of_month.day.to_f - @interpolated_actions_created_this_month = interpolate_avg(created_set, percent_of_month) - @interpolated_actions_done_this_month = interpolate_avg(done_set, percent_of_month) + interpolate_avg(set, percent_of_month) end def actions_done_last_years @@ -54,16 +51,14 @@ class StatsController < ApplicationController end def actions_done_lastyears_data - actions_done_last_months = current_user.todos.completed.select("completed_at").reorder("completed_at DESC") - actions_created_last_months = current_user.todos.select("created_at").reorder("created_at DESC" ) - - # query is sorted, so use last todo to calculate number of months - month_count = [difference_in_months(@today, actions_created_last_months.last.created_at), - difference_in_months(@today, actions_done_last_months.last.completed_at)].max + actions_last_months = current_user.todos.select("completed_at,created_at") + + month_count = [difference_in_months(@today, actions_last_months.minimum(:created_at)), + difference_in_months(@today, actions_last_months.minimum(:completed_at))].max # convert to array and fill in non-existing months - @actions_done_last_months_array = convert_to_months_from_today_array(actions_done_last_months, month_count+1, :completed_at) - @actions_created_last_months_array = convert_to_months_from_today_array(actions_created_last_months, month_count+1, :created_at) + @actions_done_last_months_array = put_events_into_month_buckets(actions_last_months, month_count+1, :completed_at) + @actions_created_last_months_array = put_events_into_month_buckets(actions_last_months, month_count+1, :created_at) # find max for graph in both hashes @max = [@actions_done_last_months_array.max, @actions_created_last_months_array.max].max @@ -77,10 +72,11 @@ class StatsController < ApplicationController correct_last_two_months(@actions_created_avg_last_months_array, month_count) # interpolate avg for this month. - interpolate_avg_for_current_month(@actions_created_last_months_array, @actions_done_last_months_array) + @interpolated_actions_created_this_month = interpolate_avg_for_current_month(@actions_created_last_months_array) + @interpolated_actions_done_this_month = interpolate_avg_for_current_month(@actions_done_last_months_array) - @created_count_array = Array.new(month_count+1, actions_created_last_months.size/month_count) - @done_count_array = Array.new(month_count+1, actions_done_last_months.size/month_count) + @created_count_array = Array.new(month_count+1, actions_last_months.select { |x| x.created_at }.size/month_count) + @done_count_array = Array.new(month_count+1, actions_last_months.select { |x| x.completed_at }.size/month_count) @month_names = Array.new(month_count+1){ |i| t('date.month_names')[ (Time.now.mon - i -1 ) % 12 + 1 ]+ " " + (Time.now - i.months).year.to_s} render :layout => false @@ -382,14 +378,17 @@ class StatsController < ApplicationController # uses the supplied block to determine array of indexes in hash # the block should return an array of indexes each is added to the hash and summed def convert_to_array(records, upper_bound) - # use 0 to initialise action count to zero - a = Array.new(upper_bound){|i| 0 } + a = Array.new(upper_bound, 0) records.each { |r| (yield r).each { |i| a[i] += 1 } } - return a + a end + def put_events_into_month_buckets(records, array_size, date_method_on_todo) + convert_to_array(records.select { |x| x.send(date_method_on_todo) }, array_size) { |r| [difference_in_months(@today, r.send(date_method_on_todo))]} + end + def convert_to_months_from_today_array(records, array_size, date_method_on_todo) - return convert_to_array(records, array_size){ |r| [difference_in_months(@today, r.send(date_method_on_todo))]} + convert_to_array(records, array_size){ |r| [difference_in_months(@today, r.send(date_method_on_todo))]} end def convert_to_days_from_today_array(records, array_size, date_method_on_todo) @@ -455,7 +454,7 @@ class StatsController < ApplicationController end def three_month_avg(set, i) - return ( (set[i]||0) + (set[i+1]||0) + (set[i+2]||0) ) / 3.0 + (set.fetch(i,0) + set.fetch(i+1,0) + set.fetch(i+2,0)) / 3.0 end def interpolate_avg(set, percent) @@ -467,6 +466,12 @@ class StatsController < ApplicationController month_data[count-1] = month_data[count-1] * 3 / 2 if count > 1 end + def make_running_avg_array(set, upper_bound) + result = Array.new(upper_bound) { |i| three_month_avg(set, i) } + result[0] = "null" + result + end + def find_running_avg_array(done_array, created_array, upper_bound) avg_done = Array.new(upper_bound){ |i| three_month_avg(done_array,i) } avg_created = Array.new(upper_bound){ |i| three_month_avg(created_array,i) } diff --git a/app/models/todo.rb b/app/models/todo.rb index 8eb054c8..b725e8ed 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -48,6 +48,7 @@ class Todo < ActiveRecord::Base scope :completed_before, lambda { |date| where("todos.completed_at < ?", date) } scope :created_after, lambda { |date| where("todos.created_at > ?", date) } scope :created_before, lambda { |date| where("todos.created_at < ?", date) } + scope :created_or_completed_after, lambda { |date| where("todos.created_at > ? or todos.completed_at > ?", date, date) } def self.due_after(date) where('todos.due > ?', date) From 91e4717168d78b132af0a7a7e00d6f0f64e46a6d Mon Sep 17 00:00:00 2001 From: Don Cruse Date: Thu, 18 Jul 2013 23:05:38 -0500 Subject: [PATCH 03/19] Removing some more intermediate values Also removing the python-esque combination methods to set multiple disparate variables from a single method by refactoring that to a simpler method. Reducing the complexity of computing running averages. Note: It is not clear to me why the actions_done_lastyears_data action is entirely unscoped on date. That seems to be the expected behavior, so I left it alone. --- app/controllers/stats_controller.rb | 39 +++++++++++------------------ 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index f2d628bb..e5b9a062 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -53,23 +53,20 @@ class StatsController < ApplicationController def actions_done_lastyears_data actions_last_months = current_user.todos.select("completed_at,created_at") - month_count = [difference_in_months(@today, actions_last_months.minimum(:created_at)), - difference_in_months(@today, actions_last_months.minimum(:completed_at))].max + month_count = difference_in_months(@today, actions_last_months.minimum(:created_at)) + # because this action is not scoped by date, the minimum created_at should always be + # less than the minimum completed_at, so no reason to check minimum completed_at # convert to array and fill in non-existing months @actions_done_last_months_array = put_events_into_month_buckets(actions_last_months, month_count+1, :completed_at) @actions_created_last_months_array = put_events_into_month_buckets(actions_last_months, month_count+1, :created_at) # find max for graph in both hashes - @max = [@actions_done_last_months_array.max, @actions_created_last_months_array.max].max + @max = (@actions_done_last_months_array + @actions_created_last_months_array).max - # find running avg - @actions_done_avg_last_months_array, @actions_created_avg_last_months_array = - find_running_avg_array(@actions_done_last_months_array, @actions_created_last_months_array, month_count+1) - - # correct last two months since the data of last+1 and last+2 are not available for avg - correct_last_two_months(@actions_done_avg_last_months_array, month_count) - correct_last_two_months(@actions_created_avg_last_months_array, month_count) + # set running avg + @actions_done_avg_last_months_array = compute_running_avg_array(@actions_done_last_months_array,month_count+1) + @actions_created_avg_last_months_array = compute_running_avg_array(@actions_created_last_months_array,month_count+1) # interpolate avg for this month. @interpolated_actions_created_this_month = interpolate_avg_for_current_month(@actions_created_last_months_array) @@ -387,10 +384,6 @@ class StatsController < ApplicationController convert_to_array(records.select { |x| x.send(date_method_on_todo) }, array_size) { |r| [difference_in_months(@today, r.send(date_method_on_todo))]} end - def convert_to_months_from_today_array(records, array_size, date_method_on_todo) - convert_to_array(records, array_size){ |r| [difference_in_months(@today, r.send(date_method_on_todo))]} - end - def convert_to_days_from_today_array(records, array_size, date_method_on_todo) return convert_to_array(records, array_size){ |r| [difference_in_days(@today, r.send(date_method_on_todo))]} end @@ -461,23 +454,19 @@ class StatsController < ApplicationController (set[0]*(1/percent) + set[1] + set[2]) / 3.0 end - def correct_last_two_months(month_data, count) - month_data[count] = month_data[count] * 3 - month_data[count-1] = month_data[count-1] * 3 / 2 if count > 1 - end - def make_running_avg_array(set, upper_bound) result = Array.new(upper_bound) { |i| three_month_avg(set, i) } result[0] = "null" result end - def find_running_avg_array(done_array, created_array, upper_bound) - avg_done = Array.new(upper_bound){ |i| three_month_avg(done_array,i) } - avg_created = Array.new(upper_bound){ |i| three_month_avg(created_array,i) } - avg_done[0] = avg_created[0] = "null" - - return avg_done, avg_created + # sets "null" on first column and cleans up last two columns, which have insufficient data + def compute_running_avg_array(set, upper_bound) + result = Array.new(upper_bound) { |i| three_month_avg(set, i) } + result[upper_bound-1] = result[upper_bound-1] * 3 + result[upper_bound-2] = result[upper_bound-2] * 3 / 2 if upper_bound > 1 + result[0] = "null" + result end end From 5e6b82c3e55e698f2df62906839a7cf4369f4217 Mon Sep 17 00:00:00 2001 From: Don Cruse Date: Thu, 18 Jul 2013 23:22:44 -0500 Subject: [PATCH 04/19] Combining the running average methods --- app/controllers/stats_controller.rb | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index e5b9a062..b82d4575 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -27,8 +27,8 @@ class StatsController < ApplicationController done_in_last_15_months = put_events_into_month_buckets(actions_last12months, 16, :completed_at) created_in_last_15_months = put_events_into_month_buckets(actions_last12months, 16, :created_at) - @actions_done_avg_last12months_array = make_running_avg_array(done_in_last_15_months, 13) - @actions_created_avg_last12months_array = make_running_avg_array(created_in_last_15_months, 13) + @actions_done_avg_last12months_array = compute_running_avg_array(done_in_last_15_months, 13) + @actions_created_avg_last12months_array = compute_running_avg_array(created_in_last_15_months, 13) # interpolate avg for current month. @interpolated_actions_created_this_month = interpolate_avg_for_current_month(@actions_created_last12months_array) @@ -454,19 +454,13 @@ class StatsController < ApplicationController (set[0]*(1/percent) + set[1] + set[2]) / 3.0 end - def make_running_avg_array(set, upper_bound) - result = Array.new(upper_bound) { |i| three_month_avg(set, i) } - result[0] = "null" - result - end - - # sets "null" on first column and cleans up last two columns, which have insufficient data + # sets "null" on first column and - if necessary - cleans up last two columns, which may have insufficient data def compute_running_avg_array(set, upper_bound) result = Array.new(upper_bound) { |i| three_month_avg(set, i) } - result[upper_bound-1] = result[upper_bound-1] * 3 - result[upper_bound-2] = result[upper_bound-2] * 3 / 2 if upper_bound > 1 + result[upper_bound-1] = result[upper_bound-1] * 3 if upper_bound == set.length + result[upper_bound-2] = result[upper_bound-2] * 3 / 2 if upper_bound > 1 and upper_bound == set.length result[0] = "null" result - end + end # unsolved, not triggered, edge case for set.length == upper_bound + 1 end From ff54506e7fa1c09e367cfd9dc7ad1e53f6d3d602 Mon Sep 17 00:00:00 2001 From: Don Cruse Date: Thu, 18 Jul 2013 23:37:34 -0500 Subject: [PATCH 05/19] Removing a single-line method --- app/controllers/stats_controller.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index b82d4575..f30b7ff4 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -42,7 +42,7 @@ class StatsController < ApplicationController def interpolate_avg_for_current_month(set) percent_of_month = Time.zone.now.day.to_f / Time.zone.now.end_of_month.day.to_f - interpolate_avg(set, percent_of_month) + (set[0]*(1/percent_of_month) + set[1] + set[2]) / 3.0 end def actions_done_last_years @@ -450,10 +450,6 @@ class StatsController < ApplicationController (set.fetch(i,0) + set.fetch(i+1,0) + set.fetch(i+2,0)) / 3.0 end - def interpolate_avg(set, percent) - (set[0]*(1/percent) + set[1] + set[2]) / 3.0 - end - # sets "null" on first column and - if necessary - cleans up last two columns, which may have insufficient data def compute_running_avg_array(set, upper_bound) result = Array.new(upper_bound) { |i| three_month_avg(set, i) } From 3d2c048c44d3130ce025e3b077878312ff6f9088 Mon Sep 17 00:00:00 2001 From: Don Cruse Date: Thu, 18 Jul 2013 23:43:44 -0500 Subject: [PATCH 06/19] Tweak to running averages --- app/controllers/stats_controller.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index f30b7ff4..65ac6739 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -450,9 +450,13 @@ class StatsController < ApplicationController (set.fetch(i,0) + set.fetch(i+1,0) + set.fetch(i+2,0)) / 3.0 end + def set_three_month_avg(set,upper_bound) + (0..upper_bound-1).map { |i| three_month_avg(set, i) } + end + # sets "null" on first column and - if necessary - cleans up last two columns, which may have insufficient data def compute_running_avg_array(set, upper_bound) - result = Array.new(upper_bound) { |i| three_month_avg(set, i) } + result = set_three_month_avg(set, upper_bound) result[upper_bound-1] = result[upper_bound-1] * 3 if upper_bound == set.length result[upper_bound-2] = result[upper_bound-2] * 3 / 2 if upper_bound > 1 and upper_bound == set.length result[0] = "null" From 25bf820edc0bcb102c684bc8740e386fcef9dfa9 Mon Sep 17 00:00:00 2001 From: Don Cruse Date: Thu, 18 Jul 2013 23:48:33 -0500 Subject: [PATCH 07/19] Simplufying interpolation method --- app/controllers/stats_controller.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index 65ac6739..405aafbd 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -41,10 +41,13 @@ class StatsController < ApplicationController end def interpolate_avg_for_current_month(set) - percent_of_month = Time.zone.now.day.to_f / Time.zone.now.end_of_month.day.to_f (set[0]*(1/percent_of_month) + set[1] + set[2]) / 3.0 end + def percent_of_month + Time.zone.now.day / Time.zone.now.end_of_month.day.to_f + end + def actions_done_last_years @page_title = t('stats.index_title') @chart = Stats::Chart.new('actions_done_lastyears_data', :height => 400, :width => 900) From 5b045d2c1a6e39ed6108c47a706a36c7ba7ca299 Mon Sep 17 00:00:00 2001 From: Don Cruse Date: Thu, 18 Jul 2013 23:56:57 -0500 Subject: [PATCH 08/19] Moving time labels to separate methods --- app/controllers/stats_controller.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index 405aafbd..2ba4eb7e 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -36,7 +36,7 @@ class StatsController < ApplicationController @created_count_array = Array.new(13, actions_last12months.created_after(@cut_off_year).count/12.0) @done_count_array = Array.new(13, actions_last12months.completed_after(@cut_off_year).count/12.0) - @month_names = Array.new(13){ |i| t('date.month_names')[ (Time.now.mon - i -1 ) % 12 + 1 ]} + @month_names = Array.new(13){ |i| label_for_month_ago(i) } render :layout => false end @@ -48,6 +48,14 @@ class StatsController < ApplicationController Time.zone.now.day / Time.zone.now.end_of_month.day.to_f end + def label_for_month_and_year_ago(i) + t('date.month_names')[ (Time.now.mon - i -1 ) % 12 + 1 ]+ " " + (Time.now - i.months).year.to_s + end + + def label_for_month_ago(i) + t('date.month_names')[ (Time.now.mon - i -1 ) % 12 + 1 ] + end + def actions_done_last_years @page_title = t('stats.index_title') @chart = Stats::Chart.new('actions_done_lastyears_data', :height => 400, :width => 900) @@ -77,7 +85,7 @@ class StatsController < ApplicationController @created_count_array = Array.new(month_count+1, actions_last_months.select { |x| x.created_at }.size/month_count) @done_count_array = Array.new(month_count+1, actions_last_months.select { |x| x.completed_at }.size/month_count) - @month_names = Array.new(month_count+1){ |i| t('date.month_names')[ (Time.now.mon - i -1 ) % 12 + 1 ]+ " " + (Time.now - i.months).year.to_s} + @month_names = Array.new(month_count+1){ |i| label_for_month_and_year_ago(i) } render :layout => false end From 845ac14176574b9c1efde5b583dc00b8a3ba1d24 Mon Sep 17 00:00:00 2001 From: Don Cruse Date: Fri, 19 Jul 2013 00:14:52 -0500 Subject: [PATCH 09/19] Moving label creation to helpers --- app/controllers/stats_controller.rb | 10 ---------- app/helpers/stats_helper.rb | 16 ++++++++++++++++ .../actions_done_last12months_data.html.erb | 2 +- .../stats/actions_done_lastyears_data.html.erb | 2 +- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index 2ba4eb7e..d6be1be0 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -36,7 +36,6 @@ class StatsController < ApplicationController @created_count_array = Array.new(13, actions_last12months.created_after(@cut_off_year).count/12.0) @done_count_array = Array.new(13, actions_last12months.completed_after(@cut_off_year).count/12.0) - @month_names = Array.new(13){ |i| label_for_month_ago(i) } render :layout => false end @@ -48,14 +47,6 @@ class StatsController < ApplicationController Time.zone.now.day / Time.zone.now.end_of_month.day.to_f end - def label_for_month_and_year_ago(i) - t('date.month_names')[ (Time.now.mon - i -1 ) % 12 + 1 ]+ " " + (Time.now - i.months).year.to_s - end - - def label_for_month_ago(i) - t('date.month_names')[ (Time.now.mon - i -1 ) % 12 + 1 ] - end - def actions_done_last_years @page_title = t('stats.index_title') @chart = Stats::Chart.new('actions_done_lastyears_data', :height => 400, :width => 900) @@ -85,7 +76,6 @@ class StatsController < ApplicationController @created_count_array = Array.new(month_count+1, actions_last_months.select { |x| x.created_at }.size/month_count) @done_count_array = Array.new(month_count+1, actions_last_months.select { |x| x.completed_at }.size/month_count) - @month_names = Array.new(month_count+1){ |i| label_for_month_and_year_ago(i) } render :layout => false end diff --git a/app/helpers/stats_helper.rb b/app/helpers/stats_helper.rb index 9e14d04b..22bbef02 100755 --- a/app/helpers/stats_helper.rb +++ b/app/helpers/stats_helper.rb @@ -4,4 +4,20 @@ module StatsHelper 9 + 2 * cloud.relative_size(tag) end + def month_and_year_label(i) + t('date.month_names')[ (Time.now.mon - i -1 ) % 12 + 1 ]+ " " + (Time.now - i.months).year.to_s + end + + def array_of_month_and_year_labels(count) + Array.new(count) { |i| month_and_year_label(i) } + end + + def month_label(i) + t('date.month_names')[ (Time.now.mon - i -1 ) % 12 + 1 ] + end + + def array_of_month_labels(count) + Array.new(count) { |i| month_label(i) } + end + end diff --git a/app/views/stats/actions_done_last12months_data.html.erb b/app/views/stats/actions_done_last12months_data.html.erb index 294e0c69..8385e2db 100755 --- a/app/views/stats/actions_done_last12months_data.html.erb +++ b/app/views/stats/actions_done_last12months_data.html.erb @@ -23,7 +23,7 @@ &values_6=<%= @actions_done_avg_last12months_array.join(",")%>& &values_7=<%= @interpolated_actions_created_this_month%>,<%=@actions_done_avg_last12months_array[1]%>& &values_8=<%= @interpolated_actions_done_this_month%>,<%=@actions_created_avg_last12months_array[1]%>& -&x_labels=<%= @month_names.join(",")%>& +&x_labels=<%= array_of_month_labels(@done_count_array.size).join(",")%>& &y_min=0& <% # add one to @max for people who have no actions completed yet. # OpenFlashChart cannot handle y_max=0 -%> diff --git a/app/views/stats/actions_done_lastyears_data.html.erb b/app/views/stats/actions_done_lastyears_data.html.erb index aa6bc284..9221e845 100644 --- a/app/views/stats/actions_done_lastyears_data.html.erb +++ b/app/views/stats/actions_done_lastyears_data.html.erb @@ -18,7 +18,7 @@ &values_6=<%= @actions_done_avg_last_months_array.join(",")%>& &values_7=<%= @interpolated_actions_created_this_month%>,<%=@actions_done_avg_last_months_array[1]%>& &values_8=<%= @interpolated_actions_done_this_month%>,<%=@actions_created_avg_last_months_array[1]%>& -&x_labels=<%= @month_names.join(",")%>& +&x_labels=<%= array_of_month_and_year_labels(@done_count_array.size).join(",")%>& &y_min=0& <% # add one to @max for people who have no actions completed yet. # OpenFlashChart cannot handle y_max=0 -%> From 7a5374d56773b334ccb9ce6c502ee83696c9362e Mon Sep 17 00:00:00 2001 From: "Brett A. Rogers" Date: Fri, 19 Jul 2013 15:43:56 -0500 Subject: [PATCH 10/19] Fix setup for calendar controller test Ensure that the expected todos are actually due in the same month --- test/controllers/calendar_controller_test.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/controllers/calendar_controller_test.rb b/test/controllers/calendar_controller_test.rb index 4957b908..19a871b1 100644 --- a/test/controllers/calendar_controller_test.rb +++ b/test/controllers/calendar_controller_test.rb @@ -1,6 +1,11 @@ require_relative '../test_helper' class CalendarControllerTest < ActionController::TestCase + def setup + todos(:call_bill).update_attribute(:due, Time.zone.now.end_of_month.beginning_of_day) + todos(:call_dino_ext).update_attribute(:due, Time.zone.now.end_of_month.beginning_of_day) + end + def test_show login_as(:admin_user) From f18f1c7345c0b1723aff8b104b34c85e31623853 Mon Sep 17 00:00:00 2001 From: "Brett A. Rogers" Date: Fri, 19 Jul 2013 17:27:38 -0500 Subject: [PATCH 11/19] Move calendar test down to unit tests Remove tests that are specific to the calendar model from controller test and move them to unit tests. --- test/controllers/calendar_controller_test.rb | 17 ------- test/models/todos/calendar_test.rb | 47 ++++++++++++++++++++ 2 files changed, 47 insertions(+), 17 deletions(-) create mode 100644 test/models/todos/calendar_test.rb diff --git a/test/controllers/calendar_controller_test.rb b/test/controllers/calendar_controller_test.rb index 19a871b1..d4f47eaa 100644 --- a/test/controllers/calendar_controller_test.rb +++ b/test/controllers/calendar_controller_test.rb @@ -1,10 +1,6 @@ require_relative '../test_helper' class CalendarControllerTest < ActionController::TestCase - def setup - todos(:call_bill).update_attribute(:due, Time.zone.now.end_of_month.beginning_of_day) - todos(:call_dino_ext).update_attribute(:due, Time.zone.now.end_of_month.beginning_of_day) - end def test_show login_as(:admin_user) @@ -14,22 +10,9 @@ class CalendarControllerTest < ActionController::TestCase projects = [projects(:timemachine), projects(:moremoney), projects(:gardenclean)] - due_today = [todos(:phone_grandfather), - todos(:call_bill_gates_every_day), - todos(:due_today)] - due_next_week = [todos(:buy_shares), - todos(:buy_stego_bait), - todos(:new_action_in_context)] - due_this_month = [todos(:call_bill), - todos(:call_dino_ext)] assert_equal "calendar", assigns['source_view'] assert_equal projects, assigns['projects'] - assert_equal due_today, assigns['calendar'].due_today - assert_equal [], assigns['calendar'].due_this_week - assert_equal due_next_week, assigns['calendar'].due_next_week - assert_equal due_this_month, assigns['calendar'].due_this_month - assert_equal [], assigns['calendar'].due_after_this_month assert_equal 8, assigns['count'] end diff --git a/test/models/todos/calendar_test.rb b/test/models/todos/calendar_test.rb new file mode 100644 index 00000000..8ac6f7ec --- /dev/null +++ b/test/models/todos/calendar_test.rb @@ -0,0 +1,47 @@ +require_relative '../../test_helper' + +module Todos + class CalendarTest < ActiveSupport::TestCase + + def setup + @calendar = Calendar.new(users(:admin_user)) + Todo.destroy_all + end + + def create_todo(due_date) + Todo.create due: due_date, + user: users(:admin_user), + description: 'Test Todo', + context: Context.first + end + + def test_due_today + due_today = create_todo(Time.zone.now) + + assert_equal [due_today], @calendar.due_today + end + + def test_due_this_week + due_this_week = create_todo(Time.zone.now.end_of_week) + assert_equal [due_this_week], @calendar.due_this_week + end + + def test_due_next_week + due_next_week = create_todo(1.week.from_now.beginning_of_day) + + assert_equal [due_next_week], @calendar.due_next_week + end + + def test_due_this_month + due_this_month = create_todo(Time.zone.now.end_of_month) + + assert_equal [due_this_month], @calendar.due_this_month + end + + def test_due_after_this_month + due_after_this_month = create_todo(1.month.from_now) + assert_equal [due_after_this_month], @calendar.due_after_this_month + end + end +end + From 3450c22e971edd0ea9242a6bc0d8413a68ae9e64 Mon Sep 17 00:00:00 2001 From: Darren Cato Date: Sun, 21 Jul 2013 13:37:35 -0400 Subject: [PATCH 12/19] first pass at csv import functionality for tracks --- app/controllers/data_controller.rb | 58 ++++++++++++++++++++++++++ app/models/project.rb | 16 +++++++ app/models/todo.rb | 30 ++++++++++++- app/views/data/csv_import.html.erb | 0 app/views/data/csv_map.html.erb | 11 +++++ app/views/data/import.html.erb | 18 ++++++++ app/views/layouts/application.html.erb | 3 +- config/locales/en.yml | 4 +- config/routes.rb | 8 ++++ 9 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 app/views/data/csv_import.html.erb create mode 100644 app/views/data/csv_map.html.erb create mode 100644 app/views/data/import.html.erb diff --git a/app/controllers/data_controller.rb b/app/controllers/data_controller.rb index f9b879f7..1dcf4a58 100644 --- a/app/controllers/data_controller.rb +++ b/app/controllers/data_controller.rb @@ -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 diff --git a/app/models/project.rb b/app/models/project.rb index d86785fe..014ad70a 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -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 diff --git a/app/models/todo.rb b/app/models/todo.rb index 8eb054c8..c72eaca2 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -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 diff --git a/app/views/data/csv_import.html.erb b/app/views/data/csv_import.html.erb new file mode 100644 index 00000000..e69de29b diff --git a/app/views/data/csv_map.html.erb b/app/views/data/csv_map.html.erb new file mode 100644 index 00000000..929faa1e --- /dev/null +++ b/app/views/data/csv_map.html.erb @@ -0,0 +1,11 @@ +

Map fields to be imported

+<%= form_tag csv_import_data_path do %> + <% @labels.each do |l| %> + <%= label_tag l %>: + <%= select_tag(l, options_for_select(@headers) ) %> +
+ <% end %> + <%= hidden_field_tag :file, @path %> + <%= hidden_field_tag :import_to, @import_to %> + <%= submit_tag "Import" %> +<% end %> \ No newline at end of file diff --git a/app/views/data/import.html.erb b/app/views/data/import.html.erb new file mode 100644 index 00000000..8984851a --- /dev/null +++ b/app/views/data/import.html.erb @@ -0,0 +1,18 @@ +
+
+
+

Importing data

+
+

Please upload your CSV file

+ <%= form_tag csv_map_data_path, :id => 'upload_form', multipart: true do %> + + <%= select_tag(:import_to, options_for_select([['Projects', 'projects'], ['Todos', 'todos']], 1) ) %> +

+ <%= file_field_tag :file %> + <%= submit_tag "Upload", :id => "upload_form_submit" %> + <% end %> +
+
+
+ +
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 783b3f82..2630f6c7 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -77,7 +77,8 @@
  • <%= t('layouts.navigation.admin') %>
    • <%= navigation_link( t('layouts.navigation.preferences'), preferences_path, {:accesskey => "u", :title => t('layouts.navigation.preferences_title')} ) %>
    • -
    • <%= navigation_link( t('layouts.navigation.export'), data_path, {:accesskey => "i", :title => t('layouts.navigation.export_title')} ) %>
    • +
    • <%= navigation_link( t('layouts.navigation.export'), data_path, {:accesskey => "e", :title => t('layouts.navigation.export_title')} ) %>
    • +
    • <%= navigation_link( t('layouts.navigation.import'), import_data_path, {:accesskey => "i", :title => t('layouts.navigation.import_title')} ) %>
    • <% if current_user.is_admin? -%>
    • <%= navigation_link(t('layouts.navigation.manage_users'), users_path, {:accesskey => "a", :title => t('layouts.navigation.manage_users_title')} ) %>
    • <% end -%> diff --git a/config/locales/en.yml b/config/locales/en.yml index fb4c3201..60ff0a1c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -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 diff --git a/config/routes.rb b/config/routes.rb index 234015b0..4c3fccb3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 From 2e13affdce19f21cc80a0c9862ea41d7d5611ddd Mon Sep 17 00:00:00 2001 From: Darren Cato Date: Tue, 23 Jul 2013 01:28:43 -0400 Subject: [PATCH 13/19] typos and style tweaks --- app/controllers/data_controller.rb | 2 +- app/models/project.rb | 4 ++-- app/models/todo.rb | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/data_controller.rb b/app/controllers/data_controller.rb index 1dcf4a58..587d9ad3 100644 --- a/app/controllers/data_controller.rb +++ b/app/controllers/data_controller.rb @@ -33,7 +33,7 @@ class DataController < ApplicationController when 'todos' @labels = [:description, :context, :project, :notes, :created_at, :due, :completed_at] else - flash[:error] = "Ivalid import desitination" + flash[:error] = "Invalid import destination" redirect_to :back end respond_to do |format| diff --git a/app/models/project.rb b/app/models/project.rb index 014ad70a..46d369ff 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -137,7 +137,7 @@ class Project < ActiveRecord::Base @age_in_days ||= (Date.today - created_at.to_date + 1).to_i end - def self.import params, user + 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 @@ -151,7 +151,7 @@ class Project < ActiveRecord::Base end end count - end + end end diff --git a/app/models/todo.rb b/app/models/todo.rb index c72eaca2..e73c73eb 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -1,6 +1,6 @@ class Todo < ActiveRecord::Base - MAX_DESC_LENGTH = 300 + MAX_DESCRIPTION_LENGTH = 300 MAX_NOTES_LENGTH = 60000 before_save :render_note @@ -434,7 +434,7 @@ class Todo < ActiveRecord::Base end end - def self.import params, user + def self.import(params, user) default_context = Context.where(:user_id=>user.id).order('id').first count = 0 @@ -455,6 +455,6 @@ class Todo < ActiveRecord::Base end end count - end + end end From 2feb90720431b607a061c03e34ec9e208dd7cfdf Mon Sep 17 00:00:00 2001 From: Darren Cato Date: Tue, 23 Jul 2013 01:52:47 -0400 Subject: [PATCH 14/19] made changes to MAX_DESCRIPTION_LENGTH everywhere --- app/models/todo.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/todo.rb b/app/models/todo.rb index e73c73eb..01f99357 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -109,7 +109,7 @@ 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 => MAX_DESC_LENGTH + validates_length_of :description, :maximum => MAX_DESCRIPTION_LENGTH validates_length_of :notes, :maximum => MAX_NOTES_LENGTH, :allow_nil => true validates_presence_of :show_from, :if => :deferred? validates_presence_of :context @@ -442,7 +442,7 @@ class Todo < ActiveRecord::Base 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.description = row[params[:description].to_i].truncate MAX_DESCRIPTION_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' From 8ff75f9b7d238e93b36d69b6a784958294b004ea Mon Sep 17 00:00:00 2001 From: Matt Bridges Date: Fri, 19 Jul 2013 13:28:34 -0500 Subject: [PATCH 15/19] Pull apart the LoginController#login action Begin pulling apart the different paths through the login action to better understand how the action responds given different state. --- app/controllers/login_controller.rb | 50 ++++++++++++++++------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/app/controllers/login_controller.rb b/app/controllers/login_controller.rb index b9fb3e90..dc51582b 100644 --- a/app/controllers/login_controller.rb +++ b/app/controllers/login_controller.rb @@ -1,5 +1,5 @@ class LoginController < ApplicationController - + layout 'login' skip_before_filter :set_session_expiration skip_before_filter :login_required @@ -14,27 +14,13 @@ class LoginController < ApplicationController case request.method when 'POST' if @user = User.authenticate(params['user_login'], params['user_password']) - session['user_id'] = @user.id - # If checkbox on login page checked, we don't expire the session after 1 hour - # of inactivity and we remember this user for future browser sessions - session['noexpiry'] = params['user_noexpiry'] - msg = (should_expire_sessions?) ? "will expire after 1 hour of inactivity." : "will not expire." - notify :notice, "Login successful: session #{msg}" - cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year, :secure => SITE_CONFIG['secure_cookies'] } - unless should_expire_sessions? - @user.remember_me - cookies[:auth_token] = { :value => @user.remember_token , :expires => @user.remember_token_expires_at, :secure => SITE_CONFIG['secure_cookies'] } - end - redirect_back_or_home - return + return handle_post_success else - @login = params['user_login'] - notify :warning, t('login.unsuccessful') + handle_post_failure end when 'GET' if User.no_users_yet? - redirect_to signup_path - return + return redirect_to signup_path end end respond_to do |format| @@ -42,7 +28,7 @@ class LoginController < ApplicationController format.m { render :action => 'login', :layout => 'mobile' } end end - + def logout logout_user end @@ -63,11 +49,31 @@ class LoginController < ApplicationController format.js end end - + private - + + def handle_post_success + session['user_id'] = @user.id + # If checkbox on login page checked, we don't expire the session after 1 hour + # of inactivity and we remember this user for future browser sessions + session['noexpiry'] = params['user_noexpiry'] + msg = (should_expire_sessions?) ? "will expire after 1 hour of inactivity." : "will not expire." + notify :notice, "Login successful: session #{msg}" + cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year, :secure => SITE_CONFIG['secure_cookies'] } + unless should_expire_sessions? + @user.remember_me + cookies[:auth_token] = { :value => @user.remember_token , :expires => @user.remember_token_expires_at, :secure => SITE_CONFIG['secure_cookies'] } + end + redirect_back_or_home + end + + def handle_post_failure + @login = params['user_login'] + notify :warning, t('login.unsuccessful') + end + def should_expire_sessions? session['noexpiry'] != "on" end - + end From 3bf7888d5a8cb5a7a5286e2956ef2d7e4651c1cd Mon Sep 17 00:00:00 2001 From: Darren Cato Date: Tue, 23 Jul 2013 13:21:56 -0400 Subject: [PATCH 16/19] i18n changes --- app/controllers/data_controller.rb | 4 ++-- config/locales/en.yml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/controllers/data_controller.rb b/app/controllers/data_controller.rb index 587d9ad3..18e3bad2 100644 --- a/app/controllers/data_controller.rb +++ b/app/controllers/data_controller.rb @@ -52,10 +52,10 @@ class DataController < ApplicationController count = Todo.import params, current_user flash[:notice] = "#{count} Todos imported" else - flash[:error] = "Ivalid import desitination" + flash[:error] = t('data.invalid_import_destination') end rescue Exception => e - flash[:error] = "Error importing CSV: #{e}" + flash[:error] = t('data.invalid_import_destination') + ": #{e}" end File.delete(params[:file]) redirect_to import_data_path diff --git a/config/locales/en.yml b/config/locales/en.yml index 60ff0a1c..021bef93 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -813,6 +813,7 @@ en: data: import_successful: Import was successful. import_errors: Some errors occurred during import + import_destination_invalid: Invalid import destination stats: index_title: TRACKS::Statistics within_one: Within 1 From 45a42105875bf98d0bc20855e048fbfbe5602505 Mon Sep 17 00:00:00 2001 From: Tim Madden Date: Wed, 24 Jul 2013 10:14:46 -0500 Subject: [PATCH 17/19] Update db/schema with new syntax --- db/schema.rb | 180 +++++++++++++++++++++++++-------------------------- 1 file changed, 90 insertions(+), 90 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index 42b51e49..96516f59 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -9,43 +9,43 @@ # from scratch. The latter is a flawed and unsustainable approach (the more migrations # you'll amass, the slower it'll run and the greater likelihood for issues). # -# It's strongly recommended to check this file into your version control system. +# It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(:version => 20130227205845) do +ActiveRecord::Schema.define(version: 20130227205845) do - create_table "contexts", :force => true do |t| - t.string "name", :null => false + create_table "contexts", force: true do |t| + t.string "name", null: false t.integer "position" - t.integer "user_id", :default => 1 + t.integer "user_id", default: 1 t.datetime "created_at" t.datetime "updated_at" - t.string "state", :limit => 20, :default => "active", :null => false + t.string "state", limit: 20, default: "active", null: false end - add_index "contexts", ["user_id", "name"], :name => "index_contexts_on_user_id_and_name" - add_index "contexts", ["user_id"], :name => "index_contexts_on_user_id" + add_index "contexts", ["user_id", "name"], name: "index_contexts_on_user_id_and_name", using: :btree + add_index "contexts", ["user_id"], name: "index_contexts_on_user_id", using: :btree - create_table "dependencies", :force => true do |t| - t.integer "successor_id", :null => false - t.integer "predecessor_id", :null => false + create_table "dependencies", force: true do |t| + t.integer "successor_id", null: false + t.integer "predecessor_id", null: false t.string "relationship_type" end - add_index "dependencies", ["predecessor_id"], :name => "index_dependencies_on_predecessor_id" - add_index "dependencies", ["successor_id"], :name => "index_dependencies_on_successor_id" + add_index "dependencies", ["predecessor_id"], name: "index_dependencies_on_predecessor_id", using: :btree + add_index "dependencies", ["successor_id"], name: "index_dependencies_on_successor_id", using: :btree - create_table "notes", :force => true do |t| - t.integer "user_id", :null => false - t.integer "project_id", :null => false + create_table "notes", force: true do |t| + t.integer "user_id", null: false + t.integer "project_id", null: false t.text "body" t.datetime "created_at" t.datetime "updated_at" end - add_index "notes", ["project_id"], :name => "index_notes_on_project_id" - add_index "notes", ["user_id"], :name => "index_notes_on_user_id" + add_index "notes", ["project_id"], name: "index_notes_on_project_id", using: :btree + add_index "notes", ["user_id"], name: "index_notes_on_user_id", using: :btree - create_table "open_id_authentication_associations", :force => true do |t| + create_table "open_id_authentication_associations", force: true do |t| t.integer "issued" t.integer "lifetime" t.string "handle" @@ -54,42 +54,42 @@ ActiveRecord::Schema.define(:version => 20130227205845) do t.binary "secret" end - create_table "open_id_authentication_nonces", :force => true do |t| - t.integer "timestamp", :null => false + create_table "open_id_authentication_nonces", force: true do |t| + t.integer "timestamp", null: false t.string "server_url" - t.string "salt", :null => false + t.string "salt", null: false end - create_table "preferences", :force => true do |t| - t.integer "user_id", :null => false - t.string "date_format", :limit => 40, :default => "%d/%m/%Y", :null => false - t.integer "week_starts", :default => 0, :null => false - t.integer "show_number_completed", :default => 5, :null => false - t.integer "staleness_starts", :default => 7, :null => false - t.boolean "show_completed_projects_in_sidebar", :default => true, :null => false - t.boolean "show_hidden_contexts_in_sidebar", :default => true, :null => false - t.integer "due_style", :default => 0, :null => false - t.integer "refresh", :default => 0, :null => false - t.boolean "verbose_action_descriptors", :default => false, :null => false - t.boolean "show_hidden_projects_in_sidebar", :default => true, :null => false - t.string "time_zone", :default => "London", :null => false - t.boolean "show_project_on_todo_done", :default => false, :null => false - t.string "title_date_format", :default => "%A, %d %B %Y", :null => false - t.integer "mobile_todos_per_page", :default => 6, :null => false + create_table "preferences", force: true do |t| + t.integer "user_id", null: false + t.string "date_format", limit: 40, default: "%d/%m/%Y", null: false + t.integer "week_starts", default: 0, null: false + t.integer "show_number_completed", default: 5, null: false + t.integer "staleness_starts", default: 7, null: false + t.boolean "show_completed_projects_in_sidebar", default: true, null: false + t.boolean "show_hidden_contexts_in_sidebar", default: true, null: false + t.integer "due_style", default: 0, null: false + t.integer "refresh", default: 0, null: false + t.boolean "verbose_action_descriptors", default: false, null: false + t.boolean "show_hidden_projects_in_sidebar", default: true, null: false + t.string "time_zone", default: "London", null: false + t.boolean "show_project_on_todo_done", default: false, null: false + t.string "title_date_format", default: "%A, %d %B %Y", null: false + t.integer "mobile_todos_per_page", default: 6, null: false t.string "sms_email" t.integer "sms_context_id" t.string "locale" - t.integer "review_period", :default => 14, :null => false + t.integer "review_period", default: 14, null: false end - add_index "preferences", ["user_id"], :name => "index_preferences_on_user_id" + add_index "preferences", ["user_id"], name: "index_preferences_on_user_id", using: :btree - create_table "projects", :force => true do |t| - t.string "name", :null => false + create_table "projects", force: true do |t| + t.string "name", null: false t.integer "position" - t.integer "user_id", :default => 1 + t.integer "user_id", default: 1 t.text "description" - t.string "state", :limit => 20, :null => false + t.string "state", limit: 20, null: false t.datetime "created_at" t.datetime "updated_at" t.integer "default_context_id" @@ -98,23 +98,23 @@ ActiveRecord::Schema.define(:version => 20130227205845) do t.datetime "last_reviewed" end - add_index "projects", ["state"], :name => "index_projects_on_state" - add_index "projects", ["user_id", "name"], :name => "index_projects_on_user_id_and_name" - add_index "projects", ["user_id", "state"], :name => "index_projects_on_user_id_and_state" - add_index "projects", ["user_id"], :name => "index_projects_on_user_id" + add_index "projects", ["state"], name: "index_projects_on_state", using: :btree + add_index "projects", ["user_id", "name"], name: "index_projects_on_user_id_and_name", using: :btree + add_index "projects", ["user_id", "state"], name: "index_projects_on_user_id_and_state", using: :btree + add_index "projects", ["user_id"], name: "index_projects_on_user_id", using: :btree - create_table "recurring_todos", :force => true do |t| - t.integer "user_id", :default => 1 - t.integer "context_id", :null => false + create_table "recurring_todos", force: true do |t| + t.integer "user_id", default: 1 + t.integer "context_id", null: false t.integer "project_id" - t.string "description", :null => false + t.string "description", null: false t.text "notes" - t.string "state", :limit => 20, :null => false + t.string "state", limit: 20, null: false t.datetime "start_from" t.string "ends_on" t.datetime "end_date" t.integer "number_of_occurences" - t.integer "occurences_count", :default => 0 + t.integer "occurences_count", default: 0 t.string "target" t.integer "show_from_delta" t.string "recurring_period" @@ -123,106 +123,106 @@ ActiveRecord::Schema.define(:version => 20130227205845) do t.integer "every_other2" t.integer "every_other3" t.string "every_day" - t.boolean "only_work_days", :default => false + t.boolean "only_work_days", default: false t.integer "every_count" t.integer "weekday" t.datetime "completed_at" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at" + t.datetime "updated_at" t.boolean "show_always" end - add_index "recurring_todos", ["state"], :name => "index_recurring_todos_on_state" - add_index "recurring_todos", ["user_id"], :name => "index_recurring_todos_on_user_id" + add_index "recurring_todos", ["state"], name: "index_recurring_todos_on_state", using: :btree + add_index "recurring_todos", ["user_id"], name: "index_recurring_todos_on_user_id", using: :btree - create_table "sessions", :force => true do |t| + create_table "sessions", force: true do |t| t.string "session_id" t.text "data" t.datetime "updated_at" end - add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id" + add_index "sessions", ["session_id"], name: "index_sessions_on_session_id", using: :btree - create_table "taggings", :force => true do |t| + create_table "taggings", force: true do |t| t.integer "taggable_id" t.integer "tag_id" t.string "taggable_type" end - add_index "taggings", ["tag_id", "taggable_id", "taggable_type"], :name => "index_taggings_on_tag_id_and_taggable_id_and_taggable_type" - add_index "taggings", ["tag_id"], :name => "index_taggings_on_tag_id" - add_index "taggings", ["taggable_id", "taggable_type"], :name => "index_taggings_on_taggable_id_and_taggable_type" + add_index "taggings", ["tag_id", "taggable_id", "taggable_type"], name: "index_taggings_on_tag_id_and_taggable_id_and_taggable_type", using: :btree + add_index "taggings", ["tag_id"], name: "index_taggings_on_tag_id", using: :btree + add_index "taggings", ["taggable_id", "taggable_type"], name: "index_taggings_on_taggable_id_and_taggable_type", using: :btree - create_table "tags", :force => true do |t| + create_table "tags", force: true do |t| t.string "name" t.datetime "created_at" t.datetime "updated_at" end - add_index "tags", ["name"], :name => "index_tags_on_name" + add_index "tags", ["name"], name: "index_tags_on_name", using: :btree - create_table "todos", :force => true do |t| - t.integer "context_id", :null => false + create_table "todos", force: true do |t| + t.integer "context_id", null: false t.integer "project_id" - t.string "description", :null => false + t.string "description", null: false t.text "notes" t.datetime "created_at" t.datetime "due" t.datetime "completed_at" - t.integer "user_id", :default => 1 + t.integer "user_id", default: 1 t.datetime "show_from" - t.string "state", :limit => 20, :null => false + t.string "state", limit: 20, null: false t.integer "recurring_todo_id" t.datetime "updated_at" t.text "rendered_notes" end - add_index "todos", ["context_id"], :name => "index_todos_on_context_id" - add_index "todos", ["project_id"], :name => "index_todos_on_project_id" - add_index "todos", ["state"], :name => "index_todos_on_state" - add_index "todos", ["user_id", "context_id"], :name => "index_todos_on_user_id_and_context_id" - add_index "todos", ["user_id", "project_id"], :name => "index_todos_on_user_id_and_project_id" - add_index "todos", ["user_id", "state"], :name => "index_todos_on_user_id_and_state" + add_index "todos", ["context_id"], name: "index_todos_on_context_id", using: :btree + add_index "todos", ["project_id"], name: "index_todos_on_project_id", using: :btree + add_index "todos", ["state"], name: "index_todos_on_state", using: :btree + add_index "todos", ["user_id", "context_id"], name: "index_todos_on_user_id_and_context_id", using: :btree + add_index "todos", ["user_id", "project_id"], name: "index_todos_on_user_id_and_project_id", using: :btree + add_index "todos", ["user_id", "state"], name: "index_todos_on_user_id_and_state", using: :btree - create_table "tolk_locales", :force => true do |t| + create_table "tolk_locales", force: true do |t| t.string "name" t.datetime "created_at" t.datetime "updated_at" end - add_index "tolk_locales", ["name"], :name => "index_tolk_locales_on_name", :unique => true + add_index "tolk_locales", ["name"], name: "index_tolk_locales_on_name", unique: true, using: :btree - create_table "tolk_phrases", :force => true do |t| + create_table "tolk_phrases", force: true do |t| t.text "key" t.datetime "created_at" t.datetime "updated_at" end - create_table "tolk_translations", :force => true do |t| + create_table "tolk_translations", force: true do |t| t.integer "phrase_id" t.integer "locale_id" t.text "text" t.text "previous_text" - t.boolean "primary_updated", :default => false + t.boolean "primary_updated", default: false t.datetime "created_at" t.datetime "updated_at" end - add_index "tolk_translations", ["phrase_id", "locale_id"], :name => "index_tolk_translations_on_phrase_id_and_locale_id", :unique => true + add_index "tolk_translations", ["phrase_id", "locale_id"], name: "index_tolk_translations_on_phrase_id_and_locale_id", unique: true, using: :btree - create_table "users", :force => true do |t| - t.string "login", :limit => 80, :null => false - t.string "crypted_password", :limit => 60, :null => false + create_table "users", force: true do |t| + t.string "login", limit: 80, null: false + t.string "crypted_password", limit: 60, null: false t.string "token" - t.boolean "is_admin", :default => false, :null => false + t.boolean "is_admin", default: false, null: false t.string "first_name" t.string "last_name" - t.string "auth_type", :default => "database", :null => false + t.string "auth_type", default: "database", null: false t.string "open_id_url" t.string "remember_token" t.datetime "remember_token_expires_at" end - add_index "users", ["login"], :name => "index_users_on_login" + add_index "users", ["login"], name: "index_users_on_login", using: :btree end From e7c6142684ec7d3ac8eae34c27fa36d28251e7a3 Mon Sep 17 00:00:00 2001 From: Matt Rogers Date: Wed, 24 Jul 2013 12:35:11 -0500 Subject: [PATCH 18/19] Update the version specifier for timecop --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index d8c629e6..635437dd 100644 --- a/Gemfile +++ b/Gemfile @@ -56,7 +56,7 @@ group :test do gem "aruba", :require => false gem "simplecov" - gem "timecop" + gem "timecop", "~> 0.6.2" # Note that > 2.14 has problems, see: # https://code.google.com/p/selenium/issues/detail?id=3075 diff --git a/Gemfile.lock b/Gemfile.lock index 61de1750..2d2e29d1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -169,7 +169,7 @@ GEM thread_safe (0.1.0) atomic tilt (1.4.1) - timecop (0.6.1) + timecop (0.6.2.2) tolk (1.3.9) safe_yaml (~> 0.8) will_paginate @@ -219,7 +219,7 @@ DEPENDENCIES sqlite3 swf_fu therubyracer - timecop + timecop (~> 0.6.2) tolk uglifier (>= 1.3.0) will_paginate From 8690dc1fcb374c92c3e1b5643bd35d35e9ca83fe Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Sun, 28 Jul 2013 13:34:48 +0200 Subject: [PATCH 19/19] update gems --- Gemfile.lock | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2d2e29d1..ad8276be 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -41,7 +41,7 @@ GEM childprocess (>= 0.3.6) cucumber (>= 1.1.1) rspec-expectations (>= 2.7.0) - atomic (1.1.9) + atomic (1.1.10) bcrypt-ruby (3.0.1) builder (3.1.4) bullet (4.6.0) @@ -63,12 +63,13 @@ GEM coffee-script (2.2.0) coffee-script-source execjs - coffee-script-source (1.6.2) - cucumber (1.3.2) + coffee-script-source (1.6.3) + cucumber (1.3.5) builder (>= 2.1.2) diff-lcs (>= 1.1.3) gherkin (~> 2.12.0) - multi_json (~> 1.3) + multi_json (~> 1.7.5) + multi_test (>= 0.0.2) cucumber-rails (1.3.0) capybara (>= 1.1.2) cucumber (>= 1.1.8) @@ -89,7 +90,7 @@ GEM hike (1.2.3) htmlentities (4.3.1) i18n (0.6.4) - jquery-rails (3.0.1) + jquery-rails (3.0.4) railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) libv8 (3.11.8.17) @@ -98,17 +99,18 @@ GEM treetop (~> 1.4.8) metaclass (0.0.1) mime-types (1.23) - mini_portile (0.5.0) + mini_portile (0.5.1) minitest (4.7.5) mocha (0.14.0) metaclass (~> 0.0.1) multi_json (1.7.7) - mysql2 (0.3.11) + multi_test (0.0.2) + mysql2 (0.3.13) nokogiri (1.6.0) mini_portile (~> 0.5.0) polyglot (0.3.3) rack (1.5.2) - rack-mini-profiler (0.1.26) + rack-mini-profiler (0.1.27) rack (>= 1.1.3) rack-test (0.6.2) rack (>= 1.0) @@ -129,13 +131,13 @@ GEM thor (>= 0.18.1, < 2.0) rake (10.1.0) ref (1.0.5) - rspec-expectations (2.13.0) + rspec-expectations (2.14.0) diff-lcs (>= 1.1.3, < 2.0) rubyzip (0.9.9) - safe_yaml (0.9.3) - sanitize (2.0.4) - nokogiri (~> 1.6.0) - sass (3.2.9) + safe_yaml (0.9.4) + sanitize (2.0.6) + nokogiri (>= 1.4.4) + sass (3.2.10) sass-rails (4.0.0) railties (>= 4.0.0.beta, < 5.0) sass (>= 3.1.10) @@ -166,18 +168,18 @@ GEM libv8 (~> 3.11.8.12) ref thor (0.18.1) - thread_safe (0.1.0) + thread_safe (0.1.2) atomic tilt (1.4.1) timecop (0.6.2.2) - tolk (1.3.9) + tolk (1.3.11) safe_yaml (~> 0.8) will_paginate treetop (1.4.14) polyglot polyglot (>= 0.3.1) tzinfo (0.3.37) - uglifier (2.1.1) + uglifier (2.1.2) execjs (>= 0.3.0) multi_json (~> 1.0, >= 1.0.2) uniform_notifier (1.2.0) @@ -185,7 +187,7 @@ GEM will_paginate (3.0.4) xpath (2.0.0) nokogiri (~> 1.3) - yard (0.8.6.1) + yard (0.8.7) PLATFORMS ruby