emailbutler 0.3.0 → 0.5.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: 2cb350207d1f0d4174a10f2589ee604cc3ddb71438ed6c63b057ef9975a93ed4
4
- data.tar.gz: a0dae6c1a23c417827d03abf56ae9386696ca175f5de107eb81473925d3010b4
3
+ metadata.gz: 66b96f7ab9361587e0c960875903a0c85cece5ed19ed6891a2acac9027600735
4
+ data.tar.gz: 93d341ed01c2a44c50b84bcdcbce9bb174a6aae6f88e896ac4f8e2a298a9cb2b
5
5
  SHA512:
6
- metadata.gz: 5c69ecaab954896b0378320e4c535dcfb152356117181fc55c3f5fb479afa73ddceee39bfbd10707c6b488710b07e8b281fa96dcc723c114fa76ed78a849aba2
7
- data.tar.gz: 8362e1119289ec26d18b29d7575d629a334265ae9365a052bc84f0e731694ad6372e314f976b22d118a31389691cc06c3194650dcc8b22f994bdfd8e05ab1282
6
+ metadata.gz: 2c3b0c916fc98bde2ab88bc1b0a226288ab1bb5123faac70b121b6d025e22e6892bfc56d55bbffb96f0c9370b15be8b4f096f3d3c773b1afd4baa614aa687fc6
7
+ data.tar.gz: b844827b40c941522993c4993a4c0aa2ab75d789a703189ed1f47c92733166a34d1c16f9b93d7e599d3a699d88e82655024146d4f879c7f28ce880457d1f9986
data/README.md CHANGED
@@ -42,6 +42,13 @@ Add this line to config/routes.rb
42
42
  mount Emailbutler::Engine => '/emailbutler'
43
43
  ```
44
44
 
45
+ ### UI styles
46
+
47
+ For adding styles for UI you need to add this line to assets/config/manifest.js
48
+ ```js
49
+ //= link emailbutler.css
50
+ ```
51
+
45
52
  ### Mailers
46
53
 
47
54
  Update you application mailer
@@ -68,8 +75,12 @@ end
68
75
 
69
76
  ### UI
70
77
 
71
- Emailbutler provides UI with rendering email tracking statistics - /emailbutler/ui/dashboard.
72
- And with opportunity to resend emails.
78
+ Emailbutler provides UI with rendering email tracking statistics - /emailbutler/ui, with opportunity to search, resend and/or destroy emails.
79
+
80
+ <img width="1463" alt="ui_index" src="https://user-images.githubusercontent.com/6195394/202743189-19d1845d-7991-494f-93c1-0dd92b0b5dac.png">
81
+
82
+ <img width="1461" alt="ui_show" src="https://user-images.githubusercontent.com/6195394/202743225-b0ba0ca2-d373-428c-973d-5ec4566a3784.png">
83
+
73
84
 
74
85
  ## License
75
86
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -1,9 +1,11 @@
1
1
  #emailbutler {
2
2
  #dashboard {
3
3
  padding-top: 1rem;
4
+ display: flex;
4
5
 
5
6
  .summary {
6
7
  list-style: none;
8
+ flex: 1;
7
9
  display: flex;
8
10
  flex-direction: row;
9
11
  padding: .75rem 1rem;
@@ -37,54 +39,74 @@
37
39
  }
38
40
  }
39
41
 
40
- .messages {
41
- width: 100%;
42
+ .search-form {
43
+ width: 20rem;
44
+ padding-right: 2rem;
42
45
 
43
- thead {
44
- tr {
45
- th {
46
- text-align: left;
47
- padding: .125rem .25rem;
48
- }
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;
49
57
  }
50
58
  }
59
+ }
51
60
 
52
- tbody {
53
- tr {
54
- &:nth-of-type(odd) {
55
- background: #e5e7eb;
56
- }
61
+ .messages {
62
+ flex: 1;
63
+ height: 100%;
64
+
65
+ .pagination {
66
+ margin-bottom: 1rem;
57
67
 
58
- &:hover {
59
- background: #d1d5db;
68
+ .page {
69
+ padding: .25rem .5rem;
70
+ background: #bbf7d0;
71
+ color: #000;
72
+
73
+ a {
74
+ color: #000;
60
75
  }
76
+ }
77
+ }
61
78
 
62
- td {
63
- padding: .125rem .25rem;
79
+ table {
80
+ width: 100%;
64
81
 
65
- &.actions {
66
- display: flex;
82
+ thead {
83
+ tr {
84
+ th {
85
+ text-align: left;
86
+ padding: .125rem .25rem;
87
+ }
88
+ }
89
+ }
67
90
 
68
- button {
69
- box-shadow: none;
70
- border: none;
71
- cursor: pointer;
72
- padding: .25rem;
91
+ tbody {
92
+ tr {
93
+ &:nth-of-type(odd) {
94
+ background: #e5e7eb;
95
+ }
73
96
 
74
- &.resend {
75
- background: #bbf7d0;
76
- margin-right: .5rem;
97
+ &:hover {
98
+ background: #d1d5db;
99
+ }
77
100
 
78
- &:hover {
79
- background: #86efac;
80
- }
81
- }
101
+ td {
102
+ padding: .125rem .25rem;
82
103
 
83
- &.destroy {
84
- background: #fecaca;
104
+ &.actions {
105
+ display: flex;
85
106
 
86
- &:hover {
87
- background: #fca5a5;
107
+ button {
108
+ &:nth-of-type(1) {
109
+ margin-right: .5rem;
88
110
  }
89
111
  }
90
112
  }
@@ -94,4 +116,24 @@
94
116
  }
95
117
  }
96
118
  }
119
+
120
+ .button {
121
+ box-shadow: none;
122
+ border: none;
123
+ cursor: pointer;
124
+ padding: .25rem;
125
+ background: #bbf7d0;
126
+
127
+ &:hover {
128
+ background: #86efac;
129
+ }
130
+
131
+ &.warning {
132
+ background: #fecaca;
133
+
134
+ &:hover {
135
+ background: #fca5a5;
136
+ }
137
+ }
138
+ }
97
139
  }
@@ -7,12 +7,12 @@ module Emailbutler
7
7
 
8
8
  def update
9
9
  Emailbutler.resend_message(@message)
10
- redirect_to ui_dashboard_index_path
10
+ redirect_to ui_index_path
11
11
  end
12
12
 
13
13
  def destroy
14
14
  Emailbutler.destroy_message(@message)
15
- redirect_to ui_dashboard_index_path
15
+ redirect_to ui_index_path
16
16
  end
17
17
 
18
18
  private
@@ -1,13 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'pagy'
4
+
3
5
  module Emailbutler
4
6
  class UiController < Emailbutler::ApplicationController
7
+ include Pagy::Backend
8
+
5
9
  http_basic_authenticate_with name: Emailbutler.configuration.ui_username,
6
10
  password: Emailbutler.configuration.ui_password,
7
11
  if: -> { basic_auth_enabled? }
8
12
 
13
+ def index
14
+ @summary = Emailbutler.count_messages_by_status
15
+ end
16
+
17
+ def show
18
+ @pagy, @messages = pagy(Emailbutler.find_messages_by(search_condition))
19
+ end
20
+
9
21
  private
10
22
 
23
+ def search_condition
24
+ {
25
+ status: params[:id] == 'all' ? nil : params[:id],
26
+ mailer: params[:mailer_name].presence,
27
+ action: params[:action_name].presence,
28
+ send_to: [params[:receiver].presence].compact.presence
29
+ }.compact
30
+ end
31
+
11
32
  def basic_auth_enabled?
12
33
  configuration = Emailbutler.configuration
13
34
 
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Emailbutler
4
+ module ApplicationHelper
5
+ include Pagy::Frontend
6
+ end
7
+ end
@@ -1,12 +1,14 @@
1
1
  <div id="dashboard">
2
2
  <ul class="summary">
3
- <li class="status-summary">
4
- <span><%= @summary.values.sum %></span>
5
- <span>Total</span>
3
+ <li>
4
+ <%= link_to ui_path(:all), class: 'status-summary' do %>
5
+ <span><%= @summary.values.sum %></span>
6
+ <span>Total</span>
7
+ <% end %>
6
8
  </li>
7
9
  <% Emailbutler.adapter.message_class.statuses.each_key do |status| %>
8
10
  <li>
9
- <%= link_to ui_dashboard_path(status), class: 'status-summary' do %>
11
+ <%= link_to ui_path(status), class: 'status-summary' do %>
10
12
  <span><%= @summary[status].to_i %></span>
11
13
  <span><%= status.capitalize %></span>
12
14
  <% end %>
@@ -1,6 +1,6 @@
1
1
  <header>
2
2
  <div class="header-wrapper flex justify-between items-center">
3
- <%= link_to ui_dashboard_index_path do %>
3
+ <%= link_to ui_index_path do %>
4
4
  <h1>Emailbutler</h1>
5
5
  <% end %>
6
6
  <nav>
@@ -0,0 +1,61 @@
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
+ <section class="messages">
20
+ <%== pagy_nav(@pagy) %>
21
+ <table cellspacing="0">
22
+ <thead>
23
+ <tr>
24
+ <th>ID</th>
25
+ <th>Mailer</th>
26
+ <th>Action</th>
27
+ <th>Send to</th>
28
+ <% if params[:id] == 'all' %>
29
+ <th>Status</th>
30
+ <% end %>
31
+ <th>Action params</th>
32
+ <th>Mailer params</th>
33
+ <th></th>
34
+ </tr>
35
+ </thead>
36
+ <tbody>
37
+ <% @messages.each do |message| %>
38
+ <tr>
39
+ <td><%= message.id %></td>
40
+ <td><%= message.mailer %></td>
41
+ <td><%= message.action %></td>
42
+ <td>
43
+ <% message.send_to.each do |receiver| %>
44
+ <p><%= receiver %></p>
45
+ <% end %>
46
+ </td>
47
+ <% if params[:id] == 'all' %>
48
+ <td><%= message.status %></td>
49
+ <% end %>
50
+ <td><%= message.params['action_params'] %></td>
51
+ <td><%= message.params['mailer_params'] %></td>
52
+ <td class="actions">
53
+ <%= button_to 'Resend', ui_message_path(message.uuid), method: :patch, class: 'button' %>
54
+ <%= button_to 'Destroy', ui_message_path(message.uuid), method: :delete, class: 'button warning' %>
55
+ </td>
56
+ </tr>
57
+ <% end %>
58
+ </tbody>
59
+ </table>
60
+ </section>
61
+ </div>
data/config/routes.rb CHANGED
@@ -3,8 +3,8 @@
3
3
  Emailbutler::Engine.routes.draw do
4
4
  post '/webhooks', to: 'webhooks#create'
5
5
 
6
+ resources :ui, only: %i[index show]
6
7
  namespace :ui do
7
- resources :dashboard, only: %i[index show]
8
8
  resources :messages, only: %i[update destroy]
9
9
  end
10
10
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Emailbutler
4
- VERSION = '0.3.0'
4
+ VERSION = '0.5.0'
5
5
  end
@@ -12,8 +12,8 @@ module Emailbutler
12
12
  'dropped' => 'failed'
13
13
  }.freeze
14
14
 
15
- def self.call(args={})
16
- new.call(**args)
15
+ def self.call(...)
16
+ new.call(...)
17
17
  end
18
18
 
19
19
  def call(payload:)
@@ -7,8 +7,8 @@ module Emailbutler
7
7
  class Receiver
8
8
  SENDGRID_USER_AGENT = 'SendGrid Event API'
9
9
 
10
- def self.call(args={})
11
- new.call(**args)
10
+ def self.call(...)
11
+ new.call(...)
12
12
  end
13
13
 
14
14
  def call(user_agent:, payload:)
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: emailbutler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.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-10-04 00:00:00.000000000 Z
11
+ date: 2022-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pagy
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.10'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.10'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rails
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -70,16 +84,16 @@ dependencies:
70
84
  name: puma
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
- - - ">"
87
+ - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: '5.0'
89
+ version: '6.0'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
- - - ">"
94
+ - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: '5.0'
96
+ version: '6.0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: rake
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +114,14 @@ dependencies:
100
114
  requirements:
101
115
  - - "~>"
102
116
  - !ruby/object:Gem::Version
103
- version: '1.3'
117
+ version: '1.39'
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
122
  - - "~>"
109
123
  - !ruby/object:Gem::Version
110
- version: '1.3'
124
+ version: '1.39'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: rubocop-performance
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -150,7 +164,8 @@ dependencies:
150
164
  - - "~>"
151
165
  - !ruby/object:Gem::Version
152
166
  version: '2.0'
153
- description: Write a longer description or delete this line.
167
+ description: Emailbutler allows you to track delivery status of emails sent by your
168
+ app.
154
169
  email:
155
170
  - kortirso@gmail.com
156
171
  executables: []
@@ -167,17 +182,16 @@ files:
167
182
  - app/assets/stylesheets/emailbutler/shared/header.scss
168
183
  - app/assets/stylesheets/emailbutler/views/dashboard.scss
169
184
  - app/controllers/emailbutler/application_controller.rb
170
- - app/controllers/emailbutler/ui/dashboard_controller.rb
171
185
  - app/controllers/emailbutler/ui/messages_controller.rb
172
186
  - app/controllers/emailbutler/ui_controller.rb
173
187
  - app/controllers/emailbutler/webhooks_controller.rb
174
- - app/views/emailbutler/ui/dashboard/index.html.erb
175
- - app/views/emailbutler/ui/dashboard/show.html.erb
188
+ - app/helpers/emailbutler/application_helper.rb
189
+ - app/views/emailbutler/ui/index.html.erb
176
190
  - app/views/emailbutler/ui/shared/_footer.html.erb
177
191
  - app/views/emailbutler/ui/shared/_header.html.erb
192
+ - app/views/emailbutler/ui/show.html.erb
178
193
  - app/views/layouts/emailbutler/application.html.erb
179
194
  - config/routes.rb
180
- - db/migrate/20220916162720_create_emailbutler_tables.rb
181
195
  - lib/emailbutler.rb
182
196
  - lib/emailbutler/adapters/active_record.rb
183
197
  - lib/emailbutler/configuration.rb
@@ -216,5 +230,5 @@ requirements: []
216
230
  rubygems_version: 3.3.7
217
231
  signing_key:
218
232
  specification_version: 4
219
- summary: Write a short summary, because RubyGems requires one.
233
+ summary: Email tracker for Ruby on Rails applications.
220
234
  test_files: []
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Emailbutler
4
- module Ui
5
- class DashboardController < Emailbutler::UiController
6
- def index
7
- @summary = Emailbutler.count_messages_by_status
8
- end
9
-
10
- def show
11
- @messages = Emailbutler.find_messages_by(status: params[:id])
12
- end
13
- end
14
- end
15
- end
@@ -1,35 +0,0 @@
1
- <div id="dashboard">
2
- <table class="messages" cellspacing="0">
3
- <thead>
4
- <tr>
5
- <th>ID</th>
6
- <th>UUID</th>
7
- <th>Mailer</th>
8
- <th>Action</th>
9
- <th>Send to</th>
10
- <th>Params</th>
11
- <th></th>
12
- </tr>
13
- </thead>
14
- <tbody>
15
- <% @messages.each do |message| %>
16
- <tr>
17
- <td><%= message.id %></td>
18
- <td><%= message.uuid %></td>
19
- <td><%= message.mailer %></td>
20
- <td><%= message.action %></td>
21
- <td>
22
- <% message.send_to.each do |receiver| %>
23
- <p><%= receiver %></p>
24
- <% end %>
25
- </td>
26
- <td><%= message.params %></td>
27
- <td class="actions">
28
- <%= button_to 'Resend', ui_message_path(message.uuid), method: :patch, class: 'resend' %>
29
- <%= button_to 'Destroy', ui_message_path(message.uuid), method: :delete, class: 'destroy' %>
30
- </td>
31
- </tr>
32
- <% end %>
33
- </tbody>
34
- </table>
35
- </div>
@@ -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