mirror of
https://github.com/TracksApp/tracks.git
synced 2025-12-28 21:08:48 +01:00
Merge branch 'master' into new-gui
This commit is contained in:
commit
d44538f604
18 changed files with 328 additions and 119 deletions
2
Gemfile
2
Gemfile
|
|
@ -68,7 +68,6 @@ group :test do
|
|||
gem "mocha", :require => false
|
||||
|
||||
gem "aruba", git: 'https://github.com/cucumber/aruba', :require => false # need 0.5.4 for piping files; 0.5.3 is latest
|
||||
gem "simplecov"
|
||||
gem "timecop", "~> 0.6.2"
|
||||
|
||||
# Note that > 2.14 has problems, see:
|
||||
|
|
@ -82,6 +81,7 @@ group :test do
|
|||
#gem "capybara-screenshot"
|
||||
#gem "launchy"
|
||||
|
||||
gem "simplecov"
|
||||
# get test coverage info on codeclimate
|
||||
gem "codeclimate-test-reporter", group: :test, require: nil
|
||||
end
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ GEM
|
|||
thor (>= 0.18.1, < 2.0)
|
||||
rake (10.1.0)
|
||||
ref (1.0.5)
|
||||
rspec-expectations (2.14.2)
|
||||
rspec-expectations (2.14.3)
|
||||
diff-lcs (>= 1.1.3, < 2.0)
|
||||
rubyzip (0.9.9)
|
||||
safe_yaml (0.9.7)
|
||||
|
|
|
|||
|
|
@ -5,19 +5,12 @@ class SearchController < ApplicationController
|
|||
def results
|
||||
@source_view = params['_source_view'] || 'search'
|
||||
@page_title = "TRACKS::Search Results for #{params[:search]}"
|
||||
terms = "%#{params[:search]}%"
|
||||
|
||||
@found_not_complete_todos = incomplete_todos(terms)
|
||||
@found_complete_todos = complete_todos(terms)
|
||||
@found_todos = @found_not_complete_todos + @found_complete_todos
|
||||
searcher = Search::SearchResults.new(current_user, params[:search])
|
||||
searcher.search
|
||||
|
||||
@found_projects = current_user.projects.with_name_or_description(terms);
|
||||
@found_notes = current_user.notes.with_body(terms);
|
||||
@found_contexts = current_user.contexts.with_name(terms)
|
||||
|
||||
# TODO: limit search to tags on todos
|
||||
@found_tags = todo_tags_by_name(current_user, terms)
|
||||
@count = @found_todos.size + @found_projects.size + @found_notes.size + @found_contexts.size + @found_tags.size
|
||||
@results = searcher.results
|
||||
@count = searcher.number_of_finds
|
||||
|
||||
init_not_done_counts
|
||||
init_project_hidden_todo_counts
|
||||
|
|
@ -26,30 +19,4 @@ class SearchController < ApplicationController
|
|||
def index
|
||||
@page_title = "TRACKS::Search"
|
||||
end
|
||||
|
||||
private
|
||||
def incomplete_todos(terms)
|
||||
current_user.todos.
|
||||
where("(todos.description LIKE ? OR todos.notes LIKE ?) AND todos.completed_at IS NULL", terms, terms).
|
||||
includes(Todo::DEFAULT_INCLUDES).
|
||||
reorder("todos.due IS NULL, todos.due ASC, todos.created_at ASC")
|
||||
end
|
||||
|
||||
def complete_todos(terms)
|
||||
current_user.todos.
|
||||
where("(todos.description LIKE ? OR todos.notes LIKE ?) AND NOT (todos.completed_at IS NULL)", terms, terms).
|
||||
includes(Todo::DEFAULT_INCLUDES).
|
||||
reorder("todos.completed_at DESC")
|
||||
end
|
||||
|
||||
def todo_tags_by_name(current_user, terms)
|
||||
Tagging.find_by_sql([
|
||||
"SELECT DISTINCT tags.name as name "+
|
||||
"FROM tags "+
|
||||
"LEFT JOIN taggings ON tags.id = taggings.tag_id "+
|
||||
"LEFT JOIN todos ON taggings.taggable_id = todos.id "+
|
||||
"WHERE todos.user_id=? "+
|
||||
"AND tags.name LIKE ? ", current_user.id, terms])
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,12 +27,16 @@ module FeedlistHelper
|
|||
return html.html_safe
|
||||
end
|
||||
|
||||
def all_feed_links(object, symbol)
|
||||
feed_links([:rss, :txt, :ical], { :controller=> 'todos', :action => 'index', symbol => object.to_param }, content_tag(:strong, object.name))
|
||||
end
|
||||
|
||||
def all_feed_links_for_project(project)
|
||||
feed_links([:rss, :txt, :ical], { :controller=> 'todos', :action => 'index', :project_id => project.to_param }, content_tag(:strong, project.name))
|
||||
all_feed_links(project, :project_id)
|
||||
end
|
||||
|
||||
def all_feed_links_for_context(context)
|
||||
feed_links([:rss, :txt, :ical], { :controller=> 'todos', :action => 'index', :context_id => context.to_param }, content_tag(:strong, context.name))
|
||||
all_feed_links(context, :context_id)
|
||||
end
|
||||
|
||||
protected
|
||||
|
|
@ -44,5 +48,6 @@ module FeedlistHelper
|
|||
def user_token_hash
|
||||
{ :token => current_user.token }
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,27 +3,14 @@ class MessageGateway < ActionMailer::Base
|
|||
extend ActionView::Helpers::SanitizeHelper::ClassMethods
|
||||
|
||||
def receive(email)
|
||||
user = get_user_from_email_address(email)
|
||||
user = get_receiving_user_from_email_address(email)
|
||||
return false if user.nil?
|
||||
return false unless check_sender_is_in_mailmap(user, email)
|
||||
|
||||
context = user.prefs.sms_context
|
||||
description = nil
|
||||
notes = nil
|
||||
|
||||
if email.multipart?
|
||||
description = get_text_or_nil(email.subject)
|
||||
notes = get_first_text_plain_part(email)
|
||||
else
|
||||
if email.subject.blank?
|
||||
description = get_decoded_text_or_nil(email.body)
|
||||
notes = nil
|
||||
else
|
||||
description = get_text_or_nil(email.subject)
|
||||
notes = get_decoded_text_or_nil(email.body)
|
||||
end
|
||||
end
|
||||
todo_params = get_todo_params(email)
|
||||
|
||||
todo_builder = TodoFromRichMessage.new(user, context.id, description, notes)
|
||||
todo_builder = TodoFromRichMessage.new(user, context.id, todo_params[:description], todo_params[:notes])
|
||||
todo = todo_builder.construct
|
||||
todo.save!
|
||||
Rails.logger.info "Saved email as todo for user #{user.login} in context #{context.name}"
|
||||
|
|
@ -32,32 +19,60 @@ class MessageGateway < ActionMailer::Base
|
|||
|
||||
private
|
||||
|
||||
def get_address(email)
|
||||
return SITE_CONFIG['email_dispatch'] == 'to' ? email.to[0] : email.from[0]
|
||||
end
|
||||
|
||||
def get_user_from_env_setting
|
||||
def get_todo_params(email)
|
||||
params = {}
|
||||
|
||||
if email.multipart?
|
||||
params[:description] = get_text_or_nil(email.subject)
|
||||
params[:notes] = get_first_text_plain_part(email)
|
||||
else
|
||||
if email.subject.blank?
|
||||
params[:description] = get_decoded_text_or_nil(email.body)
|
||||
params[:notes] = nil
|
||||
else
|
||||
params[:description] = get_text_or_nil(email.subject)
|
||||
params[:notes] = get_decoded_text_or_nil(email.body)
|
||||
end
|
||||
end
|
||||
params
|
||||
end
|
||||
|
||||
def get_receiving_user_from_email_address(email)
|
||||
SITE_CONFIG['email_dispatch'] == 'single_user' ? get_receiving_user_from_env_setting : get_receiving_user_from_mail_header(email)
|
||||
end
|
||||
|
||||
def get_receiving_user_from_env_setting
|
||||
Rails.logger.info "All received email goes to #{ENV['TRACKS_MAIL_RECEIVER']}"
|
||||
user = User.where(:login => ENV['TRACKS_MAIL_RECEIVER']).first
|
||||
Rails.logger.info "WARNING: Unknown user set for TRACKS_MAIL_RECEIVER (#{ENV['TRACKS_MAIL_RECEIVER']})" if user.nil?
|
||||
return user
|
||||
end
|
||||
|
||||
def get_user_from_mail_header(email)
|
||||
address = get_address(email)
|
||||
Rails.logger.info "Looking for user with email #{address}"
|
||||
user = User.where("preferences.sms_email" => address.strip).includes(:preference).first
|
||||
if user.nil?
|
||||
user = User.where("preferences.sms_email" => address.strip[1.100]).includes(:preference).first
|
||||
end
|
||||
if user.present? and !sender_is_in_mailmap?(user,email)
|
||||
Rails.logger.warn "#{email.from[0]} not found in mailmap for #{user.login}"
|
||||
return nil
|
||||
end
|
||||
Rails.logger.info(!user.nil? ? "Email belongs to #{user.login}" : "User unknown")
|
||||
def get_receiving_user_from_mail_header(email)
|
||||
user = get_receiving_user_from_sms_email( get_address(email) )
|
||||
Rails.logger.info(user.nil? ? "User unknown": "Email belongs to #{user.login}")
|
||||
return user
|
||||
end
|
||||
|
||||
def get_address(email)
|
||||
return SITE_CONFIG['email_dispatch'] == 'to' ? email.to[0] : email.from[0]
|
||||
end
|
||||
|
||||
def get_receiving_user_from_sms_email(address)
|
||||
Rails.logger.info "Looking for user with email #{address}"
|
||||
user = User.where("preferences.sms_email" => address.strip).includes(:preference).first
|
||||
user = User.where("preferences.sms_email" => address.strip[1.100]).includes(:preference).first if user.nil?
|
||||
return user
|
||||
end
|
||||
|
||||
def check_sender_is_in_mailmap(user, email)
|
||||
if user.present? and !sender_is_in_mailmap?(user,email)
|
||||
Rails.logger.warn "#{email.from[0]} not found in mailmap for #{user.login}"
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def sender_is_in_mailmap?(user,email)
|
||||
if SITE_CONFIG['mailmap'].is_a? Hash and SITE_CONFIG['email_dispatch'] == 'to'
|
||||
# Look for the sender in the map of allowed senders
|
||||
|
|
@ -69,11 +84,6 @@ class MessageGateway < ActionMailer::Base
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
def get_user_from_email_address(email)
|
||||
SITE_CONFIG['email_dispatch'] == 'single_user' ? get_user_from_env_setting : get_user_from_mail_header(email)
|
||||
end
|
||||
|
||||
def get_text_or_nil(text)
|
||||
return text ? sanitize(text.strip) : nil
|
||||
end
|
||||
|
|
|
|||
54
app/models/search/search_results.rb
Normal file
54
app/models/search/search_results.rb
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
module Search
|
||||
|
||||
class SearchResults
|
||||
attr_reader :results
|
||||
|
||||
def initialize(user, terms)
|
||||
@user = user
|
||||
@terms = "%#{terms}%"
|
||||
@results = {}
|
||||
end
|
||||
|
||||
def search
|
||||
results[:not_complete_todos] = incomplete_todos(@terms)
|
||||
results[:complete_todos] = complete_todos(@terms)
|
||||
results[:todos] = results[:not_complete_todos] + results[:complete_todos]
|
||||
results[:projects] = @user.projects.with_name_or_description(@terms)
|
||||
results[:notes] = @user.notes.with_body(@terms)
|
||||
results[:contexts] = @user.contexts.with_name(@terms)
|
||||
results[:tags] = todo_tags_by_name(@terms)
|
||||
end
|
||||
|
||||
def number_of_finds
|
||||
results[:todos].size + results[:projects].size + results[:notes].size + results[:contexts].size + results[:tags].size
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def incomplete_todos(terms)
|
||||
@user.todos.
|
||||
where("(todos.description LIKE ? OR todos.notes LIKE ?) AND todos.completed_at IS NULL", terms, terms).
|
||||
includes(Todo::DEFAULT_INCLUDES).
|
||||
reorder("todos.due IS NULL, todos.due ASC, todos.created_at ASC")
|
||||
end
|
||||
|
||||
def complete_todos(terms)
|
||||
@user.todos.
|
||||
where("(todos.description LIKE ? OR todos.notes LIKE ?) AND NOT (todos.completed_at IS NULL)", terms, terms).
|
||||
includes(Todo::DEFAULT_INCLUDES).
|
||||
reorder("todos.completed_at DESC")
|
||||
end
|
||||
|
||||
def todo_tags_by_name(terms)
|
||||
Tagging.find_by_sql([
|
||||
"SELECT DISTINCT tags.name as name "+
|
||||
"FROM tags "+
|
||||
"LEFT JOIN taggings ON tags.id = taggings.tag_id "+
|
||||
"LEFT JOIN todos ON taggings.taggable_id = todos.id "+
|
||||
"WHERE todos.user_id=? "+
|
||||
"AND tags.name LIKE ? ", @user.id, terms])
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -2,24 +2,24 @@
|
|||
<div class="message"><p><%= t('search.no_results') %></p></div>
|
||||
<% else -%>
|
||||
|
||||
<%= render :layout => 'show_results_collection', :object => @found_todos, :locals => { :collection_name => "found-todos", :collection_title => t('search.todos_matching_query')} do %>
|
||||
<%= render :partial => "todos/todo", :collection => @found_todos, :locals => { :parent_container_type => 'search', :suppress_context => false, :suppress_project => false, :suppress_edit_button => false } %>
|
||||
<%= render :layout => 'show_results_collection', :object => @results[:todos], :locals => { :collection_name => "found-todos", :collection_title => t('search.todos_matching_query')} do %>
|
||||
<%= render :partial => "todos/todo", :collection => @results[:todos], :locals => { :parent_container_type => 'search', :suppress_context => false, :suppress_project => false, :suppress_edit_button => false } %>
|
||||
<% end -%>
|
||||
|
||||
<%= render :layout => 'show_results_collection', :object => @found_projects, :locals => { :collection_name => "found-project", :collection_title => t('search.projects_matching_query')} do %>
|
||||
<%= render :partial => "projects/project_listing", :collection => @found_projects, :locals => { :suppress_drag_handle => true, :suppress_edit_button => true, :suppress_delete_button => true } %>
|
||||
<%= render :layout => 'show_results_collection', :object => @results[:projects], :locals => { :collection_name => "found-project", :collection_title => t('search.projects_matching_query')} do %>
|
||||
<%= render :partial => "projects/project_listing", :collection => @results[:projects], :locals => { :suppress_drag_handle => true, :suppress_edit_button => true, :suppress_delete_button => true } %>
|
||||
<% end -%>
|
||||
|
||||
<%= render :layout => 'show_results_collection', :object => @found_notes, :locals => { :collection_name => "found-notes", :collection_title => t('search.notes_matching_query')} do %>
|
||||
<%= render :partial => "notes/notes_summary", :collection=> @found_notes %>
|
||||
<%= render :layout => 'show_results_collection', :object => @results[:notes], :locals => { :collection_name => "found-notes", :collection_title => t('search.notes_matching_query')} do %>
|
||||
<%= render :partial => "notes/notes_summary", :collection=> @results[:notes] %>
|
||||
<% end -%>
|
||||
|
||||
<%= render :layout => 'show_results_collection', :object => @found_contexts, :locals => { :collection_name => "found-contexts", :collection_title => t('search.contexts_matching_query')} do %>
|
||||
<%= render :partial => "contexts/context_listing", :collection => @found_contexts, :locals => { :suppress_drag_handle => true, :suppress_edit_button => true } %>
|
||||
<%= render :layout => 'show_results_collection', :object => @results[:contexts], :locals => { :collection_name => "found-contexts", :collection_title => t('search.contexts_matching_query')} do %>
|
||||
<%= render :partial => "contexts/context_listing", :collection => @results[:contexts], :locals => { :suppress_drag_handle => true, :suppress_edit_button => true } %>
|
||||
<% end -%>
|
||||
|
||||
<%= render :layout => 'show_results_collection', :object => @found_tags, :locals => { :collection_name => "found-tags", :collection_title => t('search.tags_matching_query')} do %>
|
||||
<span class="tags"><% @found_tags.each do |tag| -%>
|
||||
<%= render :layout => 'show_results_collection', :object => @results[:tags], :locals => { :collection_name => "found-tags", :collection_title => t('search.tags_matching_query')} do %>
|
||||
<span class="tags"><% @results[:tags].each do |tag| -%>
|
||||
<span class="tag"><%= link_to tag.name, tag_path(tag.name) -%></span>
|
||||
<% end %>
|
||||
</span><br/><br/>
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ end
|
|||
class Error < StandardError; end
|
||||
class InvalidParser < StandardError; end
|
||||
|
||||
class ConsoleOptions
|
||||
class ConsoleOptionsForTemplate
|
||||
attr_reader :parser, :options, :keywords
|
||||
|
||||
def initialize
|
||||
|
|
@ -307,5 +307,5 @@ class ConsoleOptions
|
|||
end
|
||||
|
||||
if $0 == __FILE__
|
||||
ConsoleOptions.new.run(ARGV)
|
||||
ConsoleOptionsForTemplate.new.run(ARGV)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@
|
|||
# newer version of cucumber-rails. Consider adding your own code to a new file
|
||||
# instead of editing this one. Cucumber will automatically load all features/**/*.rb
|
||||
# files.
|
||||
require 'simplecov'
|
||||
SimpleCov.start 'rails'
|
||||
|
||||
require 'cucumber/rails'
|
||||
require 'aruba/cucumber'
|
||||
|
|
|
|||
|
|
@ -80,7 +80,11 @@ module IsTaggable
|
|||
end
|
||||
end
|
||||
|
||||
def tag_cast_to_string obj
|
||||
def tag_cast_to_string(obj)
|
||||
tag_array_from_obj(obj).flatten.compact.map(&:downcase).uniq
|
||||
end
|
||||
|
||||
def tag_array_from_obj(obj)
|
||||
case obj
|
||||
when Array
|
||||
obj.map! { |item| get_tag_name_from_item(item) }
|
||||
|
|
@ -88,7 +92,7 @@ module IsTaggable
|
|||
obj.split(Tag::DELIMITER).map { |tag_name| tag_name.strip.squeeze(" ") }
|
||||
else
|
||||
raise "Invalid object of class #{obj.class} as tagging method parameter"
|
||||
end.flatten.compact.map(&:downcase).uniq
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1 +1,16 @@
|
|||
task :ci => ['db:migrate', :test, :cucumber]
|
||||
task :ci do |t|
|
||||
ENV['RAILS_ENV'] ||= "test"
|
||||
|
||||
# test coverage from codeclimate
|
||||
require "codeclimate-test-reporter"
|
||||
CodeClimate::TestReporter.start
|
||||
|
||||
# local test coverage
|
||||
require 'simplecov'
|
||||
SimpleCov.start 'rails'
|
||||
|
||||
[:environment, 'db:migrate', 'test:all', 'cucumber'].each do |t|
|
||||
print "running '#{t}'\n"
|
||||
Rake::Task[t].invoke
|
||||
end
|
||||
end
|
||||
|
|
@ -1,32 +1,32 @@
|
|||
class DoneTodos
|
||||
|
||||
|
||||
def self.done_todos_for_container(user)
|
||||
completed_todos = user.todos.completed
|
||||
return done_today(completed_todos), done_rest_of_week(completed_todos), done_rest_of_month(completed_todos)
|
||||
end
|
||||
|
||||
def self.done_today(todos, includes = {:include => Todo::DEFAULT_INCLUDES})
|
||||
start_of_this_day = Time.zone.now.beginning_of_day
|
||||
# TODO: refactor to remove outer hash from includes param
|
||||
todos.completed_after(start_of_this_day).includes(includes[:include])
|
||||
todos.completed_after(beginning_of_day).includes(includes[:include])
|
||||
end
|
||||
|
||||
def self.done_rest_of_week(todos, includes = {:include => Todo::DEFAULT_INCLUDES})
|
||||
done_between(todos, includes, Time.zone.now.beginning_of_day, Time.zone.now.beginning_of_week)
|
||||
done_between(todos, includes, beginning_of_day, beginning_of_week)
|
||||
end
|
||||
|
||||
def self.done_rest_of_month(todos, includes = {:include => Todo::DEFAULT_INCLUDES})
|
||||
done_between(todos, includes, Time.zone.now.beginning_of_week, Time.zone.now.beginning_of_month)
|
||||
done_between(todos, includes, beginning_of_week, beginning_of_month)
|
||||
end
|
||||
|
||||
def self.completed_period(date)
|
||||
return nil if date.nil?
|
||||
return nil if date.nil?
|
||||
|
||||
period = nil
|
||||
period = "rest_of_month" if date > Time.zone.now.beginning_of_month
|
||||
period = "rest_of_week" if date > Time.zone.now.beginning_of_week
|
||||
period = "today" if date > Time.zone.now.beginning_of_day
|
||||
|
||||
return period
|
||||
return "today" if date >= end_of_day # treat todos with completed_at in future as done today (happens in tests)
|
||||
return "today" if date.between?(beginning_of_day, end_of_day)
|
||||
return "rest_of_week" if date >= beginning_of_week
|
||||
return "rest_of_month" if date >= beginning_of_month
|
||||
return nil
|
||||
end
|
||||
|
||||
def self.remaining_in_container(user, period)
|
||||
|
|
@ -41,4 +41,21 @@ class DoneTodos
|
|||
# TODO: refactor to remove outer hash from includes param
|
||||
todos.completed_before(start_date).completed_after(end_date).includes(includes[:include])
|
||||
end
|
||||
|
||||
def self.beginning_of_day
|
||||
Time.zone.now.beginning_of_day
|
||||
end
|
||||
|
||||
def self.end_of_day
|
||||
Time.zone.now.end_of_day
|
||||
end
|
||||
|
||||
def self.beginning_of_week
|
||||
Time.zone.now.beginning_of_week
|
||||
end
|
||||
|
||||
def self.beginning_of_month
|
||||
Time.zone.now.beginning_of_month
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
require 'simplecov'
|
||||
SimpleCov.start 'rails'
|
||||
|
||||
ENV["RAILS_ENV"] = "test"
|
||||
ENV["RAILS_ENV"] ||= "test"
|
||||
require 'test/unit'
|
||||
require 'mocha/setup'
|
||||
|
||||
|
|
|
|||
|
|
@ -42,5 +42,33 @@ class IsTaggableTest < ActiveSupport::TestCase
|
|||
t.tag_with "a, b, e, f"
|
||||
assert_equal "a, b, e, f", t.tag_list, "should add e and f and remove c and d"
|
||||
end
|
||||
|
||||
def test_editing_using_taglist
|
||||
t = Todo.create(:description => "test", :context => Context.first)
|
||||
t.tag_list = "a, b, c"
|
||||
assert_equal 3, t.tags.count
|
||||
assert_equal "a, b, c", t.tag_list
|
||||
|
||||
|
||||
t.tag_list = "d, e"
|
||||
assert_equal 2, t.tags.count
|
||||
assert_equal "d, e", t.tag_list
|
||||
end
|
||||
|
||||
def test_tag_cast_to_string
|
||||
t = Todo.create(:description => "test", :context => Context.first)
|
||||
|
||||
obj = "tag"
|
||||
assert_equal ["tag"], t.tag_cast_to_string(obj)
|
||||
|
||||
obj = ["tag1", Tag.new(name: "tag2")]
|
||||
assert_equal ["tag1", "tag2"], t.tag_cast_to_string(obj)
|
||||
|
||||
obj = {a: "hash"}
|
||||
assert_raise(RuntimeError) { t.tag_cast_to_string(obj) }
|
||||
|
||||
obj = ["string", {a: "hash"}]
|
||||
assert_raise(RuntimeError) { t.tag_cast_to_string(obj) }
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -201,6 +201,24 @@ class TodoTest < ActiveSupport::TestCase
|
|||
assert t.project.is_a?(NullProject)
|
||||
end
|
||||
|
||||
def test_update_from_project
|
||||
# Given a hidden project
|
||||
assert_not_nil @not_completed1.project
|
||||
project = @not_completed1.project
|
||||
project.hide!
|
||||
assert project.hidden?
|
||||
assert @not_completed1.reload.hidden?
|
||||
|
||||
# When I manually create a new todo in the hidden projct
|
||||
new_todo = @not_completed1.user.todos.build(description: "test", context: @not_completed1.context, project: project)
|
||||
new_todo.save!
|
||||
assert new_todo.active?
|
||||
# And I update the state of the todo from its project
|
||||
new_todo.update_state_from_project
|
||||
# Then the todo should be hidden
|
||||
assert new_todo.hidden?
|
||||
end
|
||||
|
||||
def test_initial_state_defaults_to_active
|
||||
t = Todo.new
|
||||
t.description = 'foo'
|
||||
|
|
@ -328,6 +346,31 @@ class TodoTest < ActiveSupport::TestCase
|
|||
assert @not_completed1.active?, "removing last predecessor should activate todo"
|
||||
end
|
||||
|
||||
def test_removing_precesessor_using_new_dependency_list
|
||||
# Given three active todos (@not_completed{1,2.3})
|
||||
@completed.activate!
|
||||
@not_completed3 = @completed
|
||||
|
||||
#When I add two todos as dependency to one todo
|
||||
@not_completed1.add_predecessor_list("#{@not_completed2.id}, #{@not_completed3.id}")
|
||||
@not_completed1.save_predecessors
|
||||
# blocking is not done automagically
|
||||
@not_completed1.block!
|
||||
|
||||
# Then @completed1 should have predecessors and should be blocked
|
||||
assert @not_completed1.uncompleted_predecessors?
|
||||
assert @not_completed1.pending?, "a todo with predecessors should be pending"
|
||||
|
||||
# When I set the predecessors to only todo2
|
||||
@not_completed1.add_predecessor_list("#{@not_completed2.id}") #
|
||||
@not_completed1.save_predecessors
|
||||
|
||||
# Then todo1 should have only one predecessor and it should be todo2
|
||||
assert @not_completed1.uncompleted_predecessors?
|
||||
assert_equal 1, @not_completed1.predecessors.count
|
||||
assert_equal @not_completed2, @not_completed1.predecessors.first
|
||||
end
|
||||
|
||||
def test_finding_todos_with_a_tag
|
||||
todo = @not_completed1
|
||||
todo.tag_list = "a, b, c"
|
||||
|
|
|
|||
|
|
@ -32,10 +32,21 @@ module Todos
|
|||
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)
|
||||
def test_due_this_month_at_start_month
|
||||
# should return 1 todo
|
||||
Timecop.travel(2013,9,1) do
|
||||
due_this_month = create_todo(Time.zone.now.end_of_month)
|
||||
assert_equal [due_this_month], @calendar.due_this_month
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal [due_this_month], @calendar.due_this_month
|
||||
def test_due_this_month_at_end_month
|
||||
# the todo is due next week and is thus left out for todos due rest
|
||||
# of month (i.e. after next week, but in this month)
|
||||
Timecop.travel(2013,9,23) do
|
||||
due_this_month = create_todo(Time.zone.now.end_of_month)
|
||||
assert_equal 0, @calendar.due_this_month.size
|
||||
end
|
||||
end
|
||||
|
||||
def test_due_after_this_month
|
||||
|
|
|
|||
64
test/models/todos/done_todos_test.rb
Normal file
64
test/models/todos/done_todos_test.rb
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
require_relative '../../test_helper'
|
||||
|
||||
module Todos
|
||||
class DoneTodosTest < ActiveSupport::TestCase
|
||||
|
||||
def test_completed_period
|
||||
Timecop.travel(2013,1,23,12,00,00) do # wednesday at 12:00;
|
||||
assert_equal "today", DoneTodos.completed_period(Time.zone.local(2013,1,23,9,00)) # today at 9:00
|
||||
assert_equal "rest_of_week", DoneTodos.completed_period(Time.zone.local(2013,1,21)) # monday this week
|
||||
assert_equal "rest_of_month", DoneTodos.completed_period(Time.zone.local(2013,1,8)) # tuestday in first week of jan
|
||||
|
||||
assert_nil DoneTodos.completed_period(nil)
|
||||
assert_nil DoneTodos.completed_period(Time.zone.local(2012,12,1)) # older than this month
|
||||
|
||||
assert_equal "today", DoneTodos.completed_period(Time.zone.local(2013,12,1)) # date in future -> act as if today
|
||||
end
|
||||
end
|
||||
|
||||
def test_done_today
|
||||
todos = users(:admin_user).todos
|
||||
assert 0, DoneTodos.done_today(todos, {}).count
|
||||
|
||||
t = users(:admin_user).todos.active.first
|
||||
t.complete!
|
||||
|
||||
assert 0, DoneTodos.done_today(todos.reload, {}).count
|
||||
end
|
||||
|
||||
def test_done_rest_of_week
|
||||
todos = users(:admin_user).todos
|
||||
|
||||
# When I mark a todo complete on jan 1
|
||||
Timecop.travel(2013,1,1,0,0) do
|
||||
t = users(:admin_user).todos.active.first
|
||||
t.complete!
|
||||
end
|
||||
|
||||
# Then I should be in rest_of_week on jan 2
|
||||
Timecop.travel(2013,1,2,0,0) do
|
||||
assert 0, DoneTodos.done_today(todos.reload, {}).count
|
||||
assert 1, DoneTodos.done_rest_of_week(todos.reload, {}).count
|
||||
end
|
||||
end
|
||||
|
||||
def test_done_rest_of_month
|
||||
todos = users(:admin_user).todos
|
||||
|
||||
# When I mark a todo complete on jan 1
|
||||
Timecop.travel(2013,1,1,0,0) do
|
||||
t = users(:admin_user).todos.active.first
|
||||
t.complete!
|
||||
end
|
||||
|
||||
# Then I should be in rest_of_month on jan 21
|
||||
Timecop.travel(2013,1,21,0,0) do
|
||||
assert 0, DoneTodos.done_today(todos.reload, {}).count
|
||||
assert 0, DoneTodos.done_rest_of_week(todos.reload, {}).count
|
||||
assert 1, DoneTodos.done_rest_of_month(todos.reload, {}).count
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -1,9 +1,5 @@
|
|||
ENV["RAILS_ENV"] ||= "test"
|
||||
|
||||
# test coverage from codeclimate
|
||||
require "codeclimate-test-reporter"
|
||||
CodeClimate::TestReporter.start
|
||||
|
||||
require File.expand_path('../../config/environment', __FILE__)
|
||||
require 'rails/test_help'
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue