letter_opener_web 1.3.4 → 2.0.0.pre.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/brakeman-analysis.yml +46 -0
  3. data/.github/workflows/main.yml +34 -0
  4. data/.github/workflows/release-gem.yml +32 -0
  5. data/.gitignore +1 -0
  6. data/.rspec +1 -1
  7. data/.rubocop.yml +5 -16
  8. data/.rubocop_todo.yml +19 -0
  9. data/CHANGELOG.md +22 -1
  10. data/Gemfile +4 -0
  11. data/LICENSE.txt +1 -1
  12. data/README.md +33 -24
  13. data/app/controllers/letter_opener_web/application_controller.rb +1 -0
  14. data/app/controllers/letter_opener_web/letters_controller.rb +14 -7
  15. data/app/models/letter_opener_web/letter.rb +37 -5
  16. data/app/views/layouts/letter_opener_web/_javascripts.html.erb +31 -0
  17. data/app/views/layouts/letter_opener_web/_styles.html.erb +3 -0
  18. data/{vendor/assets/javascripts/letter_opener_web/favcount.js → app/views/layouts/letter_opener_web/js/_favcount.html.erb} +9 -7
  19. data/app/views/layouts/letter_opener_web/js/_jquery.html.erb +7 -0
  20. data/app/views/layouts/letter_opener_web/letters.html.erb +5 -3
  21. data/app/views/layouts/letter_opener_web/styles/_bootstrap.html.erb +9 -0
  22. data/app/views/layouts/letter_opener_web/styles/_icon.html.erb +2 -0
  23. data/app/views/layouts/letter_opener_web/styles/_letters.html.erb +70 -0
  24. data/app/views/letter_opener_web/letters/_item.html.erb +10 -0
  25. data/app/views/letter_opener_web/letters/index.html.erb +11 -46
  26. data/config/routes.rb +5 -5
  27. data/letter_opener_web.gemspec +19 -15
  28. data/lib/letter_opener_web/delivery_method.rb +1 -1
  29. data/lib/letter_opener_web/engine.rb +0 -10
  30. data/lib/letter_opener_web/version.rb +1 -1
  31. data/lib/letter_opener_web.rb +1 -0
  32. data/spec/controllers/letter_opener_web/letters_controller_spec.rb +22 -11
  33. data/spec/dummy/app/assets/config/manifest.js +0 -2
  34. data/spec/dummy/app/assets/stylesheets/application.css +0 -16
  35. data/spec/dummy/app/channels/application_cable/channel.rb +6 -0
  36. data/spec/dummy/app/channels/application_cable/connection.rb +6 -0
  37. data/spec/dummy/app/controllers/application_controller.rb +0 -1
  38. data/spec/dummy/app/{assets/javascripts → javascript/packs}/application.js +2 -0
  39. data/spec/dummy/app/jobs/application_job.rb +9 -0
  40. data/spec/dummy/app/models/application_record.rb +5 -0
  41. data/spec/dummy/app/models/concerns/.keep +0 -0
  42. data/spec/dummy/app/views/layouts/application.html.erb +4 -7
  43. data/spec/dummy/bin/rails +2 -4
  44. data/spec/dummy/bin/rake +2 -4
  45. data/spec/dummy/bin/setup +7 -10
  46. data/spec/dummy/config/application.rb +21 -7
  47. data/spec/dummy/config/environments/development.rb +44 -6
  48. data/spec/dummy/config/environments/production.rb +51 -14
  49. data/spec/dummy/config/environments/test.rb +30 -6
  50. data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -4
  51. data/spec/dummy/config/initializers/assets.rb +5 -5
  52. data/spec/dummy/config/initializers/backtrace_silencers.rb +5 -3
  53. data/spec/dummy/config/initializers/content_security_policy.rb +29 -0
  54. data/spec/dummy/config/initializers/filter_parameter_logging.rb +3 -1
  55. data/spec/dummy/config/initializers/permissions_policy.rb +12 -0
  56. data/spec/dummy/config/locales/en.yml +11 -1
  57. data/spec/dummy/config/puma.rb +18 -22
  58. data/spec/dummy/config/routes.rb +1 -4
  59. data/spec/dummy/config.ru +1 -0
  60. data/spec/dummy/public/404.html +6 -6
  61. data/spec/dummy/public/422.html +6 -6
  62. data/spec/dummy/public/500.html +6 -6
  63. data/spec/dummy/storage/.keep +0 -0
  64. data/spec/letter_opener_web_spec.rb +2 -2
  65. data/spec/models/letter_opener_web/letter_spec.rb +62 -17
  66. data/spec/spec_helper.rb +8 -0
  67. metadata +93 -56
  68. data/.travis.yml +0 -26
  69. data/app/assets/javascripts/letter_opener_web/application.js +0 -30
  70. data/app/assets/stylesheets/letter_opener_web/application.css.erb +0 -54
  71. data/bin/rails +0 -11
  72. data/spec/dummy/app/controllers/home_controller.rb +0 -10
  73. data/spec/dummy/app/mailers/contact_mailer.rb +0 -14
  74. data/spec/dummy/app/views/contact_mailer/new_message.html.erb +0 -21
  75. data/spec/dummy/app/views/contact_mailer/new_message.text.erb +0 -3
  76. data/spec/dummy/app/views/home/index.html.erb +0 -50
  77. data/spec/dummy/bin/bundle +0 -5
  78. data/spec/dummy/bin/update +0 -31
  79. data/spec/dummy/config/initializers/new_framework_defaults.rb +0 -10
  80. data/spec/dummy/config/initializers/session_store.rb +0 -5
  81. data/spec/dummy/config/secrets.yml +0 -22
  82. data/spec/dummy/config/spring.rb +0 -8
  83. data/vendor/assets/images/letter_opener_web/blue-dot.ico +0 -0
  84. data/vendor/assets/images/letter_opener_web/glyphicons-halflings-white.png +0 -0
  85. data/vendor/assets/images/letter_opener_web/glyphicons-halflings.png +0 -0
  86. data/vendor/assets/javascripts/letter_opener_web/bootstrap.min.js +0 -6
  87. data/vendor/assets/javascripts/letter_opener_web/jquery-1.8.3.min.js +0 -2
  88. data/vendor/assets/javascripts/letter_opener_web/jquery_ujs.js +0 -429
  89. data/vendor/assets/stylesheets/letter_opener_web/bootstrap.min.css +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5371ec444a8c7c1d8446e0c61e163787a52d0e9e919ccc9113ae611c19087f02
4
- data.tar.gz: 2d6a00656c5f18e33d7a31d9dfea339c73af434c6dda1498ab803a4f0f045e96
3
+ metadata.gz: 285be7616fcef875c214cf862ce009bad30562c1de5f0cd7ea65348ef9201233
4
+ data.tar.gz: ad8acc2f43564626b87a5950debe40700f3f492f29a397fb5f8d88f6ae516747
5
5
  SHA512:
6
- metadata.gz: 02a86b66e9c4804785777ffcffc790a024d5760edbfb49453680ce11d02055542d3bdf27e8e498f9fa10ed3b531d241c55b1dc11895e3e6d496713d015819487
7
- data.tar.gz: 288baaa9373f2f02187197c49cf5078dc872ce89455ae119feb0491e756ec712a67a3d7134eb8bc66e1684579912671e3b3c785bd8aa3525f055ad751d6e0ff2
6
+ metadata.gz: 7355ec8c5c8ec6dbaa7b459475983a6da804d3f35ca30cdcb15d9b1b206877b2a92af5f0e02adc4850cebd1045c0f9ea57399d45cb883c6d357a3f9cf786cc80
7
+ data.tar.gz: f001b0b9f78aa875f6130bfb0b7443c3647f2b1edff3fc582d44890cbfafb7e0bdc55aa18ae4da30f8e936a6dda5168922414047b984f266fbbaba3a363bc604
@@ -0,0 +1,46 @@
1
+ # This workflow integrates Brakeman with GitHub's Code Scanning feature
2
+ # Brakeman is a static analysis security vulnerability scanner for Ruby on Rails applications
3
+
4
+ name: Brakeman Scan
5
+
6
+ on:
7
+ push:
8
+ branches: [ master ]
9
+ pull_request:
10
+ # The branches below must be a subset of the branches above
11
+ branches: [ master ]
12
+ schedule:
13
+ - cron: '21 4 * * 4'
14
+
15
+ jobs:
16
+ brakeman-scan:
17
+ name: Brakeman Scan
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ # Checkout the repository to the GitHub Actions runner
21
+ - name: Checkout
22
+ uses: actions/checkout@v2
23
+
24
+ # Customize the ruby version depending on your needs
25
+ - name: Setup Ruby
26
+ uses: actions/setup-ruby@v1
27
+ with:
28
+ ruby-version: '2.7'
29
+
30
+ - name: Setup Brakeman
31
+ env:
32
+ BRAKEMAN_VERSION: '4.10' # SARIF support is provided in Brakeman version 4.10+
33
+ run: |
34
+ gem install brakeman --version $BRAKEMAN_VERSION
35
+
36
+ # Execute Brakeman CLI and generate a SARIF output with the security issues identified during the analysis
37
+ - name: Scan
38
+ continue-on-error: true
39
+ run: |
40
+ brakeman -f sarif -o output.sarif.json .
41
+
42
+ # Upload the SARIF file generated in the previous step
43
+ - name: Upload SARIF
44
+ uses: github/codeql-action/upload-sarif@v1
45
+ with:
46
+ sarif_file: output.sarif.json
@@ -0,0 +1,34 @@
1
+ name: Run tests
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master, next ]
8
+
9
+ jobs:
10
+ test:
11
+
12
+ runs-on: ubuntu-latest
13
+
14
+ strategy:
15
+ matrix:
16
+ ruby-version: [2.7, 3.0]
17
+
18
+ steps:
19
+ - uses: actions/checkout@v2
20
+
21
+ - name: Set up Ruby ${{ matrix.ruby-version }}
22
+ uses: ruby/setup-ruby@v1
23
+ with:
24
+ ruby-version: ${{ matrix.ruby-version }}
25
+ bundler-cache: true
26
+
27
+ - name: Install dependencies
28
+ run: bundle install
29
+
30
+ - name: Run tests
31
+ run: bundle exec rake
32
+
33
+ - name: Build gem
34
+ run: bundle exec rake build
@@ -0,0 +1,32 @@
1
+ name: Release gem
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ jobs:
9
+ build:
10
+ name: Build + Publish
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - uses: actions/checkout@v2
15
+
16
+ - name: Set up Ruby 3.0
17
+ uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: 3.0
20
+
21
+ - run: bundle install
22
+
23
+ - name: Publish to RubyGems
24
+ run: |
25
+ mkdir -p $HOME/.gem
26
+ touch $HOME/.gem/credentials
27
+ chmod 0600 $HOME/.gem/credentials
28
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
29
+ bundle exec rake build
30
+ gem push pkg/*.gem
31
+ env:
32
+ GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
data/.gitignore CHANGED
@@ -2,6 +2,7 @@
2
2
  *.rbc
3
3
  .bundle
4
4
  .config
5
+ .ruby-version
5
6
  .yardoc
6
7
  InstalledFiles
7
8
  _yardoc
data/.rspec CHANGED
@@ -1,4 +1,4 @@
1
1
  --order rand
2
2
  --color
3
3
  --format progress
4
- --require spec_helper
4
+ --require rails_helper
data/.rubocop.yml CHANGED
@@ -1,28 +1,17 @@
1
1
  ---
2
+ inherit_from: .rubocop_todo.yml
3
+
2
4
  AllCops:
3
- TargetRubyVersion: 2.3
5
+ NewCops: enable
6
+ TargetRubyVersion: 2.7
4
7
  Exclude:
5
- - "bin/**/*"
6
8
  - "spec/dummy/bin/**/*"
7
9
  - "tmp/**/*"
8
10
  - "vendor/**/*"
9
11
 
10
- # not available in older versions of Ruby
11
- Layout/IndentHeredoc:
12
- Enabled: false
13
-
14
- Style/Documentation:
15
- Enabled: false
16
-
17
- Style/ClassAndModuleChildren:
18
- EnforcedStyle: nested
19
-
20
- Style/SingleLineBlockParams:
21
- Enabled: false
22
-
23
12
  Metrics/BlockLength:
24
13
  Exclude:
25
14
  - spec/**/*_spec.rb
26
15
 
27
- Metrics/LineLength:
16
+ Layout/LineLength:
28
17
  Max: 120
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,19 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2021-10-02 14:42:36 UTC using RuboCop version 1.22.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 5
10
+ # Configuration parameters: AllowedConstants.
11
+ Style/Documentation:
12
+ Exclude:
13
+ - 'spec/**/*'
14
+ - 'test/**/*'
15
+ - 'app/controllers/letter_opener_web/letters_controller.rb'
16
+ - 'app/models/letter_opener_web/letter.rb'
17
+ - 'lib/letter_opener_web.rb'
18
+ - 'lib/letter_opener_web/delivery_method.rb'
19
+ - 'lib/letter_opener_web/engine.rb'
data/CHANGELOG.md CHANGED
@@ -1,4 +1,25 @@
1
- ## [Unreleased](https://github.com/fgrehm/letter_opener_web/compare/v1.3.4...master)
1
+ ## [v2.0.0](https://github.com/fgrehm/letter_opener_web/compare/v1.4.1...next)
2
+
3
+ - Require Rails >= 5.2, run tests against Rails 6.1 [#113](https://github.com/fgrehm/letter_opener_web/pull/113)
4
+ - Upgrade to Bootstrap 4.2 [#113](https://github.com/fgrehm/letter_opener_web/pull/113)
5
+ - Inline CSS and Javascript [#113](https://github.com/fgrehm/letter_opener_web/pull/113)
6
+ - Add rexml gem into dependency for Ruby 3.0 [#106](https://github.com/fgrehm/letter_opener_web/pull/106)
7
+ - Add routes for Rails API mode [#69](https://github.com/fgrehm/letter_opener_web/pull/69)
8
+ - Prevent name conflict with `Letter` class [#108](https://github.com/fgrehm/letter_opener_web/pull/108)
9
+ - Add Rails' built-in CSRF protection [#111](https://github.com/fgrehm/letter_opener_web/pull/111)
10
+ - Add Rails' CSP nonce to the script tag [#112](https://github.com/fgrehm/letter_opener_web/pull/112)
11
+ - Update dev dependencies [#113](https://github.com/fgrehm/letter_opener_web/pull/113)
12
+ - Switched to using GitHub actions as CI for the project [#113](https://github.com/fgrehm/letter_opener_web/pull/113)
13
+
14
+ ## [1.4.1](https://github.com/fgrehm/letter_opener_web/compare/v1.4.0...v1.4.1) (Oct 5, 2021)
15
+
16
+ - Ensure letter is within letters base path [#110](https://github.com/fgrehm/letter_opener_web/pull/110)
17
+
18
+ ## [1.4.0](https://github.com/fgrehm/letter_opener_web/compare/v1.3.4...v1.4.0) (Jan 29, 2020)
19
+
20
+ - Removed the dependency on the asset pipeline. Good news for API-only apps! [#83](https://github.com/fgrehm/letter_opener_web/pull/83)
21
+ - Avoid `require_dependency` if Zeitwerk is enabled [#98](https://github.com/fgrehm/letter_opener_web/pull/98)
22
+ - Drop support for old rubies and rails. Ruby 2.5+ is supported and Rails 4 is no longer tested [#100](https://github.com/fgrehm/letter_opener_web/pull/100)
2
23
 
3
24
  ## [1.3.4](https://github.com/fgrehm/letter_opener_web/compare/v1.3.3...v1.3.4) (Apr 04, 2018)
4
25
 
data/Gemfile CHANGED
@@ -6,3 +6,7 @@ source 'http://rubygems.org'
6
6
  # Bundler will treat runtime dependencies like base dependencies, and
7
7
  # development dependencies will be added by default to the :development group.
8
8
  gemspec
9
+
10
+ group :test do
11
+ gem 'codecov', require: false
12
+ end
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013-2014 Fabio Rehm
1
+ Copyright (c) 2013-2021 Fabio Rehm
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # letter_opener_web
2
2
 
3
- [![Build Status](https://travis-ci.org/fgrehm/letter_opener_web.png?branch=master)](https://travis-ci.org/fgrehm/letter_opener_web) [![Gem Version](https://badge.fury.io/rb/letter_opener_web.png)](http://badge.fury.io/rb/letter_opener_web) [![Code Climate](https://codeclimate.com/github/fgrehm/letter_opener_web.png)](https://codeclimate.com/github/fgrehm/letter_opener_web) [![Gitter chat](https://badges.gitter.im/fgrehm/letter_opener_web.png)](https://gitter.im/fgrehm/letter_opener_web)
3
+ [![Build Status](https://github.com/fgrehm/letter_opener_web/actions/workflows/main.yml/badge.svg)]
4
+ [![Gem Version](https://badge.fury.io/rb/letter_opener_web.svg)](http://badge.fury.io/rb/letter_opener_web)
5
+ [![Code Climate](https://codeclimate.com/github/fgrehm/letter_opener_web.svg)](https://codeclimate.com/github/fgrehm/letter_opener_web)
4
6
 
5
7
  Gives [letter_opener](https://github.com/ryanb/letter_opener) an interface for
6
8
  browsing sent emails.
@@ -13,7 +15,7 @@ First add the gem to your development environment and run the `bundle` command t
13
15
 
14
16
  ```ruby
15
17
  group :development do
16
- gem 'letter_opener_web'
18
+ gem 'letter_opener_web', '~> 2.0'
17
19
  end
18
20
  ```
19
21
 
@@ -23,9 +25,7 @@ Add to your routes.rb:
23
25
 
24
26
  ```ruby
25
27
  Your::Application.routes.draw do
26
- if Rails.env.development?
27
- mount LetterOpenerWeb::Engine, at: "/letter_opener"
28
- end
28
+ mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
29
29
  end
30
30
  ```
31
31
 
@@ -33,8 +33,9 @@ And make sure you have [`:letter_opener` delivery method](https://github.com/rya
33
33
  configured for your app. Then visit `http://localhost:3000/letter_opener` after
34
34
  sending an email and have fun.
35
35
 
36
- If you are running the app from a [Vagrant](http://vagrantup.com) machine, you
37
- might want to skip `letter_opener`'s `launchy` calls and avoid messages like these:
36
+ If you are running the app from a [Vagrant](http://vagrantup.com) machine or Docker
37
+ container, you might want to skip `letter_opener`'s `launchy` calls and avoid messages
38
+ like these:
38
39
 
39
40
  ```terminal
40
41
  12:33:42 web.1 | Failure in opening /vagrant/tmp/letter_opener/1358825621_ba83a22/rich.html
@@ -43,19 +44,16 @@ environment variable LAUNCHY_DEBUG=true or the '-d' commandline option and file
43
44
  https://github.com/copiousfreetime/launchy/issues/new
44
45
  ```
45
46
 
46
- In that case (or if you just want to browse mails using the web interface), you
47
- can set `:letter_opener_web` as your delivery method on your
48
- `config/environments/development.rb`:
47
+ In that case (or if you really just want to browse mails using the web interface and
48
+ don't care about opening emails automatically), you can set `:letter_opener_web` as
49
+ your delivery method on your `config/environments/development.rb`:
49
50
 
50
51
  ```ruby
51
52
  config.action_mailer.delivery_method = :letter_opener_web
52
-
53
- # If not everyone on the team is using vagrant
54
- config.action_mailer.delivery_method = ENV['USER'] == 'vagrant' ? :letter_opener_web : :letter_opener
55
53
  ```
56
54
 
57
- If you're using `:letter_opener_web` as your delivery method, you can change the location of the letters by adding the
58
- following to an initializer (or in development.rb):
55
+ If you're using `:letter_opener_web` as your delivery method, you can change the location of
56
+ the letters by adding the following to an initializer (or in development.rb):
59
57
 
60
58
  ```ruby
61
59
  LetterOpenerWeb.configure do |config|
@@ -63,13 +61,16 @@ LetterOpenerWeb.configure do |config|
63
61
  end
64
62
  ```
65
63
 
66
- ## Usage on Heroku
64
+ ## Usage on pre-production environments
65
+
66
+ Some people use this gem on staging / pre-production environments to avoid having real emails
67
+ being sent out. To set that up you'll need to:
67
68
 
68
- Some people use this gem on staging environments on Heroku and to set that up
69
- is just a matter of moving the gem out of the `development` group and enabling
70
- the route for all environments on your `routes.rb`.
69
+ 1. Move the gem out of the `development` group in your `Gemfile`
70
+ 2. Set `config.action_mailer.delivery_method` on the appropriate `config/environments/<env>.rb`
71
+ 3. Enable the route for the environments on your `routes.rb`.
71
72
 
72
- In order words, your `Gemfile` will have:
73
+ In other words, your `Gemfile` will have:
73
74
 
74
75
  ```ruby
75
76
  gem 'letter_opener_web'
@@ -79,20 +80,28 @@ And your `routes.rb`:
79
80
 
80
81
  ```ruby
81
82
  Your::Application.routes.draw do
82
- mount LetterOpenerWeb::Engine, at: "/letter_opener"
83
+ # If you have a dedicated config/environments/staging.rb
84
+ mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.staging?
85
+
86
+ # If you use RAILS_ENV=production in staging environments, you'll need another
87
+ # way to disable it in "real production"
88
+ mount LetterOpenerWeb::Engine, at: "/letter_opener" unless ENV["PRODUCTION_FOR_REAL"]
83
89
  end
84
90
  ```
85
91
 
86
92
  You might also want to have a look at the sources for the [demo](http://letter-opener-web.herokuapp.com)
87
93
  available at https://github.com/fgrehm/letter_opener_web_demo.
88
94
 
89
- **NOTICE: Using this gem on Heroku will only work if your app has just one Dyno and does not send emails from background jobs. For updates on this matter please subscribe to [GH-35](https://github.com/fgrehm/letter_opener_web/issues/35)**
95
+ **NOTICE: Using this gem on Heroku will only work if your app has just one Dyno
96
+ and does not send emails from background jobs. For updates on this matter please
97
+ subscribe to [GH-35](https://github.com/fgrehm/letter_opener_web/issues/35)**
90
98
 
91
99
  ## Acknowledgements
92
100
 
93
101
  Special thanks to [@alexrothenberg](https://github.com/alexrothenberg) for some
94
- ideas on [this pull request](https://github.com/ryanb/letter_opener/pull/12).
95
-
102
+ ideas on [this pull request](https://github.com/ryanb/letter_opener/pull/12) and
103
+ [@pseudomuto](https://github.com/pseudomuto) for keeping the project alive for a
104
+ few years.
96
105
 
97
106
  ## Contributing
98
107
 
@@ -2,5 +2,6 @@
2
2
 
3
3
  module LetterOpenerWeb
4
4
  class ApplicationController < ActionController::Base
5
+ protect_from_forgery with: :exception, unless: -> { Rails.configuration.try(:api_only) }
5
6
  end
6
7
  end
@@ -1,14 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_dependency 'letter_opener_web/application_controller'
3
+ unless Rails.respond_to?(:autoloaders) && Rails.autoloaders.zeitwerk_enabled?
4
+ require_dependency 'letter_opener_web/application_controller'
5
+ end
4
6
 
5
7
  module LetterOpenerWeb
6
8
  class LettersController < ApplicationController
7
- before_action :check_style, only: [:show]
9
+ before_action :check_style, only: :show
8
10
  before_action :load_letter, only: %i[show attachment destroy]
9
11
 
10
12
  def index
11
- @letters = Letter.search
13
+ @letters = LetterOpenerWeb::Letter.search
12
14
  end
13
15
 
14
16
  def show
@@ -24,17 +26,21 @@ module LetterOpenerWeb
24
26
  file = @letter.attachments[filename]
25
27
 
26
28
  return render plain: 'Attachment not found!', status: 404 unless file.present?
29
+
27
30
  send_file(file, filename: filename, disposition: 'inline')
28
31
  end
29
32
 
30
33
  def clear
31
- Letter.destroy_all
34
+ LetterOpenerWeb::Letter.destroy_all
32
35
  redirect_to routes.letters_path
33
36
  end
34
37
 
35
38
  def destroy
36
39
  @letter.delete
37
- redirect_to routes.letters_path
40
+ respond_to do |format|
41
+ format.html { redirect_to routes.letters_path }
42
+ format.js { render js: "window.location='#{routes.letters_path}'" }
43
+ end
38
44
  end
39
45
 
40
46
  private
@@ -44,8 +50,9 @@ module LetterOpenerWeb
44
50
  end
45
51
 
46
52
  def load_letter
47
- @letter = Letter.find(params[:id])
48
- head :not_found unless @letter.exists?
53
+ @letter = LetterOpenerWeb::Letter.find(params[:id])
54
+
55
+ head :not_found unless @letter.valid?
49
56
  end
50
57
 
51
58
  def routes
@@ -33,6 +33,18 @@ module LetterOpenerWeb
33
33
  @sent_at = params[:sent_at]
34
34
  end
35
35
 
36
+ def headers
37
+ html = read_file(:rich) if style_exists?('rich')
38
+ html ||= read_file(:plain)
39
+
40
+ # NOTE: This is ugly, we should look into using nokogiri and making that a
41
+ # dependency of this gem
42
+ match_data = html.match(%r{<body>\s*<div[^>]+id="container">\s*<div[^>]+id="message_headers">\s*(<dl>.+</dl>)}m)
43
+ return remove_attachments_link(match_data[1]).html_safe if match_data && match_data[1].present?
44
+
45
+ 'UNABLE TO PARSE HEADERS'
46
+ end
47
+
36
48
  def plain_text
37
49
  @plain_text ||= adjust_link_targets(read_file(:plain))
38
50
  end
@@ -56,17 +68,28 @@ module LetterOpenerWeb
56
68
  end
57
69
 
58
70
  def delete
59
- FileUtils.rm_rf("#{LetterOpenerWeb.config.letters_location}/#{id}")
71
+ return unless valid?
72
+
73
+ FileUtils.rm_rf(base_dir.to_s)
60
74
  end
61
75
 
62
- def exists?
63
- File.exist?(base_dir)
76
+ def valid?
77
+ exists? && base_dir_within_letters_location?
64
78
  end
65
79
 
66
80
  private
67
81
 
82
+ def remove_attachments_link(headers)
83
+ xml = REXML::Document.new(headers)
84
+ if xml.root.elements.size == 10
85
+ xml.delete_element('//dd[last()]')
86
+ xml.delete_element('//dt[last()]')
87
+ end
88
+ xml.to_s
89
+ end
90
+
68
91
  def base_dir
69
- "#{LetterOpenerWeb.config.letters_location}/#{id}"
92
+ LetterOpenerWeb.config.letters_location.join(id).cleanpath
70
93
  end
71
94
 
72
95
  def read_file(style)
@@ -77,8 +100,16 @@ module LetterOpenerWeb
77
100
  File.exist?("#{base_dir}/#{style}.html")
78
101
  end
79
102
 
103
+ def exists?
104
+ File.exist?(base_dir)
105
+ end
106
+
107
+ def base_dir_within_letters_location?
108
+ base_dir.to_s.start_with?(LetterOpenerWeb.config.letters_location.to_s)
109
+ end
110
+
80
111
  def adjust_link_targets(contents)
81
- # We cannot feed the whole file to an XML parser as some mails are
112
+ # We cannot feed the whole file to a XML parser as some mails are
82
113
  # "complete" (as in they have the whole <html> structure) and letter_opener
83
114
  # prepends some information about the mail being sent, making REXML
84
115
  # complain about it
@@ -86,6 +117,7 @@ module LetterOpenerWeb
86
117
  fixed_link = fix_link_html(link)
87
118
  xml = REXML::Document.new(fixed_link).root
88
119
  next if xml.attributes['href'] =~ /(plain|rich).html/
120
+
89
121
  xml.attributes['target'] = '_blank'
90
122
  xml.add_text('') unless xml.text
91
123
  contents.gsub!(link, xml.to_s)
@@ -0,0 +1,31 @@
1
+ <%= render "layouts/letter_opener_web/js/jquery" %>
2
+ <%= render "layouts/letter_opener_web/js/favcount" %>
3
+
4
+ <script nonce="<%= content_security_policy_nonce %>">
5
+ function update_favicon(favicon) {
6
+ favicon.set($('.letter-opener a').length);
7
+ }
8
+
9
+ jQuery(function($) {
10
+ var favicon = new Favcount($('link[rel="icon"]').attr('href'));
11
+ update_favicon(favicon);
12
+
13
+ $('.letter-opener').on('click', 'a', function() {
14
+ var $this = $(this);
15
+ $('iframe').attr('src', $this.attr('href'));
16
+ $this.parents('.list-group').find('.active').removeClass('active');
17
+ $this.parent().addClass('active');
18
+ });
19
+
20
+ $('.refresh').click(function(e) {
21
+ e.preventDefault();
22
+
23
+ var wrapper = $('.letter-opener');
24
+ wrapper.find('div').text('Loading...');
25
+ wrapper.load(wrapper.data('letters-path') + ' .letter-opener', function() {
26
+ $('iframe').attr('src', $('.letter-opener a:first-child()').attr('href'));
27
+ update_favicon(favicon);
28
+ });
29
+ });
30
+ });
31
+ </script>
@@ -0,0 +1,3 @@
1
+ <%= render "layouts/letter_opener_web/styles/icon" %>
2
+ <%= render "layouts/letter_opener_web/styles/bootstrap" %>
3
+ <%= render "layouts/letter_opener_web/styles/letters" %>
@@ -1,3 +1,4 @@
1
+ <script nonce="<%= content_security_policy_nonce %>">
1
2
  /*
2
3
  * favcount.js v1.5.0
3
4
  * http://chrishunt.co/favcount
@@ -46,11 +47,10 @@
46
47
 
47
48
  function drawCanvas(canvas, opacity, font, img, count) {
48
49
  var head = document.getElementsByTagName('head')[0],
49
- favicon = document.createElement('link'),
50
+ favicon = document.querySelector('link[rel=icon]'),
51
+ newFavicon = document.createElement('link'),
50
52
  multiplier, fontSize, context, xOffset, yOffset, border, shadow;
51
53
 
52
- favicon.rel = 'icon';
53
-
54
54
  // Scale canvas elements based on favicon size
55
55
  multiplier = img.width / 16;
56
56
  fontSize = multiplier * 11;
@@ -89,14 +89,16 @@
89
89
  );
90
90
 
91
91
  // Replace favicon with new favicon
92
- favicon.href = canvas.toDataURL('image/png');
93
- head.removeChild(document.querySelector('link[rel=icon]'));
94
- head.appendChild(favicon);
92
+ newFavicon.rel = 'icon';
93
+ newFavicon.href = canvas.toDataURL('image/png');
94
+ if (favicon) { head.removeChild(favicon); }
95
+ head.appendChild(newFavicon);
95
96
  }
96
97
 
97
98
  this.Favcount = Favcount;
98
99
  }).call(this);
99
100
 
100
101
  (function(){
101
- Favcount.VERSION = '1.5.0';
102
+ Favcount.VERSION = '1.5.1';
102
103
  }).call(this);
104
+ </script>