clark_kent 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/clark_kent/application.js +18291 -0
  3. data/app/assets/stylesheets/clark_kent/application.css +21 -0
  4. data/app/controllers/clark_kent/report_columns_controller.rb +6 -3
  5. data/app/controllers/clark_kent/report_emails_controller.rb +7 -3
  6. data/app/controllers/clark_kent/report_filters_controller.rb +12 -4
  7. data/app/controllers/clark_kent/reports_controller.rb +21 -8
  8. data/app/controllers/clark_kent/user_report_emails_controller.rb +7 -3
  9. data/app/models/clark_kent/cloneable.rb +18 -0
  10. data/app/models/clark_kent/date_filter_option.rb +7 -0
  11. data/app/models/clark_kent/number_filter_option.rb +7 -0
  12. data/app/models/clark_kent/object_filter_option.rb +7 -0
  13. data/app/models/clark_kent/report.rb +49 -6
  14. data/app/models/clark_kent/report_column.rb +31 -4
  15. data/app/models/clark_kent/report_config.rb +24 -0
  16. data/app/models/clark_kent/report_date_filter.rb +0 -2
  17. data/app/models/clark_kent/report_email.rb +1 -2
  18. data/app/models/clark_kent/report_filter.rb +1 -2
  19. data/app/models/clark_kent/report_filter_error.rb +4 -0
  20. data/app/models/clark_kent/report_filter_option.rb +5 -9
  21. data/app/models/clark_kent/report_number_filter.rb +0 -3
  22. data/app/models/clark_kent/reportable.rb +28 -3
  23. data/app/models/clark_kent/resource_option.rb +10 -0
  24. data/app/models/clark_kent/sharing_scope_kind.rb +38 -4
  25. data/app/models/clark_kent/string_filter_option.rb +7 -0
  26. data/app/models/clark_kent/user_report_email.rb +2 -4
  27. data/app/views/clark_kent/report_columns/_form.html.erb +1 -1
  28. data/app/views/clark_kent/reports/_edit.html.erb +8 -4
  29. data/app/views/clark_kent/reports/show.html.erb +5 -0
  30. data/db/migrate/20131226170042_create_clark_kent_report_filter.rb +17 -0
  31. data/db/migrate/20131226170112_create_clark_kent_report_column.rb +12 -0
  32. data/db/migrate/20140114010048_create_clark_kent_report_emails.rb +9 -0
  33. data/db/migrate/20140129051754_create_clark_kent_user_report_email.rb +7 -0
  34. data/db/migrate/20150304233739_create_clark_kent_reports.rb +2 -0
  35. data/lib/clark_kent/version.rb +1 -1
  36. data/lib/clark_kent.rb +4 -2
  37. data/test/_print_report.html.erb_spec.rb +32 -0
  38. data/test/controllers/clark_kent/reports_controller_test.rb +35 -12
  39. data/test/dummy/app/controllers/application_controller.rb +12 -0
  40. data/test/dummy/app/models/department.rb +4 -0
  41. data/test/dummy/app/models/order.rb +6 -0
  42. data/test/dummy/app/models/reporting/order.rb +54 -0
  43. data/test/dummy/app/models/user.rb +9 -0
  44. data/test/dummy/app/views/layouts/application.html.erb +5 -2
  45. data/test/dummy/config/initializers/zz_clark_kent.rb +11 -0
  46. data/test/dummy/config/routes.rb +1 -1
  47. data/test/dummy/db/development.sqlite3 +0 -0
  48. data/test/dummy/db/migrate/20150309232850_create_orders.rb +10 -0
  49. data/test/dummy/db/migrate/20150309232855_create_users.rb +9 -0
  50. data/test/dummy/db/migrate/20150310143940_create_departments.rb +8 -0
  51. data/test/dummy/db/migrate/20150313144011_create_clark_kent_report_filter.clark_kent.rb +18 -0
  52. data/test/dummy/db/migrate/20150313144012_create_clark_kent_report_column.clark_kent.rb +13 -0
  53. data/test/dummy/db/migrate/20150313144013_create_clark_kent_report_emails.clark_kent.rb +10 -0
  54. data/test/dummy/db/migrate/20150313144014_create_clark_kent_user_report_email.clark_kent.rb +8 -0
  55. data/test/dummy/db/migrate/20150313144015_create_clark_kent_reports.clark_kent.rb +15 -0
  56. data/test/dummy/db/schema.rb +61 -1
  57. data/test/dummy/db/test.sqlite3 +0 -0
  58. data/test/dummy/log/development.log +18038 -0
  59. data/test/dummy/log/test.log +14137 -0
  60. data/test/dummy/tmp/cache/assets/development/sprockets/0a5b3da98f8307d16bc302a1f7206591 +0 -0
  61. data/test/dummy/tmp/cache/assets/development/sprockets/0a9995208f1340e4b34008cbd5b73c64 +0 -0
  62. data/test/dummy/tmp/cache/assets/development/sprockets/0ec37c0a58c1be93659732a3efc73581 +0 -0
  63. data/test/dummy/tmp/cache/assets/development/sprockets/0fd54fd98cd2fa0085b77e6743046927 +0 -0
  64. data/test/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  65. data/test/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  66. data/test/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  67. data/test/dummy/tmp/cache/assets/development/sprockets/8aa37926d964a9eb59cf9b940e4fe2f4 +0 -0
  68. data/test/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  69. data/test/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  70. data/test/dummy/tmp/cache/assets/development/sprockets/ebe8eac74b8e6016fd44b19e6e708e61 +0 -0
  71. data/test/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  72. data/test/dummy/tmp/cache/assets/test/sprockets/0a5b3da98f8307d16bc302a1f7206591 +0 -0
  73. data/test/dummy/tmp/cache/assets/test/sprockets/0a9995208f1340e4b34008cbd5b73c64 +0 -0
  74. data/test/dummy/tmp/cache/assets/test/sprockets/0ec37c0a58c1be93659732a3efc73581 +0 -0
  75. data/test/dummy/tmp/cache/assets/test/sprockets/0fd54fd98cd2fa0085b77e6743046927 +0 -0
  76. data/test/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  77. data/test/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  78. data/test/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  79. data/test/dummy/tmp/cache/assets/test/sprockets/60fb63be4cad769d9adc90c4c5501c67 +0 -0
  80. data/test/dummy/tmp/cache/assets/test/sprockets/8aa37926d964a9eb59cf9b940e4fe2f4 +0 -0
  81. data/test/dummy/tmp/cache/assets/test/sprockets/92058832b745b88c29a75bf2aad7245d +0 -0
  82. data/test/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  83. data/test/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  84. data/test/dummy/tmp/cache/assets/test/sprockets/ebe8eac74b8e6016fd44b19e6e708e61 +0 -0
  85. data/test/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  86. data/test/dummy/tmp/pids/server.pid +1 -0
  87. data/test/helpers/clark_kent/reports_helper_spec.rb +26 -0
  88. data/test/integration/navigation_test.rb +0 -2
  89. data/test/models/clark_kent/report_test.rb +6 -6
  90. data/test/support/db_utils.rb +29 -0
  91. data/test/test_helper.rb +7 -6
  92. metadata +148 -3
  93. data/app/assets/javascripts/clark_kent/reports.js +0 -10
@@ -0,0 +1,18 @@
1
+ module ClarkKent
2
+ module Cloneable
3
+ def cloneable_attributes
4
+ these_attrs = self.attributes.dup
5
+ these_attrs.delete('id')
6
+ these_attrs.delete('created_at')
7
+ these_attrs.delete('updated_at')
8
+ these_attrs
9
+ end
10
+
11
+ def reset_timestamps
12
+ updated_at = nil
13
+ created_at = nil
14
+ self
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ module ClarkKent
2
+ class DateFilterOption < ReportFilterOption
3
+ def filter_params
4
+ [param + '_from', param + '_until']
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module ClarkKent
2
+ class NumberFilterOption < ReportFilterOption
3
+ def filter_params
4
+ [param]
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module ClarkKent
2
+ class ObjectFilterOption < ReportFilterOption
3
+ def filter_params
4
+ [param]
5
+ end
6
+ end
7
+ end
@@ -2,12 +2,10 @@ module ClarkKent
2
2
  # load the builders
3
3
  Dir.glob(Rails.root.join('app/models/reporting/*.rb')) { |file| load file }
4
4
  class Report < ActiveRecord::Base
5
-
6
- include Cloneable
5
+ include ClarkKent::Cloneable
7
6
 
8
7
  SortDirections = {'A->Z' => 'asc', 'Z->A' => 'desc'}
9
8
 
10
- attr_accessible :resource_type, :name, :sharing_scope_id, :sharing_scope_type
11
9
  attr_accessor :summary_row_storage
12
10
 
13
11
  belongs_to :sharing_scope, polymorphic: true
@@ -80,6 +78,27 @@ module ClarkKent
80
78
  @resource_class ||= self.resource_type.constantize
81
79
  end
82
80
 
81
+ ## This ephemeral class allows us to create a row object that has the same attributes as the AR response
82
+ ## to the query, including all the custom columns defined in the resource class report config.
83
+ ## currently only used for the summary row, since we can't get that in the same AR query and have to
84
+ ## add it to the collection after the query returns.
85
+ def row_class
86
+ report_columns = self.report_columns
87
+ @row_class ||= Class.new do
88
+ report_columns.each do |report_column|
89
+ attr_accessor report_column.column_name.to_sym
90
+ end
91
+
92
+ def initialize params = {}
93
+ params.each { |key, value| send "#{key}=", value }
94
+ end
95
+
96
+ def [](key)
97
+ self.send key
98
+ end
99
+ end
100
+ end
101
+
83
102
  def sort_column
84
103
  @sort_column ||= self.report_columns.where("clark_kent_report_columns.report_sort is not NULL and clark_kent_report_columns.report_sort != ''").first
85
104
  end
@@ -88,7 +107,7 @@ module ClarkKent
88
107
  if self.sort_column
89
108
  sort_column_name = self.sort_column.column_name
90
109
  sort_direction = Report::SortDirections[sort_column.report_sort]
91
- Map.new(order_column: sort_column_name, order_direction: sort_direction)
110
+ ReportSort.new(order_column: sort_column_name, order_direction: sort_direction)
92
111
  end
93
112
  end
94
113
 
@@ -127,6 +146,9 @@ module ClarkKent
127
146
  }.flatten.compact
128
147
  end
129
148
 
149
+ ## These are the built-in filter params that define this report. They are merged at a later
150
+ ## step with the runtime params entered by the user for a specific report run.
151
+ ## nb. the sorter column here may be overridden by a runtime sort if requested by the user.
130
152
  def report_filter_params
131
153
  Hash[*self.report_filters.map{|filter| filter.filter_match_params}.flatten].
132
154
  merge(order: self.sorter)
@@ -169,6 +191,8 @@ module ClarkKent
169
191
  self.resource_class::REPORT_FILTER_OPTIONS.select{|filter| 'date_filter' == filter.kind}.map{|filter| filter.param}
170
192
  end
171
193
 
194
+ ## These are the filters available for defining a report for this resource. They do not include date
195
+ ## filters as those only make sense at runtime, or in an auto-generated, timed emailed report.
172
196
  def available_filters
173
197
  self.available_email_filters.reject{|name| self.date_filter_names.include? name}
174
198
  end
@@ -177,6 +201,8 @@ module ClarkKent
177
201
  self.available_filters.map{|id| [self.filter_options_for(id).label,id]}
178
202
  end
179
203
 
204
+ ## This is the full set of filter options for defining a report, including the date filters for
205
+ ## an automatic, timed, emailed report.
180
206
  def available_email_filters
181
207
  self.resource_class::REPORT_DEFINITION_OPTIONS.reject{|name| (self.report_filters.pluck(:filter_name)).include? name}
182
208
  end
@@ -185,10 +211,14 @@ module ClarkKent
185
211
  self.resource_class::REPORT_FILTER_OPTIONS.detect{|filter| filter.param == filter_name}.collection
186
212
  end
187
213
 
214
+ ## These are the filters available at runtime, ie. not including the ones set to define this report.
215
+ ## If updating the report, this is the set available to add as new report definition filters.
188
216
  def custom_filters
189
217
  self.resource_class::REPORT_FILTER_OPTIONS.select{|filter| self.report_filters.pluck(:filter_name).exclude? filter.param}
190
218
  end
191
219
 
220
+ ## This is the set of columns not chosed to use in the report. These are the ones available to add
221
+ ## when updating a report.
192
222
  def available_columns
193
223
  self.resource_class::REPORT_COLUMN_OPTIONS.keys.reject{|column| self.report_columns.pluck(:column_name).include? column.to_s}
194
224
  end
@@ -202,7 +232,11 @@ module ClarkKent
202
232
  end
203
233
 
204
234
  def resource_type_pretty
205
- self.resource_class.prettify_name.pluralize
235
+ if self.resource_class.respond_to? :prettify_name
236
+ self.resource_class.prettify_name.pluralize
237
+ else
238
+ self.resource_class.name.humanize
239
+ end
206
240
  end
207
241
 
208
242
  def get_filter_class(params)
@@ -220,7 +254,7 @@ module ClarkKent
220
254
  row_array = self.report_columns.map do |report_column|
221
255
  [report_column.column_name,report_column.calculate_summary(rows.map{|row| row.send(report_column.column_name)})]
222
256
  end
223
- Map.new(row_array.to_h)
257
+ row_class.new(row_array.to_h)
224
258
  end
225
259
 
226
260
  def summary_row?
@@ -269,4 +303,13 @@ module ClarkKent
269
303
  end
270
304
 
271
305
  end
306
+
307
+ class ReportSort
308
+ attr_accessor :order_column, :order_direction
309
+
310
+ def initialize params = {}
311
+ params.each { |key, value| send "#{key}=", value }
312
+ end
313
+ end
314
+
272
315
  end
@@ -1,9 +1,9 @@
1
1
  module ClarkKent
2
2
  class ReportColumn < ActiveRecord::Base
3
- include Cloneable
3
+ include ClarkKent::Cloneable
4
4
 
5
5
  SummaryMethods = ['total','average']
6
- attr_accessible :report_id, :column_name, :column_order, :report_sort, :summary_method
6
+
7
7
  belongs_to :report
8
8
 
9
9
  scope :sorted, -> { order("clark_kent_report_columns.column_order") }
@@ -14,11 +14,38 @@ module ClarkKent
14
14
 
15
15
  def calculate_summary(values)
16
16
  return nil unless self.summary_method.present?
17
- values.send self.summary_method
17
+ calculator.new(values).calculate
18
18
  end
19
19
 
20
20
  def summarizable?
21
- report.column_options_for(self.column_name).respond_to? :summarizable
21
+ report.column_options_for(self.column_name).summarizable
22
+ end
23
+
24
+ def calculator
25
+ ('ClarkKent::' + summary_method.camelcase + 'Calculator').constantize
22
26
  end
27
+
28
+ end
29
+
30
+ class AbstractCalculator
31
+ def initialize values
32
+ @values = values
33
+ end
34
+ end
35
+
36
+ class TotalCalculator < AbstractCalculator
37
+ def calculate
38
+ @values.sum
39
+ end
40
+ end
41
+
42
+ class AverageCalculator < AbstractCalculator
43
+ def calculate
44
+ if @values.length < 1
45
+ return nil
46
+ else
47
+ return (@values.sum.to_f / @values.length)
48
+ end
49
+ end
23
50
  end
24
51
  end
@@ -0,0 +1,24 @@
1
+ module ClarkKent
2
+ module ReportConfig
3
+ module ClassMethods
4
+ def filter_config(params)
5
+ filter_option_class = ('ClarkKent::' + ((params[:kind] + '_option').camelcase)).constantize
6
+ filter_option_class.new(params)
7
+ end
8
+
9
+ def column_config(params)
10
+ ClarkKent::ReportColumnConfig.new(params)
11
+ end
12
+ end
13
+ extend ClassMethods
14
+ def self.included( other )
15
+ other.extend( ClassMethods )
16
+ end
17
+ end
18
+ class ReportColumnConfig
19
+ attr_accessor :custom_select, :order_sql, :summarizable
20
+ def initialize params = {}
21
+ params.each { |key, value| send "#{key}=", value }
22
+ end
23
+ end
24
+ end
@@ -20,8 +20,6 @@ module ClarkKent
20
20
 
21
21
  before_save :handle_filter_value
22
22
 
23
- attr_accessible :kind_of_day, :offset, :duration
24
-
25
23
  def filter_match_params
26
24
  [[self.begin_param_name,self.begin_date],[self.end_param_name,self.end_date]]
27
25
  end
@@ -1,6 +1,6 @@
1
1
  module ClarkKent
2
2
  class ReportEmail < ActiveRecord::Base
3
- include Cloneable
3
+ include ClarkKent::Cloneable
4
4
 
5
5
  SEND_TIMES = {
6
6
  'Mondays' => 'Monday',
@@ -19,7 +19,6 @@ module ClarkKent
19
19
  has_many :user_report_emails, dependent: :destroy
20
20
  has_many :users, through: :user_report_emails
21
21
 
22
- attr_accessible :report_id, :when_to_send, :name
23
22
 
24
23
  def self.send_emails_for_today
25
24
  today = Date.ih_today
@@ -1,9 +1,8 @@
1
1
  module ClarkKent
2
2
  class ReportFilter < ActiveRecord::Base
3
- include Cloneable
3
+ include ClarkKent::Cloneable
4
4
 
5
5
  attr_accessor :filter_value_1, :filter_value_2
6
- attr_accessible :filter_value_1, :filter_value_2, :report_id, :filter_name, :filter_value, :filterable_id, :filterable_type, :type
7
6
  belongs_to :filterable, polymorphic: true
8
7
 
9
8
  def filter_match_params
@@ -0,0 +1,4 @@
1
+ module ClarkKent
2
+ class ReportFilterError < StandardError
3
+ end
4
+ end
@@ -1,15 +1,11 @@
1
1
  module ClarkKent
2
2
  class ReportFilterOption
3
- include Cloneable
4
3
 
5
- attr_accessor :param, :label, :collection, :kind, :select
6
- def initialize(params)
7
- self.param = params[:param] if params[:param].present?
8
- self.label = params[:label] if params[:label].present?
9
- self.collection = params[:collection] if params[:collection].present?
10
- self.kind = params[:kind] if params[:kind].present?
11
- self.select = params[:select] if params[:select].present?
12
- end
4
+ attr_accessor :param, :label, :collection, :kind, :select, :in_required_date_group
5
+
6
+ def initialize params = {}
7
+ params.each { |key, value| send "#{key}=", value }
8
+ end
13
9
 
14
10
  def label
15
11
  @label || @param
@@ -1,8 +1,5 @@
1
1
  module ClarkKent
2
2
  class ReportNumberFilter < ReportFilter
3
- include Cloneable
4
-
5
- attr_accessible :max_value, :min_value
6
3
 
7
4
  def filter_match_params
8
5
  [[self.min_param_name,self.min_value],[self.max_param_name,self.max_value]]
@@ -15,7 +15,22 @@ module ClarkKent
15
15
  query
16
16
  end
17
17
 
18
+ def required_date_params
19
+ self::REPORT_FILTER_OPTIONS.select{|rfo| rfo.in_required_date_group}.map{|rfo| rfo.filter_params}.flatten
20
+ end
21
+
22
+ def validate_params(params,report)
23
+ if required_date_params.any?
24
+ missing_params = required_date_params - params.select{|k,v| v.present? }.keys
25
+ # a bit clunky, it only requires any 2 date filters. It would be better to require at least one pair of before/after filters
26
+ if missing_params.length > (required_date_params.length - 2)
27
+ raise ClarkKent::ReportFilterError.new("At least one date range is required.")
28
+ end
29
+ end
30
+ end
31
+
18
32
  def report(params,report,count = false)
33
+ validate_params(params, report)
19
34
  @selects = []
20
35
  @includes = []
21
36
  @joins = []
@@ -48,9 +63,9 @@ module ClarkKent
48
63
  end
49
64
  query = self.all
50
65
  if @report_email and @report_email.is_a? ClarkKent::ReportEmail
51
- params = @report_email.report_filter_params.symbolize_keys!.merge(params)
66
+ params = @report_email.report_filter_params.symbolize_keys!.merge(params.symbolize_keys)
52
67
  else
53
- params = report.report_filter_params.symbolize_keys!.merge(params)
68
+ params = report.report_filter_params.symbolize_keys!.merge(params.symbolize_keys)
54
69
  end
55
70
  params.each do |param_type,param_value|
56
71
  if param_value.present?
@@ -121,8 +136,18 @@ module ClarkKent
121
136
  where("#{self.table_name}.#{field_name.to_s.sub(/_from/,'')} >= :date_limit", date_limit: match_value)
122
137
  end
123
138
 
139
+ def above_number_arel(query, field_name, match_value)
140
+ query.
141
+ where("#{self.table_name}.#{field_name.to_s.sub(/_above/,'')} >= :lower_limit", lower_limit: match_value)
142
+ end
143
+
144
+ def below_number_arel(query, field_name, match_value)
145
+ query.
146
+ where("#{self.table_name}.#{field_name.to_s.sub(/_below/,'')} <= :upper_limit", upper_limit: match_value)
147
+ end
148
+
124
149
  def order_arel(query, field_name, match_value)
125
- if match_value.is_a? Map
150
+ if match_value.is_a? ClarkKent::ReportSort
126
151
  order_column = match_value.order_column
127
152
  order_direction = match_value.order_direction
128
153
  else
@@ -0,0 +1,10 @@
1
+ module ClarkKent
2
+ class ResourceOption
3
+ attr_accessor :id, :name
4
+
5
+ def initialize params = {}
6
+ params.each { |key, value| send "#{key}=", value }
7
+ end
8
+
9
+ end
10
+ end
@@ -17,19 +17,45 @@ module ClarkKent
17
17
  self.all.detect{|ssk| klass_name == ssk.class_name}
18
18
  end
19
19
 
20
+ def self.has_some(thing)
21
+ if thing.present?
22
+ if thing.respond_to? :any?
23
+ thing.any?
24
+ else
25
+ true
26
+ end
27
+ else
28
+ false
29
+ end
30
+ end
31
+
20
32
  def self.custom
21
33
  all.select{|ssk| ['everyone',ClarkKent.user_class_name.underscore].exclude? ssk.type}
22
34
  end
23
35
 
36
+ def self.custom_for_user(user)
37
+ custom.select{|ssk| has_some(ssk.associated_containers_for(user)) }
38
+ end
39
+
24
40
  def self.select_options
25
41
  return @sharing_scope_options if @sharing_scope_options
26
42
  @sharing_scope_options = {}
27
- self.all.each do |sharing_scope|
28
- @sharing_scope_options[sharing_scope.human_name] = sharing_scope.class_name
43
+ self.all.each do |sharing_scope_kind|
44
+ @sharing_scope_options[sharing_scope_kind.human_name] = sharing_scope_kind.class_name
29
45
  end
30
46
  @sharing_scope_options
31
47
  end
32
48
 
49
+ def self.select_options_for_user(user)
50
+ sharing_scope_options = {}
51
+ self.all.each do |sharing_scope_kind|
52
+ if custom.exclude?(sharing_scope_kind) || has_some(sharing_scope_kind.associated_containers_for(user))
53
+ sharing_scope_options[sharing_scope_kind.human_name] = sharing_scope_kind.class_name
54
+ end
55
+ end
56
+ sharing_scope_options
57
+ end
58
+
33
59
  def initialize(class_name,user_association = nil)
34
60
  if 'Everyone' == class_name
35
61
  @class_name = ''
@@ -63,8 +89,16 @@ module ClarkKent
63
89
  when ClarkKent.user_class_name.underscore
64
90
  [ClarkKent::SharingScope.new(user,self)]
65
91
  else
66
- associated_containers_for(user).map do |associated_container|
67
- ClarkKent::SharingScope.new(associated_container,self)
92
+ if associated_containers_for(user).respond_to? :map
93
+ associated_containers_for(user).map do |associated_container|
94
+ ClarkKent::SharingScope.new(associated_container,self)
95
+ end
96
+ else
97
+ if associated_containers_for(user).present?
98
+ [ClarkKent::SharingScope.new(associated_containers_for(user),self)]
99
+ else
100
+ []
101
+ end
68
102
  end
69
103
  end
70
104
  end
@@ -0,0 +1,7 @@
1
+ module ClarkKent
2
+ class StringFilterOption < ReportFilterOption
3
+ def filter_params
4
+ [param]
5
+ end
6
+ end
7
+ end
@@ -1,14 +1,12 @@
1
1
  module ClarkKent
2
2
  class UserReportEmail < ActiveRecord::Base
3
- belongs_to :user
3
+ belongs_to :user, class_name: ClarkKent.user_class_name
4
4
  belongs_to :report_email
5
5
 
6
- attr_accessible :email, :report_email_id
7
-
8
6
  validates_with UserEmailValidator
9
7
 
10
8
  def email=(address)
11
- self.user = User.where("lower(users.email) = lower(:email)",email: address).first
9
+ self.user = ClarkKent.user_class.where("lower(#{ClarkKent.user_class_name.underscore.pluralize}.email) = lower(:email)",email: address).first
12
10
  self.errors.add(:email, "Couldn't find a user with that email addres") unless self.user.present?
13
11
  end
14
12
 
@@ -27,7 +27,7 @@
27
27
  </div>
28
28
  <div class="ih-span one-fifth">
29
29
  <% if !report_column.new_record? and report_column.summarizable? %>
30
- <%= f.input :summary_method, collection: ReportColumn::SummaryMethods %>
30
+ <%= f.input :summary_method, collection: ClarkKent::ReportColumn::SummaryMethods %>
31
31
  <% else %>
32
32
  &nbsp;
33
33
  <% end %>
@@ -16,15 +16,19 @@
16
16
  <div class="ih-span one-quarter">
17
17
  <div class="ih-row">sharing</div>
18
18
  <div class="ih-row">
19
- <%= f.input :sharing_scope_type, collection: ClarkKent::SharingScopeKind.select_options,
19
+ <%= f.input :sharing_scope_type, collection: ClarkKent::SharingScopeKind.select_options_for_user(current_user),
20
20
  input_html: {data: {revealer: true, sub_type: "FormFieldRevealer", revealer_children_id: "sharing_options"}},
21
21
  label: false, include_blank: false %>
22
22
  </div>
23
23
  <div class="ih-row" data-revealer-target="sharing_options">
24
24
  <%= f.input :sharing_scope_id, as: :hidden, input_html: {value: current_user.id}, wrapper_html: {'data-revealer_id' => "sharing_options", 'data-revealer-trigger' => ClarkKent.user_class_name, id: "sharing_options_#{ClarkKent.user_class_name}"} %>
25
- <% ClarkKent::SharingScopeKind.custom.each do |sharing_scope_kind| %>
26
- <%= f.input :sharing_scope_id, collection: sharing_scope_kind.associated_containers_for(current_user), label: false, include_blank: false,
27
- wrapper_html: {'data-revealer_id' => "sharing_options", 'data-revealer-trigger' => sharing_scope_kind.class_name, id: "sharing_options_#{sharing_scope_kind.class_name}"} %>
25
+ <% ClarkKent::SharingScopeKind.custom_for_user(current_user).each do |sharing_scope_kind| %>
26
+ <% if sharing_scope_kind.associated_containers_for(current_user).respond_to? :each %>
27
+ <%= f.input :sharing_scope_id, collection: sharing_scope_kind.associated_containers_for(current_user), label: false, include_blank: false,
28
+ wrapper_html: {'data-revealer_id' => "sharing_options", 'data-revealer-trigger' => sharing_scope_kind.class_name, id: "sharing_options_#{sharing_scope_kind.class_name}"} %>
29
+ <% else %>
30
+ <%= f.input :sharing_scope_id, as: :hidden, input_html: {value: sharing_scope_kind.associated_containers_for(current_user).id}, wrapper_html: {'data-revealer_id' => "sharing_options", 'data-revealer-trigger' => sharing_scope_kind.associated_containers_for(current_user).class.name, id: "sharing_options_#{sharing_scope_kind.associated_containers_for(current_user).class.name}"} %>
31
+ <% end %>
28
32
  <% end %>
29
33
  <%= f.input :sharing_scope_id, as: :hidden, input_html: {value: ''},
30
34
  wrapper_html: {'data-revealer_id' => "sharing_options", 'data-revealer-trigger' => "", id: "sharing_options_"} %>
@@ -1,6 +1,11 @@
1
1
  <h1><%= @report.name %></h1>
2
2
  <%= link_to "&larr; back to report index".html_safe, reports_url, id: 'report_index' %>
3
3
 
4
+ <% if @errors %>
5
+ <div class="error">
6
+ <%= @errors %>
7
+ </div>
8
+ <% end %>
4
9
  <div class="ih-row margin-top">
5
10
  <form action="<%= report_url(@report) %>" method="get">
6
11
  <% @report.custom_filters.each do |filter| %>
@@ -0,0 +1,17 @@
1
+ class CreateClarkKentReportFilter < ActiveRecord::Migration
2
+ def change
3
+ create_table :clark_kent_report_filters do |t|
4
+ t.integer :filterable_id
5
+ t.string :filterable_type, :string, default: 'ClarkKent::Report'
6
+ t.string :filter_name
7
+ t.string :filter_value
8
+ t.string :type
9
+ t.string :duration
10
+ t.string :kind_of_day
11
+ t.string :offset
12
+ t.timestamps
13
+ end
14
+ add_index :clark_kent_report_filters, :filterable_id
15
+ add_index :clark_kent_report_filters, :filterable_type
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ class CreateClarkKentReportColumn < ActiveRecord::Migration
2
+ def change
3
+ create_table :clark_kent_report_columns do |t|
4
+ t.integer :report_id
5
+ t.string :column_name
6
+ t.integer :column_order
7
+ t.string :report_sort
8
+ t.string :summary_method
9
+ end
10
+ add_index :clark_kent_report_columns, :report_id
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ class CreateClarkKentReportEmails < ActiveRecord::Migration
2
+ def change
3
+ create_table :clark_kent_report_emails do |t|
4
+ t.integer :report_id
5
+ t.string :when_to_send
6
+ t.string :name
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ class CreateClarkKentUserReportEmail < ActiveRecord::Migration
2
+ def change
3
+ create_table :clark_kent_user_report_emails do |t|
4
+ t.integer ClarkKent.user_class_name.underscore + '_id', :report_email_id
5
+ end
6
+ end
7
+ end
@@ -8,5 +8,7 @@ class CreateClarkKentReports < ActiveRecord::Migration
8
8
 
9
9
  t.timestamps
10
10
  end
11
+ add_index :clark_kent_reports, :sharing_scope_type
12
+ add_index :clark_kent_reports, :sharing_scope_id
11
13
  end
12
14
  end
@@ -1,3 +1,3 @@
1
1
  module ClarkKent
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/clark_kent.rb CHANGED
@@ -1,16 +1,18 @@
1
1
  require "clark_kent/engine"
2
+ require 'simple_form'
3
+ require 'thin_man'
2
4
 
3
5
  module ClarkKent
4
6
  mattr_accessor :resource_options, :user_class_name, :other_sharing_scopes, :base_controller,
5
7
  :custom_report_links
6
8
 
7
9
  def self.config(options)
8
- @@resource_options = options[:resource_options]
10
+ @@resource_options = options[:resource_options].map{|option_hash| ClarkKent::ResourceOption.new option_hash}
9
11
  @@user_class_name = options[:user_class_name]
10
12
  @@other_sharing_scopes = options[:other_sharing_scopes]
11
13
  base_controller_name = options[:base_controller_name]
12
14
  @@base_controller = base_controller_name.constantize
13
- @@custom_report_links = options[:custom_report_links]
15
+ @@custom_report_links = options[:custom_report_links] || []
14
16
  end
15
17
 
16
18
  def self.user_class
@@ -0,0 +1,32 @@
1
+ require "spec_helper"
2
+
3
+ describe "manage/reports/_print_report.html.erb" do
4
+ it "displays the print button with the modal" do
5
+ rows = nil
6
+
7
+ assign(:rows, rows)
8
+ render partial: "manage/reports/print_report", locals: { rows: rows }
9
+
10
+ expect(rendered).to eq("")
11
+ end
12
+
13
+ it "displays the print button with the modal" do
14
+ rows = mock()
15
+ rows.stubs(:count).returns(50)
16
+ rows.stubs(:total_count).returns(51)
17
+ assign(:rows, rows)
18
+ render partial: "manage/reports/print_report", locals: { rows: rows }
19
+
20
+ expect(rendered).to have_selector("div#print_report_modal")
21
+ end
22
+
23
+ it "displays just the print button" do
24
+ rows = mock()
25
+ rows.stubs(:count).returns(50)
26
+ rows.stubs(:total_count).returns(49)
27
+ assign(:rows, rows)
28
+ render partial: "manage/reports/print_report", locals: { rows: rows }
29
+
30
+ expect(rendered).not_to have_selector("div#print_report_modal")
31
+ end
32
+ end