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
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency 'nuntius/application_admin_controller'
4
+
5
+ module Nuntius
6
+ module Admin
7
+ class MessagesController < ApplicationAdminController
8
+ def index
9
+ @messages = Nuntius::Message.visible.order(created_at: :desc)
10
+ @messages = @messages.where(template_id: params[:template_id]) if params[:template_id]
11
+ end
12
+
13
+ def show
14
+ @message = Nuntius::Message.visible.find(params[:id])
15
+ end
16
+
17
+ def resend
18
+ @message = Nuntius::Message.visible.find(params[:id])
19
+ @message.resend
20
+ respond_with @message, success: t('.resend_success'), error: t('.resend_error')
21
+ end
22
+ end
23
+ end
24
+ 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 TemplatesController < ApplicationAdminController
8
+ before_action :set_objects, except: [:index]
9
+
10
+ def index
11
+ @templates = Nuntius::Template.visible.order(:description)
12
+ end
13
+
14
+ def new
15
+ @template = Nuntius::Template.new
16
+ render :edit
17
+ end
18
+
19
+ def create
20
+ @template = Nuntius::Template.new(template_params)
21
+ @template.save
22
+ respond_with :admin, @template, action: :edit
23
+ end
24
+
25
+ def edit
26
+ @template = Nuntius::Template.visible.find(params[:id])
27
+ end
28
+
29
+ def show
30
+ redirect_to :edit_admin_template, status: :see_other
31
+ end
32
+
33
+ def update
34
+ @template = Nuntius::Template.visible.find(params[:id])
35
+ @template.update(template_params)
36
+ respond_with :admin, @template
37
+ end
38
+
39
+ def destroy
40
+ @template = Nuntius::Template.visible.find(params[:id])
41
+ @template.destroy
42
+ respond_with :admin, @template
43
+ end
44
+
45
+ private
46
+
47
+ def set_objects
48
+ @layouts = Nuntius::Layout.visible
49
+ end
50
+
51
+ def template_params
52
+ params.require(:template).permit(:enabled, :klass, :event, :interval, :transport, :description, :metadata_yaml, :payload, :from, :to, :subject, :layout_id, :html, :text, :payload)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency 'nuntius/application_controller'
4
+
5
+ module Nuntius
6
+ class Api::EventsController < ApplicationController
7
+ skip_before_action :verify_authenticity_token
8
+
9
+ layout false
10
+
11
+ def create
12
+ nuntius_params = params.except(:scope, :event, :context, :controller, :action).permit!.to_h
13
+ Nuntius.event(params[:event], { params[:scope] => params[:context].permit!.to_h }, nuntius_params)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency 'nuntius/application_controller'
4
+
5
+ module Nuntius
6
+ class ApplicationAdminController < ApplicationController
7
+ include Nuntius.config.admin_authentication_module.constantize if Nuntius.config.admin_authentication_module
8
+
9
+ layout Nuntius.config.admin_layout
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nuntius
4
+ class ApplicationController < Nuntius.config.base_controller.constantize
5
+ self.responder = Auxilium::Responder
6
+ respond_to :html
7
+
8
+ protect_from_forgery with: :exception
9
+
10
+ layout Nuntius.config.layout
11
+ end
12
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency 'nuntius/application_controller'
4
+ require 'preamble'
5
+
6
+ module Nuntius
7
+ class CallbacksController < ApplicationController
8
+ skip_before_action :verify_authenticity_token
9
+
10
+ layout false
11
+
12
+ def create
13
+ message = Nuntius::Message.find(params[:message_id])
14
+ response = message.nuntius_provider(message).callback(params)
15
+
16
+ render body: response[2].first,
17
+ content_type: response[1]['Content-Type'],
18
+ layout: false
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency 'nuntius/application_admin_controller'
4
+
5
+ module Nuntius
6
+ class DashboardController < ApplicationAdminController
7
+ def show
8
+ @templates = Nuntius::Template.visible.all
9
+ @messages = Nuntius::Message.visible.order(created_at: :desc).limit(10)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency 'nuntius/application_controller'
4
+ require 'httpclient'
5
+
6
+ module Nuntius
7
+ class FeedbackController < ApplicationController
8
+ skip_before_action :verify_authenticity_token
9
+
10
+ layout false
11
+
12
+ def awssns
13
+ Nuntius::AwsSnsProcessorService.perform(notification: ::JSON.parse(request.body.read))
14
+ head :ok
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency 'nuntius/application_controller'
4
+ require 'twilio-ruby'
5
+
6
+ module Nuntius
7
+ module InboundMessages
8
+ class TwilioInboundSmsesController < ApplicationController
9
+ skip_before_action :verify_authenticity_token
10
+
11
+ layout false
12
+
13
+ # Point twilio to you nuntius mount path (/nuntius/inbound_messages/twilio_inbound_smses)
14
+ # { 'ToCountry' => 'NL',
15
+ # 'ToState' => '',
16
+ # 'SmsMessageSid' => 'SMb711289e438f577f230f5837e9c74a08',
17
+ # 'NumMedia' => '0',
18
+ # 'ToCity' => '',
19
+ # 'FromZip' => '',
20
+ # 'SmsSid' => 'SMb711289e438f577f230f5837e9c74a08',
21
+ # 'FromState' => '',
22
+ # 'SmsStatus' => 'received',
23
+ # 'FromCity' => '',
24
+ # 'Body' => 'St',
25
+ # 'FromCountry' => 'NL',
26
+ # 'To' => '+3197014204768',
27
+ # 'MessagingServiceSid' => 'MG790b6bd09f119b54ffb7f03b8841b1c9',
28
+ # 'ToZip' => '',
29
+ # 'NumSegments' => '1',
30
+ # 'MessageSid' => 'SMb711289e438f577f230f5837e9c74a08',
31
+ # 'AccountSid' => 'ACf54dd7a47a8011d65b54d472a7190549',
32
+ # 'From' => '+31641085630',
33
+ # 'ApiVersion' => '2010-04-01',
34
+ # 'controller' => 'nuntius/inbound_messages/twilio_inbound_smses',
35
+ # 'action' => 'create' }
36
+ def create
37
+ inbound_message = Nuntius::InboundMessage.find_or_create_by!(transport: 'sms', provider: 'twilio', provider_id: params[:SmsSid])
38
+ inbound_message.from = params[:From]
39
+ inbound_message.to = params[:To]
40
+ inbound_message.text = params[:Body]
41
+ inbound_message.metadata = params
42
+ inbound_message.save!
43
+
44
+ twiml = Nuntius::DeliverInboundMessageService.new(inbound_message).call
45
+
46
+ # twiml = Twilio::TwiML::MessagingResponse.new do |resp|
47
+ # resp.message body: 'The Robots are coming! Head for the hills!'
48
+ # end
49
+
50
+ render body: twiml.to_s,
51
+ content_type: 'text/xml',
52
+ layout: false
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency 'nuntius/application_controller'
4
+
5
+ module Nuntius
6
+ class MessagesController < ApplicationController
7
+ layout false
8
+
9
+ def show
10
+ @message = Nuntius::Message.find(params[:id])
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nuntius
4
+ class ApplicationDrop < Liquid::Drop
5
+ def initialize(object)
6
+ @object = object
7
+ end
8
+
9
+ def to_gid
10
+ @object.to_gid
11
+ end
12
+
13
+ def to_sgid
14
+ @object.to_sgid
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nuntius
4
+ class CampaignDrop < ApplicationDrop
5
+ delegate :id, :metadata, to: :@object
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nuntius
4
+ class LayoutDrop < ApplicationDrop
5
+ delegate :name, :metadata, :layout, to: :@object
6
+
7
+ def attachments
8
+ ActiveStorageAttachedManyDrop.new(@object.attachments)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nuntius
4
+ class MessageDrop < ApplicationDrop
5
+ delegate :id, :from, :to, :subject, :html, :text, to: :@object
6
+
7
+ def base_url
8
+ Nuntius::Engine.routes.url_helpers.message_url(@object.id, host: host)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nuntius
4
+ class TemplateDrop < ApplicationDrop
5
+ delegate :id, :metadata, :layout, to: :@object
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ module Nuntius
2
+ class BaseException < StandardError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Nuntius
2
+ class MissingMessengerException < BaseException
3
+ end
4
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nuntius
4
+ module ApplicationHelper
5
+ def nuntius_dashboard_menu
6
+ Satis::Menus::Builder.build(:dashboard) do |m|
7
+ m.item :templates, link: nuntius.admin_templates_path, icon: 'fal fa-file'
8
+ m.item :layouts, link: nuntius.admin_layouts_path, icon: 'fal fa-table-layout'
9
+ m.item :locales, link: nuntius.admin_locales_path, icon: 'fal fa-language'
10
+ m.item :campaigns, link: nuntius.admin_campaigns_path, icon: 'fal fa-megaphone'
11
+ m.item :lists, link: nuntius.admin_lists_path, icon: 'fal fa-address-book'
12
+ end
13
+ end
14
+
15
+ def nuntius_templates_menu
16
+ Satis::Menus::Builder.build(:templates) do |m|
17
+ m.item :new, link: nuntius.new_admin_template_path
18
+ end
19
+ end
20
+
21
+ def nuntius_messages_menu
22
+ Satis::Menus::Builder.build(:messages) do |m|
23
+ m.item :new, link: nuntius.new_admin_message_path
24
+ end
25
+ end
26
+
27
+ def nuntius_layouts_menu
28
+ Satis::Menus::Builder.build(:layouts) do |m|
29
+ m.item :new, link: nuntius.new_admin_layout_path
30
+ end
31
+ end
32
+
33
+ def nuntius_locales_menu
34
+ Satis::Menus::Builder.build(:locales) do |m|
35
+ m.item :new, link: nuntius.new_admin_locale_path
36
+ end
37
+ end
38
+
39
+ def nuntius_campaigns_menu
40
+ Satis::Menus::Builder.build(:campaign) do |m|
41
+ m.item :new, link: nuntius.new_admin_campaign_path
42
+ m.item :lists, link: nuntius.admin_lists_path
43
+ end
44
+ end
45
+
46
+ def nuntius_lists_menu
47
+ Satis::Menus::Builder.build(:lists) do |m|
48
+ m.item :new, link: nuntius.new_admin_list_path
49
+ end
50
+ end
51
+
52
+ def nuntius_list_menu
53
+ Satis::Menus::Builder.build(:lists) do |m|
54
+ m.item :new_subscriber, link: nuntius.new_admin_list_subscriber_path(@list) if @list.persisted?
55
+ end
56
+ end
57
+
58
+ def present(model, presenter_class = nil)
59
+ array = nil
60
+ if model.is_a? Array
61
+ array = model
62
+ model = model.first
63
+ end
64
+
65
+ klass = presenter_class || "#{model.class}Presenter".constantize
66
+ presenter = array ? array.map { |m| klass.new(m) } : klass.new(model)
67
+ yield(presenter) if block_given?
68
+ end
69
+
70
+ def method_missing(method, *args, &block)
71
+ if main_app.respond_to?(method)
72
+ main_app.send(method, *args)
73
+ else
74
+ super
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nuntius
4
+ class ApplicationJob < ActiveJob::Base
5
+ retry_on ActiveJob::DeserializationError
6
+ retry_on ActiveRecord::Deadlocked
7
+ queue_as Nuntius.config.jobs_queue_name
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Initializes the appropriate Messenger class and calls the event method
4
+ module Nuntius
5
+ class DeliverInboundMessageJob < ApplicationJob
6
+ def perform(inbound_message)
7
+ Nuntius::DeliverInboundMessageService.new(inbound_message).call
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Initializes the appropriate Messenger class and calls the event method
4
+ module Nuntius
5
+ class MessengerJob < ApplicationJob
6
+ def perform(obj, event, params = {})
7
+ return unless obj
8
+
9
+ messenger = Nuntius::BaseMessenger.messenger_for_obj(obj).new(obj, event, params)
10
+ return unless messenger.is_a?(Nuntius::CustomMessenger) || messenger.respond_to?(event.to_sym)
11
+
12
+ messenger.call
13
+ templates = messenger.templates
14
+ messenger.dispatch(templates) if templates.present?
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Initializes the appropriate Messenger class and calls the event method
4
+ module Nuntius
5
+ class ProcessInboundMessageJob < ApplicationJob
6
+ def perform(inbound_message)
7
+ Nuntius::DeliverInboundMessageService.perform(inbound_message: inbound_message)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ module Nuntius
2
+ class PurgeMessageJob < ApplicationJob
3
+ def perform(account_id, months)
4
+ messages = Nuntius::Message.distinct.select(:id).where("metadata ->> 'account_id' = :account", account: account_id)
5
+ .where(created_at: ..months.months.ago.beginning_of_day)
6
+ .where.not(status: %w[complaint bounced])
7
+
8
+ Nuntius::Message.where(parent_message_id: messages.pluck(:id)).in_batches.update_all(parent_message_id: nil)
9
+
10
+ messages.in_batches.destroy_all
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Initializes the appropriate Messenger class and calls the event method
4
+ module Nuntius
5
+ class RetrieveMailJob < ApplicationJob
6
+ def perform
7
+ klasses = Nuntius::BaseMessageBox.message_box_for(transport: :mail)
8
+
9
+ klasses.each do |klass|
10
+ RetrieveInboundMailService.new(klass.settings).call
11
+ end
12
+
13
+ Nuntius::InboundMessage.where(status: 'pending').each do |message|
14
+ Nuntius::DeliverInboundMessageJob.perform_later(message)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This job will be called only once for each provider sent out to deliver the job
4
+ module Nuntius
5
+ class TransportDeliveryJob < ApplicationJob
6
+ def perform(provider_name, message)
7
+ return if message.delivered_or_blocked?
8
+ return if message.parent_message&.delivered_or_blocked?
9
+
10
+ if message.provider != provider_name
11
+ original_message = message
12
+ message = message.dup
13
+ message.parent_message = original_message
14
+ message.status = 'pending'
15
+ message.provider_id = ''
16
+ end
17
+ message.provider = provider_name
18
+ message.save!
19
+
20
+ provider = Nuntius::BaseProvider.class_from_name(provider_name, message.transport).new(message)
21
+ message = provider.deliver
22
+ message.save! unless message.pending?
23
+
24
+ # First refresh check is after 5 seconds
25
+ if message.delivered_or_blocked?
26
+ message.cleanup!
27
+ else
28
+ Nuntius::TransportRefreshJob.set(wait: 5).perform_later(provider_name, message) unless Rails.env.development?
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Initializes the appropriate Messenger class and calls the event method
4
+ module Nuntius
5
+ class TransportRefreshJob < ApplicationJob
6
+ def perform(provider_name, message)
7
+ return if message.delivered_or_blocked? || message.refreshes >= 3
8
+
9
+ provider = Nuntius::BaseProvider.class_from_name(provider_name, message.transport).new(message)
10
+ message = provider.refresh
11
+ # FIXME: This may need to be more atomic
12
+ message.refreshes += 1
13
+ message.save!
14
+
15
+ if message.delivered_or_blocked?
16
+ message.cleanup!
17
+ else
18
+ Nuntius::TransportRefreshJob.set(wait: message.refreshes + 5).perform_later(provider_name, message)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nuntius
4
+ # Message boxes process inbound messages
5
+ class BaseMessageBox
6
+ class << self
7
+ attr_reader :routes
8
+
9
+ def provider(value = nil)
10
+ @provider = value.to_sym if value
11
+ @provider
12
+ end
13
+
14
+ def transport(value = nil)
15
+ @transport = value.to_sym if value
16
+ @transport
17
+ end
18
+
19
+ def route(mapping = nil)
20
+ @routes ||= {}
21
+ @routes = @routes.merge(mapping) if mapping.is_a?(Hash)
22
+ @routes
23
+ end
24
+
25
+ # Defines the settings
26
+ def settings(hash = {})
27
+ @settings = hash if hash
28
+ @settings
29
+ end
30
+
31
+ def deliver(message)
32
+ klasses = message_box_for(transport: message.transport.to_sym, provider: message.provider.to_sym)
33
+ klass, method = message_box_for_route(klasses, message.to)
34
+
35
+ klass.new(message).send(method) if method
36
+ end
37
+
38
+ def message_box_for(transport: nil, provider: nil)
39
+ result = descendants
40
+ result = result.select { |message_box| message_box.transport == transport } if transport
41
+ result = result.select { |message_box| message_box.provider == provider } if provider
42
+ result
43
+ end
44
+
45
+ def mail
46
+ return nil if transport != 'mail' && provider != 'imap'
47
+ return @mail if @mail
48
+
49
+ @mail = Mail.read(inbound_message.raw_message.download)
50
+ end
51
+
52
+ private
53
+
54
+ def descendants
55
+ ObjectSpace.each_object(Class).select { |k| k < self }
56
+ end
57
+
58
+ def message_box_for_route(message_boxes, recipients)
59
+ klass = message_boxes.find do |message_box|
60
+ routes = (message_box.routes || {})
61
+ routes.any? { |regexp, _method| [*recipients].any? { |recipient| regexp.match(recipient) } }
62
+ end
63
+ method = klass.routes.find { |regexp, _method| [*recipients].any? { |recipient| regexp.match(recipient) } }&.last if klass
64
+
65
+ [klass, method] if method
66
+ end
67
+ end
68
+
69
+ attr_reader :message
70
+
71
+ def initialize(message)
72
+ @message = message
73
+ end
74
+ end
75
+ end