will_filter 3.1.11 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/Gemfile +8 -3
  4. data/Gemfile.lock +182 -127
  5. data/README.rdoc +1 -10
  6. data/app/assets/images/will_filter/loading.gif +0 -0
  7. data/app/assets/javascripts/will_filter/filter.js +526 -517
  8. data/app/assets/stylesheets/will_filter/filter.css.scss +405 -108
  9. data/app/controllers/will_filter/calendar_controller.rb +10 -1
  10. data/app/controllers/will_filter/exporter_controller.rb +12 -3
  11. data/app/controllers/will_filter/filter_controller.rb +19 -10
  12. data/app/models/will_filter/filter.rb +254 -203
  13. data/app/views/will_filter/calendar/index.html.erb +55 -43
  14. data/app/views/will_filter/common/_actions_bar.html.erb +3 -3
  15. data/app/views/will_filter/common/_results_table.html.erb +55 -39
  16. data/app/views/will_filter/common/_scripts.html.erb +2 -12
  17. data/app/views/will_filter/exporter/index.html.erb +26 -22
  18. data/app/views/will_filter/filter/_condition.html.erb +25 -9
  19. data/app/views/will_filter/filter/_conditions.html.erb +12 -9
  20. data/app/views/will_filter/filter/_conditions_footer.html.erb +25 -10
  21. data/app/views/will_filter/filter/_conditions_header.html.erb +38 -24
  22. data/app/views/will_filter/filter/_container.html.erb +10 -9
  23. data/app/views/will_filter/filter/containers/_date.html.erb +8 -10
  24. data/app/views/will_filter/filter/containers/_date_range.html.erb +21 -13
  25. data/app/views/will_filter/filter/containers/_date_time.html.erb +8 -10
  26. data/app/views/will_filter/filter/containers/_date_time_range.html.erb +21 -13
  27. data/app/views/will_filter/filter/containers/_list.html.erb +16 -6
  28. data/config/routes.rb +26 -16
  29. data/deploy +63 -0
  30. data/lib/generators/will_filter/templates/config.yml +18 -5
  31. data/lib/generators/will_filter/templates/create_will_filter_filters.rb +12 -1
  32. data/lib/generators/will_filter/will_filter_generator.rb +10 -1
  33. data/lib/tasks/will_filter_tasks.rake +10 -2
  34. data/lib/will_filter.rb +10 -1
  35. data/lib/will_filter/calendar.rb +10 -1
  36. data/lib/will_filter/config.rb +31 -4
  37. data/lib/will_filter/containers/boolean.rb +10 -1
  38. data/lib/will_filter/containers/date.rb +10 -1
  39. data/lib/will_filter/containers/date_range.rb +10 -1
  40. data/lib/will_filter/containers/date_time.rb +10 -1
  41. data/lib/will_filter/containers/date_time_range.rb +10 -1
  42. data/lib/will_filter/containers/double.rb +10 -1
  43. data/lib/will_filter/containers/double_delimited.rb +10 -1
  44. data/lib/will_filter/containers/double_range.rb +10 -1
  45. data/lib/will_filter/containers/filter_list.rb +21 -7
  46. data/lib/will_filter/containers/list.rb +10 -1
  47. data/lib/will_filter/containers/nil.rb +10 -1
  48. data/lib/will_filter/containers/numeric.rb +10 -1
  49. data/lib/will_filter/containers/numeric_delimited.rb +10 -1
  50. data/lib/will_filter/containers/numeric_range.rb +10 -1
  51. data/lib/will_filter/containers/single_date.rb +12 -1
  52. data/lib/will_filter/containers/text.rb +10 -1
  53. data/lib/will_filter/containers/text_delimited.rb +11 -2
  54. data/lib/will_filter/engine.rb +10 -1
  55. data/lib/will_filter/extensions/action_controller_extension.rb +34 -10
  56. data/lib/will_filter/extensions/action_view_extension.rb +12 -3
  57. data/lib/will_filter/extensions/active_record_extension.rb +11 -1
  58. data/lib/will_filter/extensions/active_record_relation_extension.rb +51 -0
  59. data/lib/will_filter/extensions/array_extension.rb +10 -1
  60. data/lib/will_filter/filter_condition.rb +11 -7
  61. data/lib/will_filter/filter_container.rb +10 -1
  62. data/lib/will_filter/filter_exception.rb +10 -1
  63. data/lib/will_filter/railtie.rb +14 -4
  64. data/lib/will_filter/version.rb +11 -2
  65. data/spec/config/config_spec.rb +5 -5
  66. data/spec/models/will_filter/filter_spec.rb +130 -131
  67. data/test/dummy/app/assets/javascripts/application.js +3 -0
  68. data/test/dummy/app/assets/javascripts/bootstrap.js +1951 -0
  69. data/test/dummy/app/assets/javascripts/jquery-2.1.3.min.js +4 -0
  70. data/test/dummy/app/assets/javascripts/select2.min.js +3 -0
  71. data/test/dummy/app/assets/stylesheets/{application.css → application.css.sass} +5 -2
  72. data/test/dummy/app/assets/stylesheets/bootstrap.min.css +7 -0
  73. data/test/dummy/app/assets/stylesheets/select2.min.css +1 -0
  74. data/test/dummy/app/controllers/advanced_controller.rb +4 -4
  75. data/test/dummy/app/controllers/orders_controller.rb +2 -2
  76. data/test/dummy/app/controllers/simple_controller.rb +3 -3
  77. data/test/dummy/app/models/event.rb +1 -1
  78. data/test/dummy/app/models/user.rb +1 -1
  79. data/test/dummy/app/views/common/_events.html.erb +7 -13
  80. data/test/dummy/app/views/common/_menu.html.erb +25 -27
  81. data/test/dummy/app/views/layouts/application.html.erb +3 -5
  82. data/test/dummy/config/environments/development.rb +2 -0
  83. data/test/dummy/config/environments/production.rb +2 -0
  84. data/test/dummy/config/environments/test.rb +2 -0
  85. data/test/dummy/config/initializers/assets.rb +12 -0
  86. data/test/dummy/config/routes.rb +10 -10
  87. data/test/dummy/db/schema.rb +46 -50
  88. data/will_filter.gemspec +3 -3
  89. metadata +39 -44
  90. data/.rvmrc +0 -1
  91. data/app/assets/javascripts/will_filter/filter_prototype_effects.js +0 -38
  92. data/app/assets/stylesheets/will_filter/actions.css.scss +0 -27
  93. data/app/assets/stylesheets/will_filter/buttons.css.scss +0 -24
  94. data/app/assets/stylesheets/will_filter/calendar.css.scss +0 -102
  95. data/app/assets/stylesheets/will_filter/exporter.css.scss +0 -89
  96. data/app/assets/stylesheets/will_filter/results.css.scss +0 -63
  97. data/app/views/layouts/will_filter/application.html.erb +0 -14
  98. data/test/dummy/app/assets/javascripts/orders.js +0 -2
  99. data/test/dummy/app/assets/stylesheets/orders.css +0 -4
@@ -1,5 +1,14 @@
1
1
  #--
2
- # Copyright (c) 2010-2013 Michael Berkovich
2
+ # Copyright (c) 2017 Michael Berkovich, theiceberk@gmail.com
3
+ #
4
+ # __ __ ____ _ _ _____ ____ _ ______ ___ ____
5
+ # | |__| || || | | | | || || | | | / _]| \
6
+ # | | | | | | | | | | | __| | | | | | | / [_ | D )
7
+ # | | | | | | | |___ | |___ | |_ | | | |___|_| |_|| _]| /
8
+ # | ` ' | | | | || | | _] | | | | | | | [_ | \
9
+ # \ / | | | || | | | | | | | | | | || . \
10
+ # \_/\_/ |____||_____||_____| |__| |____||_____| |__| |_____||__|\_|
11
+ #
3
12
  #
4
13
  # Permission is hereby granted, free of charge, to any person obtaining
5
14
  # a copy of this software and associated documentation files (the
@@ -1,5 +1,14 @@
1
1
  #--
2
- # Copyright (c) 2010-2013 Michael Berkovich
2
+ # Copyright (c) 2017 Michael Berkovich, theiceberk@gmail.com
3
+ #
4
+ # __ __ ____ _ _ _____ ____ _ ______ ___ ____
5
+ # | |__| || || | | | | || || | | | / _]| \
6
+ # | | | | | | | | | | | __| | | | | | | / [_ | D )
7
+ # | | | | | | | |___ | |___ | |_ | | | |___|_| |_|| _]| /
8
+ # | ` ' | | | | || | | _] | | | | | | | [_ | \
9
+ # \ / | | | || | | | | | | | | | | || . \
10
+ # \_/\_/ |____||_____||_____| |__| |____||_____| |__| |_____||__|\_|
11
+ #
3
12
  #
4
13
  # Permission is hereby granted, free of charge, to any person obtaining
5
14
  # a copy of this software and associated documentation files (the
@@ -27,7 +36,7 @@ module WillFilter
27
36
  class ExporterController < ApplicationController
28
37
 
29
38
  def index
30
- @wf_filter = WillFilter::Filter.deserialize_from_params(params)
39
+ @wf_filter = WillFilter::Filter.deserialize_from_params(params.permit!)
31
40
  render :layout => false
32
41
  end
33
42
 
@@ -35,7 +44,7 @@ module WillFilter
35
44
  params[:page] = 1
36
45
  params[:wf_per_page] = 10000 # max export limit
37
46
 
38
- @wf_filter = WillFilter::Filter.deserialize_from_params(params)
47
+ @wf_filter = WillFilter::Filter.deserialize_from_params(params.permit!)
39
48
 
40
49
  if @wf_filter.custom_format?
41
50
  send_data(@wf_filter.process_custom_format, :type => 'text', :charset => 'utf-8')
@@ -1,5 +1,14 @@
1
1
  #--
2
- # Copyright (c) 2010-2013 Michael Berkovich
2
+ # Copyright (c) 2017 Michael Berkovich, theiceberk@gmail.com
3
+ #
4
+ # __ __ ____ _ _ _____ ____ _ ______ ___ ____
5
+ # | |__| || || | | | | || || | | | / _]| \
6
+ # | | | | | | | | | | | __| | | | | | | / [_ | D )
7
+ # | | | | | | | |___ | |___ | |_ | | | |___|_| |_|| _]| /
8
+ # | ` ' | | | | || | | _] | | | | | | | [_ | \
9
+ # \ / | | | || | | | | | | | | | | || . \
10
+ # \_/\_/ |____||_____||_____| |__| |____||_____| |__| |_____||__|\_|
11
+ #
3
12
  #
4
13
  # Permission is hereby granted, free of charge, to any person obtaining
5
14
  # a copy of this software and associated documentation files (the
@@ -25,24 +34,24 @@ module WillFilter
25
34
  class FilterController < ApplicationController
26
35
 
27
36
  def index
28
- @filters = WillFilter::Filter.new(WillFilter::Filter).deserialize_from_params(params).results
37
+ @filters = WillFilter::Filter.new(WillFilter::Filter).deserialize_from_params(params.permit!).results
29
38
  end
30
39
 
31
40
  def update_condition
32
- wf_filter = WillFilter::Filter.deserialize_from_params(params)
41
+ wf_filter = WillFilter::Filter.deserialize_from_params(params.permit!)
33
42
  condition = wf_filter.condition_at(params[:at_index].to_i)
34
43
  condition.container.reset_values
35
44
  render(:partial => '/will_filter/filter/conditions', :layout=>false, :locals => {:wf_filter => wf_filter})
36
45
  end
37
46
 
38
47
  def remove_condition
39
- wf_filter = WillFilter::Filter.deserialize_from_params(params)
48
+ wf_filter = WillFilter::Filter.deserialize_from_params(params.permit!)
40
49
  wf_filter.remove_condition_at(params[:at_index].to_i)
41
50
  render(:partial => '/will_filter/filter/conditions', :layout=>false, :locals => {:wf_filter => wf_filter})
42
51
  end
43
52
 
44
53
  def add_condition
45
- wf_filter = WillFilter::Filter.deserialize_from_params(params)
54
+ wf_filter = WillFilter::Filter.deserialize_from_params(params.permit!)
46
55
  index = params[:after_index].to_i
47
56
  if index == -1
48
57
  wf_filter.add_default_condition_at(wf_filter.size)
@@ -53,13 +62,13 @@ module WillFilter
53
62
  end
54
63
 
55
64
  def remove_all_conditions
56
- wf_filter = WillFilter::Filter.deserialize_from_params(params)
65
+ wf_filter = WillFilter::Filter.deserialize_from_params(params.permit!)
57
66
  wf_filter.remove_all
58
67
  render(:partial => '/will_filter/filter/conditions', :layout=>false, :locals => {:wf_filter => wf_filter})
59
68
  end
60
69
 
61
70
  def load_filter
62
- wf_filter = WillFilter::Filter.deserialize_from_params(params)
71
+ wf_filter = WillFilter::Filter.deserialize_from_params(params.permit!)
63
72
  wf_filter = wf_filter.load_filter!(params[:wf_key])
64
73
  render(:partial => '/will_filter/filter/conditions', :layout=>false, :locals => {:wf_filter => wf_filter})
65
74
  end
@@ -69,7 +78,7 @@ module WillFilter
69
78
 
70
79
  params.delete(:wf_id)
71
80
 
72
- wf_filter = WillFilter::Filter.deserialize_from_params(params)
81
+ wf_filter = WillFilter::Filter.deserialize_from_params(params.permit!)
73
82
  wf_filter.validate!
74
83
 
75
84
  unless wf_filter.errors?
@@ -85,7 +94,7 @@ module WillFilter
85
94
  raise WillFilter::FilterException.new("Update functions are disabled") unless WillFilter::Config.saving_enabled?
86
95
 
87
96
  wf_filter = WillFilter::Filter.find_by_id(params.delete(:wf_id))
88
- wf_filter.deserialize_from_params(params)
97
+ wf_filter.deserialize_from_params(params.permit!)
89
98
  wf_filter.validate!
90
99
 
91
100
  unless wf_filter.errors?
@@ -103,7 +112,7 @@ module WillFilter
103
112
  wf_filter = WillFilter::Filter.find_by_id(params[:wf_id])
104
113
  wf_filter.destroy if wf_filter
105
114
 
106
- wf_filter = WillFilter::Filter.deserialize_from_params(params)
115
+ wf_filter = WillFilter::Filter.deserialize_from_params(params.permit!)
107
116
  wf_filter.id=nil
108
117
  wf_filter.key=nil
109
118
  wf_filter.remove_all
@@ -1,5 +1,14 @@
1
1
  #--
2
- # Copyright (c) 2010-2013 Michael Berkovich
2
+ # Copyright (c) 2017 Michael Berkovich, theiceberk@gmail.com
3
+ #
4
+ # __ __ ____ _ _ _____ ____ _ ______ ___ ____
5
+ # | |__| || || | | | | || || | | | / _]| \
6
+ # | | | | | | | | | | | __| | | | | | | / [_ | D )
7
+ # | | | | | | | |___ | |___ | |_ | | | |___|_| |_|| _]| /
8
+ # | ` ' | | | | || | | _] | | | | | | | [_ | \
9
+ # \ / | | | || | | | | | | | | | | || . \
10
+ # \_/\_/ |____||_____||_____| |__| |____||_____| |__| |_____||__|\_|
11
+ #
3
12
  #
4
13
  # Permission is hereby granted, free of charge, to any person obtaining
5
14
  # a copy of this software and associated documentation files (the
@@ -26,40 +35,39 @@
26
35
  # Table name: will_filter_filters
27
36
  #
28
37
  # id INTEGER not null, primary key
29
- # type varchar(255)
30
- # name varchar(255)
31
- # data text
32
- # user_id integer
33
- # model_class_name varchar(255)
34
- # created_at datetime
35
- # updated_at datetime
38
+ # type varchar(255)
39
+ # name varchar(255)
40
+ # data text
41
+ # user_id integer
42
+ # model_class_name varchar(255)
43
+ # created_at datetime
44
+ # updated_at datetime
36
45
  #
37
46
  # Indexes
38
47
  #
39
- # index_will_filter_filters_on_user_id (user_id)
48
+ # index_will_filter_filters_on_user_id (user_id)
40
49
  #
41
50
  #++
42
51
 
43
52
  module WillFilter
44
53
  class Filter < ActiveRecord::Base
45
- self.table_name = :will_filter_filters
46
- attr_accessible :type, :name, :data, :user_id, :model_class_name
54
+ self.table_name = :will_filter_filters
47
55
 
48
56
  # set_table_name :will_filter_filters
49
57
  serialize :data
50
58
  before_save :prepare_save
51
59
  after_find :process_find
52
-
60
+
53
61
  JOIN_NAME_INDICATOR = '>'
54
62
 
55
63
  #############################################################################
56
- # Basics
64
+ # Basics
57
65
  #############################################################################
58
66
  def initialize(model_class = nil)
59
67
  super()
60
68
 
61
- if WillFilter::Config.require_filter_extensions? and self.class.name == "WillFilter::Filter"
62
- raise WillFilter::FilterException.new("Your configuration requires you to subclass the filter. Default filter cannot be created.")
69
+ if WillFilter::Config.require_filter_extensions? and self.class.name == 'WillFilter::Filter'
70
+ raise WillFilter::FilterException.new('Your configuration requires you to subclass the filter. Default filter cannot be created.')
63
71
  end
64
72
 
65
73
  self.model_class_name = model_class.to_s
@@ -68,51 +76,51 @@ module WillFilter
68
76
  def dup
69
77
  super.tap {|ii| ii.conditions = self.conditions.dup}
70
78
  end
71
-
79
+
72
80
  def prepare_save
73
81
  self.data = serialize_to_params
74
82
  self.type = self.class.name
75
83
  end
76
-
84
+
77
85
  def process_find
78
86
  @errors = {}
79
87
  deserialize_from_params(self.data)
80
88
  end
81
-
89
+
82
90
  #############################################################################
83
- # Defaults
91
+ # Defaults
84
92
  #############################################################################
85
93
  def show_export_options?
86
94
  WillFilter::Config.exporting_enabled?
87
95
  end
88
-
96
+
89
97
  def show_save_options?
90
98
  WillFilter::Config.saving_enabled?
91
99
  end
92
-
93
- def match
100
+
101
+ def match
94
102
  @match ||= :all
95
103
  end
96
-
97
- def key
104
+
105
+ def key
98
106
  @key ||= ''
99
107
  end
100
-
101
- def errors
108
+
109
+ def errors
102
110
  @errors ||= {}
103
111
  end
104
-
112
+
105
113
  def format
106
114
  @format ||= :html
107
115
  end
108
-
116
+
109
117
  def fields
110
118
  @fields ||= []
111
119
  end
112
-
120
+
113
121
  def extra_params
114
122
  @extra_params ||= {}
115
- end
123
+ end
116
124
 
117
125
  #############################################################################
118
126
  # a list of indexed fields where at least one of them has to be in a query
@@ -121,57 +129,59 @@ module WillFilter
121
129
  def required_condition_keys
122
130
  []
123
131
  end
124
-
132
+
125
133
  # For extra security, this method must be overloaded by the extending class.
126
134
  def model_class
127
135
  if WillFilter::Config.require_filter_extensions?
128
- raise WillFilter::FilterException.new("model_class method must be overloaded in the extending class.")
136
+ raise WillFilter::FilterException.new("model_class method must be overloaded in the extending class.")
129
137
  end
130
138
 
131
139
  if model_class_name.blank?
132
- raise WillFilter::FilterException.new("model_class_name was not specified.")
140
+ raise WillFilter::FilterException.new("model_class_name was not specified.")
133
141
  end
134
142
 
135
143
  @model_class ||= model_class_name.constantize
136
144
  end
137
-
145
+
138
146
  def table_name
139
147
  model_class.table_name
140
148
  end
141
-
149
+
142
150
  def key=(new_key)
143
151
  @key = new_key
144
152
  end
145
-
153
+
146
154
  def match=(new_match)
147
155
  @match = new_match
148
156
  end
149
-
157
+
150
158
  #############################################################################
151
- # Inner Joins come in a form of
159
+ # Inner Joins come in a form of
152
160
  # [[joining_model_name, column_name], [joining_model_name, column_name]]
153
161
  #############################################################################
154
162
  def inner_joins
155
163
  []
156
164
  end
157
-
165
+
158
166
  def model_columns
159
- model_class.columns
167
+ @model_columns ||= model_class.columns
160
168
  end
161
-
169
+
162
170
  def model_column_keys
163
- model_columns.collect{|col| col.name.to_sym}
171
+ @model_column_keys ||= model_columns.collect{|col| col.name.to_sym}
164
172
  end
165
-
173
+
166
174
  def contains_column?(key)
167
- model_column_keys.index(key) != nil
175
+ model_column_keys.index(key.to_sym) != nil
168
176
  end
169
-
177
+
170
178
  def definition
171
179
  @definition ||= begin
172
180
  defs = {}
173
181
  model_columns.each do |col|
174
- defs[col.name.to_sym] = default_condition_definition_for(col.name, col.sql_type)
182
+ key = col.name.to_sym
183
+ next unless contains_column?(key)
184
+ defs[key] = default_condition_definition_for(col.name, col.sql_type)
175
185
  end
176
186
  inner_joins.each do |inner_join|
177
187
  join_class = association_class(inner_join)
@@ -179,11 +189,21 @@ module WillFilter
179
189
  defs[:"#{join_class.to_s.underscore}.#{col.name.to_sym}"] = default_condition_definition_for(col.name, col.sql_type)
180
190
  end
181
191
  end
182
-
192
+
183
193
  defs
184
194
  end
185
195
  end
186
196
 
197
+ def sql_attribute_for_key(key)
198
+ if key.to_s.index('.')
199
+ parts = key.to_s.split('.')
200
+ join_class = parts.first.camelcase.constantize
201
+ "#{join_class.table_name}.#{parts.last}"
202
+ else
203
+ "#{table_name}.#{key}"
204
+ end
205
+ end
206
+
187
207
  def self.container_by_sql_type(type)
188
208
  raise WillFilter::FilterException.new("Unsupported data type #{type}") unless WillFilter::Config.data_types[type]
189
209
  WillFilter::Config.data_types[type]
@@ -192,7 +212,7 @@ module WillFilter
192
212
  def container_by_sql_type(type)
193
213
  self.class.container_by_sql_type(type)
194
214
  end
195
-
215
+
196
216
  def default_condition_definition_for(name, sql_data_type)
197
217
  type = sql_data_type.split(" ").first.split("(").first.downcase
198
218
  containers = container_by_sql_type(type)
@@ -204,52 +224,52 @@ module WillFilter
204
224
  operators[o] = c
205
225
  end
206
226
  end
207
-
227
+
208
228
  if name == "id"
209
- operators[:is_filtered_by] = :filter_list
229
+ operators[:is_filtered_by] = :filter_list
210
230
  elsif "_id" == name[-3..-1]
211
231
  begin
212
232
  name[0..-4].camelcase.constantize
213
- operators[:is_filtered_by] = :filter_list
214
- rescue
233
+ operators[:is_filtered_by] = :filter_list
234
+ rescue
215
235
  end
216
236
  end
217
-
237
+
218
238
  operators
219
239
  end
220
-
240
+
241
+ def model_class_for_column_key(key)
242
+ nil
243
+ end
244
+
221
245
  def sorted_operators(opers)
222
246
  (WillFilter::Config.operator_order & opers.keys.collect{|o| o.to_s})
223
247
  end
224
-
248
+
225
249
  def first_sorted_operator(opers)
226
250
  sorted_operators(opers).first.to_sym
227
251
  end
228
-
252
+
229
253
  def default_order
230
254
  'id'
231
255
  end
232
-
256
+
233
257
  def order
234
258
  @order ||= default_order
235
259
  @order = default_order unless contains_column?(@order.to_sym)
236
260
  @order
237
261
  end
238
-
262
+
239
263
  def default_order_type
240
264
  'desc'
241
265
  end
242
-
266
+
243
267
  def order_type
244
268
  @order_type ||= default_order_type
245
269
  @order_type = default_order_type unless ['asc', 'desc'].include?(@order_type.to_s)
246
270
  @order_type
247
271
  end
248
-
249
- def order_clause
250
- "#{order} #{order_type}"
251
- end
252
-
272
+
253
273
  def order_model
254
274
  @order_model ||= begin
255
275
  order_parts = order.split('.')
@@ -258,7 +278,7 @@ module WillFilter
258
278
  else
259
279
  model_class_name
260
280
  end
261
- end
281
+ end
262
282
  end
263
283
 
264
284
  def order_clause
@@ -269,41 +289,49 @@ module WillFilter
269
289
  else
270
290
  "#{model_class_name.constantize.table_name}.#{order_parts.first} #{order_type}"
271
291
  end
272
- end
292
+ end
273
293
  end
274
294
 
275
295
  def column_sorted?(key)
276
296
  key.to_s == order
277
297
  end
278
-
298
+
279
299
  def default_per_page
280
- 30
300
+ 100
281
301
  end
282
-
302
+
283
303
  def per_page
284
304
  @per_page ||= default_per_page
285
305
  end
286
-
306
+
287
307
  def page
288
308
  @page ||= 1
289
309
  end
290
-
310
+
291
311
  def default_per_page_options
292
- [10, 20, 30, 40, 50, 100]
312
+ [10, 20, 30, 40, 50, 100, 500, 1000]
313
+ end
314
+
315
+ def per_page_configurable?
316
+ true
293
317
  end
294
-
318
+
295
319
  def per_page_options
296
320
  @per_page_options ||= default_per_page_options.collect{ |n| [n.to_s, n.to_s] }
297
321
  end
298
-
322
+
299
323
  def match_options
300
324
  [["all", "all"], ["any", "any"]]
301
325
  end
302
-
326
+
327
+ def order_configurable?
328
+ true
329
+ end
330
+
303
331
  def order_type_options
304
332
  [["desc", "desc"], ["asc", "asc"]]
305
333
  end
306
-
334
+
307
335
  #############################################################################
308
336
  # Can be overloaded for custom titles
309
337
  #############################################################################
@@ -314,10 +342,10 @@ module WillFilter
314
342
  if title_parts.size > 1
315
343
  "#{JOIN_NAME_INDICATOR} #{title}"
316
344
  else
317
- title
345
+ title
318
346
  end
319
347
  end
320
-
348
+
321
349
  def condition_options
322
350
  @condition_options ||= begin
323
351
  opts = []
@@ -325,13 +353,13 @@ module WillFilter
325
353
  opts << [condition_title_for(cond), cond.to_s]
326
354
  end
327
355
  opts = opts.sort_by{|opt| opt.first.gsub(JOIN_NAME_INDICATOR, 'zzz') }
328
-
356
+
329
357
  separated = []
330
358
  opts.each_with_index do |opt, index|
331
359
  if index > 0
332
360
  prev_opt_parts = opts[index-1].first.split(":")
333
361
  curr_opt_parts = opt.first.split(":")
334
-
362
+
335
363
  if (prev_opt_parts.size != curr_opt_parts.size) or (curr_opt_parts.size > 1 and (prev_opt_parts.first != curr_opt_parts.first))
336
364
  key_parts = opt.last.split('.')
337
365
  separated << ["-------------- #{curr_opt_parts.first.gsub("#{JOIN_NAME_INDICATOR} ", '')} --------------", "#{key_parts.first}.id"]
@@ -342,32 +370,32 @@ module WillFilter
342
370
  separated
343
371
  end
344
372
  end
345
-
373
+
346
374
  def operator_options_for(condition_key)
347
375
  condition_key = condition_key.to_sym if condition_key.is_a?(String)
348
-
376
+
349
377
  opers = definition[condition_key]
350
378
  raise WillFilter::FilterException.new("Invalid condition #{condition_key} for filter #{self.class.name}") unless opers
351
379
  sorted_operators(opers).collect{|o| [o.to_s.gsub('_', ' '), o]}
352
380
  end
353
-
381
+
354
382
  # called by the list container, should be overloaded in a subclass
355
383
  def value_options_for(condition_key)
356
384
  []
357
385
  end
358
-
386
+
359
387
  def container_for(condition_key, operator_key)
360
388
  condition_key = condition_key.to_sym if condition_key.is_a?(String)
361
-
389
+
362
390
  opers = definition[condition_key]
363
391
  raise WillFilter::FilterException.new("Invalid condition #{condition_key} for filter #{self.class.name}") unless opers
364
392
  oper = opers[operator_key]
365
-
393
+
366
394
  # if invalid operator_key was passed, use first operator
367
395
  oper = opers[first_sorted_operator(opers)] unless oper
368
396
  oper
369
397
  end
370
-
398
+
371
399
  def conditions_for(condition_key)
372
400
  @conditions.select{|cond| cond.key == condition_key}
373
401
  end
@@ -393,80 +421,80 @@ module WillFilter
393
421
  remove_condition(condition_key)
394
422
  add_condition_at(size, condition_key, operator_key, values)
395
423
  end
396
-
424
+
397
425
  def valid_operator?(condition_key, operator_key)
398
426
  condition_key = condition_key.to_sym if condition_key.is_a?(String)
399
427
  opers = definition[condition_key]
400
428
  return false unless opers
401
429
  opers[operator_key]!=nil
402
430
  end
403
-
431
+
404
432
  def add_condition_at(index, condition_key, operator_key, values = [])
405
433
  values = [values] unless values.instance_of?(Array)
406
434
  values = values.collect{|v| v.to_s}
407
-
435
+
408
436
  condition_key = condition_key.to_sym if condition_key.is_a?(String)
409
-
437
+
410
438
  unless valid_operator?(condition_key, operator_key)
411
439
  opers = definition[condition_key]
412
440
  operator_key = first_sorted_operator(opers)
413
441
  end
414
-
442
+
415
443
  condition = WillFilter::FilterCondition.new(self, condition_key, operator_key, container_for(condition_key, operator_key), values)
416
444
  @conditions.insert(index, condition)
417
445
  end
418
-
446
+
419
447
  #############################################################################
420
448
  # options always go in [NAME, KEY] format
421
449
  #############################################################################
422
450
  def default_condition_key
423
451
  condition_options.first.last
424
452
  end
425
-
453
+
426
454
  #############################################################################
427
455
  # options always go in [NAME, KEY] format
428
456
  #############################################################################
429
457
  def default_operator_key(condition_key)
430
458
  operator_options_for(condition_key).first.last
431
459
  end
432
-
433
- def conditions=(new_conditions)
460
+
461
+ def conditions=(new_conditions)
434
462
  @conditions = new_conditions
435
463
  end
436
-
464
+
437
465
  def conditions
438
466
  @conditions ||= []
439
467
  end
440
-
468
+
441
469
  def condition_at(index)
442
470
  conditions[index]
443
471
  end
444
-
472
+
445
473
  def condition_by_key(key)
446
474
  conditions.each do |c|
447
475
  return c if c.key==key
448
476
  end
449
477
  nil
450
478
  end
451
-
479
+
452
480
  def size
453
481
  conditions.size
454
482
  end
455
-
483
+
456
484
  def add_default_condition_at(index)
457
485
  add_condition_at(index, default_condition_key, default_operator_key(default_condition_key))
458
486
  end
459
-
487
+
460
488
  def remove_condition_at(index)
461
489
  conditions.delete_at(index)
462
490
  end
463
-
491
+
464
492
  def remove_all
465
493
  @conditions = []
466
494
  end
467
-
495
+
468
496
  #############################################################################
469
- # Serialization
497
+ # Serialization
470
498
  #############################################################################
471
499
  def serialize_to_params(merge_params = {})
472
500
  params = {}
@@ -478,12 +506,12 @@ module WillFilter
478
506
  params[:wf_per_page] = per_page
479
507
  params[:wf_export_fields] = fields.join(',')
480
508
  params[:wf_export_format] = format
481
-
509
+
482
510
  0.upto(size - 1) do |index|
483
511
  condition = condition_at(index)
484
512
  condition.serialize_to_params(params, index)
485
513
  end
486
-
514
+
487
515
  params.merge!(extra_params)
488
516
  params.merge!(merge_params)
489
517
  HashWithIndifferentAccess.new(params)
@@ -497,7 +525,7 @@ module WillFilter
497
525
  end
498
526
  params.join("&")
499
527
  end
500
-
528
+
501
529
  def to_s
502
530
  to_url_params
503
531
  end
@@ -514,15 +542,15 @@ module WillFilter
514
542
 
515
543
  unless filter_instance.kind_of?(WillFilter::Filter)
516
544
  raise WillFilter::FilterException.new("Invalid filter class. Filter classes must extand WillFilter::Filter.")
517
- end
518
-
545
+ end
546
+
519
547
  if WillFilter::Config.require_filter_extensions?
520
- filter_instance.deserialize_from_params(params)
521
- else
522
- filter_class.new(params[:wf_model]).deserialize_from_params(params)
548
+ filter_instance.deserialize_from_params(params)
549
+ else
550
+ filter_class.new(params[:wf_model]).deserialize_from_params(params)
523
551
  end
524
552
  end
525
-
553
+
526
554
  def deserialize_from_params(params)
527
555
  params = HashWithIndifferentAccess.new(params) unless params.is_a?(HashWithIndifferentAccess)
528
556
 
@@ -531,28 +559,28 @@ module WillFilter
531
559
  @key = params[:wf_key] || self.id.to_s
532
560
 
533
561
  self.model_class_name = params[:wf_model] if params[:wf_model]
534
-
562
+
535
563
  @per_page = params[:wf_per_page] || default_per_page
536
564
  @page = params[:page] || 1
537
565
  @order_type = params[:wf_order_type] || default_order_type
538
566
  @order = params[:wf_order] || default_order
539
-
567
+
540
568
  self.id = params[:wf_id].to_i unless params[:wf_id].blank?
541
569
  self.name = params[:wf_name] unless params[:wf_name].blank?
542
-
570
+
543
571
  @fields = []
544
572
  unless params[:wf_export_fields].blank?
545
573
  params[:wf_export_fields].split(",").each do |fld|
546
574
  @fields << fld.to_sym
547
575
  end
548
576
  end
549
-
577
+
550
578
  if params[:wf_export_format].blank?
551
579
  @format = :html
552
- else
580
+ else
553
581
  @format = params[:wf_export_format].to_sym
554
582
  end
555
-
583
+
556
584
  i = 0
557
585
  while params["wf_c#{i}"] do
558
586
  conditon_key = params["wf_c#{i}"]
@@ -566,7 +594,7 @@ module WillFilter
566
594
  i += 1
567
595
  add_condition(conditon_key, operator_key.to_sym, values)
568
596
  end
569
-
597
+
570
598
  if params[:wf_submitted] == 'true'
571
599
  validate!
572
600
  end
@@ -574,37 +602,41 @@ module WillFilter
574
602
  if WillFilter::Config.user_filters_enabled? and WillFilter::Config.current_user
575
603
  self.user_id = WillFilter::Config.current_user.id
576
604
  end
577
-
605
+
606
+ if WillFilter::Config.project_filters_enabled? and WillFilter::Config.current_project
607
+ self.project_id = WillFilter::Config.current_project.id
608
+ end
609
+
578
610
  self
579
611
  end
580
612
  alias_method :from_params, :deserialize_from_params
581
-
613
+
582
614
  #############################################################################
583
- # Validations
615
+ # Validations
584
616
  #############################################################################
585
617
  def errors?
586
- (@errors and @errors.size > 0)
618
+ (@errors and @errors.size > 0)
587
619
  end
588
-
620
+
589
621
  def empty?
590
622
  size == 0
591
623
  end
592
-
624
+
593
625
  def has_condition?(key)
594
626
  condition_by_key(key) != nil
595
627
  end
596
-
628
+
597
629
  def valid_format?
598
630
  WillFilter::Config.default_export_formats.include?(format.to_s)
599
631
  end
600
-
632
+
601
633
  def required_conditions_met?
602
634
  return true if required_condition_keys.blank?
603
635
  sconditions = conditions.collect{|c| c.key.to_s}
604
636
  rconditions = required_condition_keys.collect{|c| c.to_s}
605
637
  not (sconditions & rconditions).empty?
606
638
  end
607
-
639
+
608
640
  def validate!
609
641
  @errors = {}
610
642
  0.upto(size - 1) do |index|
@@ -612,36 +644,41 @@ module WillFilter
612
644
  err = condition.validate
613
645
  @errors[index] = err if err
614
646
  end
615
-
647
+
616
648
  unless required_conditions_met?
617
649
  @errors[:filter] = "Filter must contain at least one of the following conditions: #{required_condition_keys.join(", ")}"
618
650
  end
619
-
651
+
620
652
  errors?
621
653
  end
622
-
654
+
623
655
  #############################################################################
624
- # SQL Conditions
656
+ # SQL Conditions
625
657
  #############################################################################
658
+
659
+ def to_sql_condition(condition)
660
+ condition.container.sql_condition
661
+ end
662
+
626
663
  def sql_conditions
627
664
  @sql_conditions ||= begin
628
- if errors?
629
- [" 1 = 2 "]
665
+ if errors?
666
+ [' 1 = 2 ']
630
667
  else
631
- all_sql_conditions = [""]
668
+ all_sql_conditions = ['']
632
669
  0.upto(size - 1) do |index|
633
670
  condition = condition_at(index)
634
671
  next if custom_condition?(condition)
635
672
  next unless condition.container
636
673
 
637
- sql_condition = condition.container.sql_condition
638
-
674
+ sql_condition = to_sql_condition(condition)
675
+
639
676
  unless sql_condition
640
677
  raise WillFilter::FilterException.new("Unsupported operator #{condition.operator_key} for container #{condition.container.class.name}")
641
678
  end
642
-
679
+
643
680
  if all_sql_conditions[0].size > 0
644
- all_sql_conditions[0] << ( match.to_sym == :all ? " AND " : " OR ")
681
+ all_sql_conditions[0] << ( match.to_sym == :all ? ' AND ' : ' OR ')
645
682
  end
646
683
 
647
684
  all_sql_conditions[0] << sql_condition[0]
@@ -656,79 +693,84 @@ module WillFilter
656
693
  end
657
694
  end
658
695
  end
659
-
696
+
660
697
  def debug_conditions(conds)
661
698
  all_conditions = []
662
699
  conds.each_with_index do |c, i|
663
700
  cond = ""
664
701
  if i == 0
665
702
  cond << "\"<b>#{c}</b>\""
666
- else
703
+ else
667
704
  cond << "<br>&nbsp;&nbsp;&nbsp;<b>#{i})</b>&nbsp;"
668
705
  if c.is_a?(Array)
669
706
  cond << "["
670
707
  cond << (c.collect{|v| "\"#{v.strip}\""}.join(", "))
671
708
  cond << "]"
672
- elsif c.is_a?(Date)
709
+ elsif c.is_a?(Date)
673
710
  cond << "\"#{c.strftime("%Y-%m-%d")}\""
674
- elsif c.is_a?(Time)
711
+ elsif c.is_a?(Time)
675
712
  cond << "\"#{c.strftime("%Y-%m-%d %H:%M:%S")}\""
676
- elsif c.is_a?(Integer)
713
+ elsif c.is_a?(Integer)
677
714
  cond << c.to_s
678
- else
715
+ else
679
716
  cond << "\"#{c}\""
680
717
  end
681
718
  end
682
-
719
+
683
720
  all_conditions << cond
684
721
  end
685
722
  all_conditions.join("")
686
723
  end
687
-
724
+
688
725
  def debug_sql_conditions
689
726
  debug_conditions(sql_conditions)
690
727
  end
691
-
728
+
692
729
  #############################################################################
693
- # Saved Filters
730
+ # Saved Filters
694
731
  #############################################################################
695
732
  def user_filters
696
733
  @user_filters ||= begin
697
- conditions = ["model_class_name = ?", self.model_class_name]
734
+ conditions = ['model_class_name = ?', self.model_class_name]
698
735
 
699
736
  if WillFilter::Config.user_filters_enabled?
700
- conditions[0] << " and user_id = ? "
737
+ conditions[0] << ' and user_id = ? '
701
738
  if WillFilter::Config.current_user and WillFilter::Config.current_user.id
702
739
  conditions << WillFilter::Config.current_user.id
703
740
  else
704
- conditions << "0"
741
+ conditions << '0'
705
742
  end
706
743
  end
707
-
708
- WillFilter::Filter.find(:all, :conditions => conditions)
709
- end
710
- end
711
744
 
712
- def saved_filters(include_default = true)
713
- @saved_filters ||= begin
714
- filters = []
715
-
716
- if include_default
717
- filters = default_filters
718
- if (filters.size > 0)
719
- filters.insert(0, ["-- Select Default Filter --", "-1"])
720
- end
721
- end
722
-
723
- if user_filters.any?
724
- filters << ["-- Select Saved Filter --", "-2"] if include_default
725
- user_filters.each do |filter|
726
- filters << [filter.name, filter.id.to_s]
745
+ if WillFilter::Config.project_filters_enabled?
746
+ conditions[0] << ' and project_id = ? '
747
+ if WillFilter::Config.current_project and WillFilter::Config.current_project.id
748
+ conditions << WillFilter::Config.current_project.id
749
+ else
750
+ conditions << '0'
727
751
  end
728
752
  end
729
-
730
- filters
753
+
754
+ WillFilter::Filter.where(conditions)
755
+ end
756
+ end
757
+
758
+ def filter_options
759
+ filters = [['', [['', '']]]]
760
+
761
+ if default_filters.any?
762
+ filters << ['Pre-defined Filters', default_filters]
731
763
  end
764
+
765
+ if saved_filters.any?
766
+ filters << ['Saved Filters', saved_filters]
767
+ end
768
+
769
+ filters
770
+ end
771
+
772
+ def saved_filters(include_default = true)
773
+ @saved_filters ||= user_filters.collect{|f| [f.name, f.id.to_s]}
732
774
  end
733
775
 
734
776
  #############################################################################
@@ -737,53 +779,53 @@ module WillFilter
737
779
  def default_filter_if_empty
738
780
  nil
739
781
  end
740
-
782
+
741
783
  def handle_empty_filter!
742
784
  return unless empty?
743
785
  return if default_filter_if_empty.nil?
744
786
  load_filter!(default_filter_if_empty)
745
787
  end
746
-
788
+
747
789
  def default_filters
748
790
  []
749
791
  end
750
-
792
+
751
793
  def default_filter_conditions(key)
752
794
  []
753
795
  end
754
-
796
+
755
797
  def load_default_filter(key)
756
798
  default_conditions = default_filter_conditions(key)
757
799
  return if default_conditions.nil? or default_conditions.empty?
758
-
800
+
759
801
  unless default_conditions.first.is_a?(Array)
760
802
  add_condition(*default_conditions)
761
803
  return
762
804
  end
763
-
805
+
764
806
  default_conditions.each do |default_condition|
765
807
  add_condition(*default_condition)
766
808
  end
767
809
  end
768
-
810
+
769
811
  def reset!
770
812
  remove_all
771
813
  @sql_conditions = nil
772
814
  @results = nil
773
815
  end
774
-
816
+
775
817
  def load_filter!(key_or_id)
776
818
  reset!
777
819
  @key = key_or_id.to_s
778
-
820
+
779
821
  load_default_filter(key)
780
822
  return self unless empty?
781
-
823
+
782
824
  filter = WillFilter::Filter.find_by_id(key_or_id.to_i)
783
825
  raise WillFilter::FilterException.new("Invalid filter key #{key_or_id.to_s}") if filter.nil?
784
826
  filter
785
827
  end
786
-
828
+
787
829
  #############################################################################
788
830
  # Export Filter Data
789
831
  #############################################################################
@@ -801,18 +843,18 @@ module WillFilter
801
843
  end
802
844
  formats
803
845
  end
804
-
846
+
805
847
  def custom_format?
806
848
  custom_formats.each do |frmt|
807
849
  return true if frmt[1].to_sym == format
808
850
  end
809
851
  false
810
852
  end
811
-
853
+
812
854
  def custom_formats
813
855
  []
814
856
  end
815
-
857
+
816
858
  def process_custom_format
817
859
  ""
818
860
  end
@@ -820,11 +862,11 @@ module WillFilter
820
862
  def association_name(inner_join)
821
863
  (inner_join.is_a?(Array) ? inner_join.first : inner_join).to_sym
822
864
  end
823
-
865
+
824
866
  def association_class(inner_join)
825
867
  model_class.new.association(association_name(inner_join)).build.class
826
- end
827
-
868
+ end
869
+
828
870
  # deprecated for Rails 3.0 and up
829
871
  def joins
830
872
  return nil if inner_joins.empty?
@@ -860,27 +902,33 @@ module WillFilter
860
902
  filtered = []
861
903
  objects.each do |obj|
862
904
  condition_flags = []
863
-
905
+
864
906
  0.upto(size - 1) do |index|
865
907
  condition = condition_at(index)
866
908
  next unless custom_condition?(condition)
867
909
  condition_flags << custom_condition_met?(condition, obj)
868
910
  end
869
-
911
+
870
912
  if condition_flags.size > 0
871
913
  next if match.to_s == "all" and condition_flags.include?(false)
872
- next unless condition_flags.include?(true)
873
- end
874
-
875
- filtered << obj
914
+ next unless condition_flags.include?(true)
915
+ end
916
+
917
+ filtered << obj
876
918
  end
877
919
  filtered
878
920
  end
879
921
 
880
922
  def results
881
923
  @results ||= begin
882
- handle_empty_filter!
883
- recs = model_class.where(sql_conditions).order(order_clause)
924
+ handle_empty_filter!
925
+
926
+ if sql_conditions and !sql_conditions[0].blank?
927
+ recs = model_class.where(sql_conditions).order(order_clause)
928
+ else
929
+ recs = model_class.order(order_clause)
930
+ end
931
+
884
932
  inner_joins.each do |inner_join|
885
933
  recs = recs.joins(association_name(inner_join))
886
934
  end
@@ -888,14 +936,17 @@ module WillFilter
888
936
  if custom_conditions?
889
937
  recs = process_custom_conditions(recs.all)
890
938
  recs = Kaminari.paginate_array(recs)
891
- end
939
+ end
940
+
892
941
 
893
942
  recs = recs.page(page).per(per_page)
943
+
894
944
  recs.wf_filter = self
945
+
895
946
  recs
896
947
  end
897
948
  end
898
-
949
+
899
950
  # sums up the column for the given conditions
900
951
  def sum(column_name)
901
952
  model_class.sum(column_name, :conditions => sql_conditions)
@@ -918,4 +969,4 @@ module WillFilter
918
969
  end
919
970
 
920
971
  end
921
- end
972
+ end