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