message_train 0.6.17 → 0.7.1

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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +16 -13
  3. data/.rubocop_todo.yml +12 -0
  4. data/.ruby-version +1 -1
  5. data/.travis.yml +1 -1
  6. data/Gemfile +28 -30
  7. data/README.md +284 -0
  8. data/Rakefile +6 -7
  9. data/VERSION +1 -1
  10. data/app/assets/javascripts/ckeditor/{config.js.coffee → config.js} +7 -6
  11. data/app/assets/stylesheets/message_train.scss +0 -8
  12. data/app/controllers/concerns/message_train_authorization.rb +37 -0
  13. data/app/controllers/concerns/message_train_support.rb +41 -69
  14. data/app/controllers/message_train/application_controller.rb +1 -0
  15. data/app/controllers/message_train/boxes_controller.rb +5 -4
  16. data/app/controllers/message_train/conversations_controller.rb +7 -5
  17. data/app/controllers/message_train/messages_controller.rb +43 -27
  18. data/app/controllers/message_train/participants_controller.rb +14 -25
  19. data/app/controllers/message_train/unsubscribes_controller.rb +96 -61
  20. data/app/helpers/message_train/application_helper.rb +13 -7
  21. data/app/helpers/message_train/attachments_helper.rb +4 -12
  22. data/app/helpers/message_train/boxes_helper.rb +4 -14
  23. data/app/helpers/message_train/collectives_helper.rb +23 -29
  24. data/app/helpers/message_train/conversations_helper.rb +52 -30
  25. data/app/helpers/message_train/messages_helper.rb +33 -20
  26. data/app/mailers/message_train/receipt_mailer.rb +22 -12
  27. data/app/models/message_train/attachment.rb +2 -2
  28. data/app/models/message_train/box.rb +182 -228
  29. data/app/models/message_train/conversation.rb +100 -103
  30. data/app/models/message_train/ignore.rb +83 -4
  31. data/app/models/message_train/message.rb +66 -117
  32. data/app/models/message_train/receipt.rb +73 -49
  33. data/app/views/message_train/boxes/show.html.haml +11 -7
  34. data/config/locales/en.yml +1 -0
  35. data/config/routes.rb +6 -12
  36. data/lib/message_train.rb +3 -1
  37. data/lib/message_train/class_methods.rb +51 -0
  38. data/lib/message_train/configuration.rb +28 -3
  39. data/lib/message_train/instance_methods.rb +209 -0
  40. data/lib/message_train/mixin.rb +25 -320
  41. data/message_train.gemspec +83 -83
  42. data/spec/controllers/message_train/boxes_controller_spec.rb +37 -19
  43. data/spec/controllers/message_train/concerns_spec.rb +21 -3
  44. data/spec/controllers/message_train/conversations_controller_spec.rb +41 -18
  45. data/spec/controllers/message_train/messages_controller_spec.rb +112 -31
  46. data/spec/controllers/message_train/participants_controller_spec.rb +33 -7
  47. data/spec/controllers/message_train/unsubscribes_controller_spec.rb +10 -8
  48. data/spec/dummy/app/assets/stylesheets/{application.css.scss → application.scss} +2 -1
  49. data/spec/dummy/app/assets/stylesheets/bootstrap-everything.scss +54 -0
  50. data/spec/dummy/app/models/group.rb +1 -1
  51. data/spec/dummy/app/views/layouts/application.html.haml +9 -8
  52. data/spec/dummy/bin/setup +8 -8
  53. data/spec/dummy/config/application.rb +0 -3
  54. data/spec/dummy/config/environments/test.rb +4 -2
  55. data/spec/dummy/db/schema.rb +94 -103
  56. data/spec/dummy/db/test.sqlite3 +0 -0
  57. data/spec/factories/attachment.rb +3 -1
  58. data/spec/factories/message.rb +2 -3
  59. data/spec/features/boxes_spec.rb +0 -3
  60. data/spec/helpers/message_train/application_helper_spec.rb +3 -2
  61. data/spec/helpers/message_train/attachment_helper_spec.rb +4 -0
  62. data/spec/helpers/message_train/boxes_helper_spec.rb +1 -0
  63. data/spec/helpers/message_train/collectives_helper_spec.rb +1 -0
  64. data/spec/helpers/message_train/conversations_helper_spec.rb +3 -2
  65. data/spec/helpers/message_train/messages_helper_spec.rb +2 -1
  66. data/spec/models/group_spec.rb +6 -4
  67. data/spec/models/message_train/box_spec.rb +0 -88
  68. data/spec/models/message_train/ignore_spec.rb +65 -0
  69. data/spec/models/message_train/message_spec.rb +6 -5
  70. data/spec/models/message_train/receipt_spec.rb +6 -8
  71. data/spec/models/role_spec.rb +2 -2
  72. data/spec/models/user_spec.rb +29 -101
  73. data/spec/rails_helper.rb +16 -30
  74. data/spec/support/feature_behaviors.rb +2 -1
  75. data/spec/support/shared_connection.rb +5 -0
  76. data/spec/support/utilities.rb +7 -8
  77. metadata +145 -120
  78. data/README.rdoc +0 -175
  79. data/spec/dummy/app/models/.keep +0 -0
  80. data/spec/dummy/log/.keep +0 -0
@@ -3,20 +3,9 @@ module MessageTrain
3
3
  module MessagesHelper
4
4
  def message_class(box, message)
5
5
  css_classes = []
6
-
7
- css_classes << if message.is_unread_for?(@box_user)
8
- 'unread panel-info'
9
- else
10
- 'read'
11
- end
12
-
13
- message.draft && css_classes << 'draft'
14
-
15
- if box.division == :trash
16
- !message.is_trashed_for?(@box_user) && css_classes << 'hide'
17
- else
18
- !message.is_untrashed_for?(@box_user) && css_classes << 'hide'
19
- end
6
+ css_classes << message_css_for_read_state(message)
7
+ css_classes << message_css_for_draft_state(message)
8
+ css_classes << message_css_for_hide_state(box, message)
20
9
  css_classes.join(' ')
21
10
  end
22
11
 
@@ -48,20 +37,44 @@ module MessageTrain
48
37
  private
49
38
 
50
39
  def message_toggle(message, icon, mark_to_set, title, options = {})
51
- options[:remote] = true
52
- options[:id] = "mark_#{mark_to_set}_#{message.id}"
53
- options[:class] = 'mark-link'
54
- options[:method] = :put
55
- options[:title] = title
56
40
  render(
57
41
  partial: 'message_train/messages/toggle',
58
42
  locals: {
59
43
  message: message,
60
44
  icon: icon,
61
45
  mark_to_set: mark_to_set,
62
- options: options
46
+ options: message_toggle_options(message, mark_to_set, title, options)
63
47
  }
64
48
  )
65
49
  end
50
+
51
+ def message_toggle_options(message, mark_to_set, title, options = {})
52
+ options[:remote] = true
53
+ options[:id] = "mark_#{mark_to_set}_#{message.id}"
54
+ options[:class] = 'mark-link'
55
+ options[:method] = :put
56
+ options[:title] = title
57
+ options
58
+ end
59
+
60
+ def message_css_for_hide_state(box, message)
61
+ if box.division == :trash
62
+ 'hide' unless message.is_trashed_for?(@box_user)
63
+ else
64
+ 'hide' unless message.is_untrashed_for?(@box_user)
65
+ end
66
+ end
67
+
68
+ def message_css_for_draft_state(message)
69
+ 'draft' if message.draft
70
+ end
71
+
72
+ def message_css_for_read_state(message)
73
+ if message.is_unread_for?(@box_user)
74
+ 'unread panel-info'
75
+ else
76
+ 'read'
77
+ end
78
+ end
66
79
  end
67
80
  end
@@ -6,22 +6,32 @@ module MessageTrain
6
6
  @recipient = receipt.recipient
7
7
  @through = receipt.received_through
8
8
  if @recipient == @through
9
- @heading = :new_message_on_site_name.l(
10
- site_name: MessageTrain.configuration.site_name
11
- )
9
+ set_self_heading
12
10
  else
13
- @through_name = @through.send(
14
- MessageTrain.configuration.name_columns[
15
- @through.class.table_name.to_sym
16
- ]
17
- )
18
- @heading = :new_message_through_on_site_name.l(
19
- site_name: MessageTrain.configuration.site_name,
20
- through: @through_name
21
- )
11
+ set_through_heading
22
12
  end
23
13
  @subject = "#{@heading}: #{@receipt.message.subject}"
24
14
  mail(to: @recipient.email, subject: @subject)
25
15
  end
16
+
17
+ private
18
+
19
+ def set_self_heading
20
+ @heading = :new_message_on_site_name.l(
21
+ site_name: MessageTrain.configuration.site_name
22
+ )
23
+ end
24
+
25
+ def set_through_heading
26
+ @through_name = @through.send(
27
+ MessageTrain.configuration.name_columns[
28
+ @through.class.table_name.to_sym
29
+ ]
30
+ )
31
+ @heading = :new_message_through_on_site_name.l(
32
+ site_name: MessageTrain.configuration.site_name,
33
+ through: @through_name
34
+ )
35
+ end
26
36
  end
27
37
  end
@@ -39,9 +39,9 @@ module MessageTrain
39
39
  ]
40
40
  )
41
41
  def image?
42
- # rubocop:disable Style/LineLength
42
+ # rubocop:disable Metrics/LineLength
43
43
  !(attachment_content_type =~ %r{^(image|(x-)?application)/(bmp|gif|jpeg|jpg|pjpeg|png|x-png)$}).nil?
44
- # rubocop:enable Style/LineLength
44
+ # rubocop:enable Metrics/LineLength
45
45
  end
46
46
 
47
47
  Paperclip.interpolates :style_prefix do |attachment, style|
@@ -1,6 +1,19 @@
1
1
  module MessageTrain
2
2
  # Box model
3
3
  class Box
4
+ MARK_METHODS = {
5
+ 'Hash' => :mark_hash,
6
+ 'Array' => :mark_array,
7
+ 'String' => :mark_id,
8
+ 'Fixnum' => :mark_id,
9
+ 'MessageTrain::Conversation' => :mark_communication
10
+ }.freeze
11
+
12
+ AUTHORIZE_METHODS = {
13
+ 'MessageTrain::Conversation' => :authorize_conversation,
14
+ 'MessageTrain::Message' => :authorize_message
15
+ }.freeze
16
+
4
17
  include ActiveModel::Model
5
18
  attr_accessor :parent, :division, :participant, :errors, :results
6
19
  alias id division
@@ -18,8 +31,7 @@ module MessageTrain
18
31
  end
19
32
 
20
33
  def unread_count
21
- found = conversations(unread: true)
22
- found.count
34
+ conversations(read: false).count
23
35
  end
24
36
 
25
37
  def conversations(options = {})
@@ -28,21 +40,6 @@ module MessageTrain
28
40
  if options[:read] == false || options[:unread]
29
41
  found = found.with_unread_for(participant)
30
42
  end
31
- if division == :trash
32
- found = found.with_trashed_for(participant)
33
- else
34
- found = found.with_untrashed_for(participant)
35
- found = if division == :drafts
36
- found.with_drafts_by(participant)
37
- else
38
- found.with_ready_for(participant)
39
- end
40
- found = if division == :ignored
41
- found.ignored(participant)
42
- else
43
- found.unignored(participant)
44
- end
45
- end
46
43
  found
47
44
  end
48
45
 
@@ -54,131 +51,76 @@ module MessageTrain
54
51
  parent.all_messages(participant).find(id)
55
52
  end
56
53
 
57
- def new_message(args = {})
58
- if args[:message_train_conversation_id].nil?
59
- message = MessageTrain::Message.new(args)
54
+ def send_message(attributes)
55
+ message = MessageTrain::Message.new attributes
56
+ return false unless authorize_send_message(message)
57
+ message.sender = participant
58
+ return message_send_error(message) unless message.save
59
+ message_send_success(message)
60
+ end
61
+
62
+ def message_send_error(message)
63
+ errors.add(message, message.errors.full_messages.to_sentence)
64
+ message
65
+ end
66
+
67
+ def message_send_success(message)
68
+ if message.draft
69
+ results.add(message, :message_saved_as_draft.l)
60
70
  else
61
- conversation = find_conversation(args[:message_train_conversation_id])
62
- previous_message = conversation.messages.last
63
- message = conversation.messages.build(args)
64
- message.subject = "Re: #{conversation.subject}"
65
- message.body = "<blockquote>#{previous_message.body}</blockquote>"\
66
- '<p>&nbsp;</p>'
67
- recipient_arrays = {}
68
- conversation.default_recipients_for(parent).each do |recipient|
69
- table_name = recipient.class.table_name
70
- recipient_arrays[table_name] ||= []
71
- recipient_arrays[table_name] << recipient.send(
72
- MessageTrain.configuration.slug_columns[table_name.to_sym]
73
- )
74
- end
75
- recipient_arrays.each do |key, array|
76
- message.recipients_to_save[key] = array.join(', ')
77
- end
71
+ results.add(message, :message_sent.l)
78
72
  end
79
73
  message
80
74
  end
81
75
 
82
- def send_message(attributes)
83
- message_to_send = MessageTrain::Message.new attributes
84
- message_to_send.sender = participant
76
+ def authorize_send_message(message)
85
77
  unless parent.valid_senders.include? participant
86
78
  errors.add(
87
- message_to_send,
79
+ message,
88
80
  :invalid_sender_for_thing.l(
89
81
  thing: "#{parent.class.name} #{parent.id}"
90
82
  )
91
83
  )
92
84
  return false
93
85
  end
94
- if message_to_send.save
95
- if message_to_send.draft
96
- results.add(message_to_send, :message_saved_as_draft.l)
97
- else
98
- results.add(message_to_send, :message_sent.l)
99
- end
100
- else
101
- errors.add(
102
- message_to_send,
103
- message_to_send.errors.full_messages.to_sentence
104
- )
105
- end
106
- message_to_send
86
+ true
107
87
  end
108
88
 
109
89
  def update_message(message, attributes)
90
+ !message.draft && raise(ActiveRecord::RecordNotFound)
110
91
  attributes.delete(:sender)
111
- if message.sender == participant && parent.valid_senders.include?(
112
- participant
113
- )
114
- message.update(attributes)
115
- message.reload
116
- if message.errors.empty?
117
- if message.draft
118
- results.add(message, :message_saved_as_draft.l)
119
- else
120
- results.add(message, :message_sent.l)
121
- end
122
- else
123
- errors.add(
124
- message,
125
- message.errors.full_messages.to_sentence
126
- )
127
- end
128
- message
129
- else
130
- errors.add(
131
- message,
132
- :access_to_message_id_denied.l(id: message.id)
133
- )
134
- false
135
- end
92
+ return false unless authorize_update_message(message)
93
+ message.update(attributes)
94
+ message.reload
95
+ return message_update_error(message) if message.errors.any?
96
+ message_update_success(message)
136
97
  end
137
98
 
138
- def ignore(object)
139
- case object.class.name
140
- when 'Hash'
141
- ignore object.values
142
- when 'Array'
143
- object.collect { |item| ignore(item) }.uniq == [true]
144
- when 'String', 'Fixnum'
145
- ignore(find_conversation(object.to_i))
146
- when 'MessageTrain::Conversation'
147
- if authorize(object)
148
- object.participant_ignore(participant)
149
- # We can assume the previous line has succeeded at this point,
150
- # because participant_ignore raises an ActiveRecord error otherwise.
151
- # Therefore we simply report success, since we got here.
152
- results.add(object, :update_successful.l)
153
- else
154
- false
155
- end
99
+ def message_update_success(message)
100
+ if message.draft
101
+ results.add(message, :message_saved_as_draft.l)
156
102
  else
157
- errors.add(self, :cannot_ignore_type.l(type: object.class.name))
103
+ results.add(message, :message_sent.l)
158
104
  end
105
+ message
159
106
  end
160
107
 
161
- def unignore(object)
162
- case object.class.name
163
- when 'Hash'
164
- unignore object.values
165
- when 'Array'
166
- object.collect { |item| unignore(item) }.uniq == [true]
167
- when 'String', 'Fixnum'
168
- unignore(find_conversation(object.to_i))
169
- when 'MessageTrain::Conversation'
170
- if authorize(object)
171
- object.participant_unignore(participant)
172
- # We can assume the previous line has succeeded at this point,
173
- # because participant_unignore raises an ActiveRecord error
174
- # otherwise. Therefore we simply report success, since we got here.
175
- results.add(object, :update_successful.l)
176
- else
177
- false
178
- end
179
- else
180
- errors.add(self, :cannot_unignore_type.l(type: object.class.name))
108
+ def message_update_error(message)
109
+ errors.add(message, message.errors.full_messages.to_sentence)
110
+ message
111
+ end
112
+
113
+ def authorize_update_message(message)
114
+ unless message.sender == participant &&
115
+ parent.valid_senders.include?(participant)
116
+ return message_access_denied(message)
181
117
  end
118
+ true
119
+ end
120
+
121
+ def message_access_denied(message)
122
+ errors.add(message, :access_to_message_id_denied.l(id: message.id))
123
+ false
182
124
  end
183
125
 
184
126
  def title
@@ -186,74 +128,73 @@ module MessageTrain
186
128
  end
187
129
 
188
130
  def message
189
- if !errors.all.empty?
190
- errors.all.collect { |x| x[:message] }.uniq.to_sentence
191
- elsif results.all.empty?
192
- :nothing_to_do.l
193
- else
194
- results.all.collect { |x| x[:message] }.uniq.to_sentence
195
- end
131
+ what_happened = errors.any? ? errors : results
132
+ return :nothing_to_do.l unless what_happened.any?
133
+ what_happened.all.map { |x| x[:message] }.uniq.to_sentence
196
134
  end
197
135
 
198
136
  def mark(mark_to_set, objects)
199
137
  objects.each do |key, object|
200
- if !object.present?
201
- # Allow skipping empty objects
202
- elsif key.to_s =~ /^(conversations|messages)$/
203
- data_type = object.class.name
204
- case data_type
205
- when 'Hash'
206
- mark(mark_to_set, key => object.values)
207
- when 'Array'
208
- object.collect do |item|
209
- mark(mark_to_set, key => item)
210
- end.uniq == [true]
211
- when 'String', 'Fixnum'
212
- model_name = "MessageTrain::#{key.to_s.classify}"
213
- model = model_name.constantize
214
- mark(mark_to_set, key => model.find_by_id!(object.to_i))
215
- when 'MessageTrain::Conversation', 'MessageTrain::Message'
216
- if authorize(object)
217
- object.mark(mark_to_set, participant)
218
- # We can assume the previous line has succeeded at this point,
219
- # because mark raises an ActiveRecord error otherwise.
220
- # Therefore we simply report success, since we got here.
221
- results.add(object, :update_successful.l)
222
- else
223
- false
224
- end
225
- else
226
- errors.add(
227
- self,
228
- :cannot_mark_with_data_type.l(data_type: data_type)
229
- )
230
- end
231
- else
138
+ next unless object.present? # Allow skipping empty objects
139
+ unless key.to_s =~ /^(conversations|messages)$/
232
140
  errors.add(self, :cannot_mark_type.l(type: key.to_s))
141
+ next
233
142
  end
143
+ mark_object mark_to_set, key, object
234
144
  end
235
145
  end
236
146
 
147
+ def mark_hash(mark_to_set, key, object)
148
+ mark(mark_to_set, key => object.values)
149
+ end
150
+
151
+ def mark_array(mark_to_set, key, object)
152
+ object.collect { |item| mark(mark_to_set, key => item) }
153
+ .uniq == [true]
154
+ end
155
+
156
+ def mark_id(mark_to_set, key, object)
157
+ model = "MessageTrain::#{key.to_s.classify}".constantize
158
+ mark_communication(mark_to_set, key, model.find_by_id!(object.to_i))
159
+ end
160
+
161
+ def mark_communication(mark_to_set, _key, object)
162
+ return unless authorize(object)
163
+ object.mark(mark_to_set, participant)
164
+ results.add(object, :update_successful.l)
165
+ end
166
+
167
+ def marking_error(object)
168
+ errors.add(
169
+ self, :cannot_mark_with_data_type.l(data_type: object.class.name)
170
+ )
171
+ object
172
+ end
173
+
174
+ def mark_object(mark_to_set, key, object)
175
+ method = MARK_METHODS[object.class.name]
176
+ return marking_error(object) if method.nil?
177
+ send(method, mark_to_set, key, object)
178
+ end
179
+
237
180
  def authorize(object)
238
- case object.class.name
239
- when 'MessageTrain::Conversation'
240
- if object.includes_receipts_for? participant
241
- true
242
- else
243
- errors.add(
244
- object,
245
- :access_to_conversation_id_denied.l(id: object.id)
246
- )
247
- end
248
- when 'MessageTrain::Message'
249
- if object.receipts.for(participant).any?
250
- true
251
- else
252
- errors.add(object, :access_to_message_id_denied.l(id: object.id))
253
- end
254
- else
255
- errors.add(object, :cannot_authorize_type.l(type: object.class.name))
256
- end
181
+ method = AUTHORIZE_METHODS[object.class.name]
182
+ return authorize_error(object) if method.nil?
183
+ send(method, object)
184
+ end
185
+
186
+ def authorize_error(object)
187
+ errors.add(object, :cannot_authorize_type.l(type: object.class.name))
188
+ end
189
+
190
+ def authorize_conversation(object)
191
+ object.includes_receipts_for?(participant) ||
192
+ errors.add(object, :access_to_conversation_id_denied.l(id: object.id))
193
+ end
194
+
195
+ def authorize_message(object)
196
+ object.receipts.for(participant).any? ||
197
+ errors.add(object, :access_to_message_id_denied.l(id: object.id))
257
198
  end
258
199
 
259
200
  # Box::Results class
@@ -266,64 +207,77 @@ module MessageTrain
266
207
  end
267
208
 
268
209
  def add(object, message)
269
- item = {}
270
- case object.class.name
271
- when 'MessageTrain::Box'
272
- item[:css_id] = 'box'
273
- route_args = {
274
- controller: 'message_train/boxes',
275
- action: :show,
276
- division: object.division
277
- }
278
- if box.parent != box.participant
279
- collective = box.parent
280
- table_part = collective.class.table_name
281
- slug_part = collective.send(
282
- MessageTrain.configuration.slug_columns[
283
- collective.class.table_name.to_sym
284
- ]
285
- )
286
- route_args[:collective_id] = "#{table_part}:#{slug_part}"
287
- end
288
- item[:path] = MessageTrain::Engine.routes.path_for(route_args)
289
- when 'MessageTrain::Conversation', 'MessageTrain::Message'
290
- if object.new_record?
291
- item[:css_id] = "#{object.class.table_name.singularize}"
292
- item[:path] = nil
293
- else
294
- item[:css_id] = "#{object.class.table_name.singularize}_"\
295
- "#{object.id.to_s}"
296
- route_args = {
297
- controller: object.class.table_name
298
- .gsub('message_train_', 'message_train/'),
299
- action: :show,
300
- box_division: box.division,
301
- id: object.id
302
- }
303
- if box.parent != box.participant
304
- collective = box.parent
305
- table_part = collective.class.table_name
306
- slug_part = collective.send(
307
- MessageTrain.configuration.slug_columns[
308
- collective.class.table_name.to_sym
309
- ]
310
- )
311
- route_args[:collective_id] = "#{table_part}:#{slug_part}"
312
- end
313
- item[:path] = MessageTrain::Engine.routes.path_for(route_args)
314
- end
315
- else
316
- item[:css_id] = object.class.name.singularize.downcase
317
- item[:path] = nil
318
- end
319
- item[:message] = message
320
- items << item
210
+ items << case object.class.name
211
+ when 'MessageTrain::Box'
212
+ result_for_box(object, message)
213
+ when 'MessageTrain::Conversation', 'MessageTrain::Message'
214
+ result_for_communication(object, message)
215
+ else
216
+ result_for_misc_object(object, message)
217
+ end
321
218
  true
322
219
  end
323
220
 
221
+ def result_for_misc_object(object, message)
222
+ css_id = object.class.name.singularize.downcase
223
+ { css_id: css_id, path: nil, message: message }
224
+ end
225
+
226
+ def result_for_communication(object, message)
227
+ return result_for_new(object, message) if object.new_record?
228
+ path = MessageTrain::Engine.routes.path_for(object_route_args(object))
229
+ css_id = "#{object.class.table_name.singularize}_#{object.id}"
230
+ { message: message, css_id: css_id, path: path }
231
+ end
232
+
233
+ def object_route_args(object)
234
+ table_name = object.class.table_name
235
+ {
236
+ controller: table_name.gsub('message_train_', 'message_train/'),
237
+ action: :show,
238
+ box_division: box.division,
239
+ id: object.id,
240
+ collective_id: collective_id_for_box(box)
241
+ }
242
+ end
243
+
244
+ def result_for_new(object, message)
245
+ {
246
+ message: message,
247
+ css_id: object.class.table_name.singularize,
248
+ path: nil
249
+ }
250
+ end
251
+
252
+ def result_for_box(object, message)
253
+ path = MessageTrain::Engine.routes.path_for(box_route_args(object))
254
+ { css_id: 'box', message: message, path: path }
255
+ end
256
+
257
+ def box_route_args(object)
258
+ {
259
+ controller: 'message_train/boxes',
260
+ action: :show,
261
+ division: object.division,
262
+ collective_id: collective_id_for_box(box)
263
+ }
264
+ end
265
+
266
+ def collective_id_for_box(box)
267
+ return if box.parent == box.participant
268
+ collective = box.parent
269
+ table_part = collective.class.table_name
270
+ slug_part = collective.message_train_slug
271
+ "#{table_part}:#{slug_part}"
272
+ end
273
+
324
274
  def all
325
275
  items
326
276
  end
277
+
278
+ def any?
279
+ items.any?
280
+ end
327
281
  end
328
282
  # Box::Errors class
329
283
  class Errors < Results