mailer-log 0.2.1 → 0.2.4

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: c36e93f917cf148538170a5874f21ae944619a9297576a0ca4f7c22d8e1df5ad
4
- data.tar.gz: 93dadd61e8429d629856adf0a740eec374019511404b7ae6f48c5fb534ebd877
3
+ metadata.gz: 3785cbf9b2307b102f2665f7d1d243a8ea47a5c24279880bff1909e8f73bd298
4
+ data.tar.gz: acec07a5240eecd4aa838003efa4121593983aaab5854412aa847df1c264ea8c
5
5
  SHA512:
6
- metadata.gz: 98e72645f62e30e6e4298951b16e028de4d3418b9020ad78a6cda3deb33ae53feacb09644f947b07d265e81d1440ab0bf76998eb699d3ecec5b197e03b196edc
7
- data.tar.gz: 4221adc21951a2f11e9c319b2f27be00ccb3a40e6d0b7b28b5f153218aaf4495bd4afd880313e48b06b9a2c072f8b22dbccdbbd41a0e61cc6517290fe9bc8bc0
6
+ metadata.gz: 2f9049e41b9200d4fcccafa04c25c145d255cff23fbb2cdd094e7fcf8892671b5046901ca92f8180f9c69302a1650745fe34320f898c6f8ff009858e3e74647a
7
+ data.tar.gz: dee222520c88d07c49b99a65d16c988ab5b4d3875653e57c03ed03acbe87368ecdda0eeb60787da3c61f50de7b3334365804bdbada95855370314ca35a877355
@@ -2,13 +2,10 @@
2
2
 
3
3
  module MailerLog
4
4
  class AdminController < ::AdminsController
5
- # Make main app routes available in views (for header_partial)
6
5
  helper Rails.application.routes.url_helpers
7
6
 
8
7
  before_action :authenticate_mailer_log!
9
8
 
10
- rescue_from 'Pundit::NotAuthorizedError', with: :render_not_found
11
-
12
9
  private
13
10
 
14
11
  def authenticate_mailer_log!
@@ -16,9 +13,5 @@ module MailerLog
16
13
 
17
14
  MailerLog.configuration.authenticate_with_proc.call(self)
18
15
  end
19
-
20
- def render_not_found
21
- raise ActionController::RoutingError, 'Not Found'
22
- end
23
16
  end
24
17
  end
@@ -5,7 +5,7 @@ module MailerLog
5
5
  skip_before_action :verify_authenticity_token
6
6
 
7
7
  before_action :verify_signature
8
- before_action :deduplicate_event
8
+ before_action :handle_deduplicate_event
9
9
 
10
10
  # POST /mailer_log/webhooks/mailgun
11
11
  def mailgun
@@ -55,12 +55,11 @@ module MailerLog
55
55
  head :unauthorized
56
56
  end
57
57
 
58
- def deduplicate_event
58
+ def handle_deduplicate_event
59
59
  event_id = params.dig('event-data', 'id')
60
60
  return true unless event_id
61
61
 
62
62
  cache_key = "mailer_log:event:#{event_id}"
63
-
64
63
  if Rails.cache.exist?(cache_key)
65
64
  head :ok
66
65
  return false
@@ -2,48 +2,73 @@
2
2
 
3
3
  module MailerLog
4
4
  module SpaHelper
5
- def mailer_log_asset_path(name)
6
- manifest = mailer_log_manifest
7
- base_path = request.script_name
8
- return "#{base_path}/assets/#{name}" unless manifest
9
-
10
- entry = manifest[name] || manifest["src/#{name}"] || manifest["assets/#{name}"]
11
- return "#{base_path}/assets/#{name}" unless entry
12
-
13
- file = entry.is_a?(Hash) ? entry['file'] : entry
14
- # Manifest paths already include 'assets/' prefix
15
- "#{base_path}/#{file}"
16
- end
17
-
18
5
  def mailer_log_js_entry
6
+ return nil if mailer_log_dev_server_url
7
+
19
8
  manifest = mailer_log_manifest
20
9
  return nil unless manifest
21
10
 
22
11
  entry = manifest['index.html'] || manifest['src/main.js']
23
12
  return nil unless entry
24
13
 
25
- entry.is_a?(Hash) ? entry['file'] : entry
14
+ file = entry.is_a?(Hash) ? entry['file'] : entry
15
+ "#{asset_base_path}/#{file}"
26
16
  end
27
17
 
28
18
  def mailer_log_css_entry
19
+ return nil if mailer_log_dev_server_url
20
+
29
21
  manifest = mailer_log_manifest
30
22
  return nil unless manifest
31
23
 
32
24
  entry = manifest['index.html']
33
25
  return nil unless entry.is_a?(Hash)
34
26
 
35
- css_files = entry['css']
36
- css_files&.first
27
+ css_file = entry['css']&.first
28
+ return nil unless css_file
29
+
30
+ "#{asset_base_path}/#{css_file}"
31
+ end
32
+
33
+ def mailer_log_dev_server_url
34
+ return nil unless ENV['MAILER_LOG_DEV_SERVER_URL']
35
+
36
+ "#{ENV['MAILER_LOG_DEV_SERVER_URL']}/mailer_log"
37
37
  end
38
38
 
39
39
  private
40
40
 
41
+ def asset_base_path
42
+ # In dev, middleware serves from gem's public dir at /mailer_log/
43
+ # In production, assets are copied to asset pipeline dir
44
+ if Rails.application.config.public_file_server.enabled
45
+ '/mailer_log'
46
+ else
47
+ "/#{asset_output_dir}/mailer_log"
48
+ end
49
+ end
50
+
51
+ def asset_output_dir
52
+ @asset_output_dir ||= if defined?(ViteRuby)
53
+ ViteRuby.config.public_output_dir
54
+ elsif defined?(Webpacker)
55
+ Webpacker.config.public_output_path.basename.to_s
56
+ else
57
+ 'assets'
58
+ end
59
+ end
60
+
41
61
  def mailer_log_manifest
42
62
  @mailer_log_manifest ||= begin
43
- manifest_path = MailerLog::Engine.root.join('public', 'mailer_log', '.vite', 'manifest.json')
44
- return nil unless File.exist?(manifest_path)
63
+ # Check Rails app's asset output directory (after assets:precompile)
64
+ rails_manifest = Rails.root.join('public', asset_output_dir, 'mailer_log', '.vite', 'manifest.json')
65
+ return JSON.parse(File.read(rails_manifest)) if File.exist?(rails_manifest)
66
+
67
+ # Fallback to gem's built-in assets (served via middleware in dev)
68
+ gem_manifest = MailerLog::Engine.root.join('public', 'mailer_log', '.vite', 'manifest.json')
69
+ return JSON.parse(File.read(gem_manifest)) if File.exist?(gem_manifest)
45
70
 
46
- JSON.parse(File.read(manifest_path))
71
+ nil
47
72
  end
48
73
  end
49
74
  end
@@ -4,10 +4,10 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Email Log</title>
7
- <% if (css = mailer_log_css_entry) %>
8
- <link rel="stylesheet" href="<%= request.script_name %>/<%= css %>">
9
- <% else %>
10
- <script type="module" src="http://localhost:5173/@vite/client"></script>
7
+ <% if (dev_url = mailer_log_dev_server_url) %>
8
+ <script type="module" src="<%= dev_url %>/@vite/client"></script>
9
+ <% elsif (css = mailer_log_css_entry) %>
10
+ <link rel="stylesheet" href="<%= css %>">
11
11
  <% end %>
12
12
  </head>
13
13
  <body class="bg-gray-100 min-h-screen">
@@ -22,10 +22,10 @@
22
22
  <%= render partial: header_partial %>
23
23
  <% end %>
24
24
  <div id="app"></div>
25
- <% if (js = mailer_log_js_entry) %>
26
- <script type="module" src="<%= request.script_name %>/<%= js %>"></script>
27
- <% else %>
28
- <script type="module" src="http://localhost:5173/src/main.js"></script>
25
+ <% if (dev_url = mailer_log_dev_server_url) %>
26
+ <script type="module" src="<%= dev_url %>/src/main.js"></script>
27
+ <% elsif (js = mailer_log_js_entry) %>
28
+ <script type="module" src="<%= js %>"></script>
29
29
  <% end %>
30
30
  </body>
31
31
  </html>
data/config/routes.rb CHANGED
@@ -10,10 +10,7 @@ MailerLog::Engine.routes.draw do
10
10
  resources :mailers, only: :index
11
11
  end
12
12
 
13
- # Static assets for Vue SPA
14
- get 'assets/*path', to: 'assets#show', as: :asset, format: false
15
-
16
- # SPA catch-all - serves Vue app for all other routes
17
- get '/', to: 'spa#index'
18
- get '/*path', to: 'spa#index', constraints: ->(req) { !req.path.start_with?('/api', '/webhooks', '/assets') }
13
+ # SPA catch-all - serves Vue app for all routes
14
+ get '*path', to: 'spa#index'
15
+ root to: 'spa#index'
19
16
  end
@@ -29,6 +29,20 @@ module MailerLog
29
29
  g.factory_bot dir: 'spec/factories'
30
30
  end
31
31
 
32
+ # Serve gem's static assets in development
33
+ # In production, assets are copied via rake task and served by nginx
34
+ initializer 'mailer_log.static_assets' do |app|
35
+ next unless app.config.public_file_server.enabled
36
+
37
+ gem_public = MailerLog::Engine.root.join('public').to_s
38
+ app.middleware.insert_before(
39
+ ActionDispatch::Static,
40
+ ActionDispatch::Static,
41
+ gem_public,
42
+ headers: { 'Cache-Control' => 'public, max-age=31536000' }
43
+ )
44
+ end
45
+
32
46
  # Load rake tasks
33
47
  rake_tasks do
34
48
  load MailerLog::Engine.root.join('lib', 'tasks', 'mailer_log.rake')
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MailerLog
4
- VERSION = '0.2.1'
4
+ VERSION = '0.2.4'
5
5
  end
@@ -1,10 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  namespace :mailer_log do
4
- desc 'Copy MailerLog assets to public/'
4
+ desc 'Copy MailerLog assets to asset pipeline output directory'
5
5
  task install_assets: :environment do
6
6
  source = MailerLog::Engine.root.join('public', 'mailer_log')
7
- destination = Rails.root.join('public', 'mailer_log')
7
+
8
+ # Detect asset output directory from ViteRuby or Webpacker
9
+ output_dir = if defined?(ViteRuby)
10
+ ViteRuby.config.public_output_dir
11
+ elsif defined?(Webpacker)
12
+ Webpacker.config.public_output_path.basename.to_s
13
+ else
14
+ 'assets'
15
+ end
16
+
17
+ destination = Rails.root.join('public', output_dir, 'mailer_log')
8
18
 
9
19
  unless source.exist?
10
20
  puts "ERROR: MailerLog assets not found at #{source}"
@@ -12,30 +22,13 @@ namespace :mailer_log do
12
22
  end
13
23
 
14
24
  FileUtils.rm_rf(destination) if destination.exist?
25
+ FileUtils.mkdir_p(destination.dirname)
15
26
  FileUtils.cp_r(source, destination)
16
27
  puts "MailerLog assets copied to #{destination}"
17
28
  end
18
-
19
- desc 'Build MailerLog Vue.js frontend (for gem development only)'
20
- task :build_frontend do
21
- frontend_dir = MailerLog::Engine.root.join('frontend')
22
-
23
- unless frontend_dir.exist?
24
- puts 'ERROR: Frontend source not available (only in gem source, not RubyGems)'
25
- exit 1
26
- end
27
-
28
- puts 'Installing npm dependencies...'
29
- system('npm install', chdir: frontend_dir.to_s) || raise('npm install failed')
30
-
31
- puts 'Building frontend...'
32
- system('npm run build', chdir: frontend_dir.to_s) || raise('npm build failed')
33
-
34
- puts 'Frontend built successfully!'
35
- end
36
29
  end
37
30
 
38
- # Hook into assets:precompile to copy MailerLog assets
31
+ # Hook into assets:precompile
39
32
  if Rake::Task.task_defined?('assets:precompile')
40
33
  Rake::Task['assets:precompile'].enhance do
41
34
  Rake::Task['mailer_log:install_assets'].invoke
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Email Log</title>
7
- <script type="module" crossorigin src="/admin/mailer-log/assets/assets/mailer_log-zD1d7Bvi.js"></script>
8
- <link rel="stylesheet" crossorigin href="/admin/mailer-log/assets/assets/index-D3WsYsVX.css">
7
+ <script type="module" crossorigin src="/mailer_log/assets/mailer_log-zD1d7Bvi.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/mailer_log/assets/index-D3WsYsVX.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="app"></div>
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.2.1
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - TrafficRunners
@@ -75,7 +75,6 @@ files:
75
75
  - app/controllers/mailer_log/api/emails_controller.rb
76
76
  - app/controllers/mailer_log/api/mailers_controller.rb
77
77
  - app/controllers/mailer_log/application_controller.rb
78
- - app/controllers/mailer_log/assets_controller.rb
79
78
  - app/controllers/mailer_log/spa_controller.rb
80
79
  - app/controllers/mailer_log/webhooks_controller.rb
81
80
  - app/helpers/mailer_log/spa_helper.rb
@@ -1,42 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module MailerLog
4
- class AssetsController < ActionController::Base
5
- skip_forgery_protection
6
-
7
- def show
8
- file_path = MailerLog::Engine.root.join('public', 'mailer_log', 'assets', params[:path])
9
-
10
- if File.exist?(file_path) && file_path.to_s.start_with?(MailerLog::Engine.root.join('public', 'mailer_log').to_s)
11
- content_type = content_type_for(file_path)
12
- send_file file_path, type: content_type, disposition: 'inline'
13
- else
14
- head :not_found
15
- end
16
- end
17
-
18
- private
19
-
20
- def content_type_for(file_path)
21
- extension = File.extname(file_path).downcase
22
- case extension
23
- when '.js'
24
- 'application/javascript'
25
- when '.css'
26
- 'text/css'
27
- when '.map'
28
- 'application/json'
29
- when '.svg'
30
- 'image/svg+xml'
31
- when '.png'
32
- 'image/png'
33
- when '.jpg', '.jpeg'
34
- 'image/jpeg'
35
- when '.woff', '.woff2'
36
- 'font/woff2'
37
- else
38
- 'application/octet-stream'
39
- end
40
- end
41
- end
42
- end