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.
- 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
|