Merge branch 'master' into new-gui

Conflicts:
	Gemfile.lock
This commit is contained in:
Reinier Balt 2014-01-07 21:01:55 +01:00
parent fa537fbeb0
commit eb1502d4e0
28 changed files with 385 additions and 221 deletions

View file

@ -1,9 +1,15 @@
language: ruby language: ruby
rvm: rvm:
- 1.9.3 - 1.9.3
- 2.0.0 - 2.0.0
- 2.1
bundler_args: --without development
before_install: before_install:
before_install:
- "gem install bundler -v=1.5.1"
- "mysql -e 'create database tracks_test;'" - "mysql -e 'create database tracks_test;'"
- "export DISPLAY=:99.0" - "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start" - "sh -e /etc/init.d/xvfb start"
@ -12,7 +18,6 @@ before_install:
script: "CODECLIMATE_REPO_TOKEN=5c52fdd2bbcd0734d56ddb2c3cbaac782da345273e8689d25f54a065ccc3397c bundle exec rake ci RACK_ENV=test" script: "CODECLIMATE_REPO_TOKEN=5c52fdd2bbcd0734d56ddb2c3cbaac782da345273e8689d25f54a065ccc3397c bundle exec rake ci RACK_ENV=test"
bundler_args: --without development
notifications: notifications:
email: false email: false

View file

@ -1,6 +1,6 @@
GIT GIT
remote: https://github.com/cucumber/aruba remote: https://github.com/cucumber/aruba
revision: adbfc240d69254d7b525876b4c5bff6b721b7d65 revision: 7afbc5c0cbae9c9a946d70c4c2735ccb86e00f08
specs: specs:
aruba (0.5.3) aruba (0.5.3)
childprocess (>= 0.3.6) childprocess (>= 0.3.6)
@ -9,35 +9,35 @@ GIT
GIT GIT
remote: https://github.com/rails/actionpack-xml_parser remote: https://github.com/rails/actionpack-xml_parser
revision: 246653ab3670f329176c1e77e6cd1a632466f06e revision: e1516064761ea26502cd79b283f6af0fa2b1edf5
specs: specs:
actionpack-xml_parser (1.0.0) actionpack-xml_parser (1.0.1)
actionpack (>= 4.0.0.rc1, < 4.1) actionpack (>= 4.0.0, < 5)
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
RedCloth (4.2.9) RedCloth (4.2.9)
aasm (3.0.22) aasm (3.0.25)
actionmailer (4.0.0) actionmailer (4.0.2)
actionpack (= 4.0.0) actionpack (= 4.0.2)
mail (~> 2.5.3) mail (~> 2.5.4)
actionpack (4.0.0) actionpack (4.0.2)
activesupport (= 4.0.0) activesupport (= 4.0.2)
builder (~> 3.1.0) builder (~> 3.1.0)
erubis (~> 2.7.0) erubis (~> 2.7.0)
rack (~> 1.5.2) rack (~> 1.5.2)
rack-test (~> 0.6.2) rack-test (~> 0.6.2)
activemodel (4.0.0) activemodel (4.0.2)
activesupport (= 4.0.0) activesupport (= 4.0.2)
builder (~> 3.1.0) builder (~> 3.1.0)
activerecord (4.0.0) activerecord (4.0.2)
activemodel (= 4.0.0) activemodel (= 4.0.2)
activerecord-deprecated_finders (~> 1.0.2) activerecord-deprecated_finders (~> 1.0.2)
activesupport (= 4.0.0) activesupport (= 4.0.2)
arel (~> 4.0.0) arel (~> 4.0.0)
activerecord-deprecated_finders (1.0.3) activerecord-deprecated_finders (1.0.3)
activesupport (4.0.0) activesupport (4.0.2)
i18n (~> 0.6, >= 0.6.4) i18n (~> 0.6, >= 0.6.4)
minitest (~> 4.2) minitest (~> 4.2)
multi_json (~> 1.3) multi_json (~> 1.3)
@ -45,16 +45,17 @@ GEM
tzinfo (~> 0.3.37) tzinfo (~> 0.3.37)
acts_as_list (0.3.0) acts_as_list (0.3.0)
activerecord (>= 3.0) activerecord (>= 3.0)
arel (4.0.0) arel (4.0.1)
atomic (1.1.14) atomic (1.1.14)
bcrypt-ruby (3.0.1) bcrypt-ruby (3.0.1)
builder (3.1.4) builder (3.1.4)
bullet (4.6.0) bullet (4.7.1)
uniform_notifier activesupport
uniform_notifier (>= 1.4.0)
cache_digests (0.3.1) cache_digests (0.3.1)
actionpack (>= 3.2) actionpack (>= 3.2)
thread_safe thread_safe
capybara (2.1.0) capybara (2.2.1)
mime-types (>= 1.16) mime-types (>= 1.16)
nokogiri (>= 1.3.3) nokogiri (>= 1.3.3)
rack (>= 1.0.0) rack (>= 1.0.0)
@ -62,20 +63,20 @@ GEM
xpath (~> 2.0) xpath (~> 2.0)
childprocess (0.3.9) childprocess (0.3.9)
ffi (~> 1.0, >= 1.0.11) ffi (~> 1.0, >= 1.0.11)
codeclimate-test-reporter (0.1.1) codeclimate-test-reporter (0.2.0)
simplecov (>= 0.7.1, < 1.0.0) simplecov (>= 0.7.1, < 1.0.0)
coffee-rails (4.0.0) coffee-rails (4.0.1)
coffee-script (>= 2.2.0) coffee-script (>= 2.2.0)
railties (>= 4.0.0.beta, < 5.0) railties (>= 4.0.0, < 5.0)
coffee-script (2.2.0) coffee-script (2.2.0)
coffee-script-source coffee-script-source
execjs execjs
coffee-script-source (1.6.3) coffee-script-source (1.6.3)
commonjs (0.2.7) commonjs (0.2.7)
cucumber (1.3.8) cucumber (1.3.10)
builder (>= 2.1.2) builder (>= 2.1.2)
diff-lcs (>= 1.1.3) diff-lcs (>= 1.1.3)
gherkin (~> 2.12.1) gherkin (~> 2.12)
multi_json (>= 1.7.5, < 2.0) multi_json (>= 1.7.5, < 2.0)
multi_test (>= 0.0.2) multi_test (>= 0.0.2)
cucumber-rails (1.4.0) cucumber-rails (1.4.0)
@ -83,25 +84,26 @@ GEM
cucumber (>= 1.2.0) cucumber (>= 1.2.0)
nokogiri (>= 1.5.0) nokogiri (>= 1.5.0)
rails (>= 3.0.0) rails (>= 3.0.0)
database_cleaner (1.1.1) database_cleaner (1.2.0)
diff-lcs (1.2.4) diff-lcs (1.2.5)
docile (1.1.1)
erubis (2.7.0) erubis (2.7.0)
execjs (2.0.1) execjs (2.0.2)
factory_girl (4.2.0) factory_girl (4.3.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
factory_girl_rails (4.2.1) factory_girl_rails (4.3.0)
factory_girl (~> 4.2.0) factory_girl (~> 4.3.0)
railties (>= 3.0.0) railties (>= 3.0.0)
ffi (1.9.0) ffi (1.9.3)
gherkin (2.12.1) gherkin (2.12.2)
multi_json (~> 1.3) multi_json (~> 1.3)
hike (1.2.3) hike (1.2.3)
htmlentities (4.3.1) htmlentities (4.3.1)
i18n (0.6.5) i18n (0.6.9)
jquery-rails (3.0.4) jquery-rails (3.0.4)
railties (>= 3.0, < 5.0) railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0) thor (>= 0.14, < 2.0)
json (1.8.0) json (1.8.1)
less (2.4.0) less (2.4.0)
commonjs (~> 0.2.7) commonjs (~> 0.2.7)
less-rails (2.4.2) less-rails (2.4.2)
@ -112,66 +114,69 @@ GEM
mime-types (~> 1.16) mime-types (~> 1.16)
treetop (~> 1.4.8) treetop (~> 1.4.8)
metaclass (0.0.1) metaclass (0.0.1)
mime-types (1.25) mime-types (1.25.1)
mini_portile (0.5.1) mini_portile (0.5.2)
minitest (4.7.5) minitest (4.7.5)
mocha (0.14.0) mocha (0.14.0)
metaclass (~> 0.0.1) metaclass (~> 0.0.1)
mousetrap-rails (0.0.12) mousetrap-rails (1.4.6)
multi_json (1.8.0) multi_json (1.8.2)
multi_test (0.0.2) multi_test (0.0.3)
mysql2 (0.3.13) mysql2 (0.3.14)
nokogiri (1.6.0) nokogiri (1.6.1)
mini_portile (~> 0.5.0) mini_portile (~> 0.5.0)
polyglot (0.3.3) polyglot (0.3.3)
protected_attributes (1.0.5)
activemodel (>= 4.0.1, < 5.0)
rack (1.5.2) rack (1.5.2)
rack-mini-profiler (0.1.31) rack-mini-profiler (0.9.0)
rack (>= 1.1.3) rack (>= 1.1.3)
rack-test (0.6.2) rack-test (0.6.2)
rack (>= 1.0) rack (>= 1.0)
rails (4.0.0) rails (4.0.2)
actionmailer (= 4.0.0) actionmailer (= 4.0.2)
actionpack (= 4.0.0) actionpack (= 4.0.2)
activerecord (= 4.0.0) activerecord (= 4.0.2)
activesupport (= 4.0.0) activesupport (= 4.0.2)
bundler (>= 1.3.0, < 2.0) bundler (>= 1.3.0, < 2.0)
railties (= 4.0.0) railties (= 4.0.2)
sprockets-rails (~> 2.0.0) sprockets-rails (~> 2.0.0)
rails_autolink (1.1.4) rails_autolink (1.1.5)
rails (> 3.1) rails (> 3.1)
railties (4.0.0) railties (4.0.2)
actionpack (= 4.0.0) actionpack (= 4.0.2)
activesupport (= 4.0.0) activesupport (= 4.0.2)
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rake (10.1.0) rake (10.1.1)
ref (1.0.5) ref (1.0.5)
rspec-expectations (2.14.3) rspec-expectations (2.14.4)
diff-lcs (>= 1.1.3, < 2.0) diff-lcs (>= 1.1.3, < 2.0)
rubyzip (0.9.9) rubyzip (1.1.0)
safe_yaml (0.9.7) safe_yaml (0.9.7)
sanitize (2.0.6) sanitize (2.0.6)
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
sass (3.2.10) sass (3.2.13)
sass-rails (4.0.0) sass-rails (4.0.1)
railties (>= 4.0.0.beta, < 5.0) railties (>= 4.0.0, < 5.0)
sass (>= 3.1.10) sass (>= 3.1.10)
sprockets-rails (~> 2.0.0) sprockets-rails (~> 2.0.0)
selenium-webdriver (2.35.1) selenium-webdriver (2.39.0)
childprocess (>= 0.2.5) childprocess (>= 0.2.5)
multi_json (~> 1.0) multi_json (~> 1.0)
rubyzip (< 1.0.0) rubyzip (~> 1.0)
websocket (~> 1.0.4) websocket (~> 1.0.4)
simplecov (0.7.1) simplecov (0.8.2)
multi_json (~> 1.0) docile (~> 1.1.0)
simplecov-html (~> 0.7.1) multi_json
simplecov-html (0.7.1) simplecov-html (~> 0.8.0)
sprockets (2.10.0) simplecov-html (0.8.0)
sprockets (2.10.1)
hike (~> 1.2) hike (~> 1.2)
multi_json (~> 1.0) multi_json (~> 1.0)
rack (~> 1.0) rack (~> 1.0)
tilt (~> 1.1, != 1.3.0) tilt (~> 1.1, != 1.3.0)
sprockets-rails (2.0.0) sprockets-rails (2.0.1)
actionpack (>= 3.0) actionpack (>= 3.0)
activesupport (>= 3.0) activesupport (>= 3.0)
sprockets (~> 2.8) sprockets (~> 2.8)
@ -187,31 +192,32 @@ GEM
atomic atomic
tilt (1.4.1) tilt (1.4.1)
timecop (0.6.3) timecop (0.6.3)
tolk (1.3.11) tolk (1.4.00)
protected_attributes
safe_yaml (~> 0.8) safe_yaml (~> 0.8)
will_paginate will_paginate
treetop (1.4.15) treetop (1.4.15)
polyglot polyglot
polyglot (>= 0.3.1) polyglot (>= 0.3.1)
turbolinks (1.3.0) turbolinks (2.1.0)
coffee-rails coffee-rails
twitter-bootstrap-rails (2.2.8) twitter-bootstrap-rails (2.2.8)
actionpack (>= 3.1) actionpack (>= 3.1)
execjs execjs
rails (>= 3.1) rails (>= 3.1)
railties (>= 3.1) railties (>= 3.1)
tzinfo (0.3.37) tzinfo (0.3.38)
uglifier (2.2.1) uglifier (2.4.0)
execjs (>= 0.3.0) execjs (>= 0.3.0)
multi_json (~> 1.0, >= 1.0.2) json (>= 1.8.0)
uniform_notifier (1.3.0) uniform_notifier (1.4.0)
websocket (1.0.7) websocket (1.0.7)
will_paginate (3.0.5) will_paginate (3.0.5)
will_paginate-bootstrap (0.2.5) will_paginate-bootstrap (1.0.0)
will_paginate (>= 3.0.3) will_paginate (>= 3.0.3)
xpath (2.0.0) xpath (2.0.0)
nokogiri (~> 1.3) nokogiri (~> 1.3)
yard (0.8.7.2) yard (0.8.7.3)
PLATFORMS PLATFORMS
ruby ruby

View file

@ -95,7 +95,7 @@ class ApplicationController < ActionController::Base
if todos_parent.nil? if todos_parent.nil?
count = 0 count = 0
elsif (todos_parent.is_a?(Project) && todos_parent.hidden?) elsif (todos_parent.is_a?(Project) && todos_parent.hidden?)
count = eval "@project_project_hidden_todo_counts[#{todos_parent.id}]" count = @project_project_hidden_todo_counts[todos_parent.id]
else else
count = eval "@#{todos_parent.class.to_s.downcase}_not_done_counts[#{todos_parent.id}]" count = eval "@#{todos_parent.class.to_s.downcase}_not_done_counts[#{todos_parent.id}]"
end end

View file

@ -747,34 +747,29 @@ class TodosController < ApplicationController
end end
end end
def get_not_completed_for_predecessor(relation, todo_id=nil)
items = relation.todos.not_completed.
where('(LOWER(todos.description) LIKE ?)', "%#{params[:term].downcase}%")
items = items.where("AND NOT(todos.id=?)", todo_id) unless todo_id.nil?
items.
includes(:context, :project).
reorder('description ASC').
limit(10)
end
def auto_complete_for_predecessor def auto_complete_for_predecessor
unless params['id'].nil? unless params['id'].nil?
get_todo_from_params get_todo_from_params
# Begin matching todos in current project, excluding @todo itself # Begin matching todos in current project, excluding @todo itself
@items = @todo.project.todos.not_completed. @items = get_not_completed_for_predecessor(@todo.project, @todo.id) unless @todo.project.nil?
where('(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id).
includes(:context, :project).
reorder('description ASC').
limit(10) unless @todo.project.nil?
# Then look in the current context, excluding @todo itself # Then look in the current context, excluding @todo itself
@items = @todo.context.todos.not_completed. @items = get_not_completed_for_predecessor(@todo.context, @todo.id) unless !@items.empty? || @todo.context.nil?
where('(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id).
includes(:context, :project).
reorder('description ASC').
limit(10) unless !@items.empty? || @todo.context.nil?
# Match todos in other projects, excluding @todo itself # Match todos in other projects, excluding @todo itself
@items = current_user.todos.not_completed. @items = get_not_completed_for_predecessor(current_user, @todo.id) unless !@items.empty?
where('(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id).
includes(:context, :project).
reorder('description ASC').
limit(10) unless !@items.empty?
else else
# New todo - TODO: Filter on current project in project view # New todo - TODO: Filter on current project in project view
@items = current_user.todos.not_completed. @items = get_not_complete_for_predecessor(current_user)
where('(LOWER(todos.description) LIKE ?)', "%#{params[:term].downcase}%").
includes(:context, :project).
reorder('description ASC').
limit(10)
end end
render :inline => format_dependencies_as_json_for_auto_complete(@items) render :inline => format_dependencies_as_json_for_auto_complete(@items)
end end
@ -1020,27 +1015,23 @@ end
end end
end end
def find_completed(relation, id, include_hidden)
todos = relation.find(id).todos.completed
todos = todos.not_hidden if !include_hidden
return todos
end
def determine_completed_count def determine_completed_count
todos=nil
source_view do |from| source_view do |from|
from.todo do from.todo { todos = current_user.todos.not_hidden.completed }
@completed_count = current_user.todos.not_hidden.completed.count from.context { todos = find_completed(current_user.contexts, @todo.context_id, @todo.context.hidden?) }
end from.project { todos = find_completed(current_user.projects, @todo.project_id, @todo.project.hidden?) unless @todo.project_id.nil? }
from.context do from.tag { todos = current_user.todos.with_tag(@tag.id).completed }
todos = current_user.contexts.find(@todo.context_id).todos.completed
todos = todos.not_hidden if !@todo.context.hidden?
@completed_count = todos.count
end
from.project do
unless @todo.project_id == nil
todos = current_user.projects.find(@todo.project_id).todos.completed
todos = todos.not_hidden if !@todo.project.hidden?
@completed_count = todos.count
end
end
from.tag do
@completed_count = current_user.todos.with_tag(@tag.id).completed.count
end
end end
@completed_count = todos.nil? ? 0 : todos.count
end end
def determine_deferred_tag_count(tag_name) def determine_deferred_tag_count(tag_name)
@ -1195,23 +1186,20 @@ end
end end
end end
def parse_date_for_update(date, error_msg)
begin
parse_date_per_user_prefs(date)
rescue
@todo.errors[:base] << error_msg
end
end
def update_date_for_update(key)
params['todo'][key] = params["todo"].has_key?(key) ? parse_date_for_update(params["todo"][key], t("todos.error.invalid_#{key}_date")) : ""
end
def update_due_and_show_from_dates def update_due_and_show_from_dates
if params["todo"].has_key?("due") %w{ due show_from }.each {|date| update_date_for_update(date) }
begin
params["todo"]["due"] = parse_date_per_user_prefs(params["todo"]["due"])
rescue
@todo.errors[:base] << "Invalid due date"
end
else
params["todo"]["due"] = ""
end
if params['todo']['show_from']
begin
params['todo']['show_from'] = parse_date_per_user_prefs(params['todo']['show_from'])
rescue
@todo.errors[:base] << "Invalid show from date"
end
end
end end
def update_completed_state def update_completed_state
@ -1283,18 +1271,18 @@ end
completed_todos.completed_after(start_of_this_day).includes(includes[:include]) completed_todos.completed_after(start_of_this_day).includes(includes[:include])
end end
def get_done_in_period(before, after, includes = {:include => Todo::DEFAULT_INCLUDES})
completed_todos.completed_before(before).completed_after(after).includes(includes[:include])
end
# all completed todos [begin_of_week, start_of_today] # all completed todos [begin_of_week, start_of_today]
def get_done_rest_of_week(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES}) def get_done_rest_of_week(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES})
start_of_this_week = Time.zone.now.beginning_of_week get_done_in_period(Time.zone.now.beginning_of_day, Time.zone.now.beginning_of_week)
start_of_this_day = Time.zone.now.beginning_of_day
completed_todos.completed_before(start_of_this_day).completed_after(start_of_this_week).includes(includes[:include])
end end
# all completed todos [begin_of_month, begin_of_week] # all completed todos [begin_of_month, begin_of_week]
def get_done_rest_of_month(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES}) def get_done_rest_of_month(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES})
start_of_this_month = Time.zone.now.beginning_of_month get_done_in_period(Time.zone.now.beginning_of_week, Time.zone.now.beginning_of_month)
start_of_this_week = Time.zone.now.beginning_of_week
completed_todos.completed_before(start_of_this_week).completed_after(start_of_this_month).includes(includes[:include])
end end
def get_not_done_todos def get_not_done_todos

View file

@ -1,6 +1,4 @@
class MessageGateway < ActionMailer::Base class MessageGateway < ActionMailer::Base
include ActionView::Helpers::SanitizeHelper
extend ActionView::Helpers::SanitizeHelper::ClassMethods
def receive(email) def receive(email)
user = get_receiving_user_from_email_address(email) user = get_receiving_user_from_email_address(email)
@ -85,11 +83,11 @@ class MessageGateway < ActionMailer::Base
end end
def get_text_or_nil(text) def get_text_or_nil(text)
return text ? sanitize(text.strip) : nil return text ? text.strip : nil
end end
def get_decoded_text_or_nil(text) def get_decoded_text_or_nil(text)
return text ? sanitize(text.decoded.strip) : nil return text ? text.decoded.strip : nil
end end
def get_first_text_plain_part(email) def get_first_text_plain_part(email)
@ -99,7 +97,7 @@ class MessageGateway < ActionMailer::Base
# remove all parts that are not text/plain # remove all parts that are not text/plain
parts.reject{|part| !part.content_type.start_with?("text/plain") } parts.reject{|part| !part.content_type.start_with?("text/plain") }
return parts.count > 0 ? sanitize(parts[0].decoded.strip) : "" return parts.count > 0 ? parts[0].decoded.strip : ""
end end
def get_all_parts(parts) def get_all_parts(parts)

View file

@ -12,6 +12,7 @@ class Project < ActiveRecord::Base
scope :uncompleted, -> { where("NOT(state = ?)", 'completed') } scope :uncompleted, -> { where("NOT(state = ?)", 'completed') }
scope :with_name_or_description, lambda { |body| where("name LIKE ? OR description LIKE ?", body, body) } scope :with_name_or_description, lambda { |body| where("name LIKE ? OR description LIKE ?", body, body) }
scope :with_namepart, lambda { |body| where("name LIKE ?", body + '%') }
validates_presence_of :name validates_presence_of :name
validates_length_of :name, :maximum => 255 validates_length_of :name, :maximum => 255
@ -88,7 +89,7 @@ class Project < ActiveRecord::Base
# as a result of acts_as_state_machine calling state=() to update the attribute # as a result of acts_as_state_machine calling state=() to update the attribute
def transition_to(candidate_state) def transition_to(candidate_state)
case candidate_state.to_sym case candidate_state.to_sym
when aasm_current_state when aasm.current_state
return return
when :hidden when :hidden
hide! hide!

View file

@ -66,7 +66,7 @@ class Todo < ActiveRecord::Base
# state machine # state machine
include AASM include AASM
aasm_initial_state Proc.new { |t| (t.show_from && t.user && (t.show_from > t.user.date)) ? :deferred : :active} aasm_initial_state = Proc.new { |t| (t.show_from && t.user && (t.show_from > t.user.date)) ? :deferred : :active}
aasm :column => :state do aasm :column => :state do

View file

@ -1,28 +1,72 @@
require 'date'
class RichMessageExtractor class RichMessageExtractor
include ActionView::Helpers::SanitizeHelper
extend ActionView::Helpers::SanitizeHelper::ClassMethods
RICH_MESSAGE_FIELDS_REGEX = /([^>@]*)@?([^>]*)>?(.*)/ PROJECT_MARKER = '~'
CONTEXT_MARKER = '@'
TICKLER_MARKER = '>'
DUE_MARKER = '<'
TAG_MARKER = '#'
STAR_MARKER = '*'
ALL_MARKERS = [
PROJECT_MARKER,
CONTEXT_MARKER,
TICKLER_MARKER,
DUE_MARKER,
TAG_MARKER,
STAR_MARKER
]
def initialize(message) def initialize(message)
@message = message @message = message
end end
def description def description
fields[1].strip desc = select_for('')
desc.blank? ? '' : sanitize(desc[1].strip)
end end
def context def context
fields[2].strip context = select_for(CONTEXT_MARKER)
context.blank? ? '' : sanitize(context[1].strip)
end end
def project def project
stripped = fields[3].strip project = select_for PROJECT_MARKER
stripped.blank? ? nil : stripped project.blank? ? nil : sanitize(project[1].strip)
end
def tags
string = @message.dup
tags = []
# Regex only matches one tag, so recurse until we have them all
while string.match /#(.*?)(?=[#{ALL_MARKERS.join}]|\Z)/
tags << sanitize($1)
string.gsub!(/##{$1}/,'')
end
tags.empty? ? nil : tags
end
def due
due = select_for DUE_MARKER
due.blank? ? nil : Date.parse(due[1].strip)
end
def show_from
show_from = select_for TICKLER_MARKER
show_from.blank? ? nil : Date.parse(show_from[1].strip)
end
def starred?
@message.include? '*'
end end
private private
def fields def select_for symbol
@message.match(RICH_MESSAGE_FIELDS_REGEX) @message.match /#{symbol}(.*?)(?=[#{ALL_MARKERS.join}]|\Z)/
end end
end end

View file

@ -14,6 +14,10 @@ class TodoFromRichMessage
description = extractor.description description = extractor.description
context = extractor.context context = extractor.context
project = extractor.project project = extractor.project
show_from = extractor.show_from
due = extractor.due
tags = extractor.tags
star = extractor.starred?
context_id = default_context_id context_id = default_context_id
if context.present? if context.present?
@ -33,17 +37,21 @@ class TodoFromRichMessage
found_project.name = project[4..259].strip found_project.name = project[4..259].strip
found_project.save! found_project.save!
else else
found_project = user.projects.active.find_by_namepart(project) found_project = user.projects.active.with_namepart(project).first
found_project = user.projects.find_by_namepart(project) if found_project.nil? found_project = user.projects.with_namepart(project).first if found_project.nil?
end end
project_id = found_project.id unless found_project.nil? project_id = found_project.id unless found_project.nil?
end end
todo = user.todos.build todo = user.todos.build
todo.description = description todo.description = description
todo.raw_notes = notes todo.raw_notes = notes
todo.context_id = context_id todo.context_id = context_id
todo.project_id = project_id unless project_id.nil? todo.project_id = project_id unless project_id.nil?
todo.show_from = show_from if show_from.is_a? Date
todo.due = due if due.is_a? Date
todo.tag_with tags unless tags.nil? || tags.empty?
todo.starred = star
todo todo
end end
end end

View file

@ -131,5 +131,5 @@
<li>Enable the "Add any gadget by URL" feature. You will find it at bottom of the list. Select Enable radio button and click Save Changes button.</li> <li>Enable the "Add any gadget by URL" feature. You will find it at bottom of the list. Select Enable radio button and click Save Changes button.</li>
<li>Now you can see Gadgets tab added to Gmail Settings. Go to the Gadgets tab</li> <li>Now you can see Gadgets tab added to Gmail Settings. Go to the Gadgets tab</li>
<li>Paste following link to the Add a gadget by its URL: and then click Add button:<br/> <li>Paste following link to the Add a gadget by its URL: and then click Add button:<br/>
<pre><%= integrations_url + "/google_gadget" %></pre></li> <pre><%= integrations_url + "/google_gadget.xml" %></pre></li>
</ul> </ul>

View file

@ -14,6 +14,7 @@
<li><a href="#email-cron-section">Automatically Email Yourself Upcoming Actions</a></li> <li><a href="#email-cron-section">Automatically Email Yourself Upcoming Actions</a></li>
<li><a href="#message_gateway">Integrate Tracks with an email server to be able to send an action through email to Tracks</a></li> <li><a href="#message_gateway">Integrate Tracks with an email server to be able to send an action through email to Tracks</a></li>
<li><a href="#mailgun">Send emails to Tracks with Mailgun</a> <li><a href="#mailgun">Send emails to Tracks with Mailgun</a>
<li><a href="#todo_rich_message_format">Rich Todo Message email format</a>
<li><a href="#google_gadget">Add Tracks as a Google Gmail gadget</a></li> <li><a href="#google_gadget">Add Tracks as a Google Gmail gadget</a></li>
</ul><br/> </ul><br/>
<p>Do you have one of your own to add? <p>Do you have one of your own to add?
@ -122,6 +123,7 @@
<a name="mailgun"> </a> <a name="mailgun"> </a>
<h2>Send emails to Tracks with Mailgun</h2> <h2>Send emails to Tracks with Mailgun</h2>
<p>
If you want to email tasks to Tracks, but cannot run a mailserver on the same host, If you want to email tasks to Tracks, but cannot run a mailserver on the same host,
you could use the <a href='www.mailgun.com'>Mailgun</a> support built in to Tracks. you could use the <a href='www.mailgun.com'>Mailgun</a> support built in to Tracks.
</p> </p>
@ -155,6 +157,36 @@ mailmap:
<p>All the comments about the email format from the section above apply to the <p>All the comments about the email format from the section above apply to the
Mailgun handling, as the data is processed the same way</p> Mailgun handling, as the data is processed the same way</p>
<a name="todo_rich_message_format"> </a>
<h2>Rich Todo Message Format</h2>
<p> For both of the above methods, the follow format can be used:</p>
<pre>my awesome todo @context ~project &lt;131012 &gt;131009 #tag1 #tag2 *</pre>
<p>The fields are:</p>
<table>
<tr>
<th>Symbol</th><th>Meaning</th>
</tr>
<tr>
<td>@</td><td>The context to place the Todo in</td>
</tr>
<tr>
<td>~</td><td>The project to place the Todo in</td>
</tr>
<tr>
<td>&lt;</td><td>The due date for the Todo (may be 2 digits for day, 4 digits for month-day, or 6 digits for yeah-month-day)</td>
</tr>
<tr>
<td>&gt;</td><td>The due date for the Todo (may be 2 digits for day, 4 digits for month-day, or 6 digits for yeah-month-day)</td>
</tr>
<tr>
<td>#</td><td>A tag to apply to the Todo - may be used multiple times</td>
</tr>
<tr>
<td>*</td><td>Flag to star the Todo</td>
</tr>
</table>
<p>All symbols are optional, and text up to the first symbol (or end of string) is used as the description of the todo</p>
<a name="google_gadget"> </a> <a name="google_gadget"> </a>
<h2>Add Tracks as a Google Gmail gadget</h2> <h2>Add Tracks as a Google Gmail gadget</h2>
<p> <p>

View file

@ -28,4 +28,4 @@
<% else -%><%= render :partial => "notes/notes_summary", :collection => @project.notes %> <% else -%><%= render :partial => "notes/notes_summary", :collection => @project.notes %>
<% end -%> <% end -%>
<h2><%= t('projects.settings') %></h2> <h2><%= t('projects.settings') %></h2>
<%= t('projects.state', :state => project.aasm_current_state.to_s) %>. <%= @project_default_context %> <%= t('projects.state', :state => project.aasm.current_state.to_s) %>. <%= @project_default_context %>

View file

@ -1,11 +1,11 @@
# TODO: is this dead code? # TODO: is this dead code?
page.select('#project_status .active span').each do |element| page.select('#project_status .active span').each do |element|
element.className = @project.aasm_current_state == :active ? 'active_state' : 'inactive_state' element.className = @project.aasm.current_state == :active ? 'active_state' : 'inactive_state'
end end
page.select('#project_status .hidden span').each do |element| page.select('#project_status .hidden span').each do |element|
element.className = @project.aasm_current_state == :hidden ? 'active_state' : 'inactive_state' element.className = @project.aasm.current_state == :hidden ? 'active_state' : 'inactive_state'
end end
page.select('#project_status .completed span').each do |element| page.select('#project_status .completed span').each do |element|
element.className = @project.aasm_current_state == :completed ? 'active_state' : 'inactive_state' element.className = @project.aasm.current_state == :completed ? 'active_state' : 'inactive_state'
end end
page.notify :notice, "Set project status to #{@project.aasm_current_state}", 5.0 page.notify :notice, "Set project status to #{@project.aasm.current_state}", 5.0

View file

@ -4,36 +4,42 @@
<h2><Actions><%= t('common.actions') %></h2> <h2><Actions><%= t('common.actions') %></h2>
<form method="get" action="<%= edit_todo_path(@todo, :format => :m)%>"> <form method="get" action="<%= edit_todo_path(@todo, :format => :m)%>">
<button><%=t('todos.edit_action')%></button> <button><%=t('todos.edit_action')%></button>
<input type="hidden" name="_method" value="put" /> <input type="hidden" name="_method" value="put" />
</form> </form>
<form method="post" action="<%=toggle_star_todo_path(@todo, :format=>:m)%>"> <form method="post" action="<%=toggle_star_todo_path(@todo, :format=>:m)%>">
<button><%=t('todos.star_action')%></button> <button><%=t('todos.star_action')%></button>
<input type="hidden" name="_method" value="put" /> <input type="hidden" name="_method" value="put" />
<%= token_tag %>
</form> </form>
<form method="post" action="<%=toggle_check_todo_path(@todo, :format=>:m)%>"> <form method="post" action="<%=toggle_check_todo_path(@todo, :format=>:m)%>">
<button><%= t('todos.mark_complete')%></button> <button><%= t('todos.mark_complete')%></button>
<input type="hidden" name="_method" value="put" /> <input type="hidden" name="_method" value="put" />
<%= token_tag %>
</form> </form>
<form method="post" action="<%=defer_todo_path(@todo, :format=>:m, :days => 1)%>"> <form method="post" action="<%=defer_todo_path(@todo, :format=>:m, :days => 1)%>">
<button><%=t('todos.defer_x_days', :count => 1)%></button> <button><%=t('todos.defer_x_days', :count => 1)%></button>
<input type="hidden" name="_method" value="put" /> <input type="hidden" name="_method" value="put" />
<%= token_tag %>
</form> </form>
<form method="post" action="<%=defer_todo_path(@todo, :format=>:m, :days => 2)%>"> <form method="post" action="<%=defer_todo_path(@todo, :format=>:m, :days => 2)%>">
<button><%=t('todos.defer_x_days', :count => 2)%></button> <button><%=t('todos.defer_x_days', :count => 2)%></button>
<input type="hidden" name="_method" value="put" /> <input type="hidden" name="_method" value="put" />
<%= token_tag %>
</form> </form>
<form method="post" action="<%=defer_todo_path(@todo, :format=>:m, :days => 3)%>"> <form method="post" action="<%=defer_todo_path(@todo, :format=>:m, :days => 3)%>">
<button><%=t('todos.defer_x_days', :count => 3)%></button> <button><%=t('todos.defer_x_days', :count => 3)%></button>
<input type="hidden" name="_method" value="put" /> <input type="hidden" name="_method" value="put" />
<%= token_tag %>
</form> </form>
<form method="post" action="<%=defer_todo_path(@todo, :format=>:m, :days => 7)%>"> <form method="post" action="<%=defer_todo_path(@todo, :format=>:m, :days => 7)%>">
<button><%=t('todos.defer_x_days', :count => 7)%></button> <button><%=t('todos.defer_x_days', :count => 7)%></button>
<input type="hidden" name="_method" value="put" /> <input type="hidden" name="_method" value="put" />
<%= token_tag %>
</form> </form>

View file

@ -68,5 +68,8 @@ module Tracksapp
config.action_view.sanitized_allowed_protocols = 'onenote', 'message' config.action_view.sanitized_allowed_protocols = 'onenote', 'message'
config.middleware.insert_after ActionDispatch::ParamsParser, ActionDispatch::XmlParamsParser config.middleware.insert_after ActionDispatch::ParamsParser, ActionDispatch::XmlParamsParser
# if a locale is invalid, the Rails app will raise an error
config.i18n.enforce_available_locales = true
end end
end end

View file

@ -471,6 +471,9 @@ en:
project_completed: Completed actions in this project project_completed: Completed actions in this project
context_completed: Completed actions in this context context_completed: Completed actions in this context
tag_hidden: "Hidden actions tagged with '%{param}'" tag_hidden: "Hidden actions tagged with '%{param}'"
error:
invalid_due_date: "Invalid due date"
invalid_show_from_date: "Invalid show from date"
completed_today: Completed today completed_today: Completed today
completed_rest_of_week: Completed in the rest of this week completed_rest_of_week: Completed in the rest of this week
completed_rest_of_month: Completed in the rest of this month completed_rest_of_month: Completed in the rest of this month

View file

@ -3,7 +3,7 @@ class FixIncorrectlyHiddenTodos < ActiveRecord::Migration
hidden_todos_without_project = hidden_todos_without_project =
Todo.where(:state => 'project_hidden', :project_id => nil) Todo.where(:state => 'project_hidden', :project_id => nil)
active_projects = Project.where(:state => 'active') active_projects = Project.where(:state => 'active').select("id")
hidden_todos_in_active_projects = hidden_todos_in_active_projects =
Todo.where(:state => 'project_hidden').where("project_id IN (?)", active_projects) Todo.where(:state => 'project_hidden').where("project_id IN (?)", active_projects)

View file

@ -10,7 +10,7 @@ There are two methods of downloading Tracks:
# If you want to live on the edge, you can get the latest development version from GitHub using git (bear in mind that this may be less stable than the released versions): # If you want to live on the edge, you can get the latest development version from GitHub using git (bear in mind that this may be less stable than the released versions):
bc. cd ~/Sites bc. cd ~/Sites
git clone git://github.com/tracksapp/tracks.git git clone https://github.com/TracksApp/tracks.git
cd tracks cd tracks

View file

@ -4,7 +4,6 @@ class PreferencesControllerTest < ActionController::TestCase
def setup def setup
super super
assert_equal "test", Rails.env
assert_equal "change-me", Tracks::Config.salt assert_equal "change-me", Tracks::Config.salt
end end

View file

@ -48,7 +48,7 @@ class ProjectsControllerTest < ActionController::TestCase
login_as(:admin_user) login_as(:admin_user)
xhr :post, :update, :id => 1, "project"=>{"name"=>p.name, "description"=>p.description, "state"=>"hidden"} xhr :post, :update, :id => 1, "project"=>{"name"=>p.name, "description"=>p.description, "state"=>"hidden"}
todos.each do |t| todos.each do |t|
assert_equal :project_hidden, t.reload().aasm_current_state assert_equal :project_hidden, t.reload().aasm.current_state
end end
assert p.reload().hidden? assert p.reload().hidden?
end end
@ -60,7 +60,7 @@ class ProjectsControllerTest < ActionController::TestCase
xhr :post, :update, :id => 1, "project"=>{"name"=>p.name, "description"=>p.description, "state"=>"hidden"} xhr :post, :update, :id => 1, "project"=>{"name"=>p.name, "description"=>p.description, "state"=>"hidden"}
xhr :post, :update, :id => 1, "project"=>{"name"=>p.name, "description"=>p.description, "state"=>"active"} xhr :post, :update, :id => 1, "project"=>{"name"=>p.name, "description"=>p.description, "state"=>"active"}
todos.each do |t| todos.each do |t|
assert_equal :active, t.reload().aasm_current_state assert_equal :active, t.reload().aasm.current_state
end end
assert p.reload().active? assert p.reload().active?
end end

View file

@ -84,7 +84,7 @@ class RecurringTodosControllerTest < ActionController::TestCase
xhr :post, :toggle_check, :id=>1, :_source_view=>"" xhr :post, :toggle_check, :id=>1, :_source_view=>""
recurring_todo_1 = RecurringTodo.find(1) # reload seems to not work recurring_todo_1 = RecurringTodo.find(1) # reload seems to not work
assert recurring_todo_1.active?, "recurring todo should be active but is #{recurring_todo_1.aasm_current_state}" assert recurring_todo_1.active?, "recurring todo should be active but is #{recurring_todo_1.aasm.current_state}"
# by making active, a new todo should be created from the pattern # by making active, a new todo should be created from the pattern
assert_equal todo_count+1, Todo.count assert_equal todo_count+1, Todo.count

View file

@ -20,7 +20,7 @@ def two_weeks_hence
end end
def way_back def way_back
Time.zone.local(2008,1,1) Time.zone.local(2008,1,1).to_s(:db)
end end
%> %>

View file

@ -4,7 +4,6 @@ class PreferenceTest < ActiveSupport::TestCase
fixtures :users, :preferences fixtures :users, :preferences
def setup def setup
assert_equal "test", ENV['RAILS_ENV']
assert_equal "change-me", Tracks::Config.salt assert_equal "change-me", Tracks::Config.salt
@admin_user = User.find(1) @admin_user = User.find(1)
@other_user = User.find(2) @other_user = User.find(2)

View file

@ -48,36 +48,36 @@ class ProjectTest < ActiveSupport::TestCase
# state machine # state machine
def test_project_initial_state_is_active def test_project_initial_state_is_active
assert_equal :active, @timemachine.aasm_current_state assert_equal :active, @timemachine.aasm.current_state
assert @timemachine.active? assert @timemachine.active?
end end
def test_hide_project def test_hide_project
@timemachine.hide! @timemachine.hide!
assert_equal :hidden, @timemachine.aasm_current_state assert_equal :hidden, @timemachine.aasm.current_state
assert @timemachine.hidden? assert @timemachine.hidden?
end end
def test_activate_project def test_activate_project
@timemachine.activate! @timemachine.activate!
assert_equal :active, @timemachine.aasm_current_state assert_equal :active, @timemachine.aasm.current_state
assert @timemachine.active? assert @timemachine.active?
end end
def test_transition_to_another_state def test_transition_to_another_state
assert_equal :active, @timemachine.aasm_current_state assert_equal :active, @timemachine.aasm.current_state
@timemachine.transition_to(:hidden) @timemachine.transition_to(:hidden)
assert_equal :hidden, @timemachine.aasm_current_state assert_equal :hidden, @timemachine.aasm.current_state
@timemachine.transition_to(:completed) @timemachine.transition_to(:completed)
assert_equal :completed, @timemachine.aasm_current_state assert_equal :completed, @timemachine.aasm.current_state
@timemachine.transition_to(:active) @timemachine.transition_to(:active)
assert_equal :active, @timemachine.aasm_current_state assert_equal :active, @timemachine.aasm.current_state
end end
def test_transition_to_same_state def test_transition_to_same_state
assert_equal :active, @timemachine.aasm_current_state assert_equal :active, @timemachine.aasm.current_state
@timemachine.transition_to(:active) @timemachine.transition_to(:active)
assert_equal :active, @timemachine.aasm_current_state assert_equal :active, @timemachine.aasm.current_state
end end
# other tests # other tests
@ -95,7 +95,7 @@ class ProjectTest < ActiveSupport::TestCase
def test_complete_project def test_complete_project
assert_nil @timemachine.completed_at assert_nil @timemachine.completed_at
@timemachine.complete! @timemachine.complete!
assert_equal :completed, @timemachine.aasm_current_state assert_equal :completed, @timemachine.aasm.current_state
assert @timemachine.completed? assert @timemachine.completed?
assert_not_nil @timemachine.completed_at, "completed_at not expected to be nil" assert_not_nil @timemachine.completed_at, "completed_at not expected to be nil"
assert_in_delta Time.now, @timemachine.completed_at, 1 assert_in_delta Time.now, @timemachine.completed_at, 1
@ -150,7 +150,7 @@ class ProjectTest < ActiveSupport::TestCase
first_todo = @moremoney.todos[0] first_todo = @moremoney.todos[0]
first_todo.show_from = Time.zone.now + 1.week first_todo.show_from = Time.zone.now + 1.week
first_todo.save! first_todo.save!
assert_equal :deferred, @moremoney.todos[0].aasm_current_state assert_equal :deferred, @moremoney.todos[0].aasm.current_state
assert_equal 1, @moremoney.todos.deferred.count assert_equal 1, @moremoney.todos.deferred.count
end end

View file

@ -1,3 +1,4 @@
require 'date'
require 'test/unit' require 'test/unit'
require 'active_support/core_ext/object/blank' require 'active_support/core_ext/object/blank'
require_relative '../../app/services/rich_message_extractor.rb' require_relative '../../app/services/rich_message_extractor.rb'
@ -5,11 +6,15 @@ require_relative '../../app/services/rich_message_extractor.rb'
class RichMessageExtractorTest < Test::Unit::TestCase class RichMessageExtractorTest < Test::Unit::TestCase
def test_message_with_all_options def test_message_with_all_options
message = "ohai@some-context>in-this-project" message = "ohai@some-context~this-project>131012<131014#tag1#tag2*"
extractor = RichMessageExtractor.new(message) extractor = RichMessageExtractor.new(message)
assert_equal "ohai", extractor.description assert_equal "ohai", extractor.description
assert_equal "some-context", extractor.context assert_equal "some-context", extractor.context
assert_equal "in-this-project", extractor.project assert_equal "this-project", extractor.project
assert_equal "2013-10-12", extractor.show_from.to_s
assert_equal "2013-10-14", extractor.due.to_s
assert_equal ["tag1","tag2"], extractor.tags
assert extractor.starred?
end end
def test_message_without_project def test_message_without_project
@ -20,12 +25,12 @@ class RichMessageExtractorTest < Test::Unit::TestCase
assert_equal nil, extractor.project assert_equal nil, extractor.project
end end
def test_message_without_project def test_message_without_context
message = " ohai @ some-context" message = " ohai ~ some-project"
extractor = RichMessageExtractor.new(message) extractor = RichMessageExtractor.new(message)
assert_equal "ohai", extractor.description assert_equal "ohai", extractor.description
assert_equal "some-context", extractor.context assert_equal "", extractor.context
assert_equal nil, extractor.project assert_equal "some-project", extractor.project
end end
def test_message_without_project_or_context def test_message_without_project_or_context
@ -52,4 +57,52 @@ class RichMessageExtractorTest < Test::Unit::TestCase
assert_equal nil, extractor.project assert_equal nil, extractor.project
end end
def test_message_with_tags
message = "some tags#tag 1#tag2"
extractor = RichMessageExtractor.new(message)
assert_equal ["tag 1","tag2"], extractor.tags
end
def test_message_with_no_tags
message = "no tags"
extractor = RichMessageExtractor.new(message)
assert_equal nil, extractor.tags
end
def test_message_with_due_date
message = "datetest<141013"
extractor = RichMessageExtractor.new(message)
assert_equal "2014-10-13", extractor.due.to_s
end
def test_message_with_no_due_date
message = "no date"
extractor = RichMessageExtractor.new(message)
assert_equal nil, extractor.due
end
def test_message_with_show_from
message = "datetest>161013"
extractor = RichMessageExtractor.new(message)
assert_equal "2016-10-13", extractor.show_from.to_s
end
def test_message_with_no_show_from
message = "no tickler"
extractor = RichMessageExtractor.new(message)
assert_equal nil, extractor.show_from
end
def test_message_with_star
message = "star test*"
extractor = RichMessageExtractor.new(message)
assert extractor.starred?
end
def test_message_with_no_star
message = "no star test"
extractor = RichMessageExtractor.new(message)
refute extractor.starred?
end
end end

View file

@ -18,4 +18,23 @@ class TodoFromRichMessageTest < ActiveSupport::TestCase
assert_equal default_context_id, new_todo.context_id assert_equal default_context_id, new_todo.context_id
end end
def test_from_rich_message_adds_all_fields
user = @completed.user
context = Context.create(:name => 'context')
project = Project.create(:name => 'project')
message = "description@context~project>131014<131017#tag1#tag2*"
builder = TodoFromRichMessage.new(user, context.id, message, "notes")
new_todo = builder.construct
assert_not_nil new_todo
assert_equal "description", new_todo.description
assert_equal "notes", new_todo.notes
assert_equal context.id, new_todo.context_id
assert_equal project.id, new_todo.project_id
assert_equal "2013-10-14 00:00:00 +0100", new_todo.show_from.to_s
assert_equal "2013-10-17 00:00:00 +0100", new_todo.due.to_s
assert_equal "starred, tag1, tag2", new_todo.tags.to_s
assert new_todo.starred?
end
end end

View file

@ -97,10 +97,10 @@ class TodoTest < ActiveSupport::TestCase
def test_defer_an_existing_todo def test_defer_an_existing_todo
@not_completed2 @not_completed2
assert_equal :active, @not_completed2.aasm_current_state assert_equal :active, @not_completed2.aasm.current_state
@not_completed2.show_from = Time.zone.now + 1.week @not_completed2.show_from = Time.zone.now + 1.week
assert @not_completed2.save, "should have saved successfully" + @not_completed2.errors.to_xml assert @not_completed2.save, "should have saved successfully" + @not_completed2.errors.to_xml
assert_equal :deferred, @not_completed2.aasm_current_state assert_equal :deferred, @not_completed2.aasm.current_state
end end
def test_create_a_new_deferred_todo def test_create_a_new_deferred_todo
@ -110,41 +110,41 @@ class TodoTest < ActiveSupport::TestCase
todo.context_id = 1 todo.context_id = 1
todo.description = 'foo' todo.description = 'foo'
assert todo.save, "should have saved successfully" + todo.errors.to_xml assert todo.save, "should have saved successfully" + todo.errors.to_xml
assert_equal :deferred, todo.aasm_current_state assert_equal :deferred, todo.aasm.current_state
end end
def test_create_a_new_deferred_todo_by_passing_attributes def test_create_a_new_deferred_todo_by_passing_attributes
user = users(:other_user) user = users(:other_user)
todo = user.todos.build(:show_from => next_week, :context_id => 1, :description => 'foo') todo = user.todos.build(:show_from => next_week, :context_id => 1, :description => 'foo')
assert todo.save, "should have saved successfully" + todo.errors.to_xml assert todo.save, "should have saved successfully" + todo.errors.to_xml
assert_equal :deferred, todo.aasm_current_state assert_equal :deferred, todo.aasm.current_state
end end
def test_toggle_completion def test_toggle_completion
t = @not_completed1 t = @not_completed1
assert_equal :active, t.aasm_current_state assert_equal :active, t.aasm.current_state
t.toggle_completion! t.toggle_completion!
assert_equal :completed, t.aasm_current_state assert_equal :completed, t.aasm.current_state
t.toggle_completion! t.toggle_completion!
assert_equal :active, t.aasm_current_state assert_equal :active, t.aasm.current_state
end end
def test_toggle_completion_with_show_from_in_future def test_toggle_completion_with_show_from_in_future
t = @not_completed1 t = @not_completed1
t.show_from= 1.week.from_now t.show_from= 1.week.from_now
t.save! t.save!
assert_equal :deferred, t.aasm_current_state assert_equal :deferred, t.aasm.current_state
t.toggle_completion! t.toggle_completion!
assert_equal :completed, t.aasm_current_state assert_equal :completed, t.aasm.current_state
end end
def test_toggle_completion_with_show_from_in_past def test_toggle_completion_with_show_from_in_past
t = @not_completed1 t = @not_completed1
t.update_attribute(:show_from, 1.week.ago) t.update_attribute(:show_from, 1.week.ago)
assert_equal :active, t.aasm_current_state assert_equal :active, t.aasm.current_state
assert t.toggle_completion!, "shoud be able to mark active todo complete even if show_from is set in the past" assert t.toggle_completion!, "shoud be able to mark active todo complete even if show_from is set in the past"
assert_equal :completed, t.aasm_current_state assert_equal :completed, t.aasm.current_state
end end
def test_activate_also_saves def test_activate_also_saves
@ -225,7 +225,7 @@ class TodoTest < ActiveSupport::TestCase
t.context_id = 1 t.context_id = 1
t.save! t.save!
t.reload t.reload
assert_equal :active, t.aasm_current_state assert_equal :active, t.aasm.current_state
end end
def test_initial_state_is_deferred_when_show_from_in_future def test_initial_state_is_deferred_when_show_from_in_future
@ -236,7 +236,7 @@ class TodoTest < ActiveSupport::TestCase
t.show_from = 1.week.from_now.to_date t.show_from = 1.week.from_now.to_date
t.save! t.save!
t.reload t.reload
assert_equal :deferred, t.aasm_current_state assert_equal :deferred, t.aasm.current_state
end end
def test_todo_is_not_starred def test_todo_is_not_starred

View file

@ -1,10 +1,10 @@
require File.expand_path(File.dirname(__FILE__) + '/../test_helper') require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
require 'timecop'
class UserTest < ActiveSupport::TestCase class UserTest < ActiveSupport::TestCase
fixtures :users, :preferences, :projects, :contexts, :todos, :recurring_todos fixtures :users, :preferences, :projects, :contexts, :todos, :recurring_todos
def setup def setup
assert_equal "test", ENV['RAILS_ENV']
assert_equal "change-me", Tracks::Config.salt assert_equal "change-me", Tracks::Config.salt
@admin_user = User.find(1) @admin_user = User.find(1)
@other_user = User.find(2) @other_user = User.find(2)
@ -374,16 +374,16 @@ class UserTest < ActiveSupport::TestCase
# test group counts for projects and contexts # test group counts for projects and contexts
project_counts = u.todos.count_by_group(:project_id) project_counts = u.todos.count_by_group(:project_id)
assert_equal "6,3,4,4", project_counts.map{|pc|pc[1]}.join(",") assert_equal [6,3,4,4], project_counts.values
context_counts = u.todos.count_by_group(:context_id) context_counts = u.todos.count_by_group(:context_id)
assert_equal "7,3,1,3,1,2", context_counts.map{|cc|cc[1]}.join(",") assert_equal [7,3,1,3,1,2], context_counts.values
# add a todo to the first context and check that the count is increased # add a todo to the first context and check that the count is increased
u.todos.create!(:description => "yet another todo", :context => u.contexts.first) u.todos.create!(:description => "yet another todo", :context => u.contexts.first)
context_counts = u.todos.reload.count_by_group(:context_id) context_counts = u.todos.reload.count_by_group(:context_id)
assert_equal "8,3,1,3,1,2", context_counts.map{|cc|cc[1]}.join(",") assert_equal [8,3,1,3,1,2], context_counts.values
end end
protected protected
@ -393,4 +393,4 @@ class UserTest < ActiveSupport::TestCase
User.create({ :login => 'quire', :password => 'quire', :password_confirmation => 'quire' }.merge(options)) User.create({ :login => 'quire', :password => 'quire', :password_confirmation => 'quire' }.merge(options))
end end
end end