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
@@ -8,81 +8,116 @@ module MessageTrain
8
8
 
9
9
  # POST /unsubscribes
10
10
  def create
11
- if params[:all]
12
- @from = nil
13
- @unsubscribe = @box_user.unsubscribe_from(@from)
14
- if @unsubscribe.errors.empty?
15
- flash[:notice] = :unsubscribe_from_all_message.l
16
- else
17
- flash[:error] = @unsubscribe.errors.full_messages.to_sentence
18
- end
19
- redirect_to message_train.unsubscribes_url
20
- return
21
- end
22
- unsub = unsubscribe_params
23
- model = unsub[:from_type].constantize
24
- @from = model.find(unsub[:from_id])
25
- if @from == @box_user || @from.allows_receiving_by?(@box_user)
26
- @unsubscribe = @box_user.unsubscribe_from(@from)
27
- if @unsubscribe.errors.empty?
28
- if @from == @box_user
29
- flash[:notice] = :unsubscribe_message.l
30
- else
31
- name_column = MessageTrain.configuration.name_columns[
32
- @from.class.table_name.to_sym
33
- ]
34
- collective_name = @from.send(name_column)
35
- collective_type = @from.class.name
36
- flash[:notice] = :collective_unsubscribe_message.l(
37
- collective_name: collective_name,
38
- collective_type: collective_type
39
- )
40
- end
41
- else
42
- flash[:error] = @unsubscribe.errors.full_messages.to_sentence
43
- end
44
- else
45
- flash[:error] = :you_are_not_in_that_collective_type.l(
46
- collective_type: model.name
47
- )
48
- raise ActiveRecord::RecordNotFound
49
- end
11
+ return unsubscribe_from_all if params[:all]
12
+ return unless unsubscribe_from_one
13
+ flash[:notice] = if @from == @box_user
14
+ unsubscribe_message_from_box_user
15
+ else
16
+ unsubscribe_message_from_other
17
+ end
50
18
  redirect_to message_train.unsubscribes_url
51
19
  end
52
20
 
53
21
  # DELETE /unsubscribes/:id
54
22
  def destroy
55
- if params[:all]
56
- @unsubscribe = @box_user.unsubscribes.where(from: nil).destroy_all
57
- flash[:notice] = :unsubscribe_all_removed_message.l
58
- else
59
- @unsubscribe = @box_user.unsubscribes.find(params[:id])
60
- @from = @unsubscribe.from
61
- if @from == @box_user
62
- message = :unsubscribe_removed_message.l
63
- else
64
- name_column = MessageTrain.configuration.name_columns[
65
- @unsubscribe.from.class.table_name.to_sym
66
- ]
67
- collective_name = @unsubscribe.from.send(name_column)
68
- collective_type = @unsubscribe.from_type
69
- message = :collective_unsubscribe_removed_message.l(
70
- collective_name: collective_name,
71
- collective_type: collective_type
72
- )
73
- end
74
- @unsubscribe.destroy
75
- flash[:notice] = message
76
- end
23
+ flash[:notice] = params[:all] ? destroy_all : destroy_one
77
24
  redirect_to message_train.unsubscribes_url
78
25
  end
79
26
 
80
27
  private
81
28
 
29
+ def destroy_all
30
+ @unsubscribe = @box_user.unsubscribes.where(from: nil).destroy_all
31
+ :unsubscribe_all_removed_message.l
32
+ end
33
+
34
+ def destroy_one
35
+ @unsubscribe = @box_user.unsubscribes.find(params[:id])
36
+ @from = @unsubscribe.from
37
+ @unsubscribe.destroy
38
+ if @from == @box_user
39
+ destroy_message_through_self
40
+ else
41
+ destroy_message_through_other
42
+ end
43
+ end
44
+
45
+ def destroy_message_through_self
46
+ :unsubscribe_removed_message.l
47
+ end
48
+
49
+ def destroy_message_through_other
50
+ name_column = MessageTrain.configuration.name_columns[
51
+ @unsubscribe.from.class.table_name.to_sym
52
+ ]
53
+ collective_name = @unsubscribe.from.send(name_column)
54
+ collective_type = @unsubscribe.from_type
55
+ :collective_unsubscribe_removed_message.l(
56
+ collective_name: collective_name,
57
+ collective_type: collective_type
58
+ )
59
+ end
60
+
82
61
  # Never trust parameters from the scary internet, only allow the white list
83
62
  # through.
84
63
  def unsubscribe_params
85
64
  params.require(:unsubscribe).permit(:from_type, :from_id)
86
65
  end
66
+
67
+ def unsubscribe_from_all
68
+ @unsubscribe = @box_user.unsubscribe_from(nil)
69
+ if @unsubscribe.errors.empty?
70
+ flash[:notice] = :unsubscribe_from_all_message.l
71
+ else
72
+ flash[:error] = @unsubscribe.errors.full_messages.to_sentence
73
+ end
74
+ redirect_to message_train.unsubscribes_url
75
+ end
76
+
77
+ def unsubscribe_from_one
78
+ unsub = unsubscribe_params
79
+ model = unsub[:from_type].constantize
80
+
81
+ @from = model.find(unsub[:from_id])
82
+ authorize_unsubscribe
83
+
84
+ @unsubscribe = @box_user.unsubscribe_from(@from)
85
+
86
+ if @unsubscribe.errors.any?
87
+ unsubscribe_errors
88
+ else
89
+ true
90
+ end
91
+ end
92
+
93
+ def authorize_unsubscribe
94
+ return true if @from.allows_receiving_by?(@box_user)
95
+ flash[:error] = :you_are_not_in_that_collective_type.l(
96
+ collective_type: @from.class.name
97
+ )
98
+ raise ActiveRecord::RecordNotFound
99
+ end
100
+
101
+ def unsubscribe_errors
102
+ flash[:error] = @unsubscribe.errors.full_messages.to_sentence
103
+ redirect_to message_train.unsubscribes_url
104
+ false
105
+ end
106
+
107
+ def unsubscribe_message_from_box_user
108
+ :unsubscribe_message.l
109
+ end
110
+
111
+ def unsubscribe_message_from_other
112
+ name_column = MessageTrain.configuration.name_columns[
113
+ @from.class.table_name.to_sym
114
+ ]
115
+ collective_name = @from.send(name_column)
116
+ collective_type = @from.class.name
117
+ :collective_unsubscribe_message.l(
118
+ collective_name: collective_name,
119
+ collective_type: collective_type
120
+ )
121
+ end
87
122
  end
88
123
  end
@@ -7,17 +7,23 @@ module MessageTrain
7
7
 
8
8
  def fuzzy_date(date)
9
9
  time = Time.parse(date.strftime('%F %T'))
10
- case Time.now - time
11
- when 0..1.minute
12
- :just_now.l
10
+ change_in_time = Time.now - time
11
+ return :just_now.l if (0..1.minute).cover? change_in_time
12
+ l(time, format: fuzzy_date_format(change_in_time))
13
+ end
14
+
15
+ private
16
+
17
+ def fuzzy_date_format(change_in_time)
18
+ case change_in_time
13
19
  when 1.minute..1.day
14
- l(time, format: :fuzzy_today)
20
+ :fuzzy_today
15
21
  when 1.day..1.week
16
- l(time, format: :fuzzy_this_week)
22
+ :fuzzy_this_week
17
23
  when 1.week..1.year
18
- l(time, format: :fuzzy_date_without_year)
24
+ :fuzzy_date_without_year
19
25
  else
20
- l(time, format: :fuzzy_date)
26
+ :fuzzy_date
21
27
  end
22
28
  end
23
29
  end
@@ -2,18 +2,10 @@ module MessageTrain
2
2
  # Attachments helper
3
3
  module AttachmentsHelper
4
4
  def attachment_icon(attachment)
5
- html = ''
6
- if attachment.image?
7
- html << image_tag(attachment.attachment.url(:thumb))
8
- else
9
- html << content_tag(
10
- :span,
11
- '',
12
- class: 'glyphicon glyphicon-save-file glyphicon-thumbnail'
13
- )
14
- html << tag(:br)
15
- html << attachment.attachment_file_name
16
- end
5
+ return image_tag(attachment.attachment.url(:thumb)) if attachment.image?
6
+ icon_class = 'glyphicon glyphicon-save-file glyphicon-thumbnail'
7
+ html = content_tag(:span, '', class: icon_class)
8
+ html << tag(:br) + attachment.attachment_file_name
17
9
  html.html_safe
18
10
  end
19
11
 
@@ -60,30 +60,20 @@ module MessageTrain
60
60
  end
61
61
 
62
62
  def boxes_dropdown_cache_key(boxes)
63
- parts = [
64
- 'boxes-dropdown',
65
- @box_user
66
- ]
63
+ parts = ['boxes-dropdown', @box_user]
67
64
  updated_at = boxes.collect do |x|
68
65
  x.conversations && x.conversations.maximum(:updated_at)
69
66
  end.compact.max
70
- updated_at && parts << [
71
- updated_at
72
- ]
67
+ parts << [updated_at] if updated_at
73
68
  parts
74
69
  end
75
70
 
76
71
  def boxes_widget_cache_key(boxes)
77
- parts = [
78
- 'boxes-widget',
79
- @box_user
80
- ]
72
+ parts = ['boxes-widget', @box_user]
81
73
  updated_at = boxes.collect do |x|
82
74
  x.conversations && x.conversations.maximum(:updated_at)
83
75
  end.compact.max
84
- updated_at && parts << [
85
- updated_at
86
- ]
76
+ parts << [updated_at] if updated_at
87
77
  parts
88
78
  end
89
79
  end
@@ -9,18 +9,27 @@ module MessageTrain
9
9
  end
10
10
 
11
11
  def collective_nav_item(box, box_user)
12
- text = collective_name(box.parent)
12
+ parent = box.parent
13
+ return unless parent.allows_access_by? box_user
14
+ division = default_division_for_box(box, box_user)
15
+ nav_item(
16
+ (collective_name(parent) + collective_badge(box)).html_safe,
17
+ message_train.collective_box_path(parent.path_part, division)
18
+ )
19
+ end
20
+
21
+ def collective_badge(box)
22
+ count = box.unread_count
23
+ return '' if count.zero?
24
+ badge(count.to_s, 'info pull-right')
25
+ end
26
+
27
+ def default_division_for_box(box, box_user)
13
28
  if box.parent.allows_receiving_by? box_user
14
- division = :in
29
+ :in
15
30
  elsif box.parent.allows_sending_by? box_user
16
- division = :sent
17
- else
18
- return
31
+ :sent
19
32
  end
20
- link = message_train.collective_box_path(box.parent.path_part, division)
21
- unread_count = box.unread_count
22
- unread_count > 0 && text << badge(unread_count.to_s, 'info pull-right')
23
- nav_item text.html_safe, link
24
33
  end
25
34
 
26
35
  def collective_list_item(box, html_options = {})
@@ -35,21 +44,12 @@ module MessageTrain
35
44
  end
36
45
 
37
46
  def collective_boxes_dropdown_list(box_user)
38
- total_unread_count = {}
39
- show = {}
40
- box_user.collective_boxes.each do |table_sym, collectives|
41
- total_unread_count[table_sym] = collectives.collect(&:unread_count).sum
42
- show[table_sym] = collectives.select do |collective_box|
43
- collective_box.parent.allows_sending_by?(box_user) ||
44
- collective_box.parent.allows_receiving_by?(box_user)
45
- end.any?
46
- end
47
47
  render(
48
48
  partial: 'message_train/collectives/dropdown_list',
49
49
  locals: {
50
50
  collective_boxes: box_user.collective_boxes,
51
- total_unread_count: total_unread_count,
52
- show: show,
51
+ total_unread_count: box_user.collective_boxes_unread_counts,
52
+ show: box_user.collective_boxes_show_flags,
53
53
  box_user: box_user
54
54
  }
55
55
  )
@@ -72,18 +72,12 @@ module MessageTrain
72
72
  end
73
73
 
74
74
  def collectives_cache_key(collective_boxes, box_user)
75
- parts = [
76
- 'collectives-dropdown',
77
- box_user
78
- ]
79
- collective_boxes.collect do |table_name, x|
75
+ parts = ['collectives-dropdown', box_user]
76
+ collective_boxes.each do |table_name, x|
80
77
  updated_at = x.collect do |y|
81
78
  y.conversations && y.conversations.maximum(:updated_at)
82
79
  end.compact.max
83
- updated_at && parts << [
84
- table_name,
85
- updated_at
86
- ]
80
+ updated_at && parts << [table_name, updated_at]
87
81
  end
88
82
  parts
89
83
  end
@@ -11,30 +11,10 @@ module MessageTrain
11
11
 
12
12
  def conversation_class(box, conversation)
13
13
  css_classes = []
14
-
15
- css_classes << if conversation.includes_unread_for?(@box_user)
16
- 'unread'
17
- else
18
- 'read'
19
- end
20
-
21
- conversation.includes_drafts_by?(@box_user) && css_classes << 'draft'
22
-
23
- !conversation.includes_undeleted_for?(@box_user) && css_classes << 'hide'
24
-
25
- if box.division == :trash
26
- !conversation.includes_trashed_for?(@box_user) &&
27
- css_classes << 'hide'
28
- else
29
- !conversation.includes_untrashed_for?(@box_user) &&
30
- css_classes << 'hide'
31
- if box.division == :ignored
32
- !conversation.participant_ignored?(@box_user) && css_classes << 'hide'
33
- else
34
- conversation.participant_ignored?(@box_user) && css_classes << 'hide'
35
- end
36
- end
37
- css_classes.uniq.join(' ')
14
+ css_classes << conversation_css_for_read_state(conversation)
15
+ css_classes << conversation_css_for_draft_state(conversation)
16
+ css_classes << conversation_css_for_hide_state(box, conversation)
17
+ css_classes.join(' ')
38
18
  end
39
19
 
40
20
  def conversation_trashed_toggle(conversation, collective = nil)
@@ -69,21 +49,63 @@ module MessageTrain
69
49
 
70
50
  # rubocop:disable Metrics/ParameterLists
71
51
  def conversation_toggle(conv, icon, mark, method, title, options = {})
72
- options[:remote] = true
73
- options[:method] = method
74
- options[:title] = title
75
- options[:class] ||= ''
76
- options[:class] += " #{mark}-toggle"
77
52
  render(
78
53
  partial: 'message_train/conversations/toggle',
79
54
  locals: {
80
55
  conversation: conv,
81
56
  icon: icon,
82
57
  mark_to_set: mark,
83
- options: options
58
+ options: conversation_toggle_options(mark, method, title, options)
84
59
  }
85
60
  )
86
61
  end
87
62
  # rubocop:enable Metrics/ParameterLists
63
+
64
+ def conversation_toggle_options(mark, method, title, options = {})
65
+ options[:remote] = true
66
+ options[:method] = method
67
+ options[:title] = title
68
+ options[:class] ||= ''
69
+ options[:class] += " #{mark}-toggle"
70
+ options
71
+ end
72
+
73
+ def conversation_css_for_hide_state(box, conversation)
74
+ conversation_css_for_deleted_state(conversation) ||
75
+ conversation_css_for_trash_state(box, conversation) ||
76
+ conversation_css_for_ignore_state(box, conversation)
77
+ end
78
+
79
+ def conversation_css_for_deleted_state(conversation)
80
+ 'hide' unless conversation.includes_undeleted_for?(@box_user)
81
+ end
82
+
83
+ def conversation_css_for_trash_state(box, conversation)
84
+ if box.division == :trash
85
+ 'hide' unless conversation.includes_trashed_for?(@box_user)
86
+ elsif !conversation.includes_untrashed_for?(@box_user)
87
+ 'hide'
88
+ end
89
+ end
90
+
91
+ def conversation_css_for_ignore_state(box, conversation)
92
+ if box.division == :ignored
93
+ 'hide' unless conversation.participant_ignored?(@box_user)
94
+ elsif conversation.participant_ignored?(@box_user)
95
+ 'hide'
96
+ end
97
+ end
98
+
99
+ def conversation_css_for_draft_state(conversation)
100
+ 'draft' if conversation.includes_drafts_by?(@box_user)
101
+ end
102
+
103
+ def conversation_css_for_read_state(conversation)
104
+ if conversation.includes_unread_for?(@box_user)
105
+ 'unread'
106
+ else
107
+ 'read'
108
+ end
109
+ end
88
110
  end
89
111
  end