Skip to content

Commit

Permalink
Adds new option "Within period" to date filter types (along with "Tod…
Browse files Browse the repository at this point in the history
…ay", "This week", "Less than days ago" and ect). When user selected "Within period" there should be 2 date editors - "from" and "to".

Note, "from" and "to" is

    * inclusive
    * ignores time difference in DB
         o "from=01/12/2008" means "from=01/12/2008 00:00:00"
	 o "to=02/12/2008" means "to=02/12/2008 23:59:59"
  • Loading branch information
Artem Vasiliev committed Jan 19, 2009
1 parent 8054880 commit ee3a154
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 11 deletions.
6 changes: 5 additions & 1 deletion app/controllers/issues_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,11 @@ def retrieve_query
@query.project = @project
if params[:fields] and params[:fields].is_a? Array
params[:fields].each do |field|
@query.add_filter(field, params[:operators][field], params[:values][field])
if @query.range_operator?(params[:operators][field])
@query.add_filter(field, params[:operators][field], [params[:from_values][field]] + [params[:to_values][field]])
else
@query.add_filter(field, params[:operators][field], params[:values][field])
end
end
else
@query.available_filters.keys.each do |field|
Expand Down
26 changes: 21 additions & 5 deletions app/models/query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class Query < ActiveRecord::Base
">t-" => :label_less_than_ago,
"<t-" => :label_more_than_ago,
"t-" => :label_ago,
"<t<" => :label_in_date_range,
"~" => :label_contains,
"!~" => :label_not_contains }

Expand All @@ -86,8 +87,8 @@ class Query < ActiveRecord::Base
:list_status => [ "o", "c", "=", "!", "*", "done", "undone" ],
:list_optional => [ "=", "!", "!*", "*" ],
:list_subprojects => [ "*", "!*", "=" ],
:date => [ "<t+", ">t+", "t+", "t", "w", ">t-", "<t-", "t-" ],
:date_past => [ ">t-", "<t-", "t-", "t", "w" ],
:date => [ "<t+", ">t+", "t+", "t", "w", ">t-", "<t-", "t-", "<t<" ],
:date_past => [ ">t-", "<t-", "t-", "t", "w", "<t<" ],
:string => [ "=", "~", "!", "!~", "!*", "*"],
:text => [ "~", "!~" ],
:integer => [ "=", ">=", "<=", "!*", "*" ] }
Expand All @@ -111,6 +112,10 @@ class Query < ActiveRecord::Base
QueryColumn.new(:created_on, :sortable => "#{Issue.table_name}.created_on", :default_order => 'desc'),
]
cattr_reader :available_columns

def range_operator?(operator)
operator == '<t<'
end

def initialize(attributes = nil)
super attributes
Expand All @@ -127,7 +132,7 @@ def validate
filters.each_key do |field|
errors.add label_for(field), :activerecord_error_blank unless
# filter requires one or more values
(values_for(field) and !values_for(field).first.blank?) or
(filters[field][:values] and !filters[field][:values].first.blank?) or
# filter doesn't require any value
["o", "c", "done", "undone", "!*", "*", "t", "w"].include? operator_for(field)
end if filters
Expand Down Expand Up @@ -217,9 +222,17 @@ def operator_for(field)
end

def values_for(field)
has_filter?(field) ? filters[field][:values] : nil
!range_operator?(operator_for(field)) && has_filter?(field) ? filters[field][:values] : nil
end

def from_value(field)
range_operator?(operator_for(field)) && has_filter?(field) ? filters[field][:values][0] : nil
end

def to_value(field)
range_operator?(operator_for(field)) && has_filter?(field) ? filters[field][:values][1] : nil
end

def label_for(field)
label = available_filters[field][:name] if available_filters.has_key?(field)
label ||= field.gsub(/\_id$/, "")
Expand Down Expand Up @@ -286,7 +299,7 @@ def statement
filters_clauses = []
filters.each_key do |field|
next if field == "subproject_id"
v = values_for(field).clone
v = filters[field][:values].clone
next unless v and !v.empty?

sql = ''
Expand Down Expand Up @@ -346,6 +359,9 @@ def statement
sql = sql + "#{db_table}.#{db_field} BETWEEN '%s' AND '%s'" % [connection.quoted_date((Date.today + v.first.to_i).to_time), connection.quoted_date((Date.today + v.first.to_i + 1).to_time)]
when "t"
sql = sql + "#{db_table}.#{db_field} BETWEEN '%s' AND '%s'" % [connection.quoted_date(Date.today.to_time), connection.quoted_date((Date.today+1).to_time)]
when "<t<"
#ok this is an island of timezone-awareness in filters
sql = sql + "#{db_table}.#{db_field} BETWEEN '%s' AND '%s'" % [connection.quoted_date(v[0].to_s.to_time - Time.zone.utc_offset), connection.quoted_date(v[1].to_s.to_time + 1.day - 1.second - Time.zone.utc_offset)]
when "w"
from = l(:general_first_day_of_week) == '7' ?
# week starts on sunday
Expand Down
14 changes: 14 additions & 0 deletions app/views/queries/_filters.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ function toggle_filter(field) {
} else {
Element.hide("operators_" + field);
Element.hide("div_values_" + field);
Element.hide("div_date_range_" + field);
}
}

Expand All @@ -40,9 +41,15 @@ function toggle_operator(field) {
case "done":
case "c":
Element.hide("div_values_" + field);
Element.hide("div_date_range_" + field);
break;
case "<t<":
Element.hide("div_values_" + field);
Element.show("div_date_range_" + field);
break;
default:
Element.show("div_values_" + field);
Element.hide("div_date_range_" + field);
break;
}
}
Expand Down Expand Up @@ -89,6 +96,13 @@ function toggle_multi_select(field) {
<%= text_field_tag "values[#{field}][]", query.values_for(field), :id => "values_#{field}", :size => 3, :class => "select-small" %>
<% end %>
</div>
<div id="div_date_range_<%= field %>" style="display:none;">
<%= '&nbsp;'*3 + l(:label_date_from).downcase %>
<%= text_field_tag "from_values[#{field}]", query.from_value(field), :id => "from_value_#{field}", :size => 10 %> <%= calendar_for("from_value_#{field}") %>
<%= '&nbsp;'*3 + l(:label_date_to).downcase %>
<%= text_field_tag "to_values[#{field}]", query.to_value(field), :id => "to_value_#{field}", :size => 10 %> <%= calendar_for("to_value_#{field}") %>
</div>

<script type="text/javascript">toggle_filter('<%= field %>');</script>
</td>
</tr>
Expand Down
2 changes: 2 additions & 0 deletions lang/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ label_date_range: Date range
label_less_than_ago: less than days ago
label_more_than_ago: more than days ago
label_ago: days ago
label_in_date_range: within period
label_contains: contains
label_not_contains: doesn't contain
label_day_plural: days
Expand Down Expand Up @@ -671,3 +672,4 @@ text_and: and
text_time_entry_intersecting_notice: Notice that this timelog entry (%s) intersects with %s.
text_time_entry_intersecting_notice_entry: entry
text_time_entry_intersecting_notice_entry_plural: entries

1 change: 0 additions & 1 deletion log/delete.me

This file was deleted.

2 changes: 1 addition & 1 deletion test/fixtures/projects.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ projects_001:
homepage: http://ecookbook.somenet.foo/
is_public: true
identifier: ecookbook
parent_id:
parent_id:
projects_002:
created_on: 2006-07-19 19:14:19 +02:00
name: OnlineStore
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/user_preferences.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ user_preferences_001:
id: 1
user_id: 1
hide_mail: true
time_zone: Samoa
time_zone: Berlin
user_preferences_002:
others: |+
--- {}
Expand Down
43 changes: 41 additions & 2 deletions test/functional/issues_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
require 'issues_controller'

# Re-raise errors caught by the controller.
class IssuesController; def rescue_action(e) raise e end; end
class IssuesController; def rescue_action(e) raise e; end; end

class IssuesControllerTest < Test::Unit::TestCase
fixtures :projects,
Expand All @@ -46,7 +46,7 @@ def setup
@controller = IssuesController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
User.current = nil
@current_user_timezone = Time.zone.name
end

def test_index
Expand Down Expand Up @@ -101,7 +101,46 @@ def test_index_with_project_and_filter
assert_template 'index.rhtml'
assert_not_nil assigns(:issues)
end

def test_date_range_filer_with(issue_date, options = {})
options.reverse_merge! :issue_date_timezone => @current_user_timezone
issue = Issue.find(2)
issue.created_on = '%s +%02d' % [issue_date,
TimeZone[options[:issue_date_timezone]].utc_offset/3600]
if block_given?
tester = lambda {|issues| yield(issues)}
else
tester = lambda do |issues|
assert issues.find {|i| i.id == 2}, 'issue 2 must get into resultest'
end
end
issue.save!
get :index, :project_id => 1,
:set_filter => 1,
:fields => ["created_on"],
:operators => {"created_on" => "<t<"},
:values => {"created_on" => [""]},
:from_values => {"created_on" => [options[:from]]},
:to_values => {"created_on" => [options[:to]]}
issues = assigns(:issues)
tester.call(issues)
end

def test_date_range_filer_with_middle_issue_date
test_date_range_filer_with('2006-07-19 17:00', :from => '2006-07-19',
:to => '2006-07-19')
end

def test_date_range_filer_with_left_edge_issue_date
test_date_range_filer_with('2006-07-19 00:00', :from => '2006-07-19',
:to => '2006-07-19')
end

def test_date_range_filer_with_right_edge_issue_date
test_date_range_filer_with('2006-07-19 23:59', :from => '2006-07-19',
:to => '2006-07-19')
end

def test_index_csv_with_project
get :index, :format => 'csv'
assert_response :success
Expand Down

0 comments on commit ee3a154

Please sign in to comment.