message_train 0.1.7 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.simplecov +8 -0
- data/.travis.yml +7 -2
- data/Gemfile +3 -0
- data/README.rdoc +37 -1
- data/Rakefile +5 -6
- data/VERSION +1 -1
- data/app/assets/javascripts/message_train.js +33 -0
- data/app/assets/stylesheets/message_train.scss +26 -0
- data/app/controllers/concerns/message_train_support.rb +127 -0
- data/app/controllers/message_train/application_controller.rb +1 -60
- data/app/controllers/message_train/boxes_controller.rb +0 -4
- data/app/controllers/message_train/messages_controller.rb +12 -6
- data/app/controllers/message_train/participants_controller.rb +1 -1
- data/app/controllers/message_train/unsubscribes_controller.rb +59 -0
- data/app/helpers/message_train/application_helper.rb +26 -0
- data/app/helpers/message_train/attachments_helper.rb +19 -0
- data/app/helpers/message_train/boxes_helper.rb +16 -11
- data/app/helpers/message_train/collectives_helper.rb +48 -0
- data/app/helpers/message_train/conversations_helper.rb +24 -16
- data/app/helpers/message_train/messages_helper.rb +14 -12
- data/app/mailers/message_train/application_mailer.rb +8 -0
- data/app/mailers/message_train/previews/receipt_mailer_preview.rb +10 -0
- data/app/mailers/message_train/receipt_mailer.rb +17 -0
- data/app/models/message_train/attachment.rb +28 -10
- data/app/models/message_train/box.rb +114 -83
- data/app/models/message_train/conversation.rb +48 -39
- data/app/models/message_train/ignore.rb +2 -6
- data/app/models/message_train/message.rb +40 -24
- data/app/models/message_train/receipt.rb +20 -10
- data/app/models/message_train/unsubscribe.rb +7 -0
- data/app/views/layouts/mailer.html.haml +6 -0
- data/app/views/message_train/application/_attachment_fields.html.haml +7 -0
- data/app/views/message_train/application/_attachment_link.html.haml +4 -0
- data/app/views/message_train/application/_widget.html.haml +6 -0
- data/app/views/message_train/boxes/_dropdown_list.html.haml +1 -2
- data/app/views/message_train/boxes/_list_item.html.haml +2 -2
- data/app/views/message_train/boxes/_widget.html.haml +4 -1
- data/app/views/message_train/boxes/show.html.haml +12 -4
- data/app/views/message_train/collectives/_dropdown_list.html.haml +6 -0
- data/app/views/message_train/collectives/_list_item.html.haml +5 -0
- data/app/views/message_train/collectives/_widget.html.haml +7 -0
- data/app/views/message_train/conversations/_conversation.html.haml +22 -7
- data/app/views/message_train/conversations/_deleted_toggle.html.haml +1 -1
- data/app/views/message_train/conversations/_ignored_toggle.html.haml +3 -3
- data/app/views/message_train/conversations/_read_toggle.html.haml +3 -3
- data/app/views/message_train/conversations/_toggle.html.haml +4 -1
- data/app/views/message_train/conversations/_trashed_toggle.html.haml +3 -3
- data/app/views/message_train/conversations/show.html.haml +4 -3
- data/app/views/message_train/messages/_deleted_toggle.html.haml +1 -1
- data/app/views/message_train/messages/_form.html.haml +22 -7
- data/app/views/message_train/messages/_message.html.haml +14 -4
- data/app/views/message_train/messages/_read_toggle.html.haml +1 -1
- data/app/views/message_train/messages/_trashed_toggle.html.haml +1 -1
- data/app/views/message_train/messages/edit.html.haml +1 -1
- data/app/views/message_train/messages/new.html.haml +4 -1
- data/app/views/message_train/participants/_field.html.haml +1 -1
- data/app/views/message_train/participants/_prefilled_field.html.haml +4 -0
- data/app/views/message_train/receipt_mailer/notification_email.html.haml +13 -0
- data/app/views/message_train/unsubscribes/index.html.haml +10 -0
- data/config/environment.rb +1 -0
- data/config/locales/en.yml +49 -7
- data/config/routes.rb +10 -2
- data/db/migrate/20150901183458_add_received_through_to_message_train_receipts.rb +6 -0
- data/db/migrate/20151004184347_add_unique_index_to_receipts.rb +5 -0
- data/db/migrate/20151124000820_create_message_train_unsubscribes.rb +14 -0
- data/lib/generators/message_train/install/install_generator.rb +8 -2
- data/lib/generators/message_train/install/templates/initializer.rb +5 -1
- data/lib/message_train/configuration.rb +11 -1
- data/lib/message_train/engine.rb +1 -0
- data/lib/message_train/mixin.rb +206 -21
- data/message_train.gemspec +66 -13
- data/spec/controllers/message_train/boxes_controller_spec.rb +10 -3
- data/spec/controllers/message_train/concerns_spec.rb +40 -0
- data/spec/controllers/message_train/conversations_controller_spec.rb +3 -3
- data/spec/controllers/message_train/messages_controller_spec.rb +60 -27
- data/spec/controllers/message_train/participants_controller_spec.rb +41 -6
- data/spec/controllers/message_train/unsubscribes_controller_spec.rb +56 -0
- data/spec/dummy/app/assets/files/message_train/attachments/{1917-Boys_Race_Above-Wiki.jpg → image-sample.jpg} +0 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/models/group.rb +16 -1
- data/spec/dummy/app/models/role.rb +22 -0
- data/spec/dummy/app/models/user.rb +1 -1
- data/spec/dummy/app/views/layouts/_top_navigation.html.haml +4 -2
- data/spec/dummy/app/views/layouts/application.html.haml +2 -3
- data/spec/dummy/app/views/pages/index.html.haml +4 -0
- data/spec/dummy/config/application.rb +6 -0
- data/spec/dummy/config/environments/development.rb +1 -0
- data/spec/dummy/config/environments/test.rb +1 -0
- data/spec/dummy/config/initializers/high_voltage.rb +3 -0
- data/spec/dummy/config/initializers/message_train.rb +6 -1
- data/spec/dummy/config/initializers/paperclip.rb +2 -2
- data/spec/dummy/config/routes.rb +2 -2
- data/spec/dummy/config/settings.yml +9 -0
- data/spec/dummy/db/migrate/{20150724142846_create_message_train_conversations.night_train.rb → 20150901183629_create_message_train_conversations.message_train.rb} +0 -0
- data/spec/dummy/db/migrate/{20150724142847_create_message_train_messages.night_train.rb → 20150901183630_create_message_train_messages.message_train.rb} +0 -0
- data/spec/dummy/db/migrate/{20150724142848_create_message_train_attachments.night_train.rb → 20150901183631_create_message_train_attachments.message_train.rb} +0 -0
- data/spec/dummy/db/migrate/{20150724142849_create_message_train_receipts.night_train.rb → 20150901183632_create_message_train_receipts.message_train.rb} +0 -0
- data/spec/dummy/db/migrate/{20150724142850_create_message_train_ignores.night_train.rb → 20150901183633_create_message_train_ignores.message_train.rb} +0 -0
- data/spec/dummy/db/migrate/20150901183634_add_received_through_to_message_train_receipts.message_train.rb +7 -0
- data/spec/dummy/db/migrate/20151004184519_add_unique_index_to_receipts.message_train.rb +6 -0
- data/spec/dummy/db/migrate/20151124001417_create_message_train_unsubscribes.message_train.rb +15 -0
- data/spec/dummy/db/schema.rb +24 -7
- data/spec/dummy/db/seeds/conversations.seeds.rb +92 -3
- data/spec/dummy/db/seeds/groups.seeds.rb +27 -0
- data/spec/dummy/db/seeds/test/attachments.seeds.rb +4 -0
- data/spec/dummy/db/seeds/unsubscribes.seeds.rb +12 -0
- data/spec/dummy/db/seeds/users.seeds.rb +27 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/factories/group.rb +4 -4
- data/spec/factories/message.rb +10 -3
- data/spec/features/boxes_spec.rb +160 -33
- data/spec/features/conversations_spec.rb +11 -4
- data/spec/features/messages_spec.rb +20 -6
- data/spec/features/unsubscribes_spec.rb +38 -0
- data/spec/helpers/message_train/application_helper_spec.rb +60 -0
- data/spec/helpers/message_train/attachment_helper_spec.rb +35 -0
- data/spec/helpers/message_train/boxes_helper_spec.rb +11 -5
- data/spec/helpers/message_train/collectives_helper_spec.rb +76 -0
- data/spec/helpers/message_train/conversations_helper_spec.rb +295 -0
- data/spec/helpers/message_train/messages_helper_spec.rb +217 -0
- data/spec/models/group_spec.rb +112 -2
- data/spec/models/message_train/attachment_spec.rb +44 -1
- data/spec/models/message_train/box_spec.rb +306 -51
- data/spec/models/message_train/conversation_spec.rb +84 -6
- data/spec/models/message_train/ignore_spec.rb +0 -4
- data/spec/models/message_train/message_spec.rb +49 -12
- data/spec/models/message_train/receipt_spec.rb +44 -8
- data/spec/models/message_train/unsubscribe_spec.rb +16 -0
- data/spec/models/role_spec.rb +125 -0
- data/spec/models/user_spec.rb +155 -26
- data/spec/rails_helper.rb +8 -1
- data/spec/support/attachments.rb +4 -0
- data/spec/support/controller_behaviors.rb +28 -0
- data/spec/support/conversations.rb +13 -0
- data/spec/support/groups.rb +3 -0
- data/spec/support/loaded_site.rb +3 -0
- data/spec/support/messages.rb +23 -0
- data/spec/support/roles.rb +4 -0
- data/spec/support/users.rb +6 -0
- data/spec/support/wysihtml5_helper.rb +8 -0
- metadata +99 -12
- data/spec/dummy/app/assets/files/message_train/attachments/Haie_rci.svg +0 -1714
- data/spec/dummy/public/capybara.html +0 -193
@@ -3,40 +3,26 @@ module MessageTrain
|
|
3
3
|
has_many :messages
|
4
4
|
has_many :ignores
|
5
5
|
has_many :receipts, through: :messages
|
6
|
+
has_many :attachments, through: :messages
|
6
7
|
|
7
8
|
# Scopes
|
8
|
-
default_scope { order(
|
9
|
-
scope :ignored, ->(participant) { where(
|
10
|
-
scope :unignored, ->(participant) {
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
where('NOT(id IN (?))', ignored_ids)
|
16
|
-
end
|
17
|
-
}
|
18
|
-
scope :filter_by_receipt_method_ids, ->(receipt_method, participant) {
|
19
|
-
all.collect { |x| x.receipts.send(receipt_method, participant).conversation_ids }.flatten.uniq
|
20
|
-
}
|
21
|
-
scope :filter_by_receipt_method, ->(receipt_method, participant) {
|
22
|
-
where('id IN (?)', filter_by_receipt_method_ids(receipt_method, participant))
|
23
|
-
}
|
24
|
-
scope :with_drafts_by, ->(participant) {
|
25
|
-
ids_with_drafts = all.collect { |x| x.messages.drafts.by(participant).conversation_ids }.flatten.uniq
|
26
|
-
where('id IN (?)', ids_with_drafts)
|
27
|
-
}
|
28
|
-
scope :with_ready_for, ->(participant) {
|
29
|
-
ids_with_ready = all.collect { |x| x.messages.ready.with_receipts_for(participant).conversation_ids }.flatten.uniq
|
30
|
-
where('id IN (?)', ids_with_ready)
|
31
|
-
}
|
9
|
+
default_scope { order(updated_at: :desc) }
|
10
|
+
scope :ignored, ->(participant) { where(id: ignored_ids_for(participant))}
|
11
|
+
scope :unignored, ->(participant) { where.not(id: ignored_ids_for(participant)) }
|
12
|
+
scope :with_drafts_by, ->(participant) { joins(:messages).where(message_train_messages: { id: messages.drafts.with_receipts_by(participant) }) }
|
13
|
+
scope :with_ready_for, ->(participant) { joins(:messages).where(message_train_messages: { id: messages.ready.with_receipts_for(participant) }) }
|
14
|
+
scope :with_messages_for, ->(participant) { joins(:messages).where(message_train_messages: { id: messages.with_receipts_for(participant) }) }
|
15
|
+
scope :with_messages_through, ->(participant) { joins(:messages).where(message_train_messages: { id: messages.with_receipts_through(participant) }) }
|
32
16
|
|
33
17
|
def default_recipients_for(sender)
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
18
|
+
default_recipients = []
|
19
|
+
messages.with_receipts_for(sender).each do |conversation|
|
20
|
+
conversation.receipts.each do |receipt|
|
21
|
+
default_recipients << receipt.recipient
|
22
|
+
end
|
23
|
+
end
|
24
|
+
default_recipients.delete(sender)
|
25
|
+
default_recipients.flatten.uniq
|
40
26
|
end
|
41
27
|
|
42
28
|
def set_ignored(participant)
|
@@ -56,17 +42,30 @@ module MessageTrain
|
|
56
42
|
end
|
57
43
|
|
58
44
|
def mark(mark, participant)
|
45
|
+
# # This fixed a bug that only Travis seemed to pick up, but it's code smell.
|
46
|
+
# if messages.nil?
|
47
|
+
# return false
|
48
|
+
# end
|
59
49
|
messages.mark(mark, participant)
|
60
50
|
end
|
61
51
|
|
62
|
-
def
|
63
|
-
|
52
|
+
def self.messages
|
53
|
+
MessageTrain::Message.joins(:conversation).where(conversation: where(nil))
|
64
54
|
end
|
65
55
|
|
66
56
|
def method_missing(method_sym, *arguments, &block)
|
67
57
|
# the first argument is a Symbol, so you need to_s it if you want to pattern match
|
68
|
-
if method_sym.to_s =~ /^includes_(.*_(by|to|for))\?$/
|
69
|
-
|
58
|
+
if method_sym.to_s =~ /^includes_((.*)_(by|to|for|through))\?$/
|
59
|
+
case $2
|
60
|
+
when 'ready', 'drafts'
|
61
|
+
if $3 == 'by'
|
62
|
+
!messages.send($2).by(arguments.first).empty?
|
63
|
+
else
|
64
|
+
!messages.send($2).receipts.send("receipts_#{$3}".to_sym, arguments.first).empty?
|
65
|
+
end
|
66
|
+
else
|
67
|
+
!receipts.send($1.to_sym, arguments.first).empty?
|
68
|
+
end
|
70
69
|
else
|
71
70
|
super
|
72
71
|
end
|
@@ -74,8 +73,15 @@ module MessageTrain
|
|
74
73
|
|
75
74
|
def self.method_missing(method_sym, *arguments, &block)
|
76
75
|
# the first argument is a Symbol, so you need to_s it if you want to pattern match
|
77
|
-
if method_sym.to_s =~ /^with_((.*)_(by|to|for))$/
|
78
|
-
|
76
|
+
if method_sym.to_s =~ /^with_((.*)_(by|to|for|through))$/
|
77
|
+
case $2
|
78
|
+
when 'ready', 'drafts'
|
79
|
+
self.messages.send($2).filter_by_receipt_method("receipts_#{$3}".to_sym, arguments.first).conversations
|
80
|
+
when 'messages'
|
81
|
+
self.messages.filter_by_receipt_method("receipts_#{$3}".to_sym, arguments.first).conversations
|
82
|
+
else
|
83
|
+
self.filter_by_receipt_method($1.to_sym, arguments.first)
|
84
|
+
end
|
79
85
|
else
|
80
86
|
super
|
81
87
|
end
|
@@ -84,7 +90,7 @@ module MessageTrain
|
|
84
90
|
# It's important to know Object defines respond_to to take two parameters: the method to check, and whether to include private methods
|
85
91
|
# http://www.ruby-doc.org/core/classes/Object.html#M000333
|
86
92
|
def respond_to?(method_sym, include_private = false)
|
87
|
-
if method_sym.to_s =~ /^includes_((.*)_(by|to|for))\?$/
|
93
|
+
if method_sym.to_s =~ /^includes_((.*)_(by|to|for|through))\?$/
|
88
94
|
true
|
89
95
|
else
|
90
96
|
super
|
@@ -92,7 +98,7 @@ module MessageTrain
|
|
92
98
|
end
|
93
99
|
|
94
100
|
def self.respond_to?(method_sym, include_private = false)
|
95
|
-
if method_sym.to_s =~ /^(.*)_(by|to|for)$/
|
101
|
+
if method_sym.to_s =~ /^with_(.*)_(by|to|for|through)$/
|
96
102
|
true
|
97
103
|
else
|
98
104
|
super
|
@@ -100,9 +106,12 @@ module MessageTrain
|
|
100
106
|
end
|
101
107
|
|
102
108
|
private
|
109
|
+
scope :filter_by_receipt_method, ->(receipt_method, participant) {
|
110
|
+
where(id: where(nil).messages.receipts.send(receipt_method, participant).conversation_ids)
|
111
|
+
}
|
103
112
|
|
104
113
|
def self.ignored_ids_for(participant)
|
105
|
-
MessageTrain::Ignore.find_all_by_participant(participant).
|
114
|
+
MessageTrain::Ignore.find_all_by_participant(participant).pluck(:conversation_id)
|
106
115
|
end
|
107
116
|
end
|
108
117
|
end
|
@@ -5,14 +5,10 @@ module MessageTrain
|
|
5
5
|
|
6
6
|
validates_presence_of :conversation, :participant
|
7
7
|
|
8
|
-
scope :find_all_by_participant, ->(participant) { where(
|
9
|
-
|
10
|
-
def self.conversation_ids
|
11
|
-
all.collect { |y| y.conversation_id }
|
12
|
-
end
|
8
|
+
scope :find_all_by_participant, ->(participant) { where(participant: participant) }
|
13
9
|
|
14
10
|
def self.conversations
|
15
|
-
MessageTrain::Conversation.where(
|
11
|
+
MessageTrain::Conversation.joins(:ignores).where(message_train_ignores: { id: where(nil) })
|
16
12
|
end
|
17
13
|
end
|
18
14
|
end
|
@@ -18,20 +18,14 @@ module MessageTrain
|
|
18
18
|
after_save :generate_receipts_or_set_draft
|
19
19
|
after_save :set_conversation_subject_if_alone
|
20
20
|
|
21
|
+
# Nested Attributes
|
22
|
+
accepts_nested_attributes_for :attachments, reject_if: :all_blank, allow_destroy: true
|
23
|
+
|
21
24
|
# Scopes
|
22
|
-
default_scope { order(
|
23
|
-
scope :
|
24
|
-
|
25
|
-
}
|
26
|
-
scope :filter_by_receipt_method, ->(receipt_method, participant) {
|
27
|
-
where('id IN (?)', filter_by_receipt_method_ids(receipt_method, participant))
|
28
|
-
}
|
29
|
-
scope :filter_out_by_receipt_method, ->(receipt_method, participant) {
|
30
|
-
where('NOT(id IN (?))', filter_by_receipt_method_ids(receipt_method, participant))
|
31
|
-
}
|
32
|
-
scope :ready, -> { where('draft = ?', false) }
|
33
|
-
scope :drafts, -> { where('draft = ?', true) }
|
34
|
-
scope :by, ->(participant) { where('sender_type = ? AND sender_id = ?', participant.class.name, participant.id) }
|
25
|
+
default_scope { order(updated_at: :desc) }
|
26
|
+
scope :ready, -> { where(draft: false) }
|
27
|
+
scope :drafts, -> { where(draft: true) }
|
28
|
+
scope :by, ->(participant) { where(sender: participant) }
|
35
29
|
scope :drafts_by, ->(participant) { drafts.by(participant) }
|
36
30
|
|
37
31
|
def mark(mark_to_set, participant)
|
@@ -42,26 +36,34 @@ module MessageTrain
|
|
42
36
|
end
|
43
37
|
|
44
38
|
def self.mark(mark_to_set, participant)
|
45
|
-
|
39
|
+
where(nil).each do |message|
|
46
40
|
message.mark(mark_to_set, participant)
|
47
41
|
end
|
48
42
|
end
|
49
43
|
|
50
44
|
def recipients
|
51
|
-
|
45
|
+
recips = []
|
46
|
+
receipts.recipient_receipt.each do |message|
|
47
|
+
recips << message.received_through
|
48
|
+
end
|
49
|
+
recips.uniq
|
52
50
|
end
|
53
51
|
|
54
52
|
def self.conversation_ids
|
55
|
-
|
53
|
+
pluck(:conversation_id)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.receipts
|
57
|
+
MessageTrain::Receipt.joins(:message).where(message_train_messages: { id: where(nil) })
|
56
58
|
end
|
57
59
|
|
58
60
|
def self.conversations
|
59
|
-
MessageTrain::Conversation.where(
|
61
|
+
MessageTrain::Conversation.joins(:messages).where(message_train_messages: { id: where(nil) })
|
60
62
|
end
|
61
63
|
|
62
64
|
def method_missing(method_sym, *arguments, &block)
|
63
65
|
# the first argument is a Symbol, so you need to_s it if you want to pattern match
|
64
|
-
if method_sym.to_s =~ /^is_((.*)_(by|to|for))\?$/
|
66
|
+
if method_sym.to_s =~ /^is_((.*)_(by|to|for|through))\?$/
|
65
67
|
!receipts.send($1.to_sym, arguments.first).empty?
|
66
68
|
elsif method_sym.to_s =~ /^mark_(.*)_for$/
|
67
69
|
receipts.for(arguments.first).first.mark($1.to_sym)
|
@@ -72,7 +74,7 @@ module MessageTrain
|
|
72
74
|
|
73
75
|
def self.method_missing(method_sym, *arguments, &block)
|
74
76
|
# the first argument is a Symbol, so you need to_s it if you want to pattern match
|
75
|
-
if method_sym.to_s =~ /^with_(.*_(by|to|for))$/
|
77
|
+
if method_sym.to_s =~ /^with_(.*_(by|to|for|through))$/
|
76
78
|
filter_by_receipt_method($1.to_sym, arguments.first)
|
77
79
|
else
|
78
80
|
super
|
@@ -82,7 +84,7 @@ module MessageTrain
|
|
82
84
|
# It's important to know Object defines respond_to to take two parameters: the method to check, and whether to include private methods
|
83
85
|
# http://www.ruby-doc.org/core/classes/Object.html#M000333
|
84
86
|
def respond_to?(method_sym, include_private = false)
|
85
|
-
if method_sym.to_s =~ /^is_.*_(by|to|for)\?$/ || method_sym.to_s =~ /^mark_.*_for\?$/
|
87
|
+
if method_sym.to_s =~ /^is_.*_(by|to|for|through)\?$/ || method_sym.to_s =~ /^mark_.*_for\?$/
|
86
88
|
true
|
87
89
|
else
|
88
90
|
super
|
@@ -90,7 +92,7 @@ module MessageTrain
|
|
90
92
|
end
|
91
93
|
|
92
94
|
def self.respond_to?(method_sym, include_private = false)
|
93
|
-
if method_sym.to_s =~ /^.*_(by|to|for)$/
|
95
|
+
if method_sym.to_s =~ /^.*_(by|to|for|through)$/
|
94
96
|
true
|
95
97
|
else
|
96
98
|
super
|
@@ -98,6 +100,11 @@ module MessageTrain
|
|
98
100
|
end
|
99
101
|
|
100
102
|
private
|
103
|
+
|
104
|
+
scope :filter_by_receipt_method, ->(receipt_method, participant) {
|
105
|
+
where(id: where(nil).receipts.send(receipt_method, participant).message_ids)
|
106
|
+
}
|
107
|
+
|
101
108
|
def create_conversation_if_blank
|
102
109
|
if conversation.nil?
|
103
110
|
self.conversation = Conversation.create(subject: subject)
|
@@ -105,7 +112,7 @@ module MessageTrain
|
|
105
112
|
end
|
106
113
|
|
107
114
|
def generate_sender_receipt
|
108
|
-
receipts.first_or_create!(
|
115
|
+
receipts.first_or_create!(recipient: sender, received_through: sender, sender: true)
|
109
116
|
end
|
110
117
|
|
111
118
|
def generate_receipts_or_set_draft
|
@@ -119,8 +126,17 @@ module MessageTrain
|
|
119
126
|
slug_column = MessageTrain.configuration.slug_columns[table.to_sym] || :slug
|
120
127
|
if model.exists?(slug_column => slug)
|
121
128
|
recipient = model.find_by(slug_column => slug)
|
122
|
-
|
123
|
-
|
129
|
+
end_recipient_method = MessageTrain.configuration.valid_recipients_methods[table.to_sym]
|
130
|
+
if end_recipient_method.nil?
|
131
|
+
unless conversation.is_ignored?(recipient)
|
132
|
+
receipts.create!(recipient: recipient, received_through: recipient)
|
133
|
+
end
|
134
|
+
else
|
135
|
+
recipient.send(end_recipient_method).uniq.each do |end_recipient|
|
136
|
+
unless conversation.is_ignored?(end_recipient) || end_recipient == sender
|
137
|
+
receipts.create!(recipient: end_recipient, received_through: recipient)
|
138
|
+
end
|
139
|
+
end
|
124
140
|
end
|
125
141
|
else
|
126
142
|
errors.add :recipients_to_save, :name_not_found.l(name: slug)
|
@@ -1,19 +1,23 @@
|
|
1
1
|
module MessageTrain
|
2
2
|
class Receipt < ActiveRecord::Base
|
3
3
|
belongs_to :recipient, polymorphic: true
|
4
|
+
belongs_to :received_through, polymorphic: true
|
4
5
|
belongs_to :message
|
5
6
|
validates_presence_of :recipient, :message
|
6
7
|
|
7
|
-
default_scope { order(
|
8
|
+
default_scope { order(updated_at: :desc) }
|
8
9
|
scope :sender_receipt, -> { where('sender = ?', true) }
|
9
10
|
scope :recipient_receipt, -> { where('sender = ?', false) }
|
10
11
|
scope :by, ->(sender) { sender_receipt.for(sender) }
|
11
12
|
scope :for, ->(recipient) { where('recipient_type = ? AND recipient_id = ?', recipient.class.name, recipient.id) }
|
12
13
|
scope :to, ->(recipient) { recipient_receipt.for(recipient) }
|
14
|
+
scope :through, ->(received_through) { where('received_through_type = ? AND received_through_id = ?', received_through.class.name, received_through.id) }
|
13
15
|
scope :trashed, ->(setting = true) { where('marked_trash = ?', setting) }
|
14
16
|
scope :read, ->(setting = true) { where('marked_read = ?', setting) }
|
15
17
|
scope :deleted, ->(setting = true) { where('marked_deleted = ?', setting) }
|
16
18
|
|
19
|
+
after_create :notify
|
20
|
+
|
17
21
|
def mark(mark_to_set)
|
18
22
|
if mark_to_set.to_s =~ /^un/
|
19
23
|
setting = false
|
@@ -27,29 +31,27 @@ module MessageTrain
|
|
27
31
|
end
|
28
32
|
|
29
33
|
def self.message_ids
|
30
|
-
|
34
|
+
pluck(:message_id)
|
31
35
|
end
|
32
36
|
|
33
37
|
def self.messages
|
34
|
-
MessageTrain::Message.where(
|
38
|
+
MessageTrain::Message.joins(:receipts).where(message_train_receipts: { id: where(nil) })
|
35
39
|
end
|
36
40
|
|
37
41
|
def self.conversation_ids
|
38
|
-
|
42
|
+
messages.conversation_ids
|
39
43
|
end
|
40
44
|
|
41
45
|
def self.conversations
|
42
|
-
MessageTrain::Conversation.where(
|
46
|
+
MessageTrain::Conversation.joins(:receipts).where(message_train_receipts: { id: where(nil) })
|
43
47
|
end
|
44
48
|
|
45
49
|
def self.method_missing(method_sym, *arguments, &block)
|
46
50
|
# the first argument is a Symbol, so you need to_s it if you want to pattern match
|
47
|
-
if method_sym.to_s =~ /^receipts_(by|to|for)$/
|
51
|
+
if method_sym.to_s =~ /^receipts_(by|to|for|through)$/
|
48
52
|
send($1.to_sym, arguments.first)
|
49
|
-
elsif method_sym.to_s =~ /^(.*)_(by|to|for)$/
|
53
|
+
elsif method_sym.to_s =~ /^(.*)_(by|to|for|through)$/
|
50
54
|
send($1.to_sym).send($2.to_sym, arguments.first)
|
51
|
-
elsif method_sym.to_s =~ /^mark_(.*)$/
|
52
|
-
mark($1.to_sym)
|
53
55
|
elsif method_sym.to_s =~ /^un(.*)$/
|
54
56
|
send($1.to_sym, false)
|
55
57
|
else
|
@@ -60,11 +62,19 @@ module MessageTrain
|
|
60
62
|
# It's important to know Object defines respond_to to take two parameters: the method to check, and whether to include private methods
|
61
63
|
# http://www.ruby-doc.org/core/classes/Object.html#M000333
|
62
64
|
def self.respond_to?(method_sym, include_private = false)
|
63
|
-
if method_sym.to_s =~ /^(.*)_(by|to|for)$/ || method_sym.to_s =~ /^
|
65
|
+
if method_sym.to_s =~ /^(.*)_(by|to|for|through)$/ || method_sym.to_s =~ /^un(.*)$/
|
64
66
|
true
|
65
67
|
else
|
66
68
|
super
|
67
69
|
end
|
68
70
|
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def notify
|
75
|
+
unless sender? or recipient.unsubscribed_from?(received_through)
|
76
|
+
ReceiptMailer.notification_email(self).deliver_later
|
77
|
+
end
|
78
|
+
end
|
69
79
|
end
|
70
80
|
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
.nested-fields.panel.panel-default
|
2
|
+
.panel-body
|
3
|
+
= link_to_remove_association '×'.html_safe, f, title: :remove_attachment.l, class: 'close', data: { confirm: :are_you_sure.l }
|
4
|
+
- if f.object.attachment.exists?
|
5
|
+
.attachment
|
6
|
+
= attachment_link(f.object)
|
7
|
+
= f.file_field :attachment
|
@@ -0,0 +1,4 @@
|
|
1
|
+
- if attachment.image?
|
2
|
+
= link_to attachment_icon(attachment), '#', class: 'thumbnail', data: { toggle: 'modal', target: '#attachment_preview', src: attachment.attachment.url(:large), original: attachment.attachment.url, text: :click_for_original.l }
|
3
|
+
- else
|
4
|
+
= link_to attachment_icon(attachment), attachment.attachment.url, class: 'thumbnail'
|
@@ -3,4 +3,7 @@
|
|
3
3
|
.text-center= link_to :compose.l, message_train.new_box_message_path(:in), class: 'btn btn-lg btn-primary btn-compose'
|
4
4
|
%ul.list-group
|
5
5
|
- boxes.each do |box|
|
6
|
-
|
6
|
+
- if @collective.nil?
|
7
|
+
= box_list_item box, class: 'list-group-item'
|
8
|
+
- else
|
9
|
+
= collective_list_item box, class: 'list-group-item'
|
@@ -1,5 +1,10 @@
|
|
1
|
-
-
|
2
|
-
|
1
|
+
- if @collective.nil?
|
2
|
+
- add_title @box.title
|
3
|
+
- marking_path = message_train.box_path(@box.division)
|
4
|
+
- else
|
5
|
+
- add_title collective_name(@collective) + ' ' + @box.title
|
6
|
+
- marking_path = message_train.collective_box_path(@collective.path_part, @box.division)
|
7
|
+
= form_tag marking_path, method: :put, remote: true, id: 'box', data: { type: :json } do
|
3
8
|
- unless @conversations.empty?
|
4
9
|
#box-actions
|
5
10
|
.btn-group.check-all
|
@@ -39,9 +44,12 @@
|
|
39
44
|
- else
|
40
45
|
%li
|
41
46
|
= link_to :mark_as_name.l(name: :ignored.l), '#0', class: 'mark', id: 'mark-ignored', data: { mark: 'ignore'}
|
42
|
-
|
47
|
+
- if @collective.nil?
|
48
|
+
= link_to :compose.l, message_train.new_box_message_path(@box.division), class: 'btn btn-primary compose'
|
49
|
+
- elsif @collective.allows_sending_by? @box_user
|
50
|
+
= link_to :compose_to_collective.l(collective: collective_name(@collective)), message_train.new_collective_box_message_path(@collective.path_part, @box.division), class: 'btn btn-primary compose'
|
43
51
|
%span#spinner.hide= icon 'refresh spinning'
|
44
52
|
= hidden_field_tag :mark_to_set
|
45
53
|
%table#message_train_conversations.table.table-condensed
|
46
54
|
= render @conversations
|
47
|
-
= paginate @conversations
|
55
|
+
= paginate @conversations
|
@@ -0,0 +1,7 @@
|
|
1
|
+
- unless collective.boxes_for_participant(box_user).empty?
|
2
|
+
%h3= :collective_messages.l(collective: collective_name(collective))
|
3
|
+
- if collective.allows_sending_by?(box_user)
|
4
|
+
.text-center= link_to :compose_to_collective.l(collective: collective_name(collective)), message_train.new_collective_box_message_path(collective.path_part, :sent), class: 'btn btn-lg btn-primary btn-compose'
|
5
|
+
%ul.list-group
|
6
|
+
- collective.boxes_for_participant(box_user).each do |box|
|
7
|
+
= collective_list_item box, class: 'list-group-item'
|
@@ -1,9 +1,24 @@
|
|
1
1
|
%tr.message_train_conversation{ class: conversation_class(@box, conversation), id: 'message_train_conversation_' + conversation.id.to_s }
|
2
2
|
%td.col-xs-1= check_box_tag "objects[conversations][#{conversation.id.to_s}]", conversation.id
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
3
|
+
- if @collective.nil?
|
4
|
+
%td.col-xs-2= link_to conversation_senders(conversation), message_train.box_conversation_path(@box.division, conversation)
|
5
|
+
%td.col-xs-8= link_to conversation.subject, message_train.box_conversation_path(@box.division, conversation)
|
6
|
+
%td
|
7
|
+
- if conversation.attachments.any?
|
8
|
+
= icon 'paperclip'
|
9
|
+
%td.col-xs-1.conversation-actions
|
10
|
+
= conversation_trashed_toggle conversation
|
11
|
+
- if @box.division == :trash
|
12
|
+
= conversation_deleted_toggle conversation
|
13
|
+
%td.col-xs-1.date-column= fuzzy_date(conversation.updated_at)
|
14
|
+
- else
|
15
|
+
%td.col-xs-2= link_to conversation_senders(conversation), message_train.collective_box_conversation_path(@collective.path_part, @box.division, conversation)
|
16
|
+
%td.col-xs-8= link_to conversation.subject, message_train.collective_box_conversation_path(@collective.path_part, @box.division, conversation)
|
17
|
+
%td
|
18
|
+
- if conversation.attachments.any?
|
19
|
+
= icon 'paperclip'
|
20
|
+
%td.col-xs-1.conversation-actions
|
21
|
+
= conversation_trashed_toggle conversation, @collective
|
22
|
+
- if @box.division == :trash
|
23
|
+
= conversation_deleted_toggle conversation, @collective
|
24
|
+
%td.col-xs-1.date-column= fuzzy_date(conversation.updated_at)
|
@@ -1 +1 @@
|
|
1
|
-
= conversation_toggle conversation, 'remove', :deleted, :put, :mark_as_name.l(name: :deleted.l), data: { confirm: :delete_forever_this_cannot_be_undone.l }
|
1
|
+
= conversation_toggle conversation, 'remove', :deleted, :put, :mark_as_name.l(name: :deleted.l), data: { confirm: :delete_forever_this_cannot_be_undone.l }, collective: collective
|
@@ -1,4 +1,4 @@
|
|
1
|
-
- if conversation.is_ignored?(@
|
2
|
-
= conversation_toggle conversation, 'volume-up', :unignore, :delete, :mark_as_name.l(name: :unignored.l)
|
1
|
+
- if conversation.is_ignored?(@box_user)
|
2
|
+
= conversation_toggle conversation, 'volume-up', :unignore, :delete, :mark_as_name.l(name: :unignored.l), collective: collective
|
3
3
|
- else
|
4
|
-
= conversation_toggle conversation, 'volume-off', :ignore, :delete, :mark_as_name.l(name: :ignored.l), data: { confirm: :are_you_sure.l}
|
4
|
+
= conversation_toggle conversation, 'volume-off', :ignore, :delete, :mark_as_name.l(name: :ignored.l), data: { confirm: :are_you_sure.l}, collective: collective
|
@@ -1,4 +1,4 @@
|
|
1
|
-
- if conversation.includes_unread_for?(@
|
2
|
-
= conversation_toggle conversation, 'eye-open', :read, :put, :mark_as_name.l(name: :read.l)
|
1
|
+
- if conversation.includes_unread_for?(@box_user)
|
2
|
+
= conversation_toggle conversation, 'eye-open', :read, :put, :mark_as_name.l(name: :read.l), collective: collective
|
3
3
|
- else
|
4
|
-
= conversation_toggle conversation, 'eye-close', :unread, :put, :mark_as_name.l(name: :unread.l)
|
4
|
+
= conversation_toggle conversation, 'eye-close', :unread, :put, :mark_as_name.l(name: :unread.l), collective: collective
|
@@ -1 +1,4 @@
|
|
1
|
-
|
1
|
+
- if options[:collective].nil?
|
2
|
+
= icon_link_to icon, '', message_train.box_path(@box.division, objects: { 'conversations' => {conversation.id.to_s => conversation.id.to_s}}, mark_to_set: mark_to_set, format: :json), options
|
3
|
+
- else
|
4
|
+
= icon_link_to icon, '', message_train.collective_box_path(options[:collective].path_part, @box.division, objects: { 'conversations' => {conversation.id.to_s => conversation.id.to_s}}, mark_to_set: mark_to_set, format: :json), options
|
@@ -1,4 +1,4 @@
|
|
1
|
-
- if conversation.includes_untrashed_for?(@
|
2
|
-
= conversation_toggle conversation, 'trash', :trash, :put, :mark_as_name.l(name: :trashed.l), data: { confirm: :are_you_sure.l}
|
1
|
+
- if conversation.includes_untrashed_for?(@box_user)
|
2
|
+
= conversation_toggle conversation, 'trash', :trash, :put, :mark_as_name.l(name: :trashed.l), data: { confirm: :are_you_sure.l}, collective: collective
|
3
3
|
- else
|
4
|
-
= conversation_toggle conversation, 'inbox', :untrash, :put, :mark_as_name.l(name: :untrashed.l)
|
4
|
+
= conversation_toggle conversation, 'inbox', :untrash, :put, :mark_as_name.l(name: :untrashed.l), collective: collective
|
@@ -1,6 +1,5 @@
|
|
1
1
|
- add_title @conversation.subject
|
2
|
-
- add_subtitle :
|
3
|
-
|
2
|
+
- add_subtitle :updated_at_time.l(time: @conversation.updated_at)
|
4
3
|
#box
|
5
4
|
#conversation-actions.pull-right
|
6
5
|
.btn.btn-default.btn-lg= conversation_ignored_toggle(@conversation)
|
@@ -8,4 +7,6 @@
|
|
8
7
|
- unless @messages.empty?
|
9
8
|
#message_train_messages.messages.panel-group{aria: { multiselectable: 'true' }, role: "tablist"}
|
10
9
|
= render @messages
|
11
|
-
= paginate @messages
|
10
|
+
= paginate @messages
|
11
|
+
= modal 'attachment_preview', :attachment_preview.l do
|
12
|
+
#image_placeholder
|
@@ -1 +1 @@
|
|
1
|
-
= message_toggle message, 'remove', :deleted, :mark_as_name.l(name: :deleted.l)
|
1
|
+
= message_toggle message, 'remove', :deleted, :mark_as_name.l(name: :deleted.l), data: { confirm: :delete_forever_this_cannot_be_undone.l }
|
@@ -1,8 +1,23 @@
|
|
1
|
-
-
|
1
|
+
- if @collective.nil?
|
2
|
+
- resource = message.new_record? ? message_train.box_messages_path(@box) : message_train.box_message_path(@box, message)
|
3
|
+
- else
|
4
|
+
- resource = message.new_record? ? message_train.collective_box_messages_path(@collective.path_part, @box) : message_train.collective_box_message_path(@collective.path_part, @box, message)
|
2
5
|
= bootstrap_form_for message, url: resource do |f|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
.row
|
7
|
+
.col-md-8
|
8
|
+
- if @collective.nil?
|
9
|
+
= render partial: 'message_train/participants/field', locals: { message: message, field_name: :users }
|
10
|
+
- else
|
11
|
+
= render partial: 'message_train/participants/prefilled_field', locals: { message: message, recipient: @collective }
|
12
|
+
= f.text_field :subject
|
13
|
+
= f.text_area :body, class: 'wysiwyg'
|
14
|
+
.col-md-4
|
15
|
+
.links
|
16
|
+
.pull-right= link_to_add_association(icon('plus'), f, :attachments, title: :add_attachment.l, class: 'btn btn-info', id: 'add-attachment', data: { association_insertion_method: 'append', association_insertion_node: '#attachments'})
|
17
|
+
%h3
|
18
|
+
= :attachments.l
|
19
|
+
#attachments
|
20
|
+
= f.fields_for :attachments do |attachment|
|
21
|
+
= render 'attachment_fields', f: attachment
|
22
|
+
= f.submit :save_as_draft.l, name: 'message[draft]'
|
23
|
+
= f.submit :send.l, class: 'btn btn-primary', name: 'message[draft]'
|