mailer-log 0.1.0 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 62eb9e79690dbc8bfda9c264bdebc0d1da51e29f5df9d54d549e9fef7420cf3d
4
- data.tar.gz: c9ff2c0973cdfd3514c6f9b40e102a4aa0784e21290b9b5eee0bfe51ceea9048
3
+ metadata.gz: 64e896ea013f8d46cb167c7ccf6da3a4e021a3e10289fbf2ff6cbf8d14f951b9
4
+ data.tar.gz: 963d939833fd64d529e6b7f9cddc11cbde95d4b9d2aed6b919226285641f66f2
5
5
  SHA512:
6
- metadata.gz: 90f81eac98bbffe31bec481a156d160597a93b4e54d510c8d61784fd02aa38807723ce5cf4b6aaa622c1bd45b30be65c2a11e4a118d887757513ba67ee571cec
7
- data.tar.gz: fab117cb20cb2368872faf733b6718fbffe1fafc51be4b58409d2f66a58cc632b20fe362194940de6dad562416db200de1c54c3dcc722fed803b3d9ffed6a7f0
6
+ metadata.gz: fe3c2c1d76822b2dc5d56ec576024ca56c41bf9a3535bb035540a1cbf2d4424f3de1b0648632c43af5683071bc84d81365cfc0ef843ca2948c298faba55e2a95
7
+ data.tar.gz: c1622125425f2c8c3e82af582202b80a332ed9d5ffa34dbc4c482f1e34d6625de03dd6279cd579545d93949ce1eb8da2a68b003c28395dd56f3f5dd785867182
@@ -6,5 +6,7 @@ module MailerLog
6
6
  # between requests and is safe for multi-threaded servers.
7
7
  class Current < ActiveSupport::CurrentAttributes
8
8
  attribute :email_data
9
+ # Set by process.action_mailer notification before interceptor runs
10
+ attribute :mailer_action, :mailer_class
9
11
  end
10
12
  end
data/config/routes.rb CHANGED
@@ -13,14 +13,7 @@ MailerLog::Engine.routes.draw do
13
13
  # Static assets for Vue SPA
14
14
  get 'assets/*path', to: 'assets#show', as: :asset, format: false
15
15
 
16
- # Legacy Admin UI (ERB-based) - keep for email preview iframe
17
- namespace :admin do
18
- resources :emails, only: %i[index show] do
19
- get :preview, on: :member
20
- end
21
- end
22
-
23
16
  # SPA catch-all - serves Vue app for all other routes
24
17
  get '/', to: 'spa#index'
25
- get '/*path', to: 'spa#index', constraints: ->(req) { !req.path.start_with?('/api', '/admin', '/webhooks', '/assets') }
18
+ get '/*path', to: 'spa#index', constraints: ->(req) { !req.path.start_with?('/api', '/webhooks', '/assets') }
26
19
  end
@@ -14,6 +14,15 @@ module MailerLog
14
14
  end
15
15
  end
16
16
 
17
+ # Subscribe to process.action_mailer to capture mailer action before delivery
18
+ initializer 'mailer_log.notifications' do
19
+ ActiveSupport::Notifications.subscribe('process.action_mailer') do |*args|
20
+ event = ActiveSupport::Notifications::Event.new(*args)
21
+ MailerLog::Current.mailer_action = event.payload[:action]
22
+ MailerLog::Current.mailer_class = event.payload[:mailer]
23
+ end
24
+ end
25
+
17
26
  config.generators do |g|
18
27
  g.test_framework :rspec
19
28
  g.fixture_replacement :factory_bot
@@ -40,10 +40,13 @@ module MailerLog
40
40
  end
41
41
 
42
42
  def extract_mailer_action(message)
43
+ # First, try to get from Current (set by process.action_mailer notification)
44
+ return MailerLog::Current.mailer_action if MailerLog::Current.mailer_action.present?
45
+
43
46
  handler = message.delivery_handler
44
47
  return 'unknown' unless handler
45
48
 
46
- if handler.respond_to?(:action_name)
49
+ if handler.respond_to?(:action_name) && !handler.is_a?(Class)
47
50
  handler.action_name.to_s
48
51
  elsif message['X-Mailer-Action']
49
52
  message['X-Mailer-Action'].to_s
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MailerLog
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.2'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mailer-log
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - TrafficRunners
@@ -71,7 +71,6 @@ files:
71
71
  - LICENSE
72
72
  - README.md
73
73
  - app/assets/stylesheets/mailer_log/emails.scss
74
- - app/controllers/mailer_log/admin/emails_controller.rb
75
74
  - app/controllers/mailer_log/admin_controller.rb
76
75
  - app/controllers/mailer_log/api/emails_controller.rb
77
76
  - app/controllers/mailer_log/api/mailers_controller.rb
@@ -86,10 +85,6 @@ files:
86
85
  - app/models/mailer_log/current.rb
87
86
  - app/models/mailer_log/email.rb
88
87
  - app/models/mailer_log/event.rb
89
- - app/views/mailer_log/admin/emails/_email.html.erb
90
- - app/views/mailer_log/admin/emails/_filters.html.erb
91
- - app/views/mailer_log/admin/emails/index.html.erb
92
- - app/views/mailer_log/admin/emails/show.html.erb
93
88
  - app/views/mailer_log/spa/index.html.erb
94
89
  - config/locales/en.yml
95
90
  - config/routes.rb
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module MailerLog
4
- module Admin
5
- class EmailsController < MailerLog::AdminController
6
- has_scope :recipient
7
- has_scope :sender
8
- has_scope :subject_search
9
- has_scope :by_mailer, as: :mailer
10
- has_scope :by_status, as: :status
11
- has_scope :date_from
12
- has_scope :date_to
13
-
14
- def index
15
- @emails = apply_scopes(MailerLog::Email.order(created_at: :desc))
16
- .page(params[:page])
17
- .per(params[:per] || 25)
18
- @mailers = MailerLog::Email.distinct.pluck(:mailer_class).compact.sort
19
- end
20
-
21
- def show
22
- @email = MailerLog::Email.find(params[:id])
23
- end
24
-
25
- def preview
26
- @email = MailerLog::Email.find(params[:id])
27
- # rubocop:disable Rails/OutputSafety
28
- render html: @email.html_body&.html_safe, layout: false
29
- # rubocop:enable Rails/OutputSafety
30
- end
31
-
32
- end
33
- end
34
- end
@@ -1,29 +0,0 @@
1
- <tr>
2
- <td class="text-nowrap">
3
- <%= email.created_at.strftime('%Y-%m-%d %H:%M') %>
4
- </td>
5
- <td>
6
- <small class="text-muted"><%= email.mailer_class %></small><br>
7
- <code class="small"><%= email.mailer_action %></code>
8
- </td>
9
- <td class="text-truncate" style="max-width: 200px;">
10
- <%= email.to_addresses.join(', ') %>
11
- </td>
12
- <td class="text-truncate" style="max-width: 250px;">
13
- <%= link_to email.subject.presence || '(no subject)', mailer_log_engine.admin_email_path(email) %>
14
- </td>
15
- <td>
16
- <% status_class = case email.status
17
- when 'delivered', 'opened', 'clicked' then 'success'
18
- when 'bounced', 'complained' then 'danger'
19
- when 'sent' then 'info'
20
- else 'secondary'
21
- end %>
22
- <span class="badge badge-<%= status_class %>"><%= email.status %></span>
23
- </td>
24
- <td class="text-right">
25
- <%= link_to mailer_log_engine.admin_email_path(email), class: 'btn btn-sm btn-outline-primary' do %>
26
- <i class="far fa-eye"></i>
27
- <% end %>
28
- </td>
29
- </tr>
@@ -1,58 +0,0 @@
1
- <%= form_tag mailer_log_engine.admin_emails_path, method: :get, class: 'mb-3' do %>
2
- <div class="row">
3
- <div class="col-md-2">
4
- <div class="form-group">
5
- <label class="small text-muted">Recipient</label>
6
- <%= text_field_tag :recipient, params[:recipient], class: 'form-control form-control-sm', placeholder: 'Email address' %>
7
- </div>
8
- </div>
9
- <div class="col-md-2">
10
- <div class="form-group">
11
- <label class="small text-muted">Sender</label>
12
- <%= text_field_tag :sender, params[:sender], class: 'form-control form-control-sm', placeholder: 'From address' %>
13
- </div>
14
- </div>
15
- <div class="col-md-2">
16
- <div class="form-group">
17
- <label class="small text-muted">Subject</label>
18
- <%= text_field_tag :subject_search, params[:subject_search], class: 'form-control form-control-sm', placeholder: 'Subject contains...' %>
19
- </div>
20
- </div>
21
- <div class="col-md-2">
22
- <div class="form-group">
23
- <label class="small text-muted">Mailer</label>
24
- <%= select_tag :mailer, options_for_select([['All', '']] + @mailers.map { |m| [m, m] }, params[:mailer]), class: 'form-control form-control-sm' %>
25
- </div>
26
- </div>
27
- <div class="col-md-2">
28
- <div class="form-group">
29
- <label class="small text-muted">Status</label>
30
- <%= select_tag :status, options_for_select([['All', ''], ['Pending', 'pending'], ['Sent', 'sent'], ['Delivered', 'delivered'], ['Opened', 'opened'], ['Clicked', 'clicked'], ['Bounced', 'bounced'], ['Complained', 'complained']], params[:status]), class: 'form-control form-control-sm' %>
31
- </div>
32
- </div>
33
- <div class="col-md-2 d-flex align-items-end">
34
- <div class="form-group w-100">
35
- <%= submit_tag 'Filter', class: 'btn btn-primary btn-sm w-100' %>
36
- </div>
37
- </div>
38
- </div>
39
- <div class="row">
40
- <div class="col-md-2">
41
- <div class="form-group">
42
- <label class="small text-muted">Date From</label>
43
- <%= date_field_tag :date_from, params[:date_from], class: 'form-control form-control-sm' %>
44
- </div>
45
- </div>
46
- <div class="col-md-2">
47
- <div class="form-group">
48
- <label class="small text-muted">Date To</label>
49
- <%= date_field_tag :date_to, params[:date_to], class: 'form-control form-control-sm' %>
50
- </div>
51
- </div>
52
- <div class="col-md-2 d-flex align-items-end">
53
- <div class="form-group">
54
- <%= link_to 'Clear', mailer_log_engine.admin_emails_path, class: 'btn btn-outline-secondary btn-sm' %>
55
- </div>
56
- </div>
57
- </div>
58
- <% end %>
@@ -1,61 +0,0 @@
1
- <% set_meta_tags title: ['Admin', 'Email Log'] if respond_to?(:set_meta_tags) %>
2
-
3
- <div class="card card-border-color card-border-color-dark card-default card-table">
4
- <div class="card-header">
5
- <span class="title p-a-1">Email Log (<%= @emails.total_count %>)</span>
6
- </div>
7
- <div class="card-body">
8
- <%= render 'filters' %>
9
-
10
- <div class="table-responsive noSwipe">
11
- <table class="table table-striped table-hover">
12
- <thead>
13
- <tr>
14
- <th>Sent At</th>
15
- <th>Mailer</th>
16
- <th>To</th>
17
- <th>Subject</th>
18
- <th>Status</th>
19
- <th></th>
20
- </tr>
21
- </thead>
22
- <tbody>
23
- <% @emails.each do |email| %>
24
- <%= render 'email', email: email %>
25
- <% end %>
26
- </tbody>
27
- </table>
28
-
29
- <% if @emails.empty? %>
30
- <div class="text-center text-muted py-4">
31
- No emails found
32
- </div>
33
- <% end %>
34
-
35
- <% # Use engine routes for pagination %>
36
- <div class="pagination-wrapper">
37
- <% if @emails.total_pages > 1 %>
38
- <nav aria-label="Pagination">
39
- <ul class="pagination justify-content-center">
40
- <% if @emails.first_page? %>
41
- <li class="page-item disabled"><span class="page-link">&laquo; First</span></li>
42
- <li class="page-item disabled"><span class="page-link">&lsaquo; Prev</span></li>
43
- <% else %>
44
- <li class="page-item"><%= link_to '&laquo; First'.html_safe, mailer_log_engine.admin_emails_path(page: 1, per: params[:per]), class: 'page-link' %></li>
45
- <li class="page-item"><%= link_to '&lsaquo; Prev'.html_safe, mailer_log_engine.admin_emails_path(page: @emails.prev_page, per: params[:per]), class: 'page-link' %></li>
46
- <% end %>
47
- <li class="page-item active"><span class="page-link">Page <%= @emails.current_page %> of <%= @emails.total_pages %></span></li>
48
- <% if @emails.last_page? %>
49
- <li class="page-item disabled"><span class="page-link">Next &rsaquo;</span></li>
50
- <li class="page-item disabled"><span class="page-link">Last &raquo;</span></li>
51
- <% else %>
52
- <li class="page-item"><%= link_to 'Next &rsaquo;'.html_safe, mailer_log_engine.admin_emails_path(page: @emails.next_page, per: params[:per]), class: 'page-link' %></li>
53
- <li class="page-item"><%= link_to 'Last &raquo;'.html_safe, mailer_log_engine.admin_emails_path(page: @emails.total_pages, per: params[:per]), class: 'page-link' %></li>
54
- <% end %>
55
- </ul>
56
- </nav>
57
- <% end %>
58
- </div>
59
- </div>
60
- </div>
61
- </div>
@@ -1,132 +0,0 @@
1
- <% set_meta_tags title: ['Admin', 'Email Log', @email.subject.presence || 'Email Details'] if respond_to?(:set_meta_tags) %>
2
-
3
- <div class="mb-3">
4
- <%= link_to mailer_log_engine.admin_emails_path, class: 'btn btn-outline-secondary btn-sm' do %>
5
- <i class="far fa-arrow-left"></i> Back to Email Log
6
- <% end %>
7
- </div>
8
-
9
- <div class="card card-border-color card-border-color-dark card-default">
10
- <div class="card-header">
11
- <span class="title"><%= @email.subject.presence || '(no subject)' %></span>
12
- <% status_class = case @email.status
13
- when 'delivered', 'opened', 'clicked' then 'success'
14
- when 'bounced', 'complained' then 'danger'
15
- when 'sent' then 'info'
16
- else 'secondary'
17
- end %>
18
- <span class="badge badge-<%= status_class %> float-right"><%= @email.status %></span>
19
- </div>
20
- <div class="card-body">
21
- <div class="row mb-4">
22
- <div class="col-md-6">
23
- <dl class="row">
24
- <dt class="col-sm-3">From</dt>
25
- <dd class="col-sm-9"><code><%= @email.from_address %></code></dd>
26
-
27
- <dt class="col-sm-3">To</dt>
28
- <dd class="col-sm-9"><code><%= @email.to_addresses.join(', ') %></code></dd>
29
-
30
- <% if @email.cc_addresses.present? %>
31
- <dt class="col-sm-3">CC</dt>
32
- <dd class="col-sm-9"><code><%= @email.cc_addresses.join(', ') %></code></dd>
33
- <% end %>
34
-
35
- <% if @email.bcc_addresses.present? %>
36
- <dt class="col-sm-3">BCC</dt>
37
- <dd class="col-sm-9"><code><%= @email.bcc_addresses.join(', ') %></code></dd>
38
- <% end %>
39
-
40
- <dt class="col-sm-3">Mailer</dt>
41
- <dd class="col-sm-9">
42
- <code><%= @email.mailer_class %>#<%= @email.mailer_action %></code>
43
- </dd>
44
-
45
- <dt class="col-sm-3">Message ID</dt>
46
- <dd class="col-sm-9">
47
- <code class="small"><%= @email.message_id %></code>
48
- </dd>
49
-
50
- <dt class="col-sm-3">Sent At</dt>
51
- <dd class="col-sm-9"><%= @email.created_at.strftime('%Y-%m-%d %H:%M:%S %Z') %></dd>
52
-
53
- <% if @email.delivered_at %>
54
- <dt class="col-sm-3">Delivered</dt>
55
- <dd class="col-sm-9"><%= @email.delivered_at.strftime('%Y-%m-%d %H:%M:%S %Z') %></dd>
56
- <% end %>
57
-
58
- <% if @email.opened_at %>
59
- <dt class="col-sm-3">Opened</dt>
60
- <dd class="col-sm-9"><%= @email.opened_at.strftime('%Y-%m-%d %H:%M:%S %Z') %></dd>
61
- <% end %>
62
-
63
- <% if @email.clicked_at %>
64
- <dt class="col-sm-3">Clicked</dt>
65
- <dd class="col-sm-9"><%= @email.clicked_at.strftime('%Y-%m-%d %H:%M:%S %Z') %></dd>
66
- <% end %>
67
-
68
- <% if @email.domain.present? %>
69
- <dt class="col-sm-3">Domain</dt>
70
- <dd class="col-sm-9"><code><%= @email.domain %></code></dd>
71
- <% end %>
72
- </dl>
73
- </div>
74
-
75
- <div class="col-md-6">
76
- <h6>Delivery Events</h6>
77
- <% if @email.events.any? %>
78
- <table class="table table-sm table-bordered">
79
- <thead class="thead-light">
80
- <tr>
81
- <th>Event</th>
82
- <th>Time</th>
83
- <th>Recipient</th>
84
- </tr>
85
- </thead>
86
- <tbody>
87
- <% @email.events.recent.each do |event| %>
88
- <tr>
89
- <td>
90
- <span class="badge badge-<%= event.event_type == 'delivered' ? 'success' : 'secondary' %>">
91
- <%= event.event_type %>
92
- </span>
93
- </td>
94
- <td class="small"><%= event.occurred_at&.strftime('%H:%M:%S') %></td>
95
- <td class="small"><%= event.recipient %></td>
96
- </tr>
97
- <% end %>
98
- </tbody>
99
- </table>
100
- <% else %>
101
- <p class="text-muted small">No delivery events recorded yet.</p>
102
- <% end %>
103
- </div>
104
- </div>
105
-
106
- <h5>Email Preview</h5>
107
- <% if @email.html_body.present? %>
108
- <iframe src="<%= mailer_log_engine.preview_admin_email_path(@email) %>"
109
- class="mailer-log-email-preview"></iframe>
110
- <% elsif @email.text_body.present? %>
111
- <pre class="bg-light p-3 mailer-log-scrollable-content"><%= @email.text_body %></pre>
112
- <% else %>
113
- <p class="text-muted">No email body available.</p>
114
- <% end %>
115
-
116
- <% if @email.call_stack.present? %>
117
- <h5 class="mt-4">Call Stack</h5>
118
- <details>
119
- <summary class="btn btn-sm btn-outline-secondary mb-2">Show call stack</summary>
120
- <pre class="bg-light p-3 small mailer-log-scrollable-content-sm"><%= @email.call_stack %></pre>
121
- </details>
122
- <% end %>
123
-
124
- <% if @email.headers.present? %>
125
- <h5 class="mt-4">Headers</h5>
126
- <details>
127
- <summary class="btn btn-sm btn-outline-secondary mb-2">Show headers</summary>
128
- <pre class="bg-light p-3 small mailer-log-scrollable-content-sm"><%= JSON.pretty_generate(@email.headers) %></pre>
129
- </details>
130
- <% end %>
131
- </div>
132
- </div>