will_filter 3.1.11 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
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