emailbutler 0.2.2
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/MIT-LICENSE +20 -0
- data/README.md +67 -0
- data/Rakefile +10 -0
- data/app/assets/config/emailbutler_manifest.js +1 -0
- data/app/assets/stylesheets/emailbutler/application.css +15 -0
- data/app/controllers/emailbutler/application_controller.rb +6 -0
- data/app/controllers/emailbutler/webhooks_controller.rb +22 -0
- data/app/views/layouts/emailbutler/application.html.erb +12 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20220908180903_create_emailbutler_tables.rb +28 -0
- data/lib/emailbutler/adapters/active_record.rb +81 -0
- data/lib/emailbutler/configuration.rb +11 -0
- data/lib/emailbutler/dsl.rb +39 -0
- data/lib/emailbutler/engine.rb +13 -0
- data/lib/emailbutler/mailers/helpers.rb +42 -0
- data/lib/emailbutler/version.rb +5 -0
- data/lib/emailbutler/webhooks/mappers/sendgrid.rb +35 -0
- data/lib/emailbutler/webhooks/receiver.rb +32 -0
- data/lib/emailbutler.rb +46 -0
- data/lib/generators/emailbutler/active_record_generator.rb +37 -0
- data/lib/generators/emailbutler/templates/migration.erb +28 -0
- data/lib/tasks/emailbutler_tasks.rake +6 -0
- metadata +208 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 07e27b9787bb6f85389d9d6628041cec10a2c422c5806b216c1e8a597a6b65f2
|
4
|
+
data.tar.gz: 1728e696da05d221df0c990f2248c0bd5e8753f2b8b3569905b054ed624845f5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 34af5717bd9e42499faa83988388cc65b6ad87e33ff7d31912e120a7e69e7d381c92ad4a4b6e926fe8c845505311bc046114caa00fb9debaceba7f2d5ceed1be
|
7
|
+
data.tar.gz: f8d56d0c8d13d74f90c32ea95a9edd6eaa3fd064eadb343233f5678389059d4eebcb74e9e1fa3e15c583fccff639371d4389b95511d51875e26c5316667c8618
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2022 Bogdanov Anton
|
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
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Emailbutler
|
2
|
+
Simple email tracker for Ruby on Rails applications.
|
3
|
+
Emailbutler allows you to track delivery status of emails sent by your app.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
```ruby
|
9
|
+
gem 'emailbutler'
|
10
|
+
```
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
```bash
|
14
|
+
$ bundle install
|
15
|
+
$ rails g emailbutler:active_record
|
16
|
+
$ rails db:migrate
|
17
|
+
```
|
18
|
+
|
19
|
+
## Engine configuration
|
20
|
+
|
21
|
+
### Initializer
|
22
|
+
|
23
|
+
Add configuration line to config/initializers/emailbutler.rb:
|
24
|
+
|
25
|
+
#### ActiveRecord
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
require 'emailbutler/adapters/active_record'
|
29
|
+
|
30
|
+
Emailbutler.configure do |config|
|
31
|
+
config.adapter = Emailbutler::Adapters::ActiveRecord.new
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
### Routes
|
36
|
+
|
37
|
+
Add this line to config/routes.rb
|
38
|
+
```ruby
|
39
|
+
mount Emailbutler::Engine => '/emailbutler'
|
40
|
+
```
|
41
|
+
|
42
|
+
### Mailers
|
43
|
+
|
44
|
+
Update you application mailer
|
45
|
+
```ruby
|
46
|
+
class ApplicationMailer < ActionMailer::Base
|
47
|
+
include Emailbutler::Mailers::Helpers
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
### Email provider webhooks settings
|
52
|
+
|
53
|
+
#### Sendgrid
|
54
|
+
|
55
|
+
- go to [Mail settings](https://app.sendgrid.com/settings/mail_settings),
|
56
|
+
- turn on Event Webhook,
|
57
|
+
- in the HTTP POST URL field, paste the URL to webhook controller of your app,
|
58
|
+
- select all deliverability data,
|
59
|
+
- save settings.
|
60
|
+
|
61
|
+
## Usage
|
62
|
+
|
63
|
+
1. Each event with sending email will create new record with message params in database.
|
64
|
+
2. Each webhook event will update status of message in database.
|
65
|
+
|
66
|
+
## License
|
67
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
//= link_directory ../stylesheets/emailbutler .css
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Emailbutler
|
4
|
+
class WebhooksController < ApplicationController
|
5
|
+
skip_before_action :verify_authenticity_token
|
6
|
+
|
7
|
+
def create
|
8
|
+
::Emailbutler::Webhooks::Receiver.call(
|
9
|
+
user_agent: request.headers['HTTP_USER_AGENT'],
|
10
|
+
payload: receiver_params.to_h
|
11
|
+
)
|
12
|
+
|
13
|
+
head :ok
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def receiver_params
|
19
|
+
params.permit('_json' => %w[smtp-id event])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/config/routes.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
class CreateEmailbutlerTables < ActiveRecord::Migration[7.0]
|
2
|
+
def self.up
|
3
|
+
enable_extension 'pgcrypto' unless extensions.include?('pgcrypto')
|
4
|
+
enable_extension 'uuid-ossp' unless extensions.include?('uuid-ossp')
|
5
|
+
|
6
|
+
create_table :emailbutler_messages do |t|
|
7
|
+
t.uuid :uuid, null: false, default: ''
|
8
|
+
t.string :mailer, null: false
|
9
|
+
t.string :action, null: false
|
10
|
+
t.jsonb :params, null: false, default: {}
|
11
|
+
t.string :send_to, array: true
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
add_index :emailbutler_messages, :uuid, unique: true
|
15
|
+
|
16
|
+
create_table :emailbutler_events do |t|
|
17
|
+
t.integer :emailbutler_message_id, null: false, index: true
|
18
|
+
t.integer :status, null: false
|
19
|
+
t.datetime :timestamp
|
20
|
+
t.timestamps
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.down
|
25
|
+
drop_table :emailbutler_messages
|
26
|
+
drop_table :emailbutler_events
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
module Emailbutler
|
6
|
+
module Adapters
|
7
|
+
class ActiveRecord
|
8
|
+
# Abstract base class for internal models
|
9
|
+
class Model < ::ActiveRecord::Base
|
10
|
+
self.abstract_class = true
|
11
|
+
end
|
12
|
+
|
13
|
+
class Emailbutler::Message < Model
|
14
|
+
self.table_name = :emailbutler_messages
|
15
|
+
|
16
|
+
REJECTED = 'rejected'
|
17
|
+
PROCESSED = 'processed'
|
18
|
+
FAILED = 'failed'
|
19
|
+
DELIVERED = 'delivered'
|
20
|
+
|
21
|
+
has_many :emailbutler_events,
|
22
|
+
class_name: 'Emailbutler::Event', dependent: :destroy, foreign_key: :emailbutler_message_id
|
23
|
+
|
24
|
+
enum status: { REJECTED => 0, PROCESSED => 1, FAILED => 2, DELIVERED => 3 }
|
25
|
+
|
26
|
+
after_initialize :generate_uuid
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def generate_uuid
|
31
|
+
self.uuid ||= SecureRandom.uuid
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Emailbutler::Event < Model
|
36
|
+
self.table_name = :emailbutler_events
|
37
|
+
|
38
|
+
belongs_to :emailbutler_message, class_name: 'Emailbutler::Message'
|
39
|
+
end
|
40
|
+
|
41
|
+
# Public: The name of the adapter.
|
42
|
+
attr_reader :name, :message_class, :event_class
|
43
|
+
|
44
|
+
# Public: Initialize a new ActiveRecord adapter instance.
|
45
|
+
#
|
46
|
+
# name - The Symbol name for this adapter. Optional (default :active_record)
|
47
|
+
# message_class - The AR class responsible for the messages table.
|
48
|
+
# event_class - The AR class responsible for the messages events table.
|
49
|
+
def initialize(options={})
|
50
|
+
@name = options.fetch(:name, :active_record)
|
51
|
+
@message_class = options.fetch(:message_class) { Emailbutler::Message }
|
52
|
+
@event_class = options.fetch(:event_class) { Emailbutler::Event }
|
53
|
+
end
|
54
|
+
|
55
|
+
# Public: Builds a message.
|
56
|
+
def build_message(args={})
|
57
|
+
@message_class.new(args)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Public: Sets attribute with value for the message.
|
61
|
+
def set_message_attribute(message, attribute, value)
|
62
|
+
message[attribute] = value
|
63
|
+
end
|
64
|
+
|
65
|
+
# Public: Saves the message.
|
66
|
+
def save_message(message)
|
67
|
+
message.save
|
68
|
+
end
|
69
|
+
|
70
|
+
# Public: Finds message by args.
|
71
|
+
def find_message_by(args={})
|
72
|
+
@message_class.find_by(args)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Public: Creates a message event.
|
76
|
+
def create_message_event(message, args={})
|
77
|
+
@event_class.create(args.merge(emailbutler_message_id: message.id))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Emailbutler
|
4
|
+
class DSL
|
5
|
+
attr_reader :adapter
|
6
|
+
|
7
|
+
# Public: Returns a new instance of the DSL.
|
8
|
+
#
|
9
|
+
# adapter - The adapter that this DSL instance should use.
|
10
|
+
def initialize(adapter)
|
11
|
+
@adapter = adapter
|
12
|
+
end
|
13
|
+
|
14
|
+
# Public: Build a message.
|
15
|
+
def build_message(args={})
|
16
|
+
adapter.build_message(args)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Public: Sets attribute with value for the message.
|
20
|
+
def set_message_attribute(*args)
|
21
|
+
adapter.set_message_attribute(*args)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Public: Saves the message.
|
25
|
+
def save_message(message)
|
26
|
+
adapter.save_message(message)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Public: Finds message by args.
|
30
|
+
def find_message_by(args={})
|
31
|
+
adapter.find_message_by(args)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Public: Creates a message event.
|
35
|
+
def create_message_event(message, args={})
|
36
|
+
adapter.create_message_event(message, args)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Emailbutler
|
4
|
+
class Engine < ::Rails::Engine
|
5
|
+
isolate_namespace Emailbutler
|
6
|
+
|
7
|
+
config.generators do |g|
|
8
|
+
g.test_framework :rspec
|
9
|
+
g.fixture_replacement :factory_bot
|
10
|
+
g.factory_bot dir: 'spec/factories'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Emailbutler
|
4
|
+
module Mailers
|
5
|
+
module Helpers
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
after_action :save_emailbutler_message
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def process_action(*args)
|
15
|
+
build_emailbutler_message(args)
|
16
|
+
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def build_emailbutler_message(args)
|
21
|
+
@message = Emailbutler.build_message(
|
22
|
+
mailer: self.class.to_s,
|
23
|
+
action: action_name,
|
24
|
+
params: serialize_params(mailer_params: params, action_params: args[1..])
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
def serialize_params(value)
|
29
|
+
return value.map { |element| serialize_params(element) } if value.is_a?(Array)
|
30
|
+
return value.transform_values { |element| serialize_params(element) } if value.is_a?(Hash)
|
31
|
+
return value.to_global_id.to_s if value.respond_to?(:to_global_id)
|
32
|
+
|
33
|
+
value
|
34
|
+
end
|
35
|
+
|
36
|
+
def save_emailbutler_message
|
37
|
+
Emailbutler.set_message_attribute(@message, :send_to, mail.to)
|
38
|
+
Emailbutler.save_message(@message)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Emailbutler
|
4
|
+
module Webhooks
|
5
|
+
module Mappers
|
6
|
+
class Sendgrid
|
7
|
+
DELIVERABILITY_MAPPER = {
|
8
|
+
'processed' => 'processed',
|
9
|
+
'delivered' => 'delivered',
|
10
|
+
'deferred' => 'failed',
|
11
|
+
'bounce' => 'failed',
|
12
|
+
'dropped' => 'failed'
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
def self.call(args={})
|
16
|
+
new.call(**args)
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(payload:)
|
20
|
+
payload['_json'].filter_map { |message|
|
21
|
+
message_uuid = message['smtp-id']
|
22
|
+
status = DELIVERABILITY_MAPPER[message['event']]
|
23
|
+
next unless message_uuid || status
|
24
|
+
|
25
|
+
{
|
26
|
+
message_uuid: message_uuid,
|
27
|
+
status: status,
|
28
|
+
timestamp: Time.at(message['timestamp']).utc.to_datetime
|
29
|
+
}
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'emailbutler/webhooks/mappers/sendgrid'
|
4
|
+
|
5
|
+
module Emailbutler
|
6
|
+
module Webhooks
|
7
|
+
class Receiver
|
8
|
+
SENDGRID_USER_AGENT = 'SendGrid Event API'
|
9
|
+
|
10
|
+
def self.call(args={})
|
11
|
+
new.call(**args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(user_agent:, payload:)
|
15
|
+
select_mapper(user_agent)
|
16
|
+
.call(payload: payload)
|
17
|
+
.each { |event|
|
18
|
+
message = Emailbutler.find_message_by(uuid: event.delete(:message_uuid))
|
19
|
+
Emailbutler.create_message_event(message, event)
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def select_mapper(user_agent)
|
26
|
+
case user_agent
|
27
|
+
when SENDGRID_USER_AGENT then Emailbutler::Webhooks::Mappers::Sendgrid
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/emailbutler.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
require 'emailbutler/version'
|
6
|
+
require 'emailbutler/engine'
|
7
|
+
require 'emailbutler/configuration'
|
8
|
+
require 'emailbutler/dsl'
|
9
|
+
require 'emailbutler/webhooks/receiver'
|
10
|
+
require 'emailbutler/mailers/helpers'
|
11
|
+
|
12
|
+
module Emailbutler
|
13
|
+
extend self
|
14
|
+
extend Forwardable
|
15
|
+
|
16
|
+
# Public: Given an adapter returns a handy DSL to all the emailbutler goodness.
|
17
|
+
def new(adapter)
|
18
|
+
DSL.new(adapter)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Public: Configure emailbutler.
|
22
|
+
#
|
23
|
+
# Emailbutler.configure do |config|
|
24
|
+
# config.adapter = Emailbutler::Adapters::ActiveRecord.new
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
def configure
|
28
|
+
yield configuration
|
29
|
+
end
|
30
|
+
|
31
|
+
# Public: Returns Emailbutler::Configuration instance.
|
32
|
+
def configuration
|
33
|
+
@configuration ||= Configuration.new
|
34
|
+
end
|
35
|
+
|
36
|
+
# Public: Default per thread emailbutler instance if configured.
|
37
|
+
# Returns Emailbutler::DSL instance.
|
38
|
+
def instance
|
39
|
+
Thread.current[:emailbutler_instance] ||= new(configuration.adapter)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Public: All the methods delegated to instance. These should match the interface of Emailbutler::DSL.
|
43
|
+
def_delegators :instance,
|
44
|
+
:adapter, :build_message, :set_message_attribute, :save_message, :find_message_by,
|
45
|
+
:create_message_event
|
46
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators/active_record'
|
4
|
+
|
5
|
+
module Emailbutler
|
6
|
+
module Generators
|
7
|
+
class ActiveRecordGenerator < ::Rails::Generators::Base
|
8
|
+
include ::Rails::Generators::Migration
|
9
|
+
desc 'Generates migration for emailbutler tables'
|
10
|
+
|
11
|
+
source_paths << File.join(File.dirname(__FILE__), 'templates')
|
12
|
+
|
13
|
+
def self.next_migration_number(dirname)
|
14
|
+
::ActiveRecord::Generators::Base.next_migration_number(dirname)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.migration_version
|
18
|
+
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]" if requires_migration_number?
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.requires_migration_number?
|
22
|
+
Rails::VERSION::MAJOR.to_i >= 5
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_migration_file
|
26
|
+
options = {
|
27
|
+
migration_version: migration_version
|
28
|
+
}
|
29
|
+
migration_template 'migration.erb', 'db/migrate/create_emailbutler_tables.rb', options
|
30
|
+
end
|
31
|
+
|
32
|
+
def migration_version
|
33
|
+
self.class.migration_version
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class CreateEmailbutlerTables < ActiveRecord::Migration<%= migration_version %>
|
2
|
+
def self.up
|
3
|
+
enable_extension 'pgcrypto' unless extensions.include?('pgcrypto')
|
4
|
+
enable_extension 'uuid-ossp' unless extensions.include?('uuid-ossp')
|
5
|
+
|
6
|
+
create_table :emailbutler_messages do |t|
|
7
|
+
t.uuid :uuid, null: false, default: ''
|
8
|
+
t.string :mailer, null: false
|
9
|
+
t.string :action, null: false
|
10
|
+
t.jsonb :params, null: false, default: {}
|
11
|
+
t.string :send_to, array: true
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
add_index :emailbutler_messages, :uuid, unique: true
|
15
|
+
|
16
|
+
create_table :emailbutler_events do |t|
|
17
|
+
t.integer :emailbutler_message_id, null: false, index: true
|
18
|
+
t.integer :status, null: false
|
19
|
+
t.datetime :timestamp
|
20
|
+
t.timestamps
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.down
|
25
|
+
drop_table :emailbutler_messages
|
26
|
+
drop_table :emailbutler_events
|
27
|
+
end
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: emailbutler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bogdanov Anton
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-09-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 6.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 6.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: sprockets-rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.4.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.4.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pg
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: puma
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '5.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '5.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '13.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '13.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.3'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.3'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop-performance
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.8'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '1.8'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rubocop-rake
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0.6'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0.6'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rubocop-rspec
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '2.0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '2.0'
|
153
|
+
description: Write a longer description or delete this line.
|
154
|
+
email:
|
155
|
+
- kortirso@gmail.com
|
156
|
+
executables: []
|
157
|
+
extensions: []
|
158
|
+
extra_rdoc_files: []
|
159
|
+
files:
|
160
|
+
- MIT-LICENSE
|
161
|
+
- README.md
|
162
|
+
- Rakefile
|
163
|
+
- app/assets/config/emailbutler_manifest.js
|
164
|
+
- app/assets/stylesheets/emailbutler/application.css
|
165
|
+
- app/controllers/emailbutler/application_controller.rb
|
166
|
+
- app/controllers/emailbutler/webhooks_controller.rb
|
167
|
+
- app/views/layouts/emailbutler/application.html.erb
|
168
|
+
- config/routes.rb
|
169
|
+
- db/migrate/20220908180903_create_emailbutler_tables.rb
|
170
|
+
- lib/emailbutler.rb
|
171
|
+
- lib/emailbutler/adapters/active_record.rb
|
172
|
+
- lib/emailbutler/configuration.rb
|
173
|
+
- lib/emailbutler/dsl.rb
|
174
|
+
- lib/emailbutler/engine.rb
|
175
|
+
- lib/emailbutler/mailers/helpers.rb
|
176
|
+
- lib/emailbutler/version.rb
|
177
|
+
- lib/emailbutler/webhooks/mappers/sendgrid.rb
|
178
|
+
- lib/emailbutler/webhooks/receiver.rb
|
179
|
+
- lib/generators/emailbutler/active_record_generator.rb
|
180
|
+
- lib/generators/emailbutler/templates/migration.erb
|
181
|
+
- lib/tasks/emailbutler_tasks.rake
|
182
|
+
homepage: https://github.com/kortirso/emailbutler
|
183
|
+
licenses:
|
184
|
+
- MIT
|
185
|
+
metadata:
|
186
|
+
homepage_uri: https://github.com/kortirso/emailbutler
|
187
|
+
source_code_uri: https://github.com/kortirso/emailbutler
|
188
|
+
changelog_uri: https://github.com/kortirso/emailbutler/blob/master/CHANGELOG.md
|
189
|
+
post_install_message:
|
190
|
+
rdoc_options: []
|
191
|
+
require_paths:
|
192
|
+
- lib
|
193
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
194
|
+
requirements:
|
195
|
+
- - ">="
|
196
|
+
- !ruby/object:Gem::Version
|
197
|
+
version: '2.7'
|
198
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
199
|
+
requirements:
|
200
|
+
- - ">="
|
201
|
+
- !ruby/object:Gem::Version
|
202
|
+
version: '0'
|
203
|
+
requirements: []
|
204
|
+
rubygems_version: 3.3.7
|
205
|
+
signing_key:
|
206
|
+
specification_version: 4
|
207
|
+
summary: Write a short summary, because RubyGems requires one.
|
208
|
+
test_files: []
|