message_train 0.1.7 → 0.2.0

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 (144) hide show
  1. checksums.yaml +4 -4
  2. data/.simplecov +8 -0
  3. data/.travis.yml +7 -2
  4. data/Gemfile +3 -0
  5. data/README.rdoc +37 -1
  6. data/Rakefile +5 -6
  7. data/VERSION +1 -1
  8. data/app/assets/javascripts/message_train.js +33 -0
  9. data/app/assets/stylesheets/message_train.scss +26 -0
  10. data/app/controllers/concerns/message_train_support.rb +127 -0
  11. data/app/controllers/message_train/application_controller.rb +1 -60
  12. data/app/controllers/message_train/boxes_controller.rb +0 -4
  13. data/app/controllers/message_train/messages_controller.rb +12 -6
  14. data/app/controllers/message_train/participants_controller.rb +1 -1
  15. data/app/controllers/message_train/unsubscribes_controller.rb +59 -0
  16. data/app/helpers/message_train/application_helper.rb +26 -0
  17. data/app/helpers/message_train/attachments_helper.rb +19 -0
  18. data/app/helpers/message_train/boxes_helper.rb +16 -11
  19. data/app/helpers/message_train/collectives_helper.rb +48 -0
  20. data/app/helpers/message_train/conversations_helper.rb +24 -16
  21. data/app/helpers/message_train/messages_helper.rb +14 -12
  22. data/app/mailers/message_train/application_mailer.rb +8 -0
  23. data/app/mailers/message_train/previews/receipt_mailer_preview.rb +10 -0
  24. data/app/mailers/message_train/receipt_mailer.rb +17 -0
  25. data/app/models/message_train/attachment.rb +28 -10
  26. data/app/models/message_train/box.rb +114 -83
  27. data/app/models/message_train/conversation.rb +48 -39
  28. data/app/models/message_train/ignore.rb +2 -6
  29. data/app/models/message_train/message.rb +40 -24
  30. data/app/models/message_train/receipt.rb +20 -10
  31. data/app/models/message_train/unsubscribe.rb +7 -0
  32. data/app/views/layouts/mailer.html.haml +6 -0
  33. data/app/views/message_train/application/_attachment_fields.html.haml +7 -0
  34. data/app/views/message_train/application/_attachment_link.html.haml +4 -0
  35. data/app/views/message_train/application/_widget.html.haml +6 -0
  36. data/app/views/message_train/boxes/_dropdown_list.html.haml +1 -2
  37. data/app/views/message_train/boxes/_list_item.html.haml +2 -2
  38. data/app/views/message_train/boxes/_widget.html.haml +4 -1
  39. data/app/views/message_train/boxes/show.html.haml +12 -4
  40. data/app/views/message_train/collectives/_dropdown_list.html.haml +6 -0
  41. data/app/views/message_train/collectives/_list_item.html.haml +5 -0
  42. data/app/views/message_train/collectives/_widget.html.haml +7 -0
  43. data/app/views/message_train/conversations/_conversation.html.haml +22 -7
  44. data/app/views/message_train/conversations/_deleted_toggle.html.haml +1 -1
  45. data/app/views/message_train/conversations/_ignored_toggle.html.haml +3 -3
  46. data/app/views/message_train/conversations/_read_toggle.html.haml +3 -3
  47. data/app/views/message_train/conversations/_toggle.html.haml +4 -1
  48. data/app/views/message_train/conversations/_trashed_toggle.html.haml +3 -3
  49. data/app/views/message_train/conversations/show.html.haml +4 -3
  50. data/app/views/message_train/messages/_deleted_toggle.html.haml +1 -1
  51. data/app/views/message_train/messages/_form.html.haml +22 -7
  52. data/app/views/message_train/messages/_message.html.haml +14 -4
  53. data/app/views/message_train/messages/_read_toggle.html.haml +1 -1
  54. data/app/views/message_train/messages/_trashed_toggle.html.haml +1 -1
  55. data/app/views/message_train/messages/edit.html.haml +1 -1
  56. data/app/views/message_train/messages/new.html.haml +4 -1
  57. data/app/views/message_train/participants/_field.html.haml +1 -1
  58. data/app/views/message_train/participants/_prefilled_field.html.haml +4 -0
  59. data/app/views/message_train/receipt_mailer/notification_email.html.haml +13 -0
  60. data/app/views/message_train/unsubscribes/index.html.haml +10 -0
  61. data/config/environment.rb +1 -0
  62. data/config/locales/en.yml +49 -7
  63. data/config/routes.rb +10 -2
  64. data/db/migrate/20150901183458_add_received_through_to_message_train_receipts.rb +6 -0
  65. data/db/migrate/20151004184347_add_unique_index_to_receipts.rb +5 -0
  66. data/db/migrate/20151124000820_create_message_train_unsubscribes.rb +14 -0
  67. data/lib/generators/message_train/install/install_generator.rb +8 -2
  68. data/lib/generators/message_train/install/templates/initializer.rb +5 -1
  69. data/lib/message_train/configuration.rb +11 -1
  70. data/lib/message_train/engine.rb +1 -0
  71. data/lib/message_train/mixin.rb +206 -21
  72. data/message_train.gemspec +66 -13
  73. data/spec/controllers/message_train/boxes_controller_spec.rb +10 -3
  74. data/spec/controllers/message_train/concerns_spec.rb +40 -0
  75. data/spec/controllers/message_train/conversations_controller_spec.rb +3 -3
  76. data/spec/controllers/message_train/messages_controller_spec.rb +60 -27
  77. data/spec/controllers/message_train/participants_controller_spec.rb +41 -6
  78. data/spec/controllers/message_train/unsubscribes_controller_spec.rb +56 -0
  79. data/spec/dummy/app/assets/files/message_train/attachments/{1917-Boys_Race_Above-Wiki.jpg → image-sample.jpg} +0 -0
  80. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  81. data/spec/dummy/app/models/group.rb +16 -1
  82. data/spec/dummy/app/models/role.rb +22 -0
  83. data/spec/dummy/app/models/user.rb +1 -1
  84. data/spec/dummy/app/views/layouts/_top_navigation.html.haml +4 -2
  85. data/spec/dummy/app/views/layouts/application.html.haml +2 -3
  86. data/spec/dummy/app/views/pages/index.html.haml +4 -0
  87. data/spec/dummy/config/application.rb +6 -0
  88. data/spec/dummy/config/environments/development.rb +1 -0
  89. data/spec/dummy/config/environments/test.rb +1 -0
  90. data/spec/dummy/config/initializers/high_voltage.rb +3 -0
  91. data/spec/dummy/config/initializers/message_train.rb +6 -1
  92. data/spec/dummy/config/initializers/paperclip.rb +2 -2
  93. data/spec/dummy/config/routes.rb +2 -2
  94. data/spec/dummy/config/settings.yml +9 -0
  95. data/spec/dummy/db/migrate/{20150724142846_create_message_train_conversations.night_train.rb → 20150901183629_create_message_train_conversations.message_train.rb} +0 -0
  96. data/spec/dummy/db/migrate/{20150724142847_create_message_train_messages.night_train.rb → 20150901183630_create_message_train_messages.message_train.rb} +0 -0
  97. data/spec/dummy/db/migrate/{20150724142848_create_message_train_attachments.night_train.rb → 20150901183631_create_message_train_attachments.message_train.rb} +0 -0
  98. data/spec/dummy/db/migrate/{20150724142849_create_message_train_receipts.night_train.rb → 20150901183632_create_message_train_receipts.message_train.rb} +0 -0
  99. data/spec/dummy/db/migrate/{20150724142850_create_message_train_ignores.night_train.rb → 20150901183633_create_message_train_ignores.message_train.rb} +0 -0
  100. data/spec/dummy/db/migrate/20150901183634_add_received_through_to_message_train_receipts.message_train.rb +7 -0
  101. data/spec/dummy/db/migrate/20151004184519_add_unique_index_to_receipts.message_train.rb +6 -0
  102. data/spec/dummy/db/migrate/20151124001417_create_message_train_unsubscribes.message_train.rb +15 -0
  103. data/spec/dummy/db/schema.rb +24 -7
  104. data/spec/dummy/db/seeds/conversations.seeds.rb +92 -3
  105. data/spec/dummy/db/seeds/groups.seeds.rb +27 -0
  106. data/spec/dummy/db/seeds/test/attachments.seeds.rb +4 -0
  107. data/spec/dummy/db/seeds/unsubscribes.seeds.rb +12 -0
  108. data/spec/dummy/db/seeds/users.seeds.rb +27 -0
  109. data/spec/dummy/db/test.sqlite3 +0 -0
  110. data/spec/factories/group.rb +4 -4
  111. data/spec/factories/message.rb +10 -3
  112. data/spec/features/boxes_spec.rb +160 -33
  113. data/spec/features/conversations_spec.rb +11 -4
  114. data/spec/features/messages_spec.rb +20 -6
  115. data/spec/features/unsubscribes_spec.rb +38 -0
  116. data/spec/helpers/message_train/application_helper_spec.rb +60 -0
  117. data/spec/helpers/message_train/attachment_helper_spec.rb +35 -0
  118. data/spec/helpers/message_train/boxes_helper_spec.rb +11 -5
  119. data/spec/helpers/message_train/collectives_helper_spec.rb +76 -0
  120. data/spec/helpers/message_train/conversations_helper_spec.rb +295 -0
  121. data/spec/helpers/message_train/messages_helper_spec.rb +217 -0
  122. data/spec/models/group_spec.rb +112 -2
  123. data/spec/models/message_train/attachment_spec.rb +44 -1
  124. data/spec/models/message_train/box_spec.rb +306 -51
  125. data/spec/models/message_train/conversation_spec.rb +84 -6
  126. data/spec/models/message_train/ignore_spec.rb +0 -4
  127. data/spec/models/message_train/message_spec.rb +49 -12
  128. data/spec/models/message_train/receipt_spec.rb +44 -8
  129. data/spec/models/message_train/unsubscribe_spec.rb +16 -0
  130. data/spec/models/role_spec.rb +125 -0
  131. data/spec/models/user_spec.rb +155 -26
  132. data/spec/rails_helper.rb +8 -1
  133. data/spec/support/attachments.rb +4 -0
  134. data/spec/support/controller_behaviors.rb +28 -0
  135. data/spec/support/conversations.rb +13 -0
  136. data/spec/support/groups.rb +3 -0
  137. data/spec/support/loaded_site.rb +3 -0
  138. data/spec/support/messages.rb +23 -0
  139. data/spec/support/roles.rb +4 -0
  140. data/spec/support/users.rb +6 -0
  141. data/spec/support/wysihtml5_helper.rb +8 -0
  142. metadata +99 -12
  143. data/spec/dummy/app/assets/files/message_train/attachments/Haie_rci.svg +0 -1714
  144. data/spec/dummy/public/capybara.html +0 -193
@@ -10,11 +10,10 @@
10
10
  = link_to "#message_#{message.id}_collapse", aria: { controls: "message_#{message.id}_collapse", expanded: 'true' }, data: { parent: '#accordion', toggle: 'collapse' }, role: "button" do
11
11
  %span.caret
12
12
  = :message_draft.l
13
- %small= message.created_at
13
+ %small= message.updated_at
14
14
  .panel-collapse.collapse.in{aria: { labelledby: "message_#{message.id}_heading" }, role: "tabpanel", id: "message_#{message.id}_collapse"}
15
15
  .panel-body
16
16
  = render partial: 'message_train/messages/form', locals: { message: message }
17
-
18
17
  - else
19
18
  .panel.panel-default{ class: message_class(@box, message), id: "message_train_message_#{message.id}", data: { mark_path: message_train.box_conversation_path(@box.division, id: message.conversation_id, objects: { 'messages' => {message.id.to_s => message.id.to_s} }) } }
20
19
  .panel-heading{role: "tab", id: "message_#{message.id}_heading"}
@@ -27,9 +26,20 @@
27
26
  = link_to "#message_#{message.id}_collapse", aria: { controls: "message_#{message.id}_collapse", expanded: 'true' }, data: { parent: '#accordion', toggle: 'collapse' }, role: "button" do
28
27
  %span.caret
29
28
  = :from_sender.l(sender: message.sender.display_name)
30
- %small= message.created_at
29
+ %small= message.updated_at
31
30
  .panel-collapse.collapse.in{aria: { labelledby: "message_#{message.id}_heading" }, role: "tabpanel", id: "message_#{message.id}_collapse"}
32
31
  .panel-body
33
32
  %p= :to_recipient.l(recipient: message_recipients(message))
34
33
  %p.lead= message.subject
35
- = message.body
34
+ = sanitize message.body
35
+ - if message.attachments.any?
36
+ .row.attachment-thumbnails
37
+ - for attachment in message.attachments
38
+ .col-md-4
39
+ = attachment_link(attachment)
40
+ - if @box.parent.allows_sending_by?(@box_user)
41
+ .panel-footer
42
+ - if @collective.nil?
43
+ = link_to :reply.l, message_train.new_box_message_path(@box, conversation_id: message.conversation_id), class: 'btn btn-primary'
44
+ - else
45
+ = link_to :reply.l, message_train.new_collective_box_message_path(@collective.path_part, @box, conversation_id: message.conversation_id), class: 'btn btn-primary'
@@ -1,4 +1,4 @@
1
- - if message.is_unread_for?(@box.parent)
1
+ - if message.is_unread_for?(@box.participant)
2
2
  = message_toggle message, 'eye-open', :read, :mark_as_name.l(name: :read.l)
3
3
  - else
4
4
  = message_toggle message, 'eye-close', :unread, :mark_as_name.l(name: :unread.l)
@@ -1,4 +1,4 @@
1
- - if message.is_untrashed_for?(@box.parent)
1
+ - if message.is_untrashed_for?(@box.participant)
2
2
  = message_toggle message, 'trash', :trash, :mark_as_name.l(name: :trashed.l), data: { confirm: :are_you_sure.l}
3
3
  - else
4
4
  = message_toggle message, 'inbox', :untrash, :mark_as_name.l(name: :untrashed.l)
@@ -1,2 +1,2 @@
1
- - add_title 'Edit Draft'
1
+ - add_title :edit_draft.l
2
2
  = render partial: 'form', locals: { message: @message }
@@ -1,2 +1,5 @@
1
- - add_title 'New Message'
1
+ - if @message.conversation_id.nil?
2
+ - add_title :new_message.l
3
+ - else
4
+ - add_title :reply.l
2
5
  = render partial: 'form', locals: { message: @message }
@@ -1,4 +1,4 @@
1
1
  .form-group
2
2
  %label.control-label= "#{field_name.to_s.singularize.humanize.titleize} Recipients"
3
3
  .recipient-input.tag-list{ data: { field_name: "message[recipients_to_save][#{field_name}]", model: field_name }, id: "message_recipients_to_save_#{field_name}" }
4
- .tag-data= message.recipients_to_save[field_name]
4
+ .tag-data= message.recipients_to_save[field_name.to_s]
@@ -0,0 +1,4 @@
1
+ - field_name = recipient.class.table_name.to_sym
2
+ %p.lead
3
+ = :to_recipient.l(recipient: collective_name(@collective))
4
+ = hidden_field_tag "message[recipients_to_save][#{field_name}]", collective_slug(recipient)
@@ -0,0 +1,13 @@
1
+ %h1
2
+ = @heading
3
+ - if @recipient == @through
4
+ %p
5
+ = :at_time_you_received_a_message.l(time: @receipt.created_at, subject: @receipt.message.subject, path: message_train.box_conversation_path(:in, @receipt.message.conversation))
6
+ %p{ style: 'font-size: .8rem; color: #666' }
7
+ = :unsubscribe_from_option.l(from: :your_inbox.l)
8
+ = link_to :manage_your_email_notifications.l, message_train.unsubscribes_url
9
+ - else
10
+ %p= :at_time_through_received_a_message.l(time: @receipt.created_at, through: @through_name, subject: @receipt.message.subject, path: message_train.collective_box_conversation_path(@through, :in, @receipt.message.conversation))
11
+ %p{ style: 'font-size: .8rem; color: #666' }
12
+ = :unsubscribe_from_option.l(from: @through_name)
13
+ = link_to :manage_your_email_notifications.l, message_train.unsubscribes_url
@@ -0,0 +1,10 @@
1
+ - add_title :manage_your_email_notifications.l
2
+ %table#subscriptions.table.table-bordered.table-condensed
3
+ - @subscriptions.each do |subscription|
4
+ %tr.subscription
5
+ %td= subscription[:from_name]
6
+ %td
7
+ - if subscription[:unsubscribe].nil?
8
+ = button_to :disable_notifications.l, message_train.unsubscribes_path(unsubscribe: { from_type: subscription[:from_type], from_id: subscription[:from_id] }), class: 'btn btn-danger', id: "unsubscribe-#{subscription[:from_type].downcase}-#{subscription[:from_id]}", confirm: :are_you_sure.l
9
+ - else
10
+ = button_to :enable_notifications.l, message_train.unsubscribe_path(subscription[:unsubscribe].id), method: :delete, class: 'btn btn-primary', id: "remove-unsubscribe-#{subscription[:unsubscribe].id}"
@@ -0,0 +1 @@
1
+ ActionMailer::Base.register_template_extension('haml')
@@ -3,48 +3,90 @@ en:
3
3
  attributes:
4
4
  'message_train/message':
5
5
  recipients_to_save: 'Recipient'
6
+ 'message_train/attachment':
7
+ attachment_file_name: 'File'
8
+ time:
9
+ formats:
10
+ fuzzy_today: '%l:%M %p'
11
+ fuzzy_this_week: '%a %l:%M %p'
12
+ fuzzy_date_without_year: '%b %-d'
13
+ fuzzy_date: '%b %-d, %Y'
14
+ access_to_that_box_denied: 'Access to that box denied'
6
15
  access_to_conversation_id_denied: "Access to Conversation %{id} denied"
7
16
  access_to_message_id_denied: "Access to Message %{id} denied"
8
17
  access_to_receipt_id_denied: "Access to Receipt %{id} denied"
18
+ add_attachment: 'Add Attachment'
9
19
  all: 'All'
10
20
  are_you_sure: 'Are you sure?'
21
+ at_time_you_received_a_message: "At %{time}, you received a message: <a href=\"%{path}\">%{subject}</a>"
22
+ at_time_through_received_a_message: "At %{time}, %{through} received a message: <a href=\"%{path}\">%{subject}</a>"
23
+ attachment_preview: 'Attachment Preview'
24
+ attachments: 'Attachments'
11
25
  box_title_in: 'Inbox'
12
- box_title_sent: 'Sent Messages'
13
- box_title_all: 'All Messages'
26
+ box_title_sent: 'Sent'
27
+ box_title_all: 'All'
14
28
  box_title_drafts: 'Drafts'
15
29
  box_title_trash: 'Trash'
16
- box_title_ignored: 'Ignored Conversations'
17
- cannot_mark_type: "Cannot mark %{type}"
30
+ box_title_ignored: 'Ignored'
18
31
  cannot_ignore_type: "Cannot ignore %{type}"
32
+ cannot_authorize_type: "Cannot authorize %{type}"
33
+ cannot_mark_empty_object: "Cannot mark: Empty Object %{object}"
34
+ cannot_mark_type: "Cannot mark %{type}"
35
+ cannot_mark_with_data_type: "Cannot mark with %{data_type}"
36
+ cannot_unignore_type: "Cannot unignore %{type}"
19
37
  check_all: 'Check All'
20
38
  class_id_not_found_in_box: "%{class} %{id} not found in box"
39
+ click_for_original: 'Click for Original'
40
+ collective_messages: "%{collective} Messages"
41
+ collective_unsubscribe_message: "You are now unsubscribed from %{collective_name}, which means that you will not be notified by email of any messages received by that %{collective_type}."
42
+ collective_unsubscribe_removed_message: "You are no longer unsubscribed from %{collective_name}, which means that you will now be notified by email of any messages received in that %{collective_type}."
21
43
  conversation_id_not_found: "Conversation %{id} not found"
22
44
  compose: 'Compose'
45
+ compose_to_collective: "Compose to %{collective}"
23
46
  delete_forever_this_cannot_be_undone: 'Delete forever? This cannot be undone.'
24
47
  deleted: 'Deleted'
48
+ disable_notifications: 'Disable Notifications'
49
+ edit_draft: 'Edit Draft'
50
+ enable_notifications: 'Enable Notifications'
25
51
  from_sender: "From: %{sender}"
26
52
  ignored: 'Ignored'
53
+ invalid_sender_for_thing: "Invalid sender for %{thing}"
54
+ just_now: 'Just Now'
55
+ manage_your_email_notifications: 'Manage Your Email Notifications'
27
56
  mark: 'Mark'
28
57
  mark_as_name: "Mark as %{name}" #e.g. Read, Unread etc.
29
58
  message_draft: 'Message Draft'
30
59
  message_saved_as_draft: 'Message saved as draft.'
31
60
  message_sent: 'Message sent.'
32
61
  messages: 'Messages'
62
+ messages_to_collective: "Messages to %{collective}"
63
+ messages_to_myself: 'Messages to Myself'
33
64
  name_not_found: "%{name} not found"
65
+ new_message: 'New Message'
66
+ new_message_on_site_name: "New Message on %{site_name}"
67
+ new_message_through_on_site_name: "New Message through %{through} on %{site_name}"
34
68
  none: 'None'
35
69
  nothing_to_do: 'Nothing to do'
36
70
  read: 'Read'
37
71
  recipient_not_found: "Recipient Not Found"
38
72
  recipients: 'Recipients'
73
+ reply: 'Reply'
74
+ remove_attachment: 'Remove Attachment'
75
+ save_as_draft: 'Save As Draft'
39
76
  send: 'Send'
40
- started_at_time: "Started at %{time}"
41
77
  table_recipients: "%{table} Recipients"
42
78
  to_recipient: 'To: %{recipient}'
43
79
  toggle_dropdown: 'Toggle Dropdown'
44
80
  trashed: 'Trashed'
45
81
  unignored: 'Unignored'
46
82
  unread: 'Unread'
83
+ unsubscribe_message: "You are now unsubscribed from messages to you, which means that you will not be notified by email of any messages received in your inbox."
84
+ unsubscribe_from_option: "You received this email because you are set to receive notifications of messages to %{from}. To unsubscribe, please visit this link:"
85
+ unsubscribe_removed_message: "You are no longer unsubscribed from messages to you, which means that you will now be notified by email of any messages received in your inbox"
47
86
  untrashed: 'Untrashed'
48
87
  update_successful: 'Update successful'
49
- wrong_number_of_arguments_for_box_expected_right_got_wrong: "Wrong number of arguments for box (expected %{right}, got %{wrong})"
50
- you_must_sign_in_or_sign_up_to_continue: 'You must sign in or sign up to continue.'
88
+ updated_at_time: "Updated at %{time}"
89
+ wrong_number_of_arguments_for_thing_expected_right_got_wrong: "Wrong number of arguments for %{thing} (expected %{right}, got %{wrong})"
90
+ you_are_not_in_that_collective_type: "You are not in that %{collective_type}"
91
+ you_must_sign_in_or_sign_up_to_continue: 'You must sign in or sign up to continue.'
92
+ your_inbox: 'your inbox'
data/config/routes.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  MessageTrain::Engine.routes.draw do
2
- authenticated MessageTrain.configuration.user_route_authentication_method do
2
+ concern :boxable do
3
3
  resources :boxes, path: 'box', param: :division, only: [:show, :update, :destroy] do
4
4
  resources :conversations, only: [:show, :update, :destroy]
5
5
  resources :messages, except: [:index, :destroy]
@@ -8,5 +8,13 @@ MessageTrain::Engine.routes.draw do
8
8
  end
9
9
  end
10
10
 
11
- match '/box(/*path)', to: redirect(MessageTrain.configuration.user_sign_in_path), via: [:get, :put, :delete]
11
+ authenticated MessageTrain.configuration.user_route_authentication_method do
12
+ concerns :boxable
13
+ resources :collectives, as: :collective, only: [], concerns: :boxable
14
+ resources :unsubscribes, only: [:index, :create, :destroy]
15
+ end
16
+
17
+ match '/box(/*path)', to: redirect(MessageTrain.configuration.user_sign_in_path), via: [:get, :put, :post, :delete]
18
+ match '/collectives(/*path)', to: redirect(MessageTrain.configuration.user_sign_in_path), via: [:get, :put, :post, :delete]
19
+ match '/unsubscribes(/*path)', to: redirect(MessageTrain.configuration.user_sign_in_path), via: [:get, :put, :post, :delete]
12
20
  end
@@ -0,0 +1,6 @@
1
+ class AddReceivedThroughToMessageTrainReceipts < ActiveRecord::Migration
2
+ def change
3
+ add_reference :message_train_receipts, :received_through, polymorphic: true
4
+ add_index :message_train_receipts, [:received_through_type, :received_through_id], name: :index_message_train_receipts_on_received_through
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ class AddUniqueIndexToReceipts < ActiveRecord::Migration
2
+ def change
3
+ add_index :message_train_receipts, [:message_id, :recipient_type, :recipient_id], name: :message_recipient, unique: true
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ class CreateMessageTrainUnsubscribes < ActiveRecord::Migration
2
+ def change
3
+ create_table :message_train_unsubscribes do |t|
4
+ t.references :recipient, polymorphic: true
5
+ t.references :from, polymorphic: true
6
+
7
+ t.timestamps null: false
8
+ end
9
+
10
+ add_index :message_train_unsubscribes, [:recipient_type, :recipient_id], name: :unsubscribe_recipient
11
+ add_index :message_train_unsubscribes, [:from_type, :from_id], name: :unsubscribe_from
12
+ add_index :message_train_unsubscribes, [:recipient_type, :recipient_id, :from_type, :from_id], name: :unsubscribe, unique: true
13
+ end
14
+ end
@@ -16,6 +16,8 @@ module MessageTrain
16
16
  template "initializer.rb", "config/initializers/message_train.rb"
17
17
  end
18
18
 
19
+ # Not doing this any more thanks to:
20
+ # http://blog.pivotal.io/pivotal-labs/labs/leave-your-migrations-in-your-rails-engines
19
21
  def add_migrations
20
22
  output "Next come migrations.", :magenta
21
23
  rake 'message_train:install:migrations'
@@ -23,8 +25,12 @@ module MessageTrain
23
25
 
24
26
  def add_route
25
27
  output "Adding MessageTrain to your routes.rb file", :magenta
26
- gsub_file "config/routes.rb", /authenticated :[a-z_0-9]+ do\s+mount MessageTrain::Engine => '\/.*', :as => 'message_train'\s+end/, ''
27
- route("authenticated :user do\n\t\tmount MessageTrain::Engine => '/', :as => 'message_train'\n\tend")
28
+ gsub_file "config/routes.rb", /mount MessageTrain::Engine => '\/.*', :as => 'message_train'/, ''
29
+ route("mount MessageTrain::Engine => '/', :as => 'message_train'")
30
+ end
31
+
32
+ def goodbye
33
+ output "Thanks for installing! Don't forget to run your migrations. See http://gemvein.com/museum/cases/message_train for configuration tips.", :magenta
28
34
  end
29
35
  end
30
36
  end
@@ -5,4 +5,8 @@ MessageTrain.configure do |config|
5
5
  # config.user_sign_in_path = '/user/sign_in'
6
6
  # config.user_route_authentication_method = :user
7
7
  # config.address_book_methods[:users] = :address_book
8
- end
8
+ config.from_email = 'from@example.com'
9
+ config.site_name = 'Example Site Name'
10
+ end
11
+
12
+ Rails.application.config.eager_load = true #FIXME: This is a weird place to put this. What would be better?
@@ -18,7 +18,12 @@ module MessageTrain
18
18
  :user_route_authentication_method,
19
19
  :address_book_method,
20
20
  :address_book_methods,
21
- :recipient_tables
21
+ :recipient_tables,
22
+ :collectives_for_recipient_methods,
23
+ :valid_senders_methods,
24
+ :valid_recipients_methods,
25
+ :from_email,
26
+ :site_name
22
27
 
23
28
  def initialize
24
29
  self.recipient_tables = {}
@@ -29,6 +34,11 @@ module MessageTrain
29
34
  self.user_route_authentication_method = :user
30
35
  self.address_book_method = :address_book # This is a fallback
31
36
  self.address_book_methods = {}
37
+ self.collectives_for_recipient_methods = {}
38
+ self.valid_senders_methods = {}
39
+ self.valid_recipients_methods = {}
40
+ self.from_email = ''
41
+ self.site_name = 'Example Site Name'
32
42
  end
33
43
 
34
44
  end
@@ -15,5 +15,6 @@ module MessageTrain
15
15
  # Rails.application.config.assets.paths << File.expand_path("../../assets/javascripts", __FILE__)
16
16
  # Rails.application.config.assets.precompile << %w( index )
17
17
  end
18
+
18
19
  end
19
20
  end
@@ -16,6 +16,7 @@ module MessageTrain
16
16
 
17
17
  if relationships.include? :recipient
18
18
  has_many :receipts, as: :recipient, class_name: 'MessageTrain::Receipt'
19
+ has_many :unsubscribes, as: :recipient, class_name: 'MessageTrain::Unsubscribe'
19
20
  end
20
21
 
21
22
  MessageTrain.configure(MessageTrain.configuration) do |config|
@@ -34,50 +35,234 @@ module MessageTrain
34
35
  if relationships.include? :recipient
35
36
  config.recipient_tables[table_sym] = name
36
37
  end
38
+
39
+ if options[:collectives_for_recipient].present?
40
+ config.collectives_for_recipient_methods[table_sym] = options[:collectives_for_recipient]
41
+ end
42
+
43
+ if options[:valid_senders].present?
44
+ config.valid_senders_methods[table_sym] = options[:valid_senders]
45
+ end
46
+
47
+ if options[:valid_recipients].present?
48
+ config.valid_recipients_methods[table_sym] = options[:valid_recipients]
49
+ end
37
50
  end
38
51
 
39
- send(:define_method, :box) { |*args|
52
+ send(:define_method, :slug_part) {
53
+ send(MessageTrain.configuration.slug_columns[table_sym])
54
+ }
55
+
56
+ send(:define_method, :path_part) {
57
+ if MessageTrain.configuration.valid_senders_methods[table_sym].present?
58
+ # This must mean it's a collective
59
+ "#{self.class.table_name}:#{slug_part}"
60
+ end
61
+ }
62
+
63
+ send(:define_method, :valid_senders) {
64
+ valid_senders_method = MessageTrain.configuration.valid_senders_methods[self.class.table_name.to_sym] || :self_collection
65
+ send(valid_senders_method)
66
+ }
67
+
68
+ send(:define_method, :allows_sending_by?) { |sender|
69
+ valid_senders.include? sender
70
+ }
71
+
72
+ send(:define_method, :valid_recipients) {
73
+ valid_recipients_method = MessageTrain.configuration.valid_recipients_methods[self.class.table_name.to_sym] || :self_collection
74
+ send(valid_recipients_method)
75
+ }
76
+
77
+ send(:define_method, :allows_receiving_by?) { |recipient|
78
+ if valid_recipients.nil? or valid_recipients.empty?
79
+ false
80
+ else
81
+ valid_recipients.include? recipient
82
+ end
83
+ }
84
+
85
+ send(:define_method, :self_collection) { # This turns a single record into an active record collection.
86
+ model = self.class
87
+ model.where(id: self.id)
88
+ }
89
+
90
+ if relationships.include? :recipient
91
+ send(:define_method, :box) { |*args|
92
+ case args.count
93
+ when 0
94
+ division = :in
95
+ participant = self
96
+ when 1
97
+ division = args[0] || :in
98
+ participant = self
99
+ when 2
100
+ division = args[0] || :in
101
+ participant = args[1] || self
102
+ else
103
+ raise :wrong_number_of_arguments_for_thing_expected_right_got_wrong.l(right: '0..2', wrong: args.count.to_s, thing: self.class.name)
104
+ end
105
+ @box ||= MessageTrain::Box.new(self, division, participant)
106
+ }
107
+
108
+ send(:define_method, :collective_boxes) { |*args|
109
+ case args.count
110
+ when 0
111
+ division = :in
112
+ participant = self
113
+ when 1
114
+ division = args[0] || :in
115
+ participant = self
116
+ when 2
117
+ division = args[0] || :in
118
+ participant = args[1] || self
119
+ else # Treat all but the division as a hash of options
120
+ raise :wrong_number_of_arguments_for_thing_expected_right_got_wrong.l(right: '0..2', wrong: args.count.to_s, thing: self.class.name)
121
+ end
122
+ collective_box_tables = MessageTrain.configuration.collectives_for_recipient_methods
123
+ collective_boxes = {}
124
+ unless collective_box_tables.empty?
125
+ collective_box_tables.each do |table_sym, collectives_method|
126
+ class_name = MessageTrain.configuration.recipient_tables[table_sym]
127
+ model = class_name.constantize
128
+ collectives = model.send(collectives_method, @box_user)
129
+ unless collectives.empty?
130
+ collectives.each do |collective|
131
+ collective_boxes[table_sym] ||= []
132
+ collective_boxes[table_sym] << collective.box(division, participant)
133
+ end
134
+ end
135
+ end
136
+ end
137
+ collective_boxes
138
+ }
139
+
140
+ send(:define_method, :all_boxes) { |*args|
141
+ case args.count
142
+ when 0
143
+ participant = self
144
+ when 1
145
+ participant = args[0] || self
146
+ else # Treat all but the division as a hash of options
147
+ raise :wrong_number_of_arguments_for_thing_expected_right_got_wrong.l(right: '0..1', wrong: args.count.to_s, thing: self.class.name)
148
+ end
149
+ divisions = [:in, :sent, :all, :drafts, :trash, :ignored]
150
+ divisions.collect { |division| MessageTrain::Box.new(self, division, participant) }
151
+ }
152
+ end
153
+
154
+ send(:define_method, :conversations) { |*args|
40
155
  case args.count
41
156
  when 0
42
157
  division = :in
158
+ participant = self
43
159
  when 1
44
- division = args[0]
45
- else
46
- raise :wrong_number_of_arguments_for_box_expected_right_got_wrong.l(right: '0..1', wrong: args.count.to_s)
160
+ division = args[0] || :in
161
+ participant = self
162
+ when 2
163
+ division = args[0] || :in
164
+ participant = args[1] || self
165
+ else # Treat all but the division as a hash of options
166
+ raise :wrong_number_of_arguments_for_thing_expected_right_got_wrong.l(right: '0..2', wrong: args.count.to_s, thing: self.class.name)
47
167
  end
48
- @box ||= MessageTrain::Box.new(self, division)
49
- }
50
-
51
- send(:define_method, :conversations) { |division|
168
+ my_conversations = MessageTrain::Conversation.with_messages_through(self)
52
169
  case division
53
170
  when :in
54
- MessageTrain::Conversation.with_untrashed_to(self)
171
+ my_conversations.with_untrashed_to(participant)
55
172
  when :sent
56
- MessageTrain::Conversation.with_untrashed_by(self)
173
+ my_conversations.with_untrashed_by(participant)
57
174
  when :all
58
- MessageTrain::Conversation.with_untrashed_for(self)
175
+ my_conversations.with_untrashed_for(participant)
59
176
  when :drafts
60
- MessageTrain::Conversation.with_drafts_by(self)
177
+ my_conversations.with_drafts_by(participant)
61
178
  when :trash
62
- MessageTrain::Conversation.with_trashed_for(self)
179
+ my_conversations.with_trashed_for(participant)
63
180
  when :ignored
64
- MessageTrain::Conversation.ignored(self)
181
+ my_conversations.ignored(participant)
65
182
  else
66
183
  nil
67
184
  end
68
185
  }
69
186
 
70
- send(:define_method, :all_boxes) {
71
- divisions = [:in, :sent, :all, :drafts, :trash, :ignored]
72
- divisions.collect { |division| MessageTrain::Box.new(self, division) }
187
+ send(:define_method, :boxes_for_participant) { |participant|
188
+ original_order = [:in, :sent, :all, :drafts, :trash, :ignored]
189
+ divisions = [:all, :trash]
190
+ if self.respond_to?(:messages) || allows_sending_by?(participant)
191
+ divisions += [:sent, :drafts]
192
+ end
193
+ if allows_receiving_by?(participant)
194
+ divisions += [:in, :ignored]
195
+ end
196
+ divisions.sort_by! { |x| original_order.index x }
197
+ divisions.collect { |division| MessageTrain::Box.new(self, division, participant) }
198
+ }
199
+
200
+ send(:define_method, :all_conversations) { |*args|
201
+ case args.count
202
+ when 0
203
+ participant = self
204
+ when 1
205
+ participant = args[0] || self
206
+ else # Treat all but the division as a hash of options
207
+ raise :wrong_number_of_arguments_for_thing_expected_right_got_wrong.l(right: '0..1', wrong: args.count.to_s, thing: self.class.name)
208
+ end
209
+ results = MessageTrain::Conversation.with_messages_through(self)
210
+ if results.empty?
211
+ []
212
+ else
213
+ results.with_messages_for(participant)
214
+ end
215
+ }
216
+
217
+ send(:define_method, :all_messages) { |*args|
218
+ case args.count
219
+ when 0
220
+ participant = self
221
+ when 1
222
+ participant = args[0] || self
223
+ else # Treat all but the division as a hash of options
224
+ raise :wrong_number_of_arguments_for_thing_expected_right_got_wrong.l(right: '0..1', wrong: args.count.to_s, thing: self.class.name)
225
+ end
226
+ results = MessageTrain::Message.with_receipts_through(self)
227
+ if results.empty?
228
+ []
229
+ else
230
+ results.with_receipts_for(participant)
231
+ end
232
+ }
233
+
234
+ send(:define_method, :unsubscribed_from?) { |from|
235
+ unsubscribes.where(from: from).exists?
73
236
  }
74
237
 
75
- send(:define_method, :all_conversations) {
76
- MessageTrain::Conversation.with_receipts_for(self)
238
+ send(:define_method, :unsubscribe_from) { |from|
239
+ unsubscribes.find_or_create_by(from: from)
77
240
  }
78
241
 
79
- send(:define_method, :all_messages) {
80
- MessageTrain::Message.with_receipts_for(self)
242
+ send(:define_method, :subscriptions) {
243
+ subscriptions = []
244
+ subscriptions << {
245
+ from: self,
246
+ from_type: self.class.name,
247
+ from_id: self.id,
248
+ from_name: :messages_to_myself.l,
249
+ unsubscribe: self.unsubscribes.find_by(from: self)
250
+ }
251
+ collective_boxes.values.each do |boxes|
252
+ boxes.each do |box|
253
+ if box.parent.allows_receiving_by?(self)
254
+ collective_name = box.parent.send(MessageTrain.configuration.name_columns[box.parent.class.table_name.to_sym])
255
+ subscriptions << {
256
+ from: box.parent,
257
+ from_type: box.parent.class.name,
258
+ from_id: box.parent.id,
259
+ from_name: :messages_to_collective.l(collective: collective_name),
260
+ unsubscribe: self.unsubscribes.find_by(from: box.parent)
261
+ }
262
+ end
263
+ end
264
+ end
265
+ subscriptions
81
266
  }
82
267
  end
83
268
  end