message_train 0.6.17 → 0.7.1

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