mirror of
https://github.com/TracksApp/tracks.git
synced 2025-12-24 03:00:12 +01:00
Merge branch 'master' of git://github.com/bsag/tracks
Signed-off-by: Reinier Balt <lrbalt@gmail.com>
This commit is contained in:
commit
dd56c86f78
25 changed files with 320 additions and 67 deletions
|
|
@ -115,7 +115,7 @@ class ApplicationController < ActionController::Base
|
|||
def format_date(date)
|
||||
if date
|
||||
date_format = prefs.date_format
|
||||
formatted_date = date.strftime("#{date_format}")
|
||||
formatted_date = date.in_time_zone(prefs.time_zone).strftime("#{date_format}")
|
||||
else
|
||||
formatted_date = ''
|
||||
end
|
||||
|
|
@ -170,11 +170,12 @@ class ApplicationController < ActionController::Base
|
|||
# set dates
|
||||
todo.recurring_todo_id = rt.id
|
||||
todo.due = rt.get_due_date(date)
|
||||
# make sure that show_from is not in the past
|
||||
|
||||
show_from_date = rt.get_show_from_date(date)
|
||||
if show_from_date.nil?
|
||||
todo.show_from=nil
|
||||
else
|
||||
# make sure that show_from is not in the past
|
||||
todo.show_from = show_from_date < Time.zone.now ? nil : show_from_date
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -186,6 +186,13 @@ class ProjectsController < ApplicationController
|
|||
init_not_done_counts(['project'])
|
||||
end
|
||||
|
||||
def actionize
|
||||
@state = params['state']
|
||||
@projects = current_user.projects.actionize(current_user.id, :state => @state) if @state
|
||||
@contexts = current_user.contexts
|
||||
init_not_done_counts(['project'])
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def render_projects_html
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ class TodosController < ApplicationController
|
|||
session :off, :only => :index, :if => Proc.new { |req| is_feed_request(req) }
|
||||
|
||||
def index
|
||||
current_user.deferred_todos.find_and_activate_ready
|
||||
@projects = current_user.projects.find(:all, :include => [:default_context])
|
||||
@contexts = current_user.contexts.find(:all)
|
||||
|
||||
|
|
@ -133,7 +134,7 @@ class TodosController < ApplicationController
|
|||
@saved = @todo.toggle_completion!
|
||||
|
||||
# check if this todo has a related recurring_todo. If so, create next todo
|
||||
check_for_next_todo if @saved
|
||||
@new_recurring_todo = check_for_next_todo(@todo) if @saved
|
||||
|
||||
respond_to do |format|
|
||||
format.js do
|
||||
|
|
@ -278,7 +279,7 @@ class TodosController < ApplicationController
|
|||
@project_id = @todo.project_id
|
||||
|
||||
# check if this todo has a related recurring_todo. If so, create next todo
|
||||
check_for_next_todo
|
||||
@new_recurring_todo = check_for_next_todo(@todo)
|
||||
|
||||
@saved = @todo.destroy
|
||||
|
||||
|
|
@ -382,7 +383,7 @@ class TodosController < ApplicationController
|
|||
|
||||
@not_done_todos = tag_collection.find(:all,
|
||||
:conditions => ['taggings.user_id = ? and state = ?', current_user.id, 'active'],
|
||||
:order => 'todos.completed_at DESC, todos.created_at DESC')
|
||||
:order => 'todos.due IS NULL, todos.due ASC, todos.created_at ASC')
|
||||
@hidden_todos = current_user.todos.find(:all,
|
||||
:include => [:taggings, :tags, :context],
|
||||
:conditions => ['tags.name = ? AND (todos.state = ? OR (contexts.hide = ? AND todos.state = ?))', @tag_name, 'project_hidden', true, 'active'],
|
||||
|
|
@ -390,6 +391,7 @@ class TodosController < ApplicationController
|
|||
@deferred = tag_collection.find(:all,
|
||||
:conditions => ['taggings.user_id = ? and state = ?', current_user.id, 'deferred'],
|
||||
:order => 'show_from ASC, todos.created_at DESC')
|
||||
|
||||
# If you've set no_completed to zero, the completed items box isn't shown on
|
||||
# the tag page
|
||||
max_completed = current_user.prefs.show_number_completed
|
||||
|
|
@ -770,33 +772,34 @@ class TodosController < ApplicationController
|
|||
['rss','atom','txt','ics'].include?(req.parameters[:format])
|
||||
end
|
||||
|
||||
def check_for_next_todo
|
||||
def check_for_next_todo(todo)
|
||||
# check if this todo has a related recurring_todo. If so, create next todo
|
||||
@new_recurring_todo = nil
|
||||
@recurring_todo = nil
|
||||
if @todo.from_recurring_todo?
|
||||
@recurring_todo = current_user.recurring_todos.find(@todo.recurring_todo_id)
|
||||
new_recurring_todo = nil
|
||||
recurring_todo = nil
|
||||
if todo.from_recurring_todo?
|
||||
recurring_todo = current_user.recurring_todos.find(todo.recurring_todo_id)
|
||||
|
||||
# check for next todo either from the due date or the show_from date
|
||||
date_to_check = @todo.due.nil? ? @todo.show_from : @todo.due
|
||||
date_to_check = todo.due.nil? ? todo.show_from : todo.due
|
||||
|
||||
# if both due and show_from are nil, check for a next todo with yesterday
|
||||
# as reference point. We pick yesterday so that new todos for today will
|
||||
# be created instead of new todos for tomorrow.
|
||||
date_to_check = Time.zone.now-1.day if date_to_check.nil?
|
||||
# if both due and show_from are nil, check for a next todo from now
|
||||
date_to_check = Time.zone.now if date_to_check.nil?
|
||||
|
||||
if @recurring_todo.active? && @recurring_todo.has_next_todo(date_to_check)
|
||||
if recurring_todo.active? && recurring_todo.has_next_todo(date_to_check)
|
||||
|
||||
# shift the reference date to yesterday if date_to_check is furher in
|
||||
# the past. This is to make sure we do not get older todos for overdue
|
||||
# todos. I.e. checking a daily todo that is overdue with 5 days will
|
||||
# create a new todo which is overdue by 4 days if we don't shift the
|
||||
# date. Discard the time part in the compare
|
||||
# date. Discard the time part in the compare. We pick yesterday so that
|
||||
# new todos due for today will be created instead of new todos for
|
||||
# tomorrow.
|
||||
date = date_to_check.at_midnight >= Time.zone.now.at_midnight ? date_to_check : Time.zone.now-1.day
|
||||
|
||||
@new_recurring_todo = create_todo_from_recurring_todo(@recurring_todo, date)
|
||||
new_recurring_todo = create_todo_from_recurring_todo(recurring_todo, date)
|
||||
end
|
||||
end
|
||||
end
|
||||
return new_recurring_todo
|
||||
end
|
||||
|
||||
def get_due_id_for_calendar(due)
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ module TodosHelper
|
|||
end
|
||||
|
||||
def defer_link(days)
|
||||
link_to_remote image_tag("defer_#{days}.png"), :url => {:controller => 'todos', :action => 'defer', :id => @todo.id, :days => days, :_source_view => (@source_view.underscore.gsub(/\s+/,'_') rescue "")}
|
||||
link_to_remote image_tag("defer_#{days}.png", :alt => "Defer #{pluralize(days, 'day')}"), :url => {:controller => 'todos', :action => 'defer', :id => @todo.id, :days => days, :_source_view => (@source_view.underscore.gsub(/\s+/,'_') rescue "")}
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -495,12 +495,14 @@ class RecurringTodo < ActiveRecord::Base
|
|||
|
||||
def get_xth_day_of_month(x, weekday, month, year)
|
||||
if x == 5
|
||||
# last -> count backwards
|
||||
last_day = Time.zone.local(year, month, Time.days_in_month(month))
|
||||
# last -> count backwards. use UTC to avoid strange timezone oddities
|
||||
# where last_day -= 1.day seems to shift tz+0100 to tz+0000
|
||||
last_day = Time.utc(year, month, Time.days_in_month(month))
|
||||
while last_day.wday != weekday
|
||||
last_day -= 1.day
|
||||
end
|
||||
return last_day
|
||||
# convert back to local timezone
|
||||
return Time.zone.local(last_day.year, last_day.month, last_day.day)
|
||||
else
|
||||
# 1-4th -> count upwards
|
||||
start = Time.zone.local(year,month,1)
|
||||
|
|
@ -517,17 +519,19 @@ class RecurringTodo < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def get_yearly_date(previous)
|
||||
|
||||
start = determine_start(previous)
|
||||
day = self.every_other1
|
||||
month = self.every_other2
|
||||
|
||||
case self.recurrence_selector
|
||||
when 0 # specific day of a specific month
|
||||
# if there is no next month n in this year, search in next year
|
||||
if start.month >= month
|
||||
start = Time.zone.local(start.year+1, month, 1) if start.day >= day
|
||||
start = Time.zone.local(start.year, month, 1) if start.day <= day
|
||||
if start.month > month || (start.month == month && start.day >= day)
|
||||
# if there is no next month n and day m in this year, search in next
|
||||
# year
|
||||
start = Time.zone.local(start.year+1, month, 1)
|
||||
else
|
||||
# if there is a next month n, stay in this year
|
||||
start = Time.zone.local(start.year, month, 1)
|
||||
end
|
||||
return Time.zone.local(start.year, month, day)
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,21 @@ class User < ActiveRecord::Base
|
|||
self.update_positions(projects.map{ |p| p.id })
|
||||
return projects
|
||||
end
|
||||
def actionize(user_id, scope_conditions = {})
|
||||
@state = scope_conditions[:state]
|
||||
query_state = ""
|
||||
query_state = "AND project.state = '" + @state +"' "if @state
|
||||
projects = Project.find_by_sql([
|
||||
"SELECT project.id, count(todo.id) as p_count " +
|
||||
"FROM projects as project " +
|
||||
"LEFT OUTER JOIN todos as todo ON todo.project_id = project.id "+
|
||||
"WHERE project.user_id = ? AND NOT todo.state='completed' " +
|
||||
query_state +
|
||||
" GROUP BY project.id ORDER by p_count DESC",user_id])
|
||||
self.update_positions(projects.map{ |p| p.id })
|
||||
projects = find(:all, :conditions => scope_conditions)
|
||||
return projects
|
||||
end
|
||||
end
|
||||
has_many :active_projects,
|
||||
:class_name => 'Project',
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ the newly created action.
|
|||
*)
|
||||
|
||||
(* Edit appropriately for your setup *)
|
||||
property myUsername to "<%= current_user.login %>"
|
||||
property myToken to "<%= current_user.token %>"
|
||||
property myContextID to <%= context.id %> (* <%= context.name %> *)
|
||||
property myUsername : "<%= current_user.login %>"
|
||||
property myToken : "<%= current_user.token %>"
|
||||
property myContextID : <%= context.id %> (* <%= context.name %> *)
|
||||
|
||||
-- this string is used when the message subject is empty
|
||||
property emptySubject : "No Subject Specified"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
<div class="project-state-group" id="list-<%= state %>-projects-container" <%= " style=\"display:none\"" if project_state_group.empty? %>>
|
||||
<h2><span id="<%= state %>-projects-count" class="badge"><%= project_state_group.length %></span><%= state.titlecase %> Projects</h2>
|
||||
<div class="menu_sort"><span class="sort_separator">Sort </span>
|
||||
<div class="alpha_sort">
|
||||
<%= link_to("Sort Alphabetically", alphabetize_projects_path(:state => state),
|
||||
<%= link_to("Alphabetically", alphabetize_projects_path(:state => state),
|
||||
:class => "alphabetize_link", :title => "Sort these projects alphabetically") %>
|
||||
<% apply_behavior '.alphabetize_link:click', :prevent_default => true do |page, element|
|
||||
page.confirming 'Are you sure that you want to sort these projects alphabetically? This will replace the existing sort order.' do
|
||||
|
|
@ -10,10 +11,21 @@
|
|||
page << remote_to_href(:complete => "alphaSort.stopWaiting()")
|
||||
end
|
||||
end
|
||||
%></div><span class="sort_separator"> | </span><div class="tasks_sort">
|
||||
<%= link_to("By number of tasks", actionize_projects_path(:state => state),
|
||||
:class => "actionize_link", :title => "Sort these projects by number of tasks") %>
|
||||
<% apply_behavior '.actionize_link:click', :prevent_default => true do |page, element|
|
||||
page.confirming 'Are you sure that you want to sort these projects by the number of tasks? This will replace the existing sort order.' do
|
||||
page << "tasksSort = this.up('.tasks_sort');
|
||||
tasksSort.startWaiting();"
|
||||
page << remote_to_href(:complete => "tasksSort.stopWaiting()")
|
||||
end
|
||||
end
|
||||
%></div>
|
||||
</div>
|
||||
|
||||
<div id="list-<%= state %>-projects" class="project-list">
|
||||
<%= render :partial => 'project_listing', :collection => project_state_group %>
|
||||
</div>
|
||||
<%= sortable_element "list-#{state}-projects", get_listing_sortable_options("list-#{state}-projects") %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
6
app/views/projects/actionize.js.rjs
Normal file
6
app/views/projects/actionize.js.rjs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
list_id = "list-#{@state}-projects"
|
||||
page.replace_html list_id,
|
||||
:partial => 'project_listing',
|
||||
:collection => @projects
|
||||
page.sortable list_id, get_listing_sortable_options(list_id)
|
||||
|
||||
|
|
@ -33,8 +33,8 @@ end %>
|
|||
<h2><label for="tag_list">Tags (separate with commas)</label></h2>
|
||||
<%= text_field_tag "tag_list", @tag_list_text, :size => 30, :tabindex => 6 %>
|
||||
<h2><label for="todo_due">Due</label></h2>
|
||||
<%= date_select("todo", "due", :order => [:day, :month, :year],
|
||||
:start_year => this_year, :include_blank => true) %>
|
||||
<%= date_select("todo", "due", {:order => [:day, :month, :year],
|
||||
:start_year => this_year, :include_blank => true}, :tabindex => 7) %>
|
||||
<h2><label for="todo_show_from">Show from</label></h2>
|
||||
<%= date_select("todo", "show_from", :order => [:day, :month, :year],
|
||||
:start_year => this_year, :include_blank => true) %>
|
||||
<%= date_select("todo", "show_from", {:order => [:day, :month, :year],
|
||||
:start_year => this_year, :include_blank => true}, :tabindex => 8) %>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<% form_tag formatted_todos_path(:m), :method => :post do %>
|
||||
<%= render :partial => 'edit_mobile' %>
|
||||
<p><input type="submit" value="Create" tabindex="6" accesskey="#" /></p>
|
||||
<p><input type="submit" value="Create" tabindex="12" accesskey="#" /></p>
|
||||
<% end -%>
|
||||
<%= link_to "Back", @return_path %>
|
||||
|
|
@ -28,6 +28,10 @@ ActionController::Routing::Routes.draw do |map|
|
|||
projects.resources :todos, :name_prefix => "project_"
|
||||
end
|
||||
|
||||
map.resources :projects, :collection => {:order => :post, :actionize => :post} do |projects|
|
||||
projects.resources :todos, :name_prefix => "project_"
|
||||
end
|
||||
|
||||
map.resources :todos,
|
||||
:member => {:toggle_check => :put, :toggle_star => :put},
|
||||
:collection => {:check_deferred => :post, :filter_to_context => :post, :filter_to_project => :post}
|
||||
|
|
|
|||
|
|
@ -6,14 +6,26 @@ class ChangeDatesToDatetimes < ActiveRecord::Migration
|
|||
change_column :recurring_todos, :end_date, :datetime
|
||||
|
||||
User.all(:include => [:todos, :recurring_todos]).each do |user|
|
||||
if !user.prefs ## ugly hack for strange edge-case of not having preferences object
|
||||
user.instance_eval do
|
||||
def at_midnight(date)
|
||||
return Time.zone.local(date.year, date.month, date.day, 0, 0, 0)
|
||||
end
|
||||
def time
|
||||
Time.zone.now
|
||||
end
|
||||
end
|
||||
end
|
||||
user.todos.each do |todo|
|
||||
todo.update_attribute(:show_from, user.at_midnight(todo.show_from)) unless todo.show_from.nil?
|
||||
todo.update_attribute(:due, user.at_midnight(todo.due)) unless todo.due.nil?
|
||||
todo[:show_from] = user.at_midnight(todo.show_from) unless todo.show_from.nil?
|
||||
todo[:due] = user.at_midnight(todo.due) unless todo.due.nil?
|
||||
todo.save_with_validation(false)
|
||||
end
|
||||
|
||||
user.recurring_todos.each do |todo|
|
||||
todo.update_attribute(:start_from, user.at_midnight(todo.start_from)) unless todo.start_from.nil?
|
||||
todo.update_attribute(:end_date, user.at_midnight(todo.end_date)) unless todo.end_date.nil?
|
||||
todo[:start_from] = user.at_midnight(todo.start_from) unless todo.start_from.nil?
|
||||
todo[:end_date] = user.at_midnight(todo.end_date) unless todo.end_date.nil?
|
||||
todo.save_with_validation(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ New features:
|
|||
4. New interface to import an email / sms messages into Tracks (needs an email server on the same server as Tracks)
|
||||
5. New buttons to quickly defer an action 1 or 7 days
|
||||
6. Calendar view to review due actions, includes iCal feed to use in your calendar app (tested with Google Calendar, Evolution, Outlook 2007)
|
||||
7. You can now sort projects on number of active todos
|
||||
|
||||
Under the hood:
|
||||
1. Move selenium tests to RSpec
|
||||
|
|
|
|||
|
|
@ -692,11 +692,14 @@ div#list-active-projects, div#list-hidden-projects, div#list-completed-projects,
|
|||
margin:20px 0px 8px 13px
|
||||
}
|
||||
|
||||
div.alpha_sort {
|
||||
div.menu_sort {
|
||||
margin-top:-20px;
|
||||
float:right;
|
||||
}
|
||||
|
||||
div.alpha_sort, div.tasks_sort,span.sort_separator {
|
||||
float:left;
|
||||
}
|
||||
|
||||
.container td {
|
||||
border: none;
|
||||
|
|
|
|||
|
|
@ -129,7 +129,8 @@ div.buttons, div.buttons a, div.buttons a:hover {text-align: right; margin-right
|
|||
div#list-active-projects, div#list-hidden-projects, div#list-completed-projects, div#list-contexts, div#projects-empty-nd {clear:right; border: 1px solid #999}
|
||||
.project-state-group h2 {margin:20px 0px 8px 13px}
|
||||
.search-result-group h2 {margin:20px 0px 8px 13px }
|
||||
div.alpha_sort {margin-top:-20px; float:right}
|
||||
div.menu_sort {margin-top:-20px; float:right}
|
||||
div.alpha_sort, div.tasks_sort,span.sort_separator {float:left}
|
||||
.container td {border: none; padding-bottom: 5px}
|
||||
.container form {border: none}
|
||||
div.project_description {background: #eee; padding: 5px; margin-top: 0px; margin-left: -5px; margin-right: -5px; color: #666; font-style: italic; font-size: 12px; font-weight: normal}
|
||||
14
test/fixtures/todos.yml
vendored
14
test/fixtures/todos.yml
vendored
|
|
@ -230,3 +230,17 @@ end
|
|||
completed_at: ~
|
||||
show_from: <%= next_week %>
|
||||
user_id: 2
|
||||
|
||||
18:
|
||||
id: 18
|
||||
user_id: 1
|
||||
context_id: 1
|
||||
project_id: 2
|
||||
description: Call Bill Gates every day
|
||||
notes: ~
|
||||
state: active
|
||||
created_at: <%= last_week %>
|
||||
due: <%= last_week %>
|
||||
completed_at: ~
|
||||
show_from: ~
|
||||
recurring_todo_id: 1
|
||||
|
|
@ -218,6 +218,15 @@ class ProjectsControllerTest < TodoContainerControllerTestBase
|
|||
get :index, { :format => "txt", :token => users(:admin_user).token }
|
||||
assert_response :ok
|
||||
end
|
||||
|
||||
def test_actionize_sorts_active_projects_by_number_of_tasks
|
||||
login_as :admin_user
|
||||
u = users(:admin_user)
|
||||
post :actionize, :state => "active", :format => 'js'
|
||||
assert_equal 1, projects(:gardenclean).position
|
||||
assert_equal 2, projects(:timemachine).position
|
||||
assert_equal 3, projects(:moremoney).position
|
||||
end
|
||||
|
||||
def test_alphabetize_sorts_active_projects_alphabetically
|
||||
login_as :admin_user
|
||||
|
|
|
|||
|
|
@ -79,6 +79,11 @@ class RecurringTodosControllerTest < ActionController::TestCase
|
|||
recurring_todo_1 = RecurringTodo.find(1)
|
||||
assert recurring_todo_1.completed?
|
||||
|
||||
# remove remaining todo
|
||||
todo = Todo.find_by_recurring_todo_id(1)
|
||||
todo.recurring_todo_id = 2
|
||||
todo.save
|
||||
|
||||
todo_count = Todo.count
|
||||
|
||||
# mark as active
|
||||
|
|
@ -120,4 +125,59 @@ class RecurringTodosControllerTest < ActionController::TestCase
|
|||
assert_equal nil, new_todo.show_from
|
||||
end
|
||||
|
||||
def test_last_sunday_of_march
|
||||
# this test is a duplicate of the unit test. Only this test covers the
|
||||
# codepath in the controllers
|
||||
|
||||
login_as(:admin_user)
|
||||
|
||||
orig_rt_count = RecurringTodo.count
|
||||
orig_todo_count = Todo.count
|
||||
|
||||
put :create,
|
||||
"context_name"=>"library",
|
||||
"project_name"=>"Build a working time machine",
|
||||
"recurring_todo" =>
|
||||
{
|
||||
"daily_every_x_days"=>"1",
|
||||
"daily_selector"=>"daily_every_x_day",
|
||||
"description"=>"new recurring pattern",
|
||||
"end_date" => "",
|
||||
"ends_on" => "no_end_date",
|
||||
"monthly_day_of_week" => "1",
|
||||
"monthly_every_x_day" => "22",
|
||||
"monthly_every_x_month2" => "1",
|
||||
"monthly_every_x_month" => "1",
|
||||
"monthly_every_xth_day"=>"1",
|
||||
"monthly_selector"=>"monthly_every_x_day",
|
||||
"notes"=>"with some notes",
|
||||
"number_of_occurences" => "",
|
||||
"recurring_period"=>"yearly",
|
||||
"recurring_show_days_before"=>"0",
|
||||
"recurring_target"=>"due_date",
|
||||
"start_from"=>"",
|
||||
"weekly_every_x_week"=>"1",
|
||||
"weekly_return_monday"=>"w",
|
||||
"yearly_day_of_week"=>"0",
|
||||
"yearly_every_x_day"=>"22",
|
||||
"yearly_every_xth_day"=>"5",
|
||||
"yearly_month_of_year2"=>"3",
|
||||
"yearly_month_of_year"=>"10",
|
||||
"yearly_selector"=>"yearly_every_xth_day"
|
||||
},
|
||||
"tag_list"=>"one, two, three, four"
|
||||
|
||||
# check new recurring todo added
|
||||
assert_equal orig_rt_count+1, RecurringTodo.count
|
||||
# check new todo added
|
||||
assert_equal orig_todo_count+1, Todo.count
|
||||
|
||||
# find the newly created todo
|
||||
new_todo = Todo.find_by_description("new recurring pattern")
|
||||
assert !new_todo.nil?
|
||||
|
||||
# the date should be 29 march 2009
|
||||
assert_equal Time.zone.local(2009,3,29), new_todo.due
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ class StatsControllerTest < Test::Unit::TestCase
|
|||
assert_equal 3, assigns['projects'].count
|
||||
assert_equal 3, assigns['projects'].count(:conditions => "state = 'active'")
|
||||
assert_equal 10, assigns['contexts'].count
|
||||
assert_equal 15, assigns['actions'].count
|
||||
assert_equal 16, assigns['actions'].count
|
||||
assert_equal 4, assigns['tags'].count
|
||||
assert_equal 2, assigns['unique_tags'].size
|
||||
assert_equal 2.week.ago.utc.beginning_of_day, assigns['first_action'].created_at
|
||||
|
|
|
|||
|
|
@ -124,9 +124,9 @@ class TodosControllerTest < Test::Rails::TestCase
|
|||
def test_update_todo_to_deferred_is_reflected_in_badge_count
|
||||
login_as(:admin_user)
|
||||
get :index
|
||||
assert_equal 10, assigns['count']
|
||||
assert_equal 11, assigns['count']
|
||||
xhr :post, :update, :id => 1, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"Make more money than Billy Gates", "todo"=>{"id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006", "show_from"=>"30/11/2030"}, "tag_list"=>"foo bar"
|
||||
assert_equal 9, assigns['down_count']
|
||||
assert_equal 10, assigns['down_count']
|
||||
end
|
||||
|
||||
def test_update_todo
|
||||
|
|
@ -188,7 +188,7 @@ class TodosControllerTest < Test::Rails::TestCase
|
|||
assert_select '>description', "Actions for #{users(:admin_user).display_name}"
|
||||
assert_select 'language', 'en-us'
|
||||
assert_select 'ttl', '40'
|
||||
assert_select 'item', 10 do
|
||||
assert_select 'item', 11 do
|
||||
assert_select 'title', /.+/
|
||||
assert_select 'description', /.*/
|
||||
assert_select 'link', %r{http://test.host/contexts/.+}
|
||||
|
|
@ -242,7 +242,7 @@ class TodosControllerTest < Test::Rails::TestCase
|
|||
assert_xml_select 'feed[xmlns="http://www.w3.org/2005/Atom"]' do
|
||||
assert_xml_select '>title', 'Tracks Actions'
|
||||
assert_xml_select '>subtitle', "Actions for #{users(:admin_user).display_name}"
|
||||
assert_xml_select 'entry', 10 do
|
||||
assert_xml_select 'entry', 11 do
|
||||
assert_xml_select 'title', /.+/
|
||||
assert_xml_select 'content[type="html"]', /.*/
|
||||
assert_xml_select 'published', /(#{Regexp.escape(projects(:timemachine).updated_at.xmlschema)}|#{Regexp.escape(projects(:moremoney).updated_at.xmlschema)})/
|
||||
|
|
@ -311,7 +311,7 @@ class TodosControllerTest < Test::Rails::TestCase
|
|||
def test_mobile_index_assigns_down_count
|
||||
login_as(:admin_user)
|
||||
get :index, { :format => "m" }
|
||||
assert_equal 10, assigns['down_count']
|
||||
assert_equal 11, assigns['down_count']
|
||||
end
|
||||
|
||||
def test_mobile_create_action_creates_a_new_todo
|
||||
|
|
@ -362,38 +362,127 @@ class TodosControllerTest < Test::Rails::TestCase
|
|||
|
||||
# link todo_1 and recurring_todo_1
|
||||
recurring_todo_1 = RecurringTodo.find(1)
|
||||
todo_1 = Todo.find(1)
|
||||
todo_1.recurring_todo_id = recurring_todo_1.id
|
||||
|
||||
# update todo_1
|
||||
assert todo_1.save
|
||||
todo_1 = Todo.find_by_recurring_todo_id(1)
|
||||
|
||||
# mark todo_1 as complete by toggle_check
|
||||
xhr :post, :toggle_check, :id => 1, :_source_view => 'todo'
|
||||
xhr :post, :toggle_check, :id => todo_1.id, :_source_view => 'todo'
|
||||
todo_1.reload
|
||||
assert todo_1.completed?
|
||||
|
||||
# check that there is only one active todo belonging to recurring_todo
|
||||
count = Todo.count(:all, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'active'})
|
||||
assert_equal 1, count
|
||||
|
||||
# check there is a new todo linked to the recurring pattern
|
||||
next_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'active'})
|
||||
assert_equal "Call Bill Gates every day", next_todo.description
|
||||
# check that the new todo is not the same as todo_1
|
||||
assert_not_equal todo_1.id, next_todo.id
|
||||
|
||||
# change recurrence pattern to weekly and set show_from 2 days befor due date
|
||||
# this forces the next todo to be put in the tickler
|
||||
# change recurrence pattern to monthly and set show_from 2 days before due
|
||||
# date this forces the next todo to be put in the tickler
|
||||
recurring_todo_1.show_from_delta = 2
|
||||
recurring_todo_1.recurring_period = 'weekly'
|
||||
recurring_todo_1.every_day = 'smtwtfs'
|
||||
recurring_todo_1.recurring_period = 'monthly'
|
||||
recurring_todo_1.recurrence_selector = 0
|
||||
recurring_todo_1.every_other1 = 1
|
||||
recurring_todo_1.every_other2 = 2
|
||||
recurring_todo_1.every_other3 = 5
|
||||
recurring_todo_1.save
|
||||
|
||||
|
||||
# mark next_todo as complete by toggle_check
|
||||
xhr :post, :toggle_check, :id => next_todo.id, :_source_view => 'todo'
|
||||
next_todo.reload
|
||||
assert next_todo.completed?
|
||||
|
||||
# check that there are three todos belonging to recurring_todo: two
|
||||
# completed and one deferred
|
||||
count = Todo.count(:all, :conditions => {:recurring_todo_id => recurring_todo_1.id})
|
||||
assert_equal 3, count
|
||||
|
||||
# check there is a new todo linked to the recurring pattern in the tickler
|
||||
next_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'deferred'})
|
||||
assert !next_todo.nil?
|
||||
assert_equal "Call Bill Gates every day", next_todo.description
|
||||
# check that the todo is in the tickler
|
||||
assert !next_todo.show_from.nil?
|
||||
end
|
||||
|
||||
|
||||
def test_toggle_check_on_rec_todo_show_from_today
|
||||
login_as(:admin_user)
|
||||
|
||||
# link todo_1 and recurring_todo_1
|
||||
recurring_todo_1 = RecurringTodo.find(1)
|
||||
todo_1 = Todo.find_by_recurring_todo_id(1)
|
||||
today = Time.now.utc.at_midnight
|
||||
|
||||
# change recurrence pattern to monthly and set show_from to today
|
||||
recurring_todo_1.target = 'show_from_date'
|
||||
recurring_todo_1.recurring_period = 'monthly'
|
||||
recurring_todo_1.recurrence_selector = 0
|
||||
recurring_todo_1.every_other1 = today.day
|
||||
recurring_todo_1.every_other2 = 1
|
||||
recurring_todo_1.save
|
||||
|
||||
# mark todo_1 as complete by toggle_check, this gets rid of todo_1 that was
|
||||
# not correctly created from the adjusted recurring pattern we defined
|
||||
# above.
|
||||
xhr :post, :toggle_check, :id => todo_1.id, :_source_view => 'todo'
|
||||
todo_1.reload
|
||||
assert todo_1.completed?
|
||||
|
||||
# locate the new todo. This todo is created from the adjusted recurring
|
||||
# pattern defined in this test
|
||||
new_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'active'})
|
||||
assert !new_todo.nil?
|
||||
|
||||
# mark new_todo as complete by toggle_check
|
||||
xhr :post, :toggle_check, :id => new_todo.id, :_source_view => 'todo'
|
||||
new_todo.reload
|
||||
assert todo_1.completed?
|
||||
|
||||
# locate the new todo in tickler
|
||||
new_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'deferred'})
|
||||
assert !new_todo.nil?
|
||||
|
||||
assert_equal "Call Bill Gates every day", new_todo.description
|
||||
# check that the new todo is not the same as todo_1
|
||||
assert_not_equal todo_1.id, new_todo.id
|
||||
|
||||
# check that the new_todo is in the tickler to show next month
|
||||
assert !new_todo.show_from.nil?
|
||||
assert_equal Time.utc(today.year, today.month+1, today.day), new_todo.show_from
|
||||
end
|
||||
|
||||
def test_check_for_next_todo
|
||||
login_as :admin_user
|
||||
|
||||
recurring_todo_1 = RecurringTodo.find(5)
|
||||
@todo = Todo.find_by_recurring_todo_id(1)
|
||||
assert @todo.from_recurring_todo?
|
||||
# rewire @todo to yearly recurring todo
|
||||
@todo.recurring_todo_id = 5
|
||||
|
||||
# make todo due tomorrow and change recurring date also to tomorrow
|
||||
@todo.due = Time.zone.now + 1.day
|
||||
@todo.save
|
||||
recurring_todo_1.every_other1 = @todo.due.day
|
||||
recurring_todo_1.every_other2 = @todo.due.month
|
||||
recurring_todo_1.save
|
||||
|
||||
# mark todo complete
|
||||
xhr :post, :toggle_check, :id => @todo.id, :_source_view => 'todo'
|
||||
@todo.reload
|
||||
assert @todo.completed?
|
||||
|
||||
# check that there is no active todo
|
||||
next_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'active'})
|
||||
assert next_todo.nil?
|
||||
|
||||
# check for new deferred todo
|
||||
next_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'deferred'})
|
||||
assert !next_todo.nil?
|
||||
# check that the due date of the new todo is later than tomorrow
|
||||
assert next_todo.due > @todo.due
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ class ContextTest < Test::Rails::TestCase
|
|||
end
|
||||
|
||||
def test_delete_context_deletes_todos_within_it
|
||||
assert_equal 6, @agenda.todos.count
|
||||
assert_equal 7, @agenda.todos.count
|
||||
agenda_todo_ids = @agenda.todos.collect{|t| t.id }
|
||||
@agenda.destroy
|
||||
agenda_todo_ids.each do |todo_id|
|
||||
|
|
@ -62,11 +62,11 @@ class ContextTest < Test::Rails::TestCase
|
|||
end
|
||||
|
||||
def test_not_done_todos
|
||||
assert_equal 5, @agenda.not_done_todos.size
|
||||
assert_equal 6, @agenda.not_done_todos.size
|
||||
t = @agenda.not_done_todos[0]
|
||||
t.complete!
|
||||
t.save!
|
||||
assert_equal 4, Context.find(@agenda.id).not_done_todos.size
|
||||
assert_equal 5, Context.find(@agenda.id).not_done_todos.size
|
||||
end
|
||||
|
||||
def test_done_todos
|
||||
|
|
|
|||
|
|
@ -172,9 +172,9 @@ class ProjectTest < Test::Rails::TestCase
|
|||
|
||||
def test_not_done_todo_count
|
||||
assert_equal 2, @timemachine.not_done_todo_count
|
||||
assert_equal 3, @moremoney.not_done_todo_count
|
||||
assert_equal 4, @moremoney.not_done_todo_count
|
||||
@moremoney.todos[0].complete!
|
||||
assert_equal 2, @moremoney.not_done_todo_count
|
||||
assert_equal 3, @moremoney.not_done_todo_count
|
||||
end
|
||||
|
||||
def test_default_context_name
|
||||
|
|
|
|||
|
|
@ -174,6 +174,9 @@ class RecurringTodoTest < Test::Rails::TestCase
|
|||
# same month, day after
|
||||
due_date = @yearly.get_due_date(@monday) # june 9th
|
||||
assert_equal Time.zone.local(2009,6,8), due_date # june 8th next year
|
||||
# very overdue
|
||||
due_date = @yearly.get_due_date(@monday+5.months-2.days) # november 7
|
||||
assert_equal Time.zone.local(2009,6,8), due_date # june 8th next year
|
||||
|
||||
@yearly.recurrence_selector = 1
|
||||
@yearly.every_other3 = 2 # second
|
||||
|
|
@ -194,6 +197,15 @@ class RecurringTodoTest < Test::Rails::TestCase
|
|||
assert_equal due_date1, due_date2
|
||||
end
|
||||
|
||||
def test_last_sunday_of_march
|
||||
@yearly.recurrence_selector = 1
|
||||
@yearly.every_other2 = 3 # march
|
||||
@yearly.every_other3 = 5 # last
|
||||
@yearly.every_count = 0 # sunday
|
||||
due_date = @yearly.get_due_date(Time.zone.local(2008,10,1)) # oct 1st
|
||||
assert_equal Time.zone.local(2009,3,29), due_date # march 29th
|
||||
end
|
||||
|
||||
def test_start_from_in_future
|
||||
# every_day should return start_day if it is in the future
|
||||
@every_day.start_from = @in_three_days
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue