diff app/models/query.rb @ 1517:dffacf8a6908 redmine-2.5

Update to Redmine SVN revision 13367 on 2.5-stable branch
author Chris Cannam
date Tue, 09 Sep 2014 09:29:00 +0100
parents e248c7af89ec
children
line wrap: on
line diff
--- a/app/models/query.rb	Tue Sep 09 09:28:31 2014 +0100
+++ b/app/models/query.rb	Tue Sep 09 09:29:00 2014 +0100
@@ -242,7 +242,9 @@
         when :date, :date_past
           case operator_for(field)
           when "=", ">=", "<=", "><"
-            add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && (!v.match(/^\d{4}-\d{2}-\d{2}$/) || (Date.parse(v) rescue nil).nil?) }
+            add_filter_error(field, :invalid) if values_for(field).detect {|v|
+              v.present? && (!v.match(/\A\d{4}-\d{2}-\d{2}(T\d{2}((:)?\d{2}){0,2}(Z|\d{2}:?\d{2})?)?\z/) || parse_date(v).nil?)
+            }
           when ">t-", "<t-", "t-", ">t+", "<t+", "t+", "><t+", "><t-"
             add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^\d+$/) }
           end
@@ -587,7 +589,7 @@
     db_field = 'value'
     filter = @available_filters[field]
     return nil unless filter
-    if filter[:format] == 'user'
+    if filter[:field].format.target_class && filter[:field].format.target_class <= User
       if value.delete('me')
         value.push User.current.id.to_s
       end
@@ -624,7 +626,7 @@
       if value.any?
         case type_for(field)
         when :date, :date_past
-          sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), (Date.parse(value.first) rescue nil))
+          sql = date_clause(db_table, db_field, parse_date(value.first), parse_date(value.first))
         when :integer
           if is_custom_filter
             sql = "(#{db_table}.#{db_field} <> '' AND CAST(CASE #{db_table}.#{db_field} WHEN '' THEN '0' ELSE #{db_table}.#{db_field} END AS decimal(30,3)) = #{value.first.to_i})"
@@ -659,7 +661,7 @@
       sql << " AND #{db_table}.#{db_field} <> ''" if is_custom_filter
     when ">="
       if [:date, :date_past].include?(type_for(field))
-        sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), nil)
+        sql = date_clause(db_table, db_field, parse_date(value.first), nil)
       else
         if is_custom_filter
           sql = "(#{db_table}.#{db_field} <> '' AND CAST(CASE #{db_table}.#{db_field} WHEN '' THEN '0' ELSE #{db_table}.#{db_field} END AS decimal(30,3)) >= #{value.first.to_f})"
@@ -669,7 +671,7 @@
       end
     when "<="
       if [:date, :date_past].include?(type_for(field))
-        sql = date_clause(db_table, db_field, nil, (Date.parse(value.first) rescue nil))
+        sql = date_clause(db_table, db_field, nil, parse_date(value.first))
       else
         if is_custom_filter
           sql = "(#{db_table}.#{db_field} <> '' AND CAST(CASE #{db_table}.#{db_field} WHEN '' THEN '0' ELSE #{db_table}.#{db_field} END AS decimal(30,3)) <= #{value.first.to_f})"
@@ -679,7 +681,7 @@
       end
     when "><"
       if [:date, :date_past].include?(type_for(field))
-        sql = date_clause(db_table, db_field, (Date.parse(value[0]) rescue nil), (Date.parse(value[1]) rescue nil))
+        sql = date_clause(db_table, db_field, parse_date(value[0]), parse_date(value[1]))
       else
         if is_custom_filter
           sql = "(#{db_table}.#{db_field} <> '' AND CAST(CASE #{db_table}.#{db_field} WHEN '' THEN '0' ELSE #{db_table}.#{db_field} END AS decimal(30,3)) BETWEEN #{value[0].to_f} AND #{value[1].to_f})"
@@ -764,29 +766,13 @@
 
   # Adds a filter for the given custom field
   def add_custom_field_filter(field, assoc=nil)
-    case field.field_format
-    when "text"
-      options = { :type => :text }
-    when "list"
-      options = { :type => :list_optional, :values => field.possible_values }
-    when "date"
-      options = { :type => :date }
-    when "bool"
-      options = { :type => :list, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]] }
-    when "int"
-      options = { :type => :integer }
-    when "float"
-      options = { :type => :float }
-    when "user", "version"
-      return unless project
-      values = field.possible_values_options(project)
-      if User.current.logged? && field.field_format == 'user'
-        values.unshift ["<< #{l(:label_me)} >>", "me"]
+    options = field.format.query_filter_options(field, self)
+    if field.format.target_class && field.format.target_class <= User
+      if options[:values].is_a?(Array) && User.current.logged?
+        options[:values].unshift ["<< #{l(:label_me)} >>", "me"]
       end
-      options = { :type => :list_optional, :values => values }
-    else
-      options = { :type => :string }
     end
+
     filter_id = "cf_#{field.id}"
     filter_name = field.name
     if assoc.present?
@@ -795,7 +781,6 @@
     end
     add_available_filter filter_id, options.merge({
       :name => filter_name,
-      :format => field.field_format,
       :field => field
     })
   end
@@ -826,19 +811,24 @@
   def date_clause(table, field, from, to)
     s = []
     if from
-      from_yesterday = from - 1
-      from_yesterday_time = Time.local(from_yesterday.year, from_yesterday.month, from_yesterday.day)
+      if from.is_a?(Date)
+        from = Time.local(from.year, from.month, from.day).yesterday.end_of_day
+      else
+        from = from - 1 # second
+      end
       if self.class.default_timezone == :utc
-        from_yesterday_time = from_yesterday_time.utc
+        from = from.utc
       end
-      s << ("#{table}.#{field} > '%s'" % [connection.quoted_date(from_yesterday_time.end_of_day)])
+      s << ("#{table}.#{field} > '%s'" % [connection.quoted_date(from)])
     end
     if to
-      to_time = Time.local(to.year, to.month, to.day)
+      if to.is_a?(Date)
+        to = Time.local(to.year, to.month, to.day).end_of_day
+      end
       if self.class.default_timezone == :utc
-        to_time = to_time.utc
+        to = to.utc
       end
-      s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date(to_time.end_of_day)])
+      s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date(to)])
     end
     s.join(' AND ')
   end
@@ -848,6 +838,15 @@
     date_clause(table, field, (days_from ? Date.today + days_from : nil), (days_to ? Date.today + days_to : nil))
   end
 
+  # Returns a Date or Time from the given filter value
+  def parse_date(arg)
+    if arg.to_s =~ /\A\d{4}-\d{2}-\d{2}T/
+      Time.parse(arg) rescue nil
+    else
+      Date.parse(arg) rescue nil
+    end
+  end
+
   # Additional joins required for the given sort options
   def joins_for_order_statement(order_options)
     joins = []