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.
- checksums.yaml +4 -4
- data/.rubocop.yml +16 -13
- data/.rubocop_todo.yml +12 -0
- data/.ruby-version +1 -1
- data/.travis.yml +1 -1
- data/Gemfile +28 -30
- data/README.md +284 -0
- data/Rakefile +6 -7
- data/VERSION +1 -1
- data/app/assets/javascripts/ckeditor/{config.js.coffee → config.js} +7 -6
- data/app/assets/stylesheets/message_train.scss +0 -8
- data/app/controllers/concerns/message_train_authorization.rb +37 -0
- data/app/controllers/concerns/message_train_support.rb +41 -69
- data/app/controllers/message_train/application_controller.rb +1 -0
- data/app/controllers/message_train/boxes_controller.rb +5 -4
- data/app/controllers/message_train/conversations_controller.rb +7 -5
- data/app/controllers/message_train/messages_controller.rb +43 -27
- data/app/controllers/message_train/participants_controller.rb +14 -25
- data/app/controllers/message_train/unsubscribes_controller.rb +96 -61
- data/app/helpers/message_train/application_helper.rb +13 -7
- data/app/helpers/message_train/attachments_helper.rb +4 -12
- data/app/helpers/message_train/boxes_helper.rb +4 -14
- data/app/helpers/message_train/collectives_helper.rb +23 -29
- data/app/helpers/message_train/conversations_helper.rb +52 -30
- data/app/helpers/message_train/messages_helper.rb +33 -20
- data/app/mailers/message_train/receipt_mailer.rb +22 -12
- data/app/models/message_train/attachment.rb +2 -2
- data/app/models/message_train/box.rb +182 -228
- data/app/models/message_train/conversation.rb +100 -103
- data/app/models/message_train/ignore.rb +83 -4
- data/app/models/message_train/message.rb +66 -117
- data/app/models/message_train/receipt.rb +73 -49
- data/app/views/message_train/boxes/show.html.haml +11 -7
- data/config/locales/en.yml +1 -0
- data/config/routes.rb +6 -12
- data/lib/message_train.rb +3 -1
- data/lib/message_train/class_methods.rb +51 -0
- data/lib/message_train/configuration.rb +28 -3
- data/lib/message_train/instance_methods.rb +209 -0
- data/lib/message_train/mixin.rb +25 -320
- data/message_train.gemspec +83 -83
- data/spec/controllers/message_train/boxes_controller_spec.rb +37 -19
- data/spec/controllers/message_train/concerns_spec.rb +21 -3
- data/spec/controllers/message_train/conversations_controller_spec.rb +41 -18
- data/spec/controllers/message_train/messages_controller_spec.rb +112 -31
- data/spec/controllers/message_train/participants_controller_spec.rb +33 -7
- data/spec/controllers/message_train/unsubscribes_controller_spec.rb +10 -8
- data/spec/dummy/app/assets/stylesheets/{application.css.scss → application.scss} +2 -1
- data/spec/dummy/app/assets/stylesheets/bootstrap-everything.scss +54 -0
- data/spec/dummy/app/models/group.rb +1 -1
- data/spec/dummy/app/views/layouts/application.html.haml +9 -8
- data/spec/dummy/bin/setup +8 -8
- data/spec/dummy/config/application.rb +0 -3
- data/spec/dummy/config/environments/test.rb +4 -2
- data/spec/dummy/db/schema.rb +94 -103
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/factories/attachment.rb +3 -1
- data/spec/factories/message.rb +2 -3
- data/spec/features/boxes_spec.rb +0 -3
- data/spec/helpers/message_train/application_helper_spec.rb +3 -2
- data/spec/helpers/message_train/attachment_helper_spec.rb +4 -0
- data/spec/helpers/message_train/boxes_helper_spec.rb +1 -0
- data/spec/helpers/message_train/collectives_helper_spec.rb +1 -0
- data/spec/helpers/message_train/conversations_helper_spec.rb +3 -2
- data/spec/helpers/message_train/messages_helper_spec.rb +2 -1
- data/spec/models/group_spec.rb +6 -4
- data/spec/models/message_train/box_spec.rb +0 -88
- data/spec/models/message_train/ignore_spec.rb +65 -0
- data/spec/models/message_train/message_spec.rb +6 -5
- data/spec/models/message_train/receipt_spec.rb +6 -8
- data/spec/models/role_spec.rb +2 -2
- data/spec/models/user_spec.rb +29 -101
- data/spec/rails_helper.rb +16 -30
- data/spec/support/feature_behaviors.rb +2 -1
- data/spec/support/shared_connection.rb +5 -0
- data/spec/support/utilities.rb +7 -8
- metadata +145 -120
- data/README.rdoc +0 -175
- data/spec/dummy/app/models/.keep +0 -0
- 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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
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
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
20
|
+
:fuzzy_today
|
15
21
|
when 1.day..1.week
|
16
|
-
|
22
|
+
:fuzzy_this_week
|
17
23
|
when 1.week..1.year
|
18
|
-
|
24
|
+
:fuzzy_date_without_year
|
19
25
|
else
|
20
|
-
|
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
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
29
|
+
:in
|
15
30
|
elsif box.parent.allows_sending_by? box_user
|
16
|
-
|
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:
|
52
|
-
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
|
-
|
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 <<
|
16
|
-
|
17
|
-
|
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
|