emailbutler 0.2.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 86c998b3d9e29ae064f2b2881b392661d785534883a28f40cb7fd5e846e5cf69
4
- data.tar.gz: 4952983e5fc06ea2e90f2d2504d66d6c7ea083281796d30b7e71154096235e1d
3
+ metadata.gz: 97c7cc6c31716442ed040ee06b451d2a3a6abdac9262c08e5fee1c9c6de4f385
4
+ data.tar.gz: '048cacc8bb87d36cd5bd7b5ccced2b726dcde665ec3398adc348a605a2dd6774'
5
5
  SHA512:
6
- metadata.gz: eedddd11e3d27324ceeb712c3f9821ede81fe3a02970166c6d7c67b546333ffdd8ce5ffc9cf885879a8020c966233c6aa51088d683546dda472645156f77c3d2
7
- data.tar.gz: da1e97498ff6853525d05a8cfe988aef95cccd3b82e39803c966218945904a45c2830b17bd3a5eea5a728b02eb0e47faf0e4d3b9fdd2e503c87423f3d816df6d
6
+ metadata.gz: ed85dfd33c8f3a0e3f2a091db4921f1a70d696abbfd0869408bca4a1fa66f6f90bfd3d542a88f204b29c0e2c2c9b0a328e9252d1ba5183b7de8edeafc889abb1
7
+ data.tar.gz: 688b1af36d7eaa8ce68f5467ed4a7c22cdd442e0d126e013ac1b9c890f1ff1e308079fe9ee32696403aa21921d1f04f7b78ed3ca68f643bd735981cef571d4c4
data/README.md CHANGED
@@ -29,6 +29,9 @@ require 'emailbutler/adapters/active_record'
29
29
 
30
30
  Emailbutler.configure do |config|
31
31
  config.adapter = Emailbutler::Adapters::ActiveRecord.new
32
+ config.ui_username = 'username'
33
+ config.ui_password = 'password'
34
+ config.ui_secured_environments = ['production']
32
35
  end
33
36
  ```
34
37
 
@@ -63,5 +66,10 @@ end
63
66
  1. Each event with sending email will create new record with message params in database.
64
67
  2. Each webhook event will update status of message in database.
65
68
 
69
+ ### UI
70
+
71
+ Emailbutler provides UI with rendering email tracking statistics - /emailbutler/ui.
72
+ And with opportunity to resend and/or destroy emails.
73
+
66
74
  ## License
67
75
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -1 +1 @@
1
- //= link_directory ../stylesheets/emailbutler .css
1
+ //= link_directory ../stylesheets .css
@@ -0,0 +1,42 @@
1
+ @import url('https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600&display=swap&subset=cyrillic');
2
+
3
+ #emailbutler, #emailbutler body {
4
+ margin: 0;
5
+ padding: 0;
6
+ min-height: 100vh;
7
+ height: 100%;
8
+ }
9
+
10
+ #emailbutler {
11
+ font-family: "Source Sans Pro", "Helvetica", "Open Sans", sans-serif;
12
+ box-sizing: border-box;
13
+
14
+ body {
15
+ position: relative;
16
+ display: flex;
17
+ flex-direction: column;
18
+
19
+ * {
20
+ box-sizing: border-box;
21
+
22
+ &:focus {
23
+ outline: none;
24
+ }
25
+ }
26
+
27
+ p {
28
+ margin: 0;
29
+ }
30
+
31
+ .content {
32
+ flex: 1;
33
+ width: 100%;
34
+ max-width: 90rem;
35
+ margin: 0 auto;
36
+ }
37
+
38
+ h1, h2, h3, h4, h5, h6 {
39
+ margin: 0;
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,10 @@
1
+ footer {
2
+ border-top: 1px solid #e5e7eb;
3
+
4
+ .footer-wrapper {
5
+ width: 100%;
6
+ max-width: 90rem;
7
+ margin: 0 auto;
8
+ padding: .5rem 1rem;
9
+ }
10
+ }
@@ -0,0 +1,26 @@
1
+ header {
2
+ border-bottom: 1px solid #e5e7eb;
3
+
4
+ .header-wrapper {
5
+ display: flex;
6
+ justify-content: space-between;
7
+ align-items: center;
8
+ width: 100%;
9
+ max-width: 90rem;
10
+ margin: 0 auto;
11
+ padding: .5rem 0;
12
+
13
+ a {
14
+ text-decoration: none;
15
+ color: #000;
16
+ }
17
+ }
18
+ }
19
+
20
+ @media screen and (max-width: 48rem) {
21
+ header {
22
+ .header-wrapper {
23
+ flex-direction: column;
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,121 @@
1
+ #emailbutler {
2
+ #dashboard {
3
+ padding-top: 1rem;
4
+ display: flex;
5
+
6
+ .summary {
7
+ list-style: none;
8
+ flex: 1;
9
+ display: flex;
10
+ flex-direction: row;
11
+ padding: .75rem 1rem;
12
+ background: #e5e7eb;
13
+ border-radius: .125rem;
14
+ margin: 0;
15
+
16
+ li {
17
+ flex: 1;
18
+ text-align: center;
19
+
20
+ a {
21
+ text-decoration: none;
22
+ }
23
+ }
24
+
25
+ .status-summary {
26
+ display: flex;
27
+ flex-direction: column;
28
+ color: #000;
29
+ padding: .5rem 0;
30
+
31
+ &:hover {
32
+ background: #d1d5db;
33
+ }
34
+
35
+ span:nth-of-type(1) {
36
+ margin-bottom: .25rem;
37
+ font-weight: 600;
38
+ }
39
+ }
40
+ }
41
+
42
+ .search-form {
43
+ width: 20rem;
44
+ padding-right: 2rem;
45
+
46
+ .form-field {
47
+ display: flex;
48
+ flex-direction: column;
49
+ margin-bottom: .5rem;
50
+
51
+ label {
52
+ margin-bottom: .25rem;
53
+ }
54
+
55
+ input {
56
+ padding: .25rem;
57
+ }
58
+ }
59
+ }
60
+
61
+ .messages {
62
+ flex: 1;
63
+ height: 100%;
64
+
65
+ thead {
66
+ tr {
67
+ th {
68
+ text-align: left;
69
+ padding: .125rem .25rem;
70
+ }
71
+ }
72
+ }
73
+
74
+ tbody {
75
+ tr {
76
+ &:nth-of-type(odd) {
77
+ background: #e5e7eb;
78
+ }
79
+
80
+ &:hover {
81
+ background: #d1d5db;
82
+ }
83
+
84
+ td {
85
+ padding: .125rem .25rem;
86
+
87
+ &.actions {
88
+ display: flex;
89
+
90
+ button {
91
+ &:nth-of-type(1) {
92
+ margin-right: .5rem;
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }
98
+ }
99
+ }
100
+ }
101
+
102
+ .button {
103
+ box-shadow: none;
104
+ border: none;
105
+ cursor: pointer;
106
+ padding: .25rem;
107
+ background: #bbf7d0;
108
+
109
+ &:hover {
110
+ background: #86efac;
111
+ }
112
+
113
+ &.warning {
114
+ background: #fecaca;
115
+
116
+ &:hover {
117
+ background: #fca5a5;
118
+ }
119
+ }
120
+ }
121
+ }
@@ -0,0 +1,4 @@
1
+ @import 'emailbutler/core/base';
2
+ @import 'emailbutler/shared/header';
3
+ @import 'emailbutler/shared/footer';
4
+ @import 'emailbutler/views/dashboard';
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Emailbutler
4
+ module Ui
5
+ class MessagesController < Emailbutler::UiController
6
+ before_action :find_message
7
+
8
+ def update
9
+ Emailbutler.resend_message(@message)
10
+ redirect_to ui_index_path
11
+ end
12
+
13
+ def destroy
14
+ Emailbutler.destroy_message(@message)
15
+ redirect_to ui_index_path
16
+ end
17
+
18
+ private
19
+
20
+ def find_message
21
+ @message = Emailbutler.find_message_by(uuid: params[:id])
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Emailbutler
4
+ class UiController < Emailbutler::ApplicationController
5
+ http_basic_authenticate_with name: Emailbutler.configuration.ui_username,
6
+ password: Emailbutler.configuration.ui_password,
7
+ if: -> { basic_auth_enabled? }
8
+
9
+ def index
10
+ @summary = Emailbutler.count_messages_by_status
11
+ end
12
+
13
+ def show
14
+ @messages = Emailbutler.find_messages_by(search_condition)
15
+ end
16
+
17
+ private
18
+
19
+ def search_condition
20
+ {
21
+ status: params[:id],
22
+ mailer: params[:mailer_name].presence,
23
+ action: params[:action_name].presence,
24
+ send_to: [params[:receiver].presence].compact.presence
25
+ }.compact
26
+ end
27
+
28
+ def basic_auth_enabled?
29
+ configuration = Emailbutler.configuration
30
+
31
+ return false if configuration.ui_username.blank?
32
+ return false if configuration.ui_password.blank?
33
+
34
+ configuration.ui_secured_environments.include?(Rails.env)
35
+ end
36
+ end
37
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Emailbutler
4
- class WebhooksController < ApplicationController
4
+ class WebhooksController < Emailbutler::ApplicationController
5
5
  skip_before_action :verify_authenticity_token
6
6
 
7
7
  def create
@@ -0,0 +1,16 @@
1
+ <div id="dashboard">
2
+ <ul class="summary">
3
+ <li class="status-summary">
4
+ <span><%= @summary.values.sum %></span>
5
+ <span>Total</span>
6
+ </li>
7
+ <% Emailbutler.adapter.message_class.statuses.each_key do |status| %>
8
+ <li>
9
+ <%= link_to ui_path(status), class: 'status-summary' do %>
10
+ <span><%= @summary[status].to_i %></span>
11
+ <span><%= status.capitalize %></span>
12
+ <% end %>
13
+ </li>
14
+ <% end %>
15
+ </ul>
16
+ </div>
@@ -0,0 +1,8 @@
1
+ <footer>
2
+ <div class="footer-wrapper flex flex-row justify-between">
3
+ <div>
4
+ </div>
5
+ <div>
6
+ </div>
7
+ </div>
8
+ </footer>
@@ -0,0 +1,9 @@
1
+ <header>
2
+ <div class="header-wrapper flex justify-between items-center">
3
+ <%= link_to ui_index_path do %>
4
+ <h1>Emailbutler</h1>
5
+ <% end %>
6
+ <nav>
7
+ </nav>
8
+ </div>
9
+ </header>
@@ -0,0 +1,52 @@
1
+ <div id="dashboard">
2
+ <section class="search-form">
3
+ <%= form_with url: ui_path(params[:id]), method: :get do |form| %>
4
+ <div class="form-field">
5
+ <%= form.label :mailer_name, 'Mailer', class: 'form-label' %>
6
+ <%= form.text_field :mailer_name, class: 'form-value', value: params[:mailer_name] %>
7
+ </div>
8
+ <div class="form-field">
9
+ <%= form.label :action_name, 'Action', class: 'form-label' %>
10
+ <%= form.text_field :action_name, class: 'form-value', value: params[:action_name] %>
11
+ </div>
12
+ <div class="form-field">
13
+ <%= form.label :receiver, 'Receiver', class: 'form-label' %>
14
+ <%= form.text_field :receiver, class: 'form-value', value: params[:receiver] %>
15
+ </div>
16
+ <%= form.submit 'Search', class: 'button' %>
17
+ <% end %>
18
+ </section>
19
+ <table class="messages" cellspacing="0">
20
+ <thead>
21
+ <tr>
22
+ <th>ID</th>
23
+ <th>Mailer</th>
24
+ <th>Action</th>
25
+ <th>Send to</th>
26
+ <th>Action params</th>
27
+ <th>Mailer params</th>
28
+ <th></th>
29
+ </tr>
30
+ </thead>
31
+ <tbody>
32
+ <% @messages.each do |message| %>
33
+ <tr>
34
+ <td><%= message.id %></td>
35
+ <td><%= message.mailer %></td>
36
+ <td><%= message.action %></td>
37
+ <td>
38
+ <% message.send_to.each do |receiver| %>
39
+ <p><%= receiver %></p>
40
+ <% end %>
41
+ </td>
42
+ <td><%= message.params['action_params'] %></td>
43
+ <td><%= message.params['mailer_params'] %></td>
44
+ <td class="actions">
45
+ <%= button_to 'Resend', ui_message_path(message.uuid), method: :patch, class: 'button' %>
46
+ <%= button_to 'Destroy', ui_message_path(message.uuid), method: :delete, class: 'button warning' %>
47
+ </td>
48
+ </tr>
49
+ <% end %>
50
+ </tbody>
51
+ </table>
52
+ </div>
@@ -1,12 +1,16 @@
1
1
  <!DOCTYPE html>
2
- <html>
2
+ <html id="emailbutler">
3
3
  <head>
4
4
  <title>Emailbutler</title>
5
5
  <%= csrf_meta_tags %>
6
6
  <%= csp_meta_tag %>
7
- <%= stylesheet_link_tag 'emailbutler/application', media: 'all' %>
7
+ <%= stylesheet_link_tag 'emailbutler', media: 'all' %>
8
8
  </head>
9
- <body>
10
- <%= yield %>
9
+ <body id="emailbutler-body">
10
+ <%= render 'emailbutler/ui/shared/header' %>
11
+ <div class="content">
12
+ <%= yield %>
13
+ </div>
14
+ <%= render 'emailbutler/ui/shared/footer' %>
11
15
  </body>
12
16
  </html>
data/config/routes.rb CHANGED
@@ -2,4 +2,9 @@
2
2
 
3
3
  Emailbutler::Engine.routes.draw do
4
4
  post '/webhooks', to: 'webhooks#create'
5
+
6
+ resources :ui, only: %i[index show]
7
+ namespace :ui do
8
+ resources :messages, only: %i[update destroy]
9
+ end
5
10
  end
@@ -5,6 +5,8 @@ require 'active_record'
5
5
  module Emailbutler
6
6
  module Adapters
7
7
  class ActiveRecord
8
+ include Emailbutler::Helpers
9
+
8
10
  # Abstract base class for internal models
9
11
  class Model < ::ActiveRecord::Base
10
12
  self.abstract_class = true
@@ -68,6 +70,29 @@ module Emailbutler
68
70
  rescue ::ActiveRecord::StaleObjectError
69
71
  update_message(message.reload, args)
70
72
  end
73
+
74
+ # Public: Groups messages by status and count them.
75
+ def count_messages_by_status
76
+ @message_class.group(:status).count
77
+ end
78
+
79
+ # Public: Finds messages by args.
80
+ def find_messages_by(args={})
81
+ @message_class.where(args).order(created_at: :desc)
82
+ end
83
+
84
+ # Public: Resends the message.
85
+ def resend_message(message)
86
+ ::ActiveRecord::Base.transaction do
87
+ message.destroy
88
+ resend_message_with_mailer(message)
89
+ end
90
+ end
91
+
92
+ # Public: Destroy the message.
93
+ def destroy_message(message)
94
+ message.destroy
95
+ end
71
96
  end
72
97
  end
73
98
  end
@@ -2,10 +2,17 @@
2
2
 
3
3
  module Emailbutler
4
4
  class Configuration
5
- attr_accessor :adapter
5
+ attr_accessor :adapter, :ui_username, :ui_password, :ui_secured_environments
6
6
 
7
7
  def initialize
8
8
  @adapter = nil
9
+
10
+ # It's required to specify these 3 variables to enable basic auth to UI
11
+ @ui_username = ''
12
+ @ui_password = ''
13
+
14
+ # Secured environments variable must directly contains environment names
15
+ @ui_secured_environments = []
9
16
  end
10
17
  end
11
18
  end
@@ -35,5 +35,25 @@ module Emailbutler
35
35
  def update_message(message, args={})
36
36
  adapter.update_message(message, args)
37
37
  end
38
+
39
+ # Public: Groups messages by status and count them.
40
+ def count_messages_by_status
41
+ adapter.count_messages_by_status
42
+ end
43
+
44
+ # Public: Finds messages by args.
45
+ def find_messages_by(args={})
46
+ adapter.find_messages_by(args)
47
+ end
48
+
49
+ # Public: Resends the message.
50
+ def resend_message(message)
51
+ adapter.resend_message(message)
52
+ end
53
+
54
+ # Public: Destroys the message.
55
+ def destroy_message(message)
56
+ adapter.destroy_message(message)
57
+ end
38
58
  end
39
59
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Emailbutler
4
+ module Helpers
5
+ private
6
+
7
+ def resend_message_with_mailer(message)
8
+ params = message.params
9
+
10
+ mailer = message.mailer.constantize
11
+ mailer = mailer.with(serialize(params['mailer_params'])) if params['mailer_params'].present?
12
+ mailer = mailer.method(message.action)
13
+ mailer = params['action_params'] ? mailer.call(*serialize(params['action_params'])) : mailer.call
14
+ mailer.deliver_now
15
+ end
16
+
17
+ def serialize(value, reverse=true)
18
+ return value.map { |element| serialize(element, reverse) } if value.is_a?(Array)
19
+ return value.transform_values { |element| serialize(element, reverse) } if value.is_a?(Hash)
20
+
21
+ reverse ? deserialize_value(value) : serialize_value(value)
22
+ end
23
+
24
+ def serialize_value(value)
25
+ return value.to_global_id.to_s if value.respond_to?(:to_global_id)
26
+
27
+ value
28
+ end
29
+
30
+ def deserialize_value(value)
31
+ return GlobalID::Locator.locate(value) if value.is_a?(String) && value.starts_with?('gid://')
32
+
33
+ value
34
+ end
35
+ end
36
+ end
@@ -4,6 +4,7 @@ module Emailbutler
4
4
  module Mailers
5
5
  module Helpers
6
6
  extend ActiveSupport::Concern
7
+ include Emailbutler::Helpers
7
8
 
8
9
  included do
9
10
  after_action :save_emailbutler_message
@@ -21,18 +22,10 @@ module Emailbutler
21
22
  @message = Emailbutler.build_message(
22
23
  mailer: self.class.to_s,
23
24
  action: action_name,
24
- params: serialize_params(mailer_params: params, action_params: args[1..])
25
+ params: serialize({ mailer_params: params, action_params: args[1..] }, false)
25
26
  )
26
27
  end
27
28
 
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
29
  def save_emailbutler_message
37
30
  Emailbutler.set_message_attribute(@message, :send_to, mail.to)
38
31
  Emailbutler.save_message(@message)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Emailbutler
4
- VERSION = '0.2.3'
4
+ VERSION = '0.4.0'
5
5
  end
data/lib/emailbutler.rb CHANGED
@@ -7,6 +7,7 @@ require 'emailbutler/engine'
7
7
  require 'emailbutler/configuration'
8
8
  require 'emailbutler/dsl'
9
9
  require 'emailbutler/webhooks/receiver'
10
+ require 'emailbutler/helpers'
10
11
  require 'emailbutler/mailers/helpers'
11
12
 
12
13
  module Emailbutler
@@ -42,5 +43,5 @@ module Emailbutler
42
43
  # Public: All the methods delegated to instance. These should match the interface of Emailbutler::DSL.
43
44
  def_delegators :instance,
44
45
  :adapter, :build_message, :set_message_attribute, :save_message, :find_message_by,
45
- :update_message
46
+ :update_message, :count_messages_by_status, :find_messages_by, :resend_message, :destroy_message
46
47
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: emailbutler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bogdanov Anton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-16 00:00:00.000000000 Z
11
+ date: 2022-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -25,19 +25,19 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: 6.0.0
27
27
  - !ruby/object:Gem::Dependency
28
- name: sprockets-rails
28
+ name: sass-rails
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 3.4.0
33
+ version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 3.4.0
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -70,16 +70,16 @@ dependencies:
70
70
  name: puma
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">"
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '5.0'
75
+ version: '6.0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">"
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '5.0'
82
+ version: '6.0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rake
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '1.3'
103
+ version: '1.39'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '1.3'
110
+ version: '1.39'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: rubocop-performance
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -150,7 +150,8 @@ dependencies:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
152
  version: '2.0'
153
- description: Write a longer description or delete this line.
153
+ description: Emailbutler allows you to track delivery status of emails sent by your
154
+ app.
154
155
  email:
155
156
  - kortirso@gmail.com
156
157
  executables: []
@@ -161,17 +162,27 @@ files:
161
162
  - README.md
162
163
  - Rakefile
163
164
  - app/assets/config/emailbutler_manifest.js
164
- - app/assets/stylesheets/emailbutler/application.css
165
+ - app/assets/stylesheets/emailbutler.scss
166
+ - app/assets/stylesheets/emailbutler/core/base.scss
167
+ - app/assets/stylesheets/emailbutler/shared/footer.scss
168
+ - app/assets/stylesheets/emailbutler/shared/header.scss
169
+ - app/assets/stylesheets/emailbutler/views/dashboard.scss
165
170
  - app/controllers/emailbutler/application_controller.rb
171
+ - app/controllers/emailbutler/ui/messages_controller.rb
172
+ - app/controllers/emailbutler/ui_controller.rb
166
173
  - app/controllers/emailbutler/webhooks_controller.rb
174
+ - app/views/emailbutler/ui/index.html.erb
175
+ - app/views/emailbutler/ui/shared/_footer.html.erb
176
+ - app/views/emailbutler/ui/shared/_header.html.erb
177
+ - app/views/emailbutler/ui/show.html.erb
167
178
  - app/views/layouts/emailbutler/application.html.erb
168
179
  - config/routes.rb
169
- - db/migrate/20220916162720_create_emailbutler_tables.rb
170
180
  - lib/emailbutler.rb
171
181
  - lib/emailbutler/adapters/active_record.rb
172
182
  - lib/emailbutler/configuration.rb
173
183
  - lib/emailbutler/dsl.rb
174
184
  - lib/emailbutler/engine.rb
185
+ - lib/emailbutler/helpers.rb
175
186
  - lib/emailbutler/mailers/helpers.rb
176
187
  - lib/emailbutler/version.rb
177
188
  - lib/emailbutler/webhooks/mappers/sendgrid.rb
@@ -204,5 +215,5 @@ requirements: []
204
215
  rubygems_version: 3.3.7
205
216
  signing_key:
206
217
  specification_version: 4
207
- summary: Write a short summary, because RubyGems requires one.
218
+ summary: Email tracker for Ruby on Rails applications.
208
219
  test_files: []
@@ -1,15 +0,0 @@
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
- */
@@ -1,23 +0,0 @@
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.integer :status, null: false, default: 0
13
- t.datetime :timestamp
14
- t.integer :lock_version
15
- t.timestamps
16
- end
17
- add_index :emailbutler_messages, :uuid, unique: true
18
- end
19
-
20
- def self.down
21
- drop_table :emailbutler_messages
22
- end
23
- end