paper_plane 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Changelog.md +0 -0
- data/README.md +39 -0
- data/lib/generators/paper_plane_generator.rb +37 -0
- data/lib/paper_plane.rb +12 -0
- data/lib/paper_plane/base.rb +151 -0
- data/lib/paper_plane/callbacks.rb +78 -0
- data/lib/paper_plane/flight_route_registerer.rb +36 -0
- data/lib/paper_plane/flight_routes/base.rb +200 -0
- data/lib/paper_plane/flight_routes/class_methods.rb +31 -0
- data/lib/paper_plane/flight_routes/email.rb +62 -0
- data/lib/paper_plane/flight_routes/sms.rb +25 -0
- data/lib/paper_plane/fly_job.rb +15 -0
- data/lib/paper_plane/railtie.rb +13 -0
- data/lib/paper_plane/version.rb +3 -0
- data/lib/templates/paper_plane/email.tt +1 -0
- data/lib/templates/paper_plane/paper_plane.rb.tt +9 -0
- data/lib/templates/paper_plane/sms.tt +0 -0
- metadata +183 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6ab5d44238081d9bd9e9c1dd59577cb978f3dbc1511f854e4a336c299be62c1a
|
4
|
+
data.tar.gz: 4e4d5882e678e1ffbbcc35b792b6d8363c5d1711038c2f2494cb125a75f44702
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a19ef9859c9dbf035a9f2376fff68d93c5cbc06b0d892eff9330bc317dbda98dea96aa88acc7a2d54ccfda75587118a87340c76a56f7a83f2561138459b2e672
|
7
|
+
data.tar.gz: 53d265c286c1b4a74f797f7e8695c08b1a3effbac719cc31b13d4ed69e99b3badec1ba7ab446a7aac5e3a8f4e4fd20b357141507e94e225df64ef8ce5a6f7773
|
data/Changelog.md
ADDED
File without changes
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# PaperPlane
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/paper_plane`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'paper_plane'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install paper_plane
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/paper_plane.
|
36
|
+
|
37
|
+
## License
|
38
|
+
|
39
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class PaperPlaneGenerator < Rails::Generators::NamedBase
|
4
|
+
argument :messages, type: :array, default: [], banner: 'action action'
|
5
|
+
|
6
|
+
TEMPLATE_ROUTES = {
|
7
|
+
email: 'md',
|
8
|
+
sms: 'text'
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
def create_paper_plane_file
|
12
|
+
template('paper_plane.rb', File.join('app/paper_planes', class_path, "#{file_name}_paper_plane.rb"))
|
13
|
+
|
14
|
+
messages.each do |message|
|
15
|
+
I18n.available_locales.each do |locale|
|
16
|
+
flight_routes.each do |route_name, route_extension|
|
17
|
+
template(
|
18
|
+
"#{route_name}",
|
19
|
+
File.join(
|
20
|
+
'app/paper_planes',
|
21
|
+
class_path,
|
22
|
+
file_name,
|
23
|
+
message,
|
24
|
+
"#{route_name}.#{locale}.#{route_extension}.erb"
|
25
|
+
)
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def flight_routes
|
33
|
+
TEMPLATE_ROUTES.except(*options[:skip_routes])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
data/lib/paper_plane.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'paper_plane/base'
|
4
|
+
require 'paper_plane/flight_route_registerer'
|
5
|
+
require 'paper_plane/fly_job'
|
6
|
+
require 'paper_plane/callbacks'
|
7
|
+
|
8
|
+
module PaperPlane
|
9
|
+
extend ActiveSupport::Autoload
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'paper_plane/railtie' if defined?(Rails)
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'objectified'
|
4
|
+
require 'active_support/callbacks'
|
5
|
+
require 'active_support/core_ext/enumerable'
|
6
|
+
|
7
|
+
require 'paper_plane/callbacks'
|
8
|
+
require 'paper_plane/flight_routes/base'
|
9
|
+
require 'paper_plane/flight_routes/email'
|
10
|
+
require 'paper_plane/flight_routes/sms'
|
11
|
+
|
12
|
+
# defines PaperPlane::Base, the dad of all paper_planes.
|
13
|
+
module PaperPlane
|
14
|
+
class Base
|
15
|
+
include ActiveSupport::Callbacks
|
16
|
+
include Objectified
|
17
|
+
|
18
|
+
include PaperPlane::Callbacks
|
19
|
+
|
20
|
+
object_type :paper_plane
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def skip(*flight_routes_types)
|
24
|
+
define_method(:skipped_flight_routes) do
|
25
|
+
@skipped_flight_routes = flight_routes_types
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def flight_routes
|
30
|
+
@flight_routes ||= {}
|
31
|
+
end
|
32
|
+
|
33
|
+
def register_flight_route(route_name, flight_route)
|
34
|
+
flight_routes[route_name] = flight_route
|
35
|
+
end
|
36
|
+
|
37
|
+
def template_formats(**map)
|
38
|
+
@template_formats = map || {}
|
39
|
+
end
|
40
|
+
|
41
|
+
def fly_action(mid, **kwargs)
|
42
|
+
new(**kwargs).tap do |paper_plane|
|
43
|
+
paper_plane.run_callbacks(:flying) do
|
44
|
+
paper_plane.send(mid)
|
45
|
+
paper_plane.fly(mid)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def method_missing(mid, *args, &block)
|
51
|
+
if instance_methods(false).include? mid
|
52
|
+
fly_action(mid, *args)
|
53
|
+
else
|
54
|
+
super
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def respond_to_missing?(method_name, include_private = false)
|
59
|
+
instance_methods(false).include?(method_name) || super
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.inherited(subclass)
|
64
|
+
subclass.class_eval do
|
65
|
+
object_type :paper_plane
|
66
|
+
register_flight_route :email, PaperPlane::FlightRoutes::Email
|
67
|
+
register_flight_route :sms, PaperPlane::FlightRoutes::Sms
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
attr_reader :flight_routes, :params, :mid
|
72
|
+
|
73
|
+
# set the routes to fly
|
74
|
+
def initialize(**kwargs)
|
75
|
+
@template_formats = template_formats
|
76
|
+
@skipped_flight_routes = []
|
77
|
+
@flight_routes = self.class.flight_routes
|
78
|
+
@paper_plane_name = base_klass_string
|
79
|
+
@recipient ||= kwargs.delete(:to)
|
80
|
+
@async ||= kwargs.delete(:async) || ENV['RAILS_ENV'] == 'development'
|
81
|
+
@params = kwargs
|
82
|
+
end
|
83
|
+
|
84
|
+
# set message and call private do_fly method
|
85
|
+
def fly(mid)
|
86
|
+
@mid = mid
|
87
|
+
|
88
|
+
if @async
|
89
|
+
do_fly
|
90
|
+
else
|
91
|
+
PaperPlane::FlyJob.fly_later(self.class.to_s, mid, **params)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# flies without enqueing jobs
|
96
|
+
def fly_now!(mid)
|
97
|
+
@async = true
|
98
|
+
|
99
|
+
fly(mid)
|
100
|
+
end
|
101
|
+
|
102
|
+
# determines which routes the paper_plane should skip
|
103
|
+
def skip(*flight_routes_types)
|
104
|
+
@skipped_flight_routes.concat(flight_routes_types)
|
105
|
+
end
|
106
|
+
|
107
|
+
# determines whether the piegon is going to fly this route
|
108
|
+
def flying_route?(route_type)
|
109
|
+
skipped_flight_routes.exclude? route_type
|
110
|
+
end
|
111
|
+
|
112
|
+
# extracts context from the method in the paper_plane, to be injected in each flight route
|
113
|
+
def context
|
114
|
+
instance_variables.map { |attribute| [attribute, instance_variable_get(attribute)] }.to_h
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
attr_reader :skipped_flight_routes
|
120
|
+
|
121
|
+
def do_fly
|
122
|
+
flight_routes.each do |route_name, _route_object|
|
123
|
+
# next unless route.fly?(args)
|
124
|
+
next unless flying_route?(route_name)
|
125
|
+
|
126
|
+
fly_route(route_name)
|
127
|
+
end
|
128
|
+
self
|
129
|
+
end
|
130
|
+
|
131
|
+
def fly_route(type)
|
132
|
+
raise NoMessageError, 'There are no messages to deliver' unless mid
|
133
|
+
|
134
|
+
begin
|
135
|
+
flight_routes[type].fly(mid, context, **params)
|
136
|
+
rescue
|
137
|
+
_logger.error "Error in #{self.class}##{mid}: Could not send #{type.to_s.titleize}!."
|
138
|
+
else
|
139
|
+
_logger.debug "#{type.to_s.titleize} processed."
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def template_formats
|
144
|
+
self.class.template_formats
|
145
|
+
end
|
146
|
+
|
147
|
+
def _logger
|
148
|
+
@_logger ||= Logger.new(STDOUT)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/version'
|
4
|
+
require 'active_support/callbacks'
|
5
|
+
require 'active_support/concern'
|
6
|
+
|
7
|
+
module PaperPlane
|
8
|
+
# Add callbacks support to Active Delivery (requires ActiveSupport::Callbacks)
|
9
|
+
#
|
10
|
+
# # Run method before delivering notification
|
11
|
+
# # NOTE: when `false` is returned the executation is halted
|
12
|
+
# before_fly :do_something
|
13
|
+
#
|
14
|
+
# # You can specify a notification method (to run callback only for that method)
|
15
|
+
# before_fly :do_mail_something, on: :mail
|
16
|
+
#
|
17
|
+
# # or for push notifications
|
18
|
+
# before_fly :do_mail_something, on: :push
|
19
|
+
#
|
20
|
+
# # after_ and around_ callbacks are also supported
|
21
|
+
# after_fly :cleanup
|
22
|
+
#
|
23
|
+
# around_fly :set_context
|
24
|
+
CALLBACK_TERMINATOR = if ::ActiveSupport::VERSION::MAJOR >= 5
|
25
|
+
->(_target, result) { result.call == false }
|
26
|
+
else
|
27
|
+
->(_target, result) { result == false }
|
28
|
+
end
|
29
|
+
|
30
|
+
module Callbacks
|
31
|
+
extend ActiveSupport::Concern
|
32
|
+
|
33
|
+
included do
|
34
|
+
include ActiveSupport::Callbacks
|
35
|
+
|
36
|
+
define_flight_callbacks :flying
|
37
|
+
end
|
38
|
+
|
39
|
+
class_methods do
|
40
|
+
def _normalize_callback_options(options)
|
41
|
+
_normalize_callback_option(options, :only, :if)
|
42
|
+
_normalize_callback_option(options, :except, :unless)
|
43
|
+
end
|
44
|
+
|
45
|
+
def _normalize_callback_option(options, from, to)
|
46
|
+
if (from = options[from])
|
47
|
+
from_set = Array(from).map(&:to_s).to_set
|
48
|
+
from = proc { |c| from_set.include? c.notification_name.to_s }
|
49
|
+
options[to] = Array(options[to]).unshift(from)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def define_flight_callbacks(route_name)
|
54
|
+
define_callbacks route_name,
|
55
|
+
terminator: CALLBACK_TERMINATOR,
|
56
|
+
skip_after_callbacks_if_terminated: true
|
57
|
+
end
|
58
|
+
|
59
|
+
def before_flying(method_or_block = nil, on: :flying, **options, &block)
|
60
|
+
method_or_block ||= block
|
61
|
+
_normalize_callback_options(options)
|
62
|
+
set_callback on, :before, method_or_block, options
|
63
|
+
end
|
64
|
+
|
65
|
+
def after_flying(method_or_block = nil, on: :flying, **options, &block)
|
66
|
+
method_or_block ||= block
|
67
|
+
_normalize_callback_options(options)
|
68
|
+
set_callback on, :after, method_or_block, options
|
69
|
+
end
|
70
|
+
|
71
|
+
def around_flying(method_or_block = nil, on: :flying, **options, &block)
|
72
|
+
method_or_block ||= block
|
73
|
+
_normalize_callback_options(options)
|
74
|
+
set_callback on, :around, method_or_block, options
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'paper_plane/flight_routes/base'
|
4
|
+
require 'paper_plane/flight_routes/email'
|
5
|
+
require 'paper_plane/flight_routes/sms'
|
6
|
+
|
7
|
+
module PaperPlane
|
8
|
+
module FlightRouteRegisterer
|
9
|
+
def self.call(klass)
|
10
|
+
klass.class_eval do
|
11
|
+
extend ClassMethods
|
12
|
+
|
13
|
+
register_email
|
14
|
+
register_channel
|
15
|
+
register_sms
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module ClassMethods
|
20
|
+
def register_email
|
21
|
+
end
|
22
|
+
|
23
|
+
def register_channel
|
24
|
+
end
|
25
|
+
|
26
|
+
def register_sms
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# object_klass = begin
|
33
|
+
# object_klass_for(:deliverer)
|
34
|
+
# rescue NameError
|
35
|
+
# nil
|
36
|
+
# end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
require 'paper_plane/flight_routes/class_methods'
|
2
|
+
|
3
|
+
module PaperPlane
|
4
|
+
module FlightRoutes
|
5
|
+
NoRecipientError = Class.new(ArgumentError)
|
6
|
+
NoTemplateError = Class.new(ArgumentError)
|
7
|
+
DoFlyUndefined = Class.new(NoMethodError)
|
8
|
+
|
9
|
+
class Base
|
10
|
+
def self.inherited(subklass)
|
11
|
+
subklass.class_eval do
|
12
|
+
extend PaperPlane::FlightRoutes::ClassMethods
|
13
|
+
default_views 'app/paper_planes'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_accessor :context, :recipient
|
18
|
+
|
19
|
+
def initialize(route_name = nil)
|
20
|
+
@_route_name = route_name || _default_route_name
|
21
|
+
@_engine = _default_engine
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.fly(mid, context, **args)
|
25
|
+
new.fly(mid, context, **args)
|
26
|
+
end
|
27
|
+
|
28
|
+
# to be overriden by children
|
29
|
+
def fly(mid, context, **args)
|
30
|
+
@method = mid
|
31
|
+
@args = args
|
32
|
+
@context = context
|
33
|
+
|
34
|
+
_extract_recipient
|
35
|
+
_extract_template_formats
|
36
|
+
_extract_paper_plane_name
|
37
|
+
|
38
|
+
begin
|
39
|
+
do_fly
|
40
|
+
rescue NoTemplateError
|
41
|
+
_logger.debug "'#{route_name}' skipped for lack of suited template => path: '#{_template_file_path}'; extension: #{_template_formats}."
|
42
|
+
else
|
43
|
+
_logger.debug "#{route_name} sent!"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def do_fly
|
48
|
+
raise DoFlyUndefined, 'Please override :do_fly in your flight route.'
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def contextualize
|
54
|
+
context.each do |variable, value|
|
55
|
+
next unless variable.to_s.starts_with? '@'
|
56
|
+
|
57
|
+
instance_variable_set(variable, value)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def action
|
62
|
+
@method.to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
def route_name
|
66
|
+
@_route_name.to_s
|
67
|
+
end
|
68
|
+
|
69
|
+
def template
|
70
|
+
return _renderer.render(*_render_payload) if _template_exists?
|
71
|
+
|
72
|
+
raise NoTemplateError, "Could not find template for '#{_template_file_path}' with extension: #{_template_formats}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def locale
|
76
|
+
@locale || @recipient.locale || I18n.locale
|
77
|
+
end
|
78
|
+
|
79
|
+
def _render_payload
|
80
|
+
[
|
81
|
+
_view_context,
|
82
|
+
template: _template_file_path,
|
83
|
+
locals: _template_locals
|
84
|
+
]
|
85
|
+
end
|
86
|
+
|
87
|
+
def _logger
|
88
|
+
@_logger ||= Logger.new(STDOUT)
|
89
|
+
end
|
90
|
+
|
91
|
+
def _template_locals
|
92
|
+
context
|
93
|
+
end
|
94
|
+
|
95
|
+
def _lookup_context
|
96
|
+
@_lookup_context ||= ActionView::LookupContext.new(_view_resolver)
|
97
|
+
end
|
98
|
+
|
99
|
+
def _view_resolver
|
100
|
+
@_view_resolver ||= ActionView::FileSystemResolver.new(_default_views_folder)
|
101
|
+
end
|
102
|
+
|
103
|
+
def _view_context
|
104
|
+
@_view_context ||= ActionView::Base.new(_lookup_context)
|
105
|
+
end
|
106
|
+
|
107
|
+
# def _output_buffer
|
108
|
+
# @_output_buffer ||= ActionView::OutputBuffer.new
|
109
|
+
# end
|
110
|
+
|
111
|
+
def _renderer
|
112
|
+
@_renderer ||= ActionView::Renderer.new(_lookup_context)
|
113
|
+
end
|
114
|
+
|
115
|
+
def _template_formats
|
116
|
+
@_template_formats = %i[text]
|
117
|
+
end
|
118
|
+
|
119
|
+
def _extract_template_formats
|
120
|
+
@_template_formats = @context.dig(:@template_formats)
|
121
|
+
end
|
122
|
+
|
123
|
+
def _extract_paper_plane_name
|
124
|
+
@_paper_plane_name = @context.dig(:@paper_plane_name)
|
125
|
+
end
|
126
|
+
|
127
|
+
def _extract_recipient
|
128
|
+
unless @context.key?(:@recipient)
|
129
|
+
raise NoRecipientError, 'please specify the recipient value by setting @to = recipient'
|
130
|
+
end
|
131
|
+
|
132
|
+
@recipient = @context.dig(:@recipient)
|
133
|
+
end
|
134
|
+
|
135
|
+
def _template_file_path
|
136
|
+
[_template_folder, _template_name].join('/')
|
137
|
+
end
|
138
|
+
|
139
|
+
def _template_name
|
140
|
+
if _localized_template_exists?
|
141
|
+
_localized_template_name
|
142
|
+
else
|
143
|
+
_base_template_name
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def _localized_file_path
|
148
|
+
File.join(_full_template_folder_path, _localized_template_name)
|
149
|
+
end
|
150
|
+
|
151
|
+
def _localized_template_name
|
152
|
+
[_base_template_name, '.', locale].join
|
153
|
+
end
|
154
|
+
|
155
|
+
def _base_template_name
|
156
|
+
[action, route_name].join('/')
|
157
|
+
end
|
158
|
+
|
159
|
+
def _full_template_folder_path
|
160
|
+
Rails.root.join(_default_views_folder, _template_folder)
|
161
|
+
end
|
162
|
+
|
163
|
+
def _template_folder
|
164
|
+
_paper_plane_templates_path
|
165
|
+
end
|
166
|
+
|
167
|
+
def _template_full_file_path
|
168
|
+
File.join(_full_template_folder_path, _template_name)
|
169
|
+
end
|
170
|
+
|
171
|
+
def _default_engine
|
172
|
+
self.class._default_engine
|
173
|
+
end
|
174
|
+
|
175
|
+
def _default_template_format
|
176
|
+
self.class._default_template_format
|
177
|
+
end
|
178
|
+
|
179
|
+
def _default_views_folder
|
180
|
+
Rails.root.join(self.class._default_views_folder)
|
181
|
+
end
|
182
|
+
|
183
|
+
def _paper_plane_templates_path
|
184
|
+
@_paper_plane_name.underscore
|
185
|
+
end
|
186
|
+
|
187
|
+
def _default_route_name
|
188
|
+
self.class.to_s.underscore.split('/').last
|
189
|
+
end
|
190
|
+
|
191
|
+
def _template_exists?
|
192
|
+
!Dir.glob([_template_full_file_path, '*.*'].join).empty?
|
193
|
+
end
|
194
|
+
|
195
|
+
def _localized_template_exists?
|
196
|
+
!Dir.glob([_localized_file_path, '*.*'].join).empty?
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module PaperPlane
|
2
|
+
module FlightRoutes
|
3
|
+
module ClassMethods
|
4
|
+
def default_engine(engine)
|
5
|
+
@engine = engine
|
6
|
+
end
|
7
|
+
|
8
|
+
def default_views(folder_path)
|
9
|
+
@default_views_folder = folder_path
|
10
|
+
end
|
11
|
+
|
12
|
+
def default_format(format)
|
13
|
+
@default_template_format = format
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def _default_views_folder
|
19
|
+
@default_views_folder
|
20
|
+
end
|
21
|
+
|
22
|
+
def _engine
|
23
|
+
@engine
|
24
|
+
end
|
25
|
+
|
26
|
+
def _default_template_format
|
27
|
+
@default_template_format
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'action_mailer'
|
2
|
+
|
3
|
+
module PaperPlane
|
4
|
+
module FlightRoutes
|
5
|
+
class Email < Base
|
6
|
+
default_engine ActionMailer::Base
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def do_fly
|
11
|
+
_preprend_view_lookup
|
12
|
+
_insert_mailer_method
|
13
|
+
_set_layout
|
14
|
+
|
15
|
+
@_template_formats = %i[html text]
|
16
|
+
|
17
|
+
mail = @_engine.send(@method, context.merge(headers: headers))
|
18
|
+
|
19
|
+
if Rails.env.development?
|
20
|
+
LetterOpener::DeliveryMethod.new.deliver!(mail)
|
21
|
+
else
|
22
|
+
mail.deliver!
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def headers
|
27
|
+
{
|
28
|
+
template_path: _template_folder,
|
29
|
+
template_name: _template_name,
|
30
|
+
subject: subject,
|
31
|
+
to: recipient.email,
|
32
|
+
from: 'Christophe Vercarre <christophe@colochousing.com>',
|
33
|
+
charset: 'utf-8',
|
34
|
+
bcc: ENV['EMAIL_INTERCEPTOR_RECIPIENTS'].split(',')
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def subject
|
39
|
+
@context.dig(:@subject)
|
40
|
+
end
|
41
|
+
|
42
|
+
def _insert_mailer_method
|
43
|
+
@_engine.define_method(@method) do |context|
|
44
|
+
context.each do |var, _v|
|
45
|
+
next unless var.to_s.starts_with? '@'
|
46
|
+
|
47
|
+
instance_variable_set(var, context.dig(var))
|
48
|
+
end
|
49
|
+
mail(context[:headers])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def _preprend_view_lookup
|
54
|
+
@_engine.prepend_view_path _default_views_folder
|
55
|
+
end
|
56
|
+
|
57
|
+
def _set_layout
|
58
|
+
@_engine.layout 'email'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'twilio-ruby'
|
2
|
+
|
3
|
+
module PaperPlane
|
4
|
+
module FlightRoutes
|
5
|
+
class Sms < Base
|
6
|
+
default_engine Twilio::REST::Client.new(ENV['TWILIO_ACCOUNT_SID'], ENV['TWILIO_AUTH_TOKEN'])
|
7
|
+
|
8
|
+
def do_fly
|
9
|
+
return if intercept?
|
10
|
+
|
11
|
+
@_engine.create(message_payload)
|
12
|
+
end
|
13
|
+
|
14
|
+
def message_payload
|
15
|
+
{
|
16
|
+
from: ENV['TWILIO_NUMBER'],
|
17
|
+
to: recipient.full_mobile_number,
|
18
|
+
body: template
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def intercept?; end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'active_job'
|
2
|
+
|
3
|
+
module PaperPlane
|
4
|
+
class FlyJob < ActiveJob::Base
|
5
|
+
queue_as :paper_planes
|
6
|
+
|
7
|
+
class << self
|
8
|
+
alias_method :fly_later, :perform_later
|
9
|
+
end
|
10
|
+
|
11
|
+
def perform(paper_plane_name, action_name, **args)
|
12
|
+
paper_plane_name.constantize.fly_action(action_name, **args.merge(async: true))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'railties/rails/railtie'
|
4
|
+
|
5
|
+
module PaperPlane
|
6
|
+
class Railtie < ::Rails::Railtie
|
7
|
+
config.eager_load_namespaces << PaperPlane
|
8
|
+
|
9
|
+
# generators do
|
10
|
+
# require 'path/to/my_railtie_generator'
|
11
|
+
# end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%% message.subject = "New Email" %>
|
File without changes
|
metadata
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: paper_plane
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Guilherme Andrade
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-07-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.0'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 6.0.3
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '6.0'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 6.0.3
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: actionmailer
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '6.0'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 6.0.3
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '6.0'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 6.0.3
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: activejob
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '6.0'
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 6.0.3
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '6.0'
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 6.0.3
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: twilio-ruby
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - "~>"
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '5.27'
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 5.27.1
|
83
|
+
type: :runtime
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '5.27'
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 5.27.1
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: objectified
|
95
|
+
requirement: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: 0.1.3
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 0.1.3
|
103
|
+
type: :runtime
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 0.1.3
|
110
|
+
- - "~>"
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: 0.1.3
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: railties
|
115
|
+
requirement: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - "~>"
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '6.0'
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: 6.0.3
|
123
|
+
type: :runtime
|
124
|
+
prerelease: false
|
125
|
+
version_requirements: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - "~>"
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '6.0'
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: 6.0.3
|
133
|
+
description: A featherweight library for multi thread message deliveries.
|
134
|
+
email:
|
135
|
+
- guilherme.andrade.ao@gmail.com
|
136
|
+
executables: []
|
137
|
+
extensions: []
|
138
|
+
extra_rdoc_files: []
|
139
|
+
files:
|
140
|
+
- Changelog.md
|
141
|
+
- README.md
|
142
|
+
- lib/generators/paper_plane_generator.rb
|
143
|
+
- lib/paper_plane.rb
|
144
|
+
- lib/paper_plane/base.rb
|
145
|
+
- lib/paper_plane/callbacks.rb
|
146
|
+
- lib/paper_plane/flight_route_registerer.rb
|
147
|
+
- lib/paper_plane/flight_routes/base.rb
|
148
|
+
- lib/paper_plane/flight_routes/class_methods.rb
|
149
|
+
- lib/paper_plane/flight_routes/email.rb
|
150
|
+
- lib/paper_plane/flight_routes/sms.rb
|
151
|
+
- lib/paper_plane/fly_job.rb
|
152
|
+
- lib/paper_plane/railtie.rb
|
153
|
+
- lib/paper_plane/version.rb
|
154
|
+
- lib/templates/paper_plane/email.tt
|
155
|
+
- lib/templates/paper_plane/paper_plane.rb.tt
|
156
|
+
- lib/templates/paper_plane/sms.tt
|
157
|
+
homepage: https://github.com/guilherme-andrade/paper_plane
|
158
|
+
licenses:
|
159
|
+
- MIT
|
160
|
+
metadata:
|
161
|
+
homepage_uri: https://github.com/guilherme-andrade/paper_plane
|
162
|
+
source_code_uri: https://github.com/guilherme-andrade/paper_plane
|
163
|
+
changelog_uri: https://github.com/guilherme-andrade/paper_plane/blob/master/Changelog.md
|
164
|
+
post_install_message:
|
165
|
+
rdoc_options: []
|
166
|
+
require_paths:
|
167
|
+
- lib
|
168
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - ">="
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0'
|
173
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
174
|
+
requirements:
|
175
|
+
- - ">="
|
176
|
+
- !ruby/object:Gem::Version
|
177
|
+
version: '0'
|
178
|
+
requirements: []
|
179
|
+
rubygems_version: 3.0.3
|
180
|
+
signing_key:
|
181
|
+
specification_version: 4
|
182
|
+
summary: A featherweight library for multi thread message deliveries.
|
183
|
+
test_files: []
|