From 6bc915140064e040bee4cf440a415c6bcaf54f6f Mon Sep 17 00:00:00 2001 From: Carsten Otto Date: Sun, 29 May 2016 22:58:35 +0200 Subject: [PATCH 1/5] use @not_done_todos for feeds fixes #1726 the name @not_done_todos is wrong and should be replaced in a dedicated fix --- app/views/todos/index.atom.builder | 4 ++-- app/views/todos/index.ics.erb | 2 +- app/views/todos/index.rss.builder | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/todos/index.atom.builder b/app/views/todos/index.atom.builder index 6c49ba80..85f6ffb4 100644 --- a/app/views/todos/index.atom.builder +++ b/app/views/todos/index.atom.builder @@ -1,9 +1,9 @@ atom_feed do |feed| feed.title(@feed_title) feed.subtitle(@feed_description) - feed.updated(@todos.last.updated_at) + feed.updated(@not_done_todos.last.updated_at) - @todos.each do |todo| + @not_done_todos.each do |todo| feed.entry(todo) do |entry| entry.title(h(todo.description)) entry.link(todo.project ? project_url(todo.project) : context_url(todo.context)) diff --git a/app/views/todos/index.ics.erb b/app/views/todos/index.ics.erb index 7fee3a19..8873ba13 100644 --- a/app/views/todos/index.ics.erb +++ b/app/views/todos/index.ics.erb @@ -8,7 +8,7 @@ TZID:<%= ENV['TZ'] || 'GMT' %> LAST-MODIFIED:<%= Time.now.strftime("%Y%m%dT%H%M%SZ") %> TZNAME:<%= ENV['TZ'] %> END:VTIMEZONE -<% for @todo in @todos -%> +<% for @todo in @not_done_todos -%> BEGIN:VTODO DTSTAMP:<%= @todo.created_at.strftime("%Y%m%dT%H%M%SZ") %> DTSTART;VALUE=DATE:<%= @todo.created_at.strftime("%Y%m%d") %> diff --git a/app/views/todos/index.rss.builder b/app/views/todos/index.rss.builder index e6e61a39..a74faaf7 100644 --- a/app/views/todos/index.rss.builder +++ b/app/views/todos/index.rss.builder @@ -7,7 +7,7 @@ xml.rss :version => "2.0" do xml.language 'en-us' xml.ttl 40 - @todos.each do |todo| + @not_done_todos.each do |todo| xml.item do xml.title h(todo.description) xml.description feed_content_for_todo(todo) From d7aa83b74738bc36fd18d1fc25ccafb760da853b Mon Sep 17 00:00:00 2001 From: Carsten Otto Date: Fri, 3 Jun 2016 23:38:17 +0200 Subject: [PATCH 2/5] add tests for feeds and reorganize existing tests --- test/controllers/todos_controller_test.rb | 278 ++++++++++++++++------ test/test_helper.rb | 24 +- 2 files changed, 233 insertions(+), 69 deletions(-) diff --git a/test/controllers/todos_controller_test.rb b/test/controllers/todos_controller_test.rb index 910c6c7f..3e995b34 100644 --- a/test/controllers/todos_controller_test.rb +++ b/test/controllers/todos_controller_test.rb @@ -461,7 +461,7 @@ class TodosControllerTest < ActionController::TestCase # feeds ####### - def test_rss_feed + def test_rss_feed_not_completed login_as(:admin_user) get :index, { :format => "rss" } assert_equal 'application/rss+xml', @response.content_type @@ -473,31 +473,188 @@ class TodosControllerTest < ActionController::TestCase assert_select '>description', "Actions for #{users(:admin_user).display_name}" assert_select 'language', 'en-us' assert_select 'ttl', '40' - assert_select 'item', 17 do + assert_select 'item', 11 do assert_select 'title', /.+/ assert_select 'description', /.*/ assert_select 'link', %r{http://test.host/contexts/.+} assert_select 'guid', %r{http://test.host/todos/.+} - assert_select 'pubDate', todos(:book).updated_at.to_s(:rfc822) + assert_select 'pubDate', todos(:call_bill_gates_every_day).created_at.to_s(:rfc822) end end end end + def test_atom_feed_not_completed + login_as :admin_user + get :index, { :format => "atom" } + assert_equal 'application/atom+xml', @response.content_type + # #puts @response.body + + 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', 11 do + assert_xml_select 'title', /.+/ + assert_xml_select 'content[type="html"]', /.*/ + assert_xml_select 'published', /(#{Regexp.escape(todos(:book).updated_at.xmlschema)}|#{Regexp.escape(projects(:moremoney).updated_at.xmlschema)})/ + end + end + end + + def test_text_feed_not_completed + login_as(:admin_user) + get :index, { :format => "txt" } + assert_equal 'text/plain', @response.content_type + assert !(/ /.match(@response.body)) + assert_number_of_items_in_text_feed 11 + end + + def test_ical_feed_not_completed + login_as :admin_user + get :index, { :format => "ics" } + assert_equal 'text/calendar', @response.content_type + assert !(/ /.match(@response.body)) + assert_number_of_items_in_ical_feed 11 + end + + def test_rss_feed_completed_in_last_week + login_as(:admin_user) + get :index, { :format => "rss", :done => '7' } + + assert_number_of_items_in_rss_feed 3 + end + + def test_atom_feed_completed_in_last_week + login_as(:admin_user) + get :index, { :format => "atom", :done => '7' } + + assert_number_of_items_in_atom_feed 3 + end + + def test_text_feed_completed_in_last_week + login_as(:admin_user) + get :index, { :format => "text", :done => '7' } + + assert_number_of_items_in_text_feed 3 + end + + def test_ical_feed_completed_in_last_week + login_as(:admin_user) + get :index, { :format => "ics", :done => '7' } + + assert_number_of_items_in_ical_feed 3 + end + def test_rss_feed_with_limit login_as(:admin_user) get :index, { :format => "rss", :limit => '5' } - assert_xml_select 'rss[version="2.0"]' do - assert_select 'channel' do - assert_select '>title', 'Tracks Actions' - assert_select '>description', "Actions for #{users(:admin_user).display_name}" - assert_select 'item', 5 do - assert_select 'title', /.+/ - assert_select 'description', /.*/ - end - end - end + assert_number_of_items_in_rss_feed 5 + end + + def test_atom_feed_with_limit + login_as(:admin_user) + get :index, { :format => "atom", :limit => '5' } + + assert_number_of_items_in_atom_feed 5 + end + + def test_text_feed_with_limit + login_as(:admin_user) + get :index, { :format => "text", :limit => '5' } + + assert_number_of_items_in_text_feed 5 + end + + def test_ical_feed_with_limit + login_as(:admin_user) + get :index, { :format => "ics", :limit => '5' } + + assert_number_of_items_in_ical_feed 5 + end + + def test_rss_feed_filter_by_context + login_as(:admin_user) + get :index, { :format => "rss", :context_id => 2 } + + assert_number_of_items_in_rss_feed 3 + end + + def test_atom_feed_filter_by_context + login_as(:admin_user) + get :index, { :format => "atom", :context_id => 2 } + + assert_number_of_items_in_atom_feed 3 + end + + def test_text_feed_filter_by_context + login_as(:admin_user) + get :index, { :format => "text", :context_id => 2 } + + assert_number_of_items_in_text_feed 3 + end + + def test_ical_feed_filter_by_context + login_as(:admin_user) + get :index, { :format => "ics", :context_id => 2 } + + assert_number_of_items_in_ical_feed 3 + end + + def test_rss_feed_filter_by_project + login_as(:admin_user) + get :index, { :format => "rss", :project_id => 2 } + + assert_number_of_items_in_rss_feed 4 + end + + def test_atom_feed_filter_by_project + login_as(:admin_user) + get :index, { :format => "atom", :project_id => 2 } + + assert_number_of_items_in_atom_feed 4 + end + + def test_text_feed_filter_by_project + login_as(:admin_user) + get :index, { :format => "text", :project_id => 2 } + + assert_number_of_items_in_text_feed 4 + end + + def test_ical_feed_filter_by_project + login_as(:admin_user) + get :index, { :format => "ics", :project_id => 2 } + + assert_number_of_items_in_ical_feed 4 + end + + def test_rss_feed_filter_by_project_and_context + login_as(:admin_user) + get :index, { :format => "rss", :project_id => 2, :context_id => 2 } + + assert_number_of_items_in_rss_feed 1 + end + + def test_atom_feed_filter_by_project_and_context + login_as(:admin_user) + get :index, { :format => "atom", :project_id => 2, :context_id => 2 } + + assert_number_of_items_in_atom_feed 1 + end + + def test_text_feed_filter_by_project_and_context + login_as(:admin_user) + get :index, { :format => "text", :project_id => 2, :context_id => 2 } + + assert_number_of_items_in_text_feed 1 + end + + def test_ical_feed_filter_by_project_and_context + login_as(:admin_user) + get :index, { :format => "ics", :project_id => 2, :context_id => 2 } + + assert_number_of_items_in_ical_feed 1 end def test_rss_feed_not_accessible_to_anonymous_user_without_token @@ -506,85 +663,70 @@ class TodosControllerTest < ActionController::TestCase assert_response 401 end + def test_atom_feed_not_accessible_to_anonymous_user_without_token + login_as nil + get :index, { :format => "atom" } + assert_response 401 + end + + def test_text_feed_not_accessible_to_anonymous_user_without_token + login_as nil + get :index, { :format => "txt" } + assert_response 401 + end + def test_rss_feed_not_accessible_to_anonymous_user_with_invalid_token login_as nil get :index, { :format => "rss", :token => 'foo' } assert_response 401 end - def test_rss_feed_accessible_to_anonymous_user_with_valid_token - login_as nil - get :index, { :format => "rss", :token => users(:admin_user).token } - assert_response :ok - end - - def test_atom_feed_content - login_as :admin_user - get :index, { :format => "atom" } - assert_equal 'application/atom+xml', @response.content_type - # #puts @response.body - - 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', 17 do - assert_xml_select 'title', /.+/ - assert_xml_select 'content[type="html"]', /.*/ - assert_xml_select 'published', /(#{Regexp.escape(todos(:book).updated_at.xmlschema)}|#{Regexp.escape(projects(:moremoney).updated_at.xmlschema)})/ - end - end - end - - def test_atom_feed_not_accessible_to_anonymous_user_without_token - login_as nil - get :index, { :format => "atom" } - assert_response 401 - end - def test_atom_feed_not_accessible_to_anonymous_user_with_invalid_token login_as nil get :index, { :format => "atom", :token => 'foo' } assert_response 401 end - def test_atom_feed_accessible_to_anonymous_user_with_valid_token - login_as nil - get :index, { :format => "atom", :token => users(:admin_user).token } - assert_response :ok - end - - def test_text_feed_content - login_as(:admin_user) - get :index, { :format => "txt" } - assert_equal 'text/plain', @response.content_type - assert !(/ /.match(@response.body)) - # #puts @response.body - end - - def test_text_feed_not_accessible_to_anonymous_user_without_token - login_as nil - get :index, { :format => "txt" } - assert_response 401 - end - def test_text_feed_not_accessible_to_anonymous_user_with_invalid_token login_as nil get :index, { :format => "txt", :token => 'foo' } assert_response 401 end + def test_rss_feed_accessible_to_anonymous_user_with_valid_token + login_as nil + get :index, { :format => "rss", :token => users(:admin_user).token } + assert_response :ok + end + + def test_atom_feed_accessible_to_anonymous_user_with_valid_token + login_as nil + get :index, { :format => "atom", :token => users(:admin_user).token } + assert_response :ok + end + def test_text_feed_accessible_to_anonymous_user_with_valid_token login_as nil get :index, { :format => "txt", :token => users(:admin_user).token } assert_response :ok end - def test_ical_feed_content - login_as :admin_user - get :index, { :format => "ics" } - assert_equal 'text/calendar', @response.content_type - assert !(/ /.match(@response.body)) - # #puts @response.body + def test_ical_feed_accessible_to_anonymous_user_with_valid_token + login_as nil + get :index, { :format => "ics", :token => users(:admin_user).token } + assert_response :ok + end + + def test_tag_rss_feed_not_accessible_to_anonymous_user_without_token + login_as nil + get :tag, {:name => "foo", :format => "rss" } + assert_response 401 + end + + def test_tag_atom_feed_not_accessible_to_anonymous_user_without_token + login_as nil + get :tag, {:name => "foo", :format => "atom" } + assert_response 401 end def test_tag_text_feed_not_accessible_to_anonymous_user_without_token diff --git a/test/test_helper.rb b/test/test_helper.rb index 4912f6d8..883ba35b 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -89,7 +89,29 @@ class ActionController::TestCase @html_document = xml_document assert_select(*args, &block) end - + + def assert_number_of_items_in_rss_feed(expected) + assert_xml_select 'rss[version="2.0"]' do + assert_select 'channel' do + assert_select 'item', expected + end + end + end + + def assert_number_of_items_in_atom_feed(expected) + assert_xml_select 'feed[xmlns="http://www.w3.org/2005/Atom"]' do + assert_xml_select 'entry', expected + end + end + + def assert_number_of_items_in_text_feed(expected) + assert_equal expected, @response.body.scan(/^ \- /).size + end + + def assert_number_of_items_in_ical_feed(expected) + assert_equal expected, @response.body.scan(/^BEGIN:VTODO/).size + end + private def get_model_class From f18ef64db473d67e4a1296aaaf68010a3c4e348f Mon Sep 17 00:00:00 2001 From: Carsten Otto Date: Fri, 3 Jun 2016 23:42:11 +0200 Subject: [PATCH 3/5] fix time zone issue in test --- test/models/recurring_todo_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/models/recurring_todo_test.rb b/test/models/recurring_todo_test.rb index bc1ed08d..b82fa6b8 100644 --- a/test/models/recurring_todo_test.rb +++ b/test/models/recurring_todo_test.rb @@ -11,7 +11,7 @@ class RecurringTodoTest < ActiveSupport::TestCase @every_month = @monthly_every_last_friday @yearly = recurring_todos(:birthday_reinier) - @today = Time.now.utc + @today = Time.zone.now @tomorrow = @today + 1.day @in_three_days = @today + 3.days @in_four_days = @in_three_days + 1.day # need a day after start_from From 0511ea3a3ae38b792e103250524384c71f5e5e62 Mon Sep 17 00:00:00 2001 From: Matt Rogers Date: Sat, 20 Aug 2016 14:43:42 -0500 Subject: [PATCH 4/5] Add a fallback to :other for i18n In most cases, translations don't supply `:few` even though the language may support the construct. Instead of the app blowing up if the translation for `:few` doesn't exist, fall back to `:other` instead. --- config/initializers/i18n-config.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/initializers/i18n-config.rb b/config/initializers/i18n-config.rb index d9f738a6..a951eeac 100644 --- a/config/initializers/i18n-config.rb +++ b/config/initializers/i18n-config.rb @@ -27,10 +27,11 @@ module I18n::Backend::Pluralization n==1 ? :one : :other # default :en end end + key = :other if key == :few && !entry.has_key?(key) #fallback to :other if :few is missing raise InvalidPluralizationData.new(entry, n) unless entry.has_key?(key) entry[key] end end I18n::Backend::Simple.send(:include, I18n::Backend::Pluralization) -I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) \ No newline at end of file +I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) From c2296b5b998c417d6af92ad82d60410b3dd84463 Mon Sep 17 00:00:00 2001 From: Matt Rogers Date: Thu, 25 Aug 2016 23:10:40 -0500 Subject: [PATCH 5/5] Use Arel to generate case insensitve tag searches --- app/controllers/todos_controller.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 4f58bde5..298e3bc0 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -702,9 +702,9 @@ class TodosController < ApplicationController def tags # TODO: limit to current_user - tags_beginning = Tag.where('name like ?', params[:term]+'%') - tags_all = Tag.where('name like ?', '%'+params[:term]+'%') - tags_all= tags_all - tags_beginning + tags_beginning = Tag.where(Tag.arel_table[:name].matches("#{params[:term]}%")) + tags_all = Tag.where(Tag.arel_table[:name].matches("%#{params[:term]}%")) + tags_all = tags_all - tags_beginning respond_to do |format| format.autocomplete { render :text => for_autocomplete(tags_beginning+tags_all, params[:term]) }