nuntius 0.1.1 → 1.0.27

Sign up to get free protection for your applications and to get access to all the features.
Files changed (169) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +199 -63
  4. data/Rakefile +62 -1
  5. data/app/controllers/nuntius/admin/campaigns_controller.rb +56 -0
  6. data/app/controllers/nuntius/admin/layouts/attachments_controller.rb +32 -0
  7. data/app/controllers/nuntius/admin/layouts_controller.rb +50 -0
  8. data/app/controllers/nuntius/admin/lists/subscribers_controller.rb +50 -0
  9. data/app/controllers/nuntius/admin/lists_controller.rb +46 -0
  10. data/app/controllers/nuntius/admin/locales_controller.rb +46 -0
  11. data/app/controllers/nuntius/admin/messages_controller.rb +24 -0
  12. data/app/controllers/nuntius/admin/templates_controller.rb +56 -0
  13. data/app/controllers/nuntius/api/events_controller.rb +16 -0
  14. data/app/controllers/nuntius/application_admin_controller.rb +11 -0
  15. data/app/controllers/nuntius/application_controller.rb +12 -0
  16. data/app/controllers/nuntius/callbacks_controller.rb +21 -0
  17. data/app/controllers/nuntius/dashboard_controller.rb +12 -0
  18. data/app/controllers/nuntius/feedback_controller.rb +17 -0
  19. data/app/controllers/nuntius/inbound_messages/twilio_inbound_smses_controller.rb +56 -0
  20. data/app/controllers/nuntius/messages_controller.rb +13 -0
  21. data/app/drops/nuntius/application_drop.rb +17 -0
  22. data/app/drops/nuntius/campaign_drop.rb +7 -0
  23. data/app/drops/nuntius/layout_drop.rb +11 -0
  24. data/app/drops/nuntius/message_drop.rb +11 -0
  25. data/app/drops/nuntius/template_drop.rb +7 -0
  26. data/app/exceptions/nuntius/base_exception.rb +4 -0
  27. data/app/exceptions/nuntius/missing_messenger_exception.rb +4 -0
  28. data/app/helpers/nuntius/application_helper.rb +78 -0
  29. data/app/jobs/nuntius/application_job.rb +9 -0
  30. data/app/jobs/nuntius/deliver_inbound_message_job.rb +10 -0
  31. data/app/jobs/nuntius/messenger_job.rb +17 -0
  32. data/app/jobs/nuntius/process_inbound_message_job.rb +10 -0
  33. data/app/jobs/nuntius/purge_message_job.rb +13 -0
  34. data/app/jobs/nuntius/retrieve_mail_job.rb +18 -0
  35. data/app/jobs/nuntius/transport_delivery_job.rb +32 -0
  36. data/app/jobs/nuntius/transport_refresh_job.rb +22 -0
  37. data/app/message_boxes/nuntius/base_message_box.rb +75 -0
  38. data/app/messengers/nuntius/base_messenger.rb +193 -0
  39. data/app/messengers/nuntius/custom_messenger.rb +6 -0
  40. data/app/models/nuntius/application_record.rb +11 -0
  41. data/app/models/nuntius/attachment.rb +13 -0
  42. data/app/models/nuntius/campaign.rb +75 -0
  43. data/app/models/nuntius/concerns/metadata_scoped.rb +31 -0
  44. data/app/models/nuntius/concerns/yamlify.rb +23 -0
  45. data/app/models/nuntius/inbound_message.rb +14 -0
  46. data/app/models/nuntius/layout.rb +13 -0
  47. data/app/models/nuntius/list.rb +10 -0
  48. data/app/models/nuntius/locale.rb +11 -0
  49. data/app/models/nuntius/message.rb +148 -0
  50. data/app/models/nuntius/subscriber.rb +12 -0
  51. data/app/models/nuntius/template.rb +102 -0
  52. data/app/presenters/application_presenter.rb +28 -0
  53. data/app/presenters/template_presenter.rb +17 -0
  54. data/app/providers/nuntius/apnotic_push_provider.rb +44 -0
  55. data/app/providers/nuntius/base_provider.rb +72 -0
  56. data/app/providers/nuntius/firebase_push_provider.rb +26 -0
  57. data/app/providers/nuntius/houston_push_provider.rb +40 -0
  58. data/app/providers/nuntius/message_bird_sms_provider.rb +39 -0
  59. data/app/providers/nuntius/slack_slack_provider.rb +36 -0
  60. data/app/providers/nuntius/smtp_mail_provider.rb +80 -0
  61. data/app/providers/nuntius/twilio_sms_provider.rb +37 -0
  62. data/app/providers/nuntius/twilio_voice_provider.rb +70 -0
  63. data/app/reportlets/nuntius/application_reportlet.rb +35 -0
  64. data/app/reportlets/nuntius/daily_messages_per_template_reportlet.rb +50 -0
  65. data/app/runners/nuntius/application_runner.rb +6 -0
  66. data/app/runners/nuntius/basic_application_runner.rb +15 -0
  67. data/app/runners/nuntius/timebased_events_runner.rb +15 -0
  68. data/app/services/nuntius/application_service.rb +7 -0
  69. data/app/services/nuntius/aws_sns_processor_service.rb +81 -0
  70. data/app/services/nuntius/deliver_inbound_message_service.rb +14 -0
  71. data/app/services/nuntius/retrieve_inbound_mail_service.rb +36 -0
  72. data/app/tables/nuntius_campaigns_table.rb +21 -0
  73. data/app/tables/nuntius_layouts_table.rb +24 -0
  74. data/app/tables/nuntius_lists_table.rb +19 -0
  75. data/app/tables/nuntius_locales_table.rb +18 -0
  76. data/app/tables/nuntius_messages_table.rb +36 -0
  77. data/app/tables/nuntius_subscribers_table.rb +19 -0
  78. data/app/tables/nuntius_templates_table.rb +30 -0
  79. data/app/transports/nuntius/base_transport.rb +36 -0
  80. data/app/transports/nuntius/mail_transport.rb +35 -0
  81. data/app/transports/nuntius/push_transport.rb +15 -0
  82. data/app/transports/nuntius/slack_transport.rb +6 -0
  83. data/app/transports/nuntius/sms_transport.rb +6 -0
  84. data/app/transports/nuntius/voice_transport.rb +6 -0
  85. data/app/validators/liquid_validator.rb +11 -0
  86. data/app/views/nuntius/admin/campaigns/edit.html.slim +49 -0
  87. data/app/views/nuntius/admin/campaigns/index.html.slim +2 -0
  88. data/app/views/nuntius/admin/layouts/attachments/_attachments.html.slim +28 -0
  89. data/app/views/nuntius/admin/layouts/attachments/_index.html.slim +2 -0
  90. data/app/views/nuntius/admin/layouts/attachments/create.json.jbuilder +5 -0
  91. data/app/views/nuntius/admin/layouts/edit.html.slim +24 -0
  92. data/app/views/nuntius/admin/layouts/index.html.slim +2 -0
  93. data/app/views/nuntius/admin/lists/edit.html.slim +14 -0
  94. data/app/views/nuntius/admin/lists/index.html.slim +2 -0
  95. data/app/views/nuntius/admin/lists/subscribers/edit.html.slim +14 -0
  96. data/app/views/nuntius/admin/locales/edit.html.slim +14 -0
  97. data/app/views/nuntius/admin/locales/index.html.slim +2 -0
  98. data/app/views/nuntius/admin/messages/index.html.slim +2 -0
  99. data/app/views/nuntius/admin/messages/show.html.slim +56 -0
  100. data/app/views/nuntius/admin/templates/edit.html.slim +81 -0
  101. data/app/views/nuntius/admin/templates/index.html.slim +2 -0
  102. data/app/views/nuntius/dashboard/show.html.slim +7 -0
  103. data/app/views/nuntius/messages/show.html.slim +7 -0
  104. data/config/locales/en.yml +22 -0
  105. data/config/locales/nl.yml +22 -0
  106. data/config/routes.rb +38 -0
  107. data/config/webpack/development.js +5 -0
  108. data/config/webpack/environment.js +4 -0
  109. data/config/webpack/production.js +5 -0
  110. data/config/webpack/test.js +5 -0
  111. data/config/webpacker.yml +119 -0
  112. data/db/migrate/20190301201541_create_nuntius_templates.rb +27 -0
  113. data/db/migrate/20190301202436_create_nuntius_messages.rb +30 -0
  114. data/db/migrate/20190322112815_create_nuntius_lists.rb +12 -0
  115. data/db/migrate/20190322114340_create_nuntius_campaigns.rb +18 -0
  116. data/db/migrate/20190322121338_create_nuntius_subscribers.rb +17 -0
  117. data/db/migrate/20190327123535_add_metadata_to_models.rb +8 -0
  118. data/db/migrate/20190327124407_create_nuntius_layouts.rb +24 -0
  119. data/db/migrate/20190327143921_add_campaign_to_message.rb +7 -0
  120. data/db/migrate/20190327155112_add_state_to_campaign.rb +7 -0
  121. data/db/migrate/20190412103335_add_enabled_to_templates.rb +7 -0
  122. data/db/migrate/20190417125153_change_message_status_default.rb +9 -0
  123. data/db/migrate/20190417144554_add_nuntiable_to_subscriber.rb +7 -0
  124. data/db/migrate/20190521135011_add_payload_to_nuntius_messages.rb +7 -0
  125. data/db/migrate/20190522122657_add_metadata_to_nuntius_message.rb +7 -0
  126. data/db/migrate/20190825080757_update_nuntius_message_sending_to_sent.rb +11 -0
  127. data/db/migrate/20200220154927_change_nuntius_templates_payload_type.rb +7 -0
  128. data/db/migrate/20200224132337_create_nuntius_locales.rb +13 -0
  129. data/db/migrate/20200318095339_create_nuntius_attachments.rb +12 -0
  130. data/db/migrate/20200407050646_add_interval_to_nuntius_template.rb +5 -0
  131. data/db/migrate/20200430131219_make_html_processing_optional.rb +6 -0
  132. data/db/migrate/20200430154032_make_html_processing_optional_revert.rb +6 -0
  133. data/db/migrate/20201121185718_create_nuntius_inbound_messages.rb +21 -0
  134. data/db/migrate/20220412114148_add_last_sent_to_message.rb +5 -0
  135. data/lib/nuntius/active_record_helpers.rb +28 -0
  136. data/lib/nuntius/active_storage_helpers.rb +8 -0
  137. data/lib/nuntius/configuration.rb +97 -0
  138. data/lib/nuntius/deprecator.rb +8 -0
  139. data/lib/nuntius/devise.rb +19 -0
  140. data/lib/nuntius/engine.rb +46 -0
  141. data/lib/nuntius/i18n_store.rb +100 -0
  142. data/lib/nuntius/liquid/tags/attach_tag.rb +44 -0
  143. data/lib/nuntius/mail_allow_list.rb +23 -0
  144. data/lib/nuntius/nuntiable.rb +24 -0
  145. data/lib/nuntius/state_machine.rb +19 -0
  146. data/lib/nuntius/transactio.rb +30 -0
  147. data/lib/nuntius/version.rb +3 -1
  148. data/lib/nuntius.rb +74 -8
  149. data/lib/preamble.rb +87 -0
  150. data/lib/tasks/nuntius_tasks.rake +27 -0
  151. metadata +532 -67
  152. data/.gitignore +0 -4
  153. data/Gemfile +0 -4
  154. data/lib/nuntius/encodings/url_safe_base64.rb +0 -26
  155. data/lib/nuntius/encodings.rb +0 -9
  156. data/lib/nuntius/envelope.rb +0 -45
  157. data/lib/nuntius/key.rb +0 -47
  158. data/lib/nuntius/messenger.rb +0 -37
  159. data/nuntius.gemspec +0 -23
  160. data/spec/keys/alice.pem +0 -27
  161. data/spec/keys/alice.pub +0 -9
  162. data/spec/keys/bob.pem +0 -27
  163. data/spec/keys/bob.pub +0 -9
  164. data/spec/nuntius/encodings/url_safe_base64_spec.rb +0 -36
  165. data/spec/nuntius/envelope_spec.rb +0 -6
  166. data/spec/nuntius/key_spec.rb +0 -12
  167. data/spec/nuntius/messenger_spec.rb +0 -26
  168. data/spec/spec_helper.rb +0 -9
  169. data/spec/support/keys.rb +0 -3
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 736ed78b3a455b90aad20c47ba9bf6c3946cb7d45dc064c33d689a622ac40f18
4
+ data.tar.gz: c2f9abeeffe69fe5f28df8af6b0ff1c72c3c73d743b9156f0a12ed6daca3d1a9
5
+ SHA512:
6
+ metadata.gz: a6fe800fc712a05dc2a35166a28a6d3c0d41f248365ca1cdb3f529f1430e77ca11553342cc0681490b1aaad952de6f87b89412f8329501e79765c556efa3428f
7
+ data.tar.gz: 4e79093e36ffeb8967aa5568a064b41828c33dcd3da32bf87ff0a5ed3504f5c3dc2794560c237254e63ed042a521442d3c51e57ca54690f209057e5bc29b73a5
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2018 Tom de Grunt
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,93 +1,229 @@
1
- # Nuntius:
1
+ # Nuntius
2
2
 
3
- > A messenger, reporter, courier, bearer of news or tidings
3
+ Nuntius offers messaging and notifications for ActiveRecord models in Ruby on Rails applications.
4
4
 
5
- Nuntius is a simple scheme to send and receive messages in a cryptographicaly secure and compatible way.
5
+ ## Setup
6
+
7
+ Add Nuntius to your Gemfile and run bundle install to install it.
8
+
9
+ Create an initializer (config/initializers/messaging.rb) and configure as desired:
10
+
11
+ ```ruby
12
+ Nuntius.setup do
13
+ # Have Nuntius log to the Rails.logger
14
+ config.logger = Rails.logger
15
+
16
+ # Allow custom events (default = false)
17
+ # Enable this option to allow use of Nuntius with a Hash
18
+ config.allow_custom_events = true
19
+
20
+ # Configure the transport you want to use
21
+
22
+ # Enable e-mail
23
+ config.transport :mail
24
+ # Enable push notifications
25
+ config.transport :push
26
+ # Enable SMS
27
+ config.transport :sms
28
+ # Enable voice
29
+ config.transport :voice
30
+ # Enable Slack
31
+ config.transport :slack
32
+
33
+ # Configure providers for each of the transports you enabled above.
34
+ # Advised is to either do this using credentials, environment variables, or somewhere in a model (securely stored away).
35
+ config.provider :slack, transport: :slack, settings: lambda { |_message|
36
+ Rails.application.credentials[:slack]
37
+ }
38
+ end
39
+ ```
40
+
41
+ Mount the Rails engine in your routes.rb to enable Nuntius' maintenance pages:
42
+
43
+ ```ruby
44
+ Rails.application.routes.draw do
45
+ # your own routes ...
46
+ mount Nuntius::Engine, at: '/messaging', as: 'nuntius' # change the path and aliases at your own discretion
47
+ end
48
+ ```
49
+
50
+ To enable you to send messages with Nuntius you need to make one or more ActiveRecord models nuntiable:
51
+
52
+ ```ruby
53
+ class Car < ApplicationRecord
54
+ nuntiable
55
+ end
56
+ ```
57
+
58
+ Additionally you need to define an extension of the Nuntius::BaseMessenger for the same model with a matching name (in app/messengers):
59
+
60
+ ```ruby
61
+ class CarMessenger < Nuntius::BaseMessenger
62
+ def your_event(car, params)
63
+ # your optional logic here
64
+ end
65
+ end
66
+ ```
67
+
68
+ If you are using the state_machines-activemodel gem you can pass use_state_machine: true to the
69
+ nuntiable call, this will automatically define empty methods for these events on the model's
70
+ messenger class if they are not defined already.
71
+
72
+ Additionally the use_state_machine option will add an after_commit hook to the state machine
73
+ to automatically trigger the event for the state transition.
6
74
 
7
75
  ## Usage
8
76
 
9
- ### Encript a Message
77
+ ### With templates
78
+
79
+ Usually you would call Nuntius programatically with code by using Templates. In this case you would use for example:
10
80
 
11
81
  ```ruby
12
- require 'nuntius'
13
-
14
- sender = Nuntius::Key.new( File.read('private_key_path') )
15
- messenger = Nuntius::Mesenger.new({
16
- :key => sender
17
- })
18
-
19
- receiver = Nuntius::Key.new( File.read('public_key_path') )
20
-
21
- envelope = messenger.wrap({
22
- :message => "Message Content",
23
- :to => receiver
24
- })
25
-
26
- envelope.data
27
- # => The encripted message
28
- envelope.key
29
- # => The encripted message key
30
- envelope.signature
31
- # => The encripted message signature
82
+ Nuntius.event(:your_event, car)
32
83
  ```
33
84
 
34
- ### Decript a message
85
+ When custom events are enabled you can also do the following:
35
86
 
36
87
  ```ruby
37
- require 'nuntius'
88
+ Nuntius.event('shipped', { shipped: { to: 'test@example.com', ref: 'Test-123'} }, attachments: [ { url: 'http://example.com' } ])
89
+ ```
38
90
 
39
- receiver = Nuntius::Key.new( File.read('private_key_path') )
40
- messenger = Nuntius::Mesenger.new({
41
- :key => receiver
42
- })
91
+ For the above cases you need to define templates, this is done with the maintenace pages under
92
+ /messaging/admin/templates (/messaging is whatever you have defined in your routes file).
43
93
 
44
- sender = Nuntius::Key.new( File.read('public_key_path') )
94
+ When Nuntius#message is called a message will be sent for every matching template. To allow you to
95
+ send different messages under different circumstances you can specify a template_scope on the messenger
96
+ class that uses the template's metadata in combination with the nuntiable object to determine whether
97
+ or not the template should be used.
45
98
 
46
- envelope = Nuntius::Envelope.new({
47
- :data => 'The encripted message'
48
- :key => 'The encripted message key'
49
- :signature => 'The encripted message signature'
50
- })
99
+ ### Timebased events
51
100
 
52
- message = messenger.unwrap({
53
- :envelope => envelope,
54
- :from => sender
55
- })
101
+ If you want to send messages based on time intervals you can add such events to your messenger with the
102
+ timebased_scope class method like so:
56
103
 
57
- message
58
- # => The verified and decripted raw message
104
+ ```ruby
105
+ class CarMessenger < Nuntius::BaseMessenger
106
+ # time_range is a range, for a before scope the time_range the interval is added to the current
107
+ # time, the end of the range is 1 hour from the start.
108
+ timebased_scope :before_tuneup do |time_range, metadata|
109
+ cars = Car.where(tuneup_at: time_range)
110
+ cars = cars.where(color: metadata['color']) if metadata['color'].present?
111
+ cars
112
+ end
113
+
114
+ # For an after scope the time_range the interval is taken from the current time, the end of the
115
+ # range is 1 hour from its start.
116
+ timebased_scope :after_tuneup do |time_range, metadata|
117
+ cars = Car.where(tuneup_at: time_range)
118
+ cars = cars.where(color: metadata['color']) if metadata['color'].present?
119
+ cars
120
+ end
121
+ end
59
122
  ```
60
123
 
61
- ## Encription Scheme
124
+ This method also requires you to configure a template using the maintenance pages. When you choose
125
+ a timebased scope as an event you will be prompted to enter an interval, you can enter anything in the
126
+ following formats:
62
127
 
63
- Under the hood Nuntius is just a wrapper around OpenSSL and by default uses [RSA]( http://en.wikipedia.org/wiki/RSA_%28algorithm%29 ), [AES](http://en.wikipedia.org/wiki/Advanced_Encryption_Standard) in [CBC mode](http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29) and [SHA512](http://en.wikipedia.org/wiki/SHA512) to encript/decript and sign/verify the messages and [URL Safe Base64](http://en.wikipedia.org/wiki/Base64#RFC_4648) to encode/decode the results.
128
+ - N minute(s)
129
+ - N hour(s)
130
+ - N day(s)
131
+ - N week(s)
132
+ - N month(s)
64
133
 
65
- The whole scheme can be sumarized in 4 steps:
134
+ To send timebased messages you need to execute Nuntius::TimestampBasedMessagesRunner.call, you could do this
135
+ in a cronjob every 5 minutes with "bundle exec rails runner Nuntius::TimestampBasedMessagesRunner.call"
66
136
 
67
- * The message is encripted using AES-256-CBC with a randomly generated key.
68
- * The key is then encrypted using the receiver's public RSA key.
69
- * The encripted message's digest is calculated using SHA512 and then signed using the sender's private RSA key.
70
- * Finally the encripted message, the encripted key and the signed digest are encoded using the RFC4648 URL Safe Base 64 encoding
137
+ ### Direct
71
138
 
72
- In other terms, encrypting a message with nuntius is the same as doing
139
+ Another more direct way of using Nuntius is by just instantiating a message:
73
140
 
74
141
  ```ruby
75
- require 'openssl'
142
+ Nuntius::Message.new(to: 'tom@boxture.com', subject: 'Test', text: 'Test text', nuntiable: channel).deliver_as(:mail)
143
+ ```
76
144
 
77
- sender = OpenSSL::PKey::RSA.new( File.read('sender_private_key') )
78
- receiver = OpenSSL::PKey::RSA.new( File.read('receiver_public_key') )
145
+ or
79
146
 
80
- cipher = OpenSSL::Cipher.new("AES-256-CBC").encrypt
81
-
82
- key = receiver.public_encrypt( cipher.random_key )
147
+ ```ruby
148
+ user = User.find(1)
149
+ user.messages.new(to: 'test@example.com', subject: 'Test', text: 'Test text').deliver_as(:mail)
150
+ ```
83
151
 
84
- data = cipher.update("message") + cipher.final
152
+ Here we still need a nuntiable object, in case provider settings can differ from object to object.
85
153
 
86
- signature = receiver.private_encrypt( OpenSSL::Digest::SHA512.new(data).digest )
154
+ You can also define custom events, which take a scope and an event name:
87
155
 
88
- result = {
89
- :data => [data].pack("m0").tr("+/","-_").gsub("=","")
90
- :key => [key].pack("m0").tr("+/","-_").gsub("=","")
91
- :signature => [signature].pack("m0").tr("+/","-_").gsub("=","")
92
- }
156
+ ```ruby
157
+ Nuntius.event('packed', packing: {smurrefluts: 'hatseflats'})
158
+ ```
159
+
160
+ The main key of the hash passed will also be the liquid variable.
161
+
162
+ ### Inbound
163
+
164
+ Inbound messages are also possible, currently mail/IMAP and Twilio inbound SMS are supported.
165
+
166
+ ## Transports
167
+
168
+ ### Mail
169
+
170
+ #### AWS SES
171
+
172
+ In case you use AWS SES, you can use the SNS Feedback Notifications to automatically mark messages as read, or deal with complaints and bounces. Create a AWS SNS topic, with a HTTPS subscription with the following URL (pattern):
173
+
174
+ Use the following URL: https://<host>/messaging/feedback/awssns
175
+
176
+ The actual URL may be different depending on your routing setup.
177
+
178
+ The subscription will automatically be confirmed.
179
+
180
+ Next in AWS SES, configure the SNS topic to receive feedback notifications for Bounce, Complaint and Delivery and include original headers.
181
+
182
+ ### SMS
183
+
184
+ ### Push
185
+
186
+ ### Voice
187
+
188
+ #### Twilio
189
+
190
+ Information on voice TWIML is here: https://www.twilio.com/docs/voice/twiml/gather
191
+ You can try voices here: https://www.twilio.com/console/voice/twiml/text-to-speech
192
+
193
+ ```
194
+ <?xml version="1.0" encoding="UTF-8"?>
195
+ <Response>
196
+ <Say language="nl-NL">
197
+ Hallo, dit is een bericht van Boxture!
198
+ <break strength="x-weak" time="100ms"/>
199
+ <p>We geven je zo je wachtwoord-herstel-code, dus pak een pen en schrijf mee.</p>
200
+ </Say>
201
+ <Gather input="dtmf" numDigits="1" action="{%raw%}{{url}}{%endraw%}/code">
202
+ <Say language="nl-NL">Druk een toets om verder te gaan.</Say>
203
+ </Gather>
204
+ <Redirect>{%raw%}{{url}}{%endraw%}/code</Redirect>
205
+ </Response>
206
+
207
+ ---
208
+ path: /code
209
+ ---
210
+ <?xml version="1.0" encoding="UTF-8"?>
211
+ <Response>
212
+ <Gather input="dtmf" numDigits="1">
213
+ <Say language="nl-NL">
214
+ <s>Je code is:</s>
215
+ <break strength="x-weak" time="100ms"/>
216
+ <prosody rate="x-slow"><say-as interpret-as="character">1 n a x d 8 b</say-as></prosody>
217
+ <break strength="x-weak" time="1s"/>
218
+ Druk een toets om te herhalen, of hang op.
219
+ </Say>
220
+ </Gather>
221
+ <Redirect>{%raw%}{{url}}{%endraw%}/code</Redirect>
222
+ </Response>
223
+ ```
224
+
225
+ ## Testing
226
+
227
+ ```
228
+ bundle exec sidekiq -C test/dummy/config/sidekiq.yml -r test/dummy
93
229
  ```
data/Rakefile CHANGED
@@ -1 +1,62 @@
1
- require "bundler/gem_tasks"
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+
9
+ require 'rdoc/task'
10
+
11
+ RDoc::Task.new(:rdoc) do |rdoc|
12
+ rdoc.rdoc_dir = 'rdoc'
13
+ rdoc.title = 'Nuntius'
14
+ rdoc.options << '--line-numbers'
15
+ rdoc.rdoc_files.include('README.md')
16
+ rdoc.rdoc_files.include('lib/**/*.rb')
17
+ end
18
+
19
+ APP_RAKEFILE = File.expand_path('test/dummy/Rakefile', __dir__)
20
+ load 'rails/tasks/engine.rake'
21
+
22
+ load 'rails/tasks/statistics.rake'
23
+
24
+ require 'bundler/gem_tasks'
25
+
26
+ require 'rake/testtask'
27
+
28
+ Rake::TestTask.new(:test) do |t|
29
+ t.libs << 'test'
30
+ t.pattern = 'test/**/*_test.rb'
31
+ t.verbose = false
32
+ t.warning = false
33
+ end
34
+
35
+ task default: :test
36
+
37
+ # Adds the Auxilium semver task
38
+ spec = Gem::Specification.find_by_name 'auxilium'
39
+ load "#{spec.gem_dir}/lib/tasks/semver.rake"
40
+
41
+ namespace :nuntius do
42
+ namespace :webpacker do
43
+ desc 'Install deps with yarn'
44
+ task :yarn_install do
45
+ Dir.chdir(File.join(__dir__, '../..')) do
46
+ system 'yarn install --no-progress --production'
47
+ end
48
+ end
49
+
50
+ desc 'Compile JavaScript packs using webpack for production with digests'
51
+ task compile: %i[yarn_install environment] do
52
+ Webpacker.with_node_env('production') do
53
+ if Nuntius.webpacker.commands.compile
54
+ # Successful compilation!
55
+ else
56
+ # Failed compilation
57
+ exit!
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency 'nuntius/application_admin_controller'
4
+
5
+ module Nuntius
6
+ module Admin
7
+ class CampaignsController < ApplicationAdminController
8
+ before_action :set_objects, except: [:index]
9
+
10
+ def index
11
+ @campaigns = Nuntius::Campaign.visible.order(created_at: :desc)
12
+ end
13
+
14
+ def new
15
+ render :edit
16
+ end
17
+
18
+ def create
19
+ @campaign.save
20
+ respond_with :admin, @campaign, action: :edit
21
+ end
22
+
23
+ def show
24
+ redirect_to :edit_admin_campaign, status: :see_other
25
+ end
26
+
27
+ def edit; end
28
+
29
+ def update
30
+ saved = @campaign.update(campaign_params)
31
+
32
+ if saved && params[:commit] == 'send'
33
+ @campaign.publish! if @campaign.can_publish?
34
+ redirect_to :edit_admin_campaign, status: :see_other
35
+ else
36
+ respond_with :admin, @campaign
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def set_objects
43
+ @campaign = params[:id] ? Nuntius::Campaign.visible.find(params[:id]) : Nuntius::Campaign.new(campaign_params)
44
+ @lists = Nuntius::List.visible
45
+ @layouts = Nuntius::Layout.visible
46
+ @messages = Nuntius::Message.where(campaign: @campaign)
47
+ end
48
+
49
+ def campaign_params
50
+ return unless params[:campaign]
51
+
52
+ params.require(:campaign).permit(:name, :transport, :layout_id, :list_id, :from, :subject, :text, :html)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nuntius
4
+ module Admin
5
+ module Layouts
6
+ class AttachmentsController < ApplicationController
7
+ before_action :set_objects
8
+
9
+ def index; end
10
+
11
+ def create
12
+ params[:attachments].each do |file|
13
+ @layout.attachments.attach(file)
14
+ end
15
+ end
16
+
17
+ def destroy
18
+ attachment = @layout.attachments.find_by(id: params[:id])
19
+ attachment&.purge
20
+
21
+ render :create
22
+ end
23
+
24
+ private
25
+
26
+ def set_objects
27
+ @layout = Nuntius::Layout.visible.find(params[:layout_id]) if params[:layout_id]
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency 'nuntius/application_admin_controller'
4
+
5
+ module Nuntius
6
+ module Admin
7
+ class LayoutsController < ApplicationAdminController
8
+ def index
9
+ @layouts = Nuntius::Layout.visible.order(:name)
10
+ end
11
+
12
+ def new
13
+ @layout = Nuntius::Layout.new
14
+ render :edit
15
+ end
16
+
17
+ def create
18
+ @layout = Nuntius::Layout.new(layout_params)
19
+ @layout.save
20
+ respond_with :admin, @layout
21
+ end
22
+
23
+ def edit
24
+ @layout = Nuntius::Layout.visible.find(params[:id])
25
+ end
26
+
27
+ def show
28
+ redirect_to :edit_admin_layout, status: :see_other
29
+ end
30
+
31
+ def update
32
+ @layout = Nuntius::Layout.visible.find(params[:id])
33
+ @layout.update(layout_params)
34
+ respond_with :admin, @layout
35
+ end
36
+
37
+ def destroy
38
+ @layout = Nuntius::Layout.visible.find(params[:id])
39
+ @layout.destroy
40
+ respond_with @layout
41
+ end
42
+
43
+ private
44
+
45
+ def layout_params
46
+ params.require(:layout).permit(:name, :data, :metadata_yaml)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency 'nuntius/application_admin_controller'
4
+
5
+ module Nuntius
6
+ module Admin
7
+ module Lists
8
+ class SubscribersController < ApplicationAdminController
9
+ before_action :set_objects
10
+
11
+ def index
12
+ @subscribers = @list.subscribers.all
13
+ end
14
+
15
+ def new
16
+ @subscriber = @list.subscribers.new
17
+ render :edit
18
+ end
19
+
20
+ def create
21
+ @subscriber = @list.subscribers.new(subscriber_params)
22
+ @subscriber.save
23
+ # FIXME: This should redirect to list
24
+ respond_with :admin, :list, @subscriber, collection_location: -> { nuntius.admin_list_url(@list) }, location: -> { nuntius.admin_list_url(@list) }, status: :see_other
25
+ end
26
+
27
+ def edit
28
+ @subscriber = @list.subscribers.find(params[:id])
29
+ end
30
+
31
+ def update
32
+ @subscriber = @list.subscribers.find(params[:id])
33
+ @subscriber.update(subscriber_params)
34
+ # FIXME: This should redirect to list
35
+ respond_with :admin, :list, @subscriber, collection_location: -> { nuntius.admin_list_url(@list) }, location: -> { nuntius.admin_list_url(@list) }, status: :see_other
36
+ end
37
+
38
+ private
39
+
40
+ def subscriber_params
41
+ params.require(:subscriber).permit(:first_name, :last_name, :email, :phone_number, tags: [])
42
+ end
43
+
44
+ def set_objects
45
+ @list = List.find(params[:list_id])
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency 'nuntius/application_admin_controller'
4
+
5
+ module Nuntius
6
+ module Admin
7
+ class ListsController < ApplicationAdminController
8
+
9
+ def index
10
+ @lists = Nuntius::List.visible.order(:name)
11
+ end
12
+
13
+ def new
14
+ @list = Nuntius::List.new
15
+ render :edit
16
+ end
17
+
18
+ def create
19
+ @list = Nuntius::List.create(list_params)
20
+ respond_with :admin, @list
21
+ end
22
+
23
+ def show
24
+ redirect_to :edit_admin_list, status: :see_other
25
+ end
26
+
27
+ def edit
28
+ @list = Nuntius::List.visible.find(params[:id])
29
+ end
30
+
31
+ def update
32
+ @list = Nuntius::List.visible.find(params[:id])
33
+ @list.update(list_params)
34
+ respond_with :admin, @list
35
+ end
36
+
37
+ private
38
+
39
+ def set_objects; end
40
+
41
+ def list_params
42
+ params.require(:list).permit(:name)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency 'nuntius/application_admin_controller'
4
+
5
+ module Nuntius
6
+ module Admin
7
+ class LocalesController < ApplicationAdminController
8
+ def index
9
+ @locales = Nuntius::Locale.visible.order(:key)
10
+ end
11
+
12
+ def new
13
+ @locale = Nuntius::Locale.new
14
+ render :edit
15
+ end
16
+
17
+ def create
18
+ @locale = Nuntius::Locale.new(locale_params)
19
+ @locale.save
20
+ respond_with :admin, @locale
21
+ end
22
+
23
+ def show
24
+ redirect_to :edit_admin_locales, status: :see_other
25
+ end
26
+
27
+ def edit
28
+ @locale = Nuntius::Locale.visible.find(params[:id])
29
+ end
30
+
31
+ def update
32
+ @locale = Nuntius::Locale.visible.find(params[:id])
33
+ @locale.update(locale_params)
34
+ respond_with :admin, @locale
35
+ end
36
+
37
+ private
38
+
39
+ def set_objects; end
40
+
41
+ def locale_params
42
+ params.require(:locale).permit(:key, :data, :metadata_yaml, :data_yaml)
43
+ end
44
+ end
45
+ end
46
+ end