letter_opener_web_wally 2.0.1

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.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/brakeman-analysis.yml +36 -0
  3. data/.github/workflows/main.yml +29 -0
  4. data/.github/workflows/release-gem.yml +32 -0
  5. data/.gitignore +20 -0
  6. data/.rspec +4 -0
  7. data/.rubocop.yml +29 -0
  8. data/.rubocop_todo.yml +19 -0
  9. data/CHANGELOG.md +95 -0
  10. data/Gemfile +8 -0
  11. data/LICENSE.txt +0 -0
  12. data/README.md +176 -0
  13. data/Rakefile +10 -0
  14. data/app/controllers/letter_opener_web/application_controller.rb +7 -0
  15. data/app/controllers/letter_opener_web/letters_controller.rb +77 -0
  16. data/app/models/letter_opener_web/aws_letter.rb +98 -0
  17. data/app/models/letter_opener_web/base_letter.rb +93 -0
  18. data/app/models/letter_opener_web/letter.rb +54 -0
  19. data/app/models/letter_opener_web/s3_message.rb +25 -0
  20. data/app/views/layouts/letter_opener_web/_javascripts.html.erb +31 -0
  21. data/app/views/layouts/letter_opener_web/_styles.html.erb +3 -0
  22. data/app/views/layouts/letter_opener_web/js/_favcount.html.erb +104 -0
  23. data/app/views/layouts/letter_opener_web/js/_jquery.html.erb +7 -0
  24. data/app/views/layouts/letter_opener_web/letters.html.erb +15 -0
  25. data/app/views/layouts/letter_opener_web/styles/_bootstrap.html.erb +9 -0
  26. data/app/views/layouts/letter_opener_web/styles/_icon.html.erb +2 -0
  27. data/app/views/layouts/letter_opener_web/styles/_letters.html.erb +70 -0
  28. data/app/views/letter_opener_web/letters/_item.html.erb +10 -0
  29. data/app/views/letter_opener_web/letters/index.html.erb +24 -0
  30. data/bin/setup +6 -0
  31. data/config/routes.rb +9 -0
  32. data/letter_opener_web.gemspec +35 -0
  33. data/lib/letter_opener_web/delivery_method.rb +29 -0
  34. data/lib/letter_opener_web/engine.rb +20 -0
  35. data/lib/letter_opener_web/version.rb +5 -0
  36. data/lib/letter_opener_web.rb +52 -0
  37. data/script/pre-push +2 -0
  38. data/spec/controllers/letter_opener_web/letters_controller_spec.rb +282 -0
  39. data/spec/dummy/Rakefile +8 -0
  40. data/spec/dummy/app/assets/config/manifest.js +3 -0
  41. data/spec/dummy/app/assets/images/.keep +0 -0
  42. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  43. data/spec/dummy/app/channels/application_cable/channel.rb +6 -0
  44. data/spec/dummy/app/channels/application_cable/connection.rb +6 -0
  45. data/spec/dummy/app/controllers/application_controller.rb +4 -0
  46. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  47. data/spec/dummy/app/helpers/application_helper.rb +4 -0
  48. data/spec/dummy/app/javascript/packs/application.js +15 -0
  49. data/spec/dummy/app/jobs/application_job.rb +9 -0
  50. data/spec/dummy/app/mailers/application_mailer.rb +6 -0
  51. data/spec/dummy/app/models/application_record.rb +5 -0
  52. data/spec/dummy/app/models/concerns/.keep +0 -0
  53. data/spec/dummy/app/views/layouts/application.html.erb +15 -0
  54. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  55. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  56. data/spec/dummy/bin/rails +4 -0
  57. data/spec/dummy/bin/rake +4 -0
  58. data/spec/dummy/bin/setup +33 -0
  59. data/spec/dummy/config/application.rb +37 -0
  60. data/spec/dummy/config/boot.rb +7 -0
  61. data/spec/dummy/config/environment.rb +7 -0
  62. data/spec/dummy/config/environments/development.rb +78 -0
  63. data/spec/dummy/config/environments/production.rb +122 -0
  64. data/spec/dummy/config/environments/test.rb +61 -0
  65. data/spec/dummy/config/initializers/application_controller_renderer.rb +10 -0
  66. data/spec/dummy/config/initializers/assets.rb +14 -0
  67. data/spec/dummy/config/initializers/backtrace_silencers.rb +10 -0
  68. data/spec/dummy/config/initializers/content_security_policy.rb +30 -0
  69. data/spec/dummy/config/initializers/cookies_serializer.rb +7 -0
  70. data/spec/dummy/config/initializers/filter_parameter_logging.rb +8 -0
  71. data/spec/dummy/config/initializers/inflections.rb +18 -0
  72. data/spec/dummy/config/initializers/mime_types.rb +6 -0
  73. data/spec/dummy/config/initializers/permissions_policy.rb +13 -0
  74. data/spec/dummy/config/initializers/wrap_parameters.rb +16 -0
  75. data/spec/dummy/config/locales/en.yml +33 -0
  76. data/spec/dummy/config/puma.rb +45 -0
  77. data/spec/dummy/config/routes.rb +5 -0
  78. data/spec/dummy/config.ru +8 -0
  79. data/spec/dummy/lib/assets/.keep +0 -0
  80. data/spec/dummy/log/.keep +0 -0
  81. data/spec/dummy/public/404.html +67 -0
  82. data/spec/dummy/public/422.html +67 -0
  83. data/spec/dummy/public/500.html +66 -0
  84. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  85. data/spec/dummy/public/apple-touch-icon.png +0 -0
  86. data/spec/dummy/public/favicon.ico +0 -0
  87. data/spec/dummy/storage/.keep +0 -0
  88. data/spec/letter_opener_web_spec.rb +47 -0
  89. data/spec/models/letter_opener_web/aws_letter_spec.rb +196 -0
  90. data/spec/models/letter_opener_web/letter_spec.rb +184 -0
  91. data/spec/rails_helper.rb +8 -0
  92. data/spec/spec_helper.rb +8 -0
  93. metadata +291 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a34ba978b666fa88474ab1697dfa5d323e7d15043ab62e308e5668169afdfcb9
4
+ data.tar.gz: d9966db09bb55a8087663f307544635260049d4c0ddaff8340b057ee1087ee3e
5
+ SHA512:
6
+ metadata.gz: 0df7f91a15f1777e24c2e0e1d1de818e9c2072f29c7331fb287ccebe87854d81218bc4f0835df61b8eafdf4b7d9be485747398c88fd151be5aefe6294c2ada49
7
+ data.tar.gz: bead6616179ea77f6b7fdc1d76e3d8452a8a40fec479a00226169a28409c59936c95db961eeee97bf0d77e591ee925efe9ba171ecc8960a3305e21f750a50865
@@ -0,0 +1,36 @@
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: [main]
9
+ pull_request:
10
+ # The branches below must be a subset of the branches above
11
+ branches: [main]
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, JRuby and TruffleRuby
26
+ uses: ruby/setup-ruby@v1.196.0
27
+ with:
28
+ ruby-version: 3.2
29
+
30
+ # Install dependencies
31
+ - name: Install dependencies
32
+ run: bundle install
33
+
34
+ # Run Brakeman
35
+ - name: Brakeman code scanning
36
+ uses: standardnotes/brakeman-action@v1.0.0
@@ -0,0 +1,29 @@
1
+ name: Run tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - name: Checkout repository
14
+ uses: actions/checkout@v2
15
+
16
+ - name: Set up Ruby 3.2
17
+ uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: 3.2
20
+ bundler-cache: true
21
+
22
+ - name: Install dependencies
23
+ run: bundle install
24
+
25
+ - name: Run tests
26
+ run: bundle exec rake
27
+
28
+ - name: Build gem
29
+ 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.2
17
+ uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: 3.2
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 ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .ruby-version
6
+ .yardoc
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ spec/dummy/log/
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
19
+ Gemfile.lock
20
+
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --order rand
2
+ --color
3
+ --format progress
4
+ --require rails_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,29 @@
1
+ ---
2
+ inherit_from: .rubocop_todo.yml
3
+
4
+ AllCops:
5
+ NewCops: enable
6
+ TargetRubyVersion: 3.2
7
+ Exclude:
8
+ - "spec/dummy/bin/**/*"
9
+ - "tmp/**/*"
10
+ - "vendor/**/*"
11
+
12
+ Metrics/BlockLength:
13
+ Exclude:
14
+ - spec/**/*_spec.rb
15
+
16
+ Layout/LineLength:
17
+ Max: 120
18
+
19
+ Style/Documentation:
20
+ Enabled: false
21
+
22
+ Metrics/MethodLength:
23
+ Max: 20
24
+
25
+ Metrics/AbcSize:
26
+ Max: 25
27
+
28
+ Gemspec/DevelopmentDependencies:
29
+ Enabled: false
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 ADDED
@@ -0,0 +1,95 @@
1
+ ## [v2.0.0](https://github.com/fgrehm/letter_opener_web/compare/v1.4.1...v2.0.0)
2
+
3
+ - Require Rails >= 5.2, run tests against Rails 6.1 [#113](https://github.com/fgrehm/letter_opener_web/pull/113)
4
+ - Inline CSS and Javascript, to avoid dependency on asset pipeline [#113](https://github.com/fgrehm/letter_opener_web/pull/113)
5
+ - Upgrade to Bootstrap 5.1.1 [#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)
23
+
24
+ ## [1.3.4](https://github.com/fgrehm/letter_opener_web/compare/v1.3.3...v1.3.4) (Apr 04, 2018)
25
+
26
+ ### Fixed
27
+
28
+ - Due to a load order issue, sometimes the main `ApplicationController` was used by this gem (unnecessary) [#82](https://github.com/fgrehm/letter_opener_web/pull/82)
29
+
30
+ ## [1.3.3](https://github.com/fgrehm/letter_opener_web/compare/v1.3.2...v1.3.3) (Jan 29, 2018)
31
+
32
+ - Set `LAUNCHY_DRY_RUN` explicitly to avoid `Launchy::CommandNotFoundError` [#75](https://github.com/fgrehm/letter_opener_web/pull/75)
33
+ - Update Ruby matrix for test to include more recent versions [#77](https://github.com/fgrehm/letter_opener_web/pull/77)
34
+
35
+ ## [1.3.2](https://github.com/fgrehm/letter_opener_web/compare/v1.3.1...v1.3.2) (Jan 14, 2018)
36
+
37
+ - Disable Launchy with ENV to avoid redefining the whole delivery method [#73](https://github.com/fgrehm/letter_opener_web/pull/73)
38
+ - Fix new Rubocop warnings [#72](https://github.com/fgrehm/letter_opener_web/pull/72)
39
+ - Hover state fixed to only highlight `tbody>tr` [#70](https://github.com/fgrehm/letter_opener_web/pull/70)
40
+ - Use `ActiveSupport.on_load` to make sure we don't have load order issues [#66](https://github.com/fgrehm/letter_opener_web/pull/66)
41
+
42
+ ## [1.3.1](https://github.com/fgrehm/letter_opener_web/compare/v1.3.0...v1.3.1) (Feb 04, 2017)
43
+
44
+ - Remove warnings about unused variables [#45](https://github.com/fgrehm/letter_opener_web/pull/45)
45
+ - Remove Rails 5 deprecation warnings [#54](https://github.com/fgrehm/letter_opener_web/pull/54)
46
+
47
+ ## [1.3.0](https://github.com/fgrehm/letter_opener_web/compare/v1.2.3...v1.3.0) (Feb 02, 2015)
48
+
49
+ - Depend on `railties` and `actionmailer` [#38](https://github.com/fgrehm/letter_opener_web/pull/38)
50
+
51
+ ## [1.2.3](https://github.com/fgrehm/letter_opener_web/compare/v1.2.2...v1.2.3) (Sep 12, 2014)
52
+
53
+ - Fix exception with `sprockets-rails` >= `2.1.4` [#32](https://github.com/fgrehm/letter_opener_web/issues/32) / [#33](https://github.com/fgrehm/letter_opener_web/pull/33)
54
+
55
+ ## [1.2.2](https://github.com/fgrehm/letter_opener_web/compare/v1.2.1...v1.2.2) (Jul 17, 2014)
56
+
57
+ - Precompile glyphicons [#30](https://github.com/fgrehm/letter_opener_web/pull/30)
58
+ - Display letters count on the favicon [#29](https://github.com/fgrehm/letter_opener_web/pull/29)
59
+ - Validate params passed in to the LettersController and return a 404 in case an email can't be found [#28](https://github.com/fgrehm/letter_opener_web/pull/28)
60
+
61
+ ## [1.2.1](https://github.com/fgrehm/letter_opener_web/compare/v1.2.0...v1.2.1) (Apr 07, 2014)
62
+
63
+ - Improve Rails 3 compatibility [#26](https://github.com/fgrehm/letter_opener_web/pull/26) / [#27](https://github.com/fgrehm/letter_opener_web/pull/27)
64
+
65
+ ## [1.2.0](https://github.com/fgrehm/letter_opener_web/compare/v1.1.3...v1.2.0) (Apr 07, 2014)
66
+
67
+ - Add support for removing a single email [#23](https://github.com/fgrehm/letter_opener_web/pull/23)
68
+ - Move vendored assets into the `letter_opener_web` folder [#24](https://github.com/fgrehm/letter_opener_web/issues/24)
69
+ - Avoid matching `<address>` when changing email links to open on new tabs [#22](https://github.com/fgrehm/letter_opener_web/pull/22)
70
+
71
+ ## [1.1.3](https://github.com/fgrehm/letter_opener_web/compare/v1.1.2...v1.1.3) (Feb 21, 2014)
72
+
73
+ - Include assets into `precompile` list [#21](https://github.com/fgrehm/letter_opener_web/pull/21)
74
+
75
+ ## [1.1.2](https://github.com/fgrehm/letter_opener_web/compare/v1.1.1...v1.1.2) (Dec 12, 2013)
76
+
77
+ - Nicely handle empty links [#18](https://github.com/fgrehm/letter_opener_web/pull/18)
78
+
79
+ ## [1.1.1](https://github.com/fgrehm/letter_opener_web/compare/v1.1.0...v1.1.1) (Oct 15, 2013)
80
+
81
+ - Fix deprecation warning on Rails 4 [#17](https://github.com/fgrehm/letter_opener_web/pull/17)
82
+
83
+ ## [1.1.0](https://github.com/fgrehm/letter_opener_web/compare/v1.0.3...v1.1.0) (Aug 29, 2013)
84
+
85
+ - "Relax" Rails dependency in order to use the gem on 4.0 [#15](https://github.com/fgrehm/letter_opener_web/issues/15)
86
+
87
+ ## [1.0.3](https://github.com/fgrehm/letter_opener_web/compare/v1.0.2...v1.0.3) (May 29, 2013)
88
+
89
+ - Fix clear button [#12](https://github.com/fgrehm/letter_opener_web/issues/12), tks to [@grumpit](https://github.com/grumpit)
90
+
91
+ ## Previous
92
+
93
+ The changelog began with version 1.0.3 so any changes prior to that
94
+ can be seen by checking the tagged releases and reading git commit
95
+ messages.
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'http://rubygems.org'
4
+
5
+ # Declare your gem's dependencies in letter_opener_web.gemspec.
6
+ # Bundler will treat runtime dependencies like base dependencies, and
7
+ # development dependencies will be added by default to the :development group.
8
+ gemspec
data/LICENSE.txt ADDED
File without changes
data/README.md ADDED
@@ -0,0 +1,176 @@
1
+ # letter_opener_web
2
+
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)
6
+
7
+ Gives [letter_opener](https://github.com/ryanb/letter_opener) an interface for
8
+ browsing sent emails.
9
+
10
+ Check out http://letter-opener-web.herokuapp.com to see it in action.
11
+
12
+ ## Installation
13
+
14
+ First add the gem to your development environment and run the `bundle` command to install it.
15
+
16
+ ```ruby
17
+ group :development do
18
+ gem 'letter_opener_web', '~> 2.0'
19
+ end
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ Add to your routes.rb:
25
+
26
+ ```ruby
27
+ Your::Application.routes.draw do
28
+ mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.configuration.delivery_method == :letter_opener_web
29
+ end
30
+ ```
31
+
32
+ And make sure you have [`:letter_opener` delivery method](https://github.com/ryanb/letter_opener#rails-setup)
33
+ configured for your app. Then visit `http://localhost:3000/letter_opener` after
34
+ sending an email and have fun.
35
+
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:
39
+
40
+ ```terminal
41
+ 12:33:42 web.1 | Failure in opening /vagrant/tmp/letter_opener/1358825621_ba83a22/rich.html
42
+ with options {}: Unable to find a browser command. If this is unexpected, Please rerun with
43
+ environment variable LAUNCHY_DEBUG=true or the '-d' commandline option and file a bug at
44
+ https://github.com/copiousfreetime/launchy/issues/new
45
+ ```
46
+
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`:
50
+
51
+ ```ruby
52
+ config.action_mailer.delivery_method = :letter_opener_web
53
+ ```
54
+
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):
57
+
58
+ ```ruby
59
+ LetterOpenerWeb.configure do |config|
60
+ config.letters_location = Rails.root.join('your', 'new', 'path')
61
+ end
62
+ ```
63
+
64
+ Letter Opener Web can also be used with Amazon S3 to store letters instead of filesystem.
65
+ You can change the storage type by adding the following to an initializer (or indevelopment.rb):
66
+
67
+ ```ruby
68
+ LetterOpenerWeb.configure do |config|
69
+ config.letters_storage = :s3
70
+ config.letters_location = "any/prefix/you/want"
71
+ config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID']
72
+ config.aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
73
+ config.aws_region = ENV['AWS_REGION']
74
+ config.aws_bucket = ENV['AWS_BUCKET']
75
+ end
76
+ ```
77
+
78
+ ## Usage on pre-production environments
79
+
80
+ Some people use this gem on staging / pre-production environments to avoid having real emails
81
+ being sent out. To set that up you'll need to:
82
+
83
+ 1. Move the gem out of the `development` group in your `Gemfile`
84
+ 2. Set `config.action_mailer.delivery_method` on the appropriate `config/environments/<env>.rb`
85
+ 3. Enable the route for the environments on your `routes.rb`.
86
+
87
+ In other words, your `Gemfile` will have:
88
+
89
+ ```ruby
90
+ gem 'letter_opener_web'
91
+ ```
92
+
93
+ And your `routes.rb`:
94
+
95
+ ```ruby
96
+ Your::Application.routes.draw do
97
+ # If you have a dedicated config/environments/staging.rb
98
+ mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.staging?
99
+
100
+ # If you use RAILS_ENV=production in staging environments, you'll need another
101
+ # way to disable it in "real production"
102
+ mount LetterOpenerWeb::Engine, at: "/letter_opener" unless ENV["PRODUCTION_FOR_REAL"]
103
+ end
104
+ ```
105
+
106
+ You might also want to have a look at the sources for the [demo](http://letter-opener-web.herokuapp.com)
107
+ available at https://github.com/fgrehm/letter_opener_web_demo.
108
+
109
+ ### Usage with Amazon S3 to support multiple separated instances
110
+
111
+ If you are using this gem on Heroku and your application is not using one Dyno or your have containerized setup, the default configuration won't work as the e-mail is saved on the server. You can use S3 bucket instead.
112
+
113
+ **1. Configure AWS environment:**
114
+
115
+ * Create new non-public bucket, note the name and the region
116
+ * Create new user using IAM or use existing one for which you already have `aws_access_key_id` and `aws_secret_access_key`
117
+ * Assign proper policy to the user. Replace `your-bucket-name` with the name of the bucket you have created
118
+
119
+ ```json
120
+ {
121
+ "Version": "2012-10-17",
122
+ "Statement": [
123
+ {
124
+ "Sid": "VisualEditor0",
125
+ "Effect": "Allow",
126
+ "Action": [
127
+ "s3:PutObject",
128
+ "s3:PutObjectAcl",
129
+ "s3:GetObject",
130
+ "s3:DeleteObject*"
131
+ ],
132
+ "Resource": "arn:aws:s3:::your-bucket-name/*"
133
+ },
134
+ {
135
+ "Sid": "VisualEditor1",
136
+ "Effect": "Allow",
137
+ "Action": [
138
+ "s3:ListBucket"
139
+ ],
140
+ "Resource": "arn:aws:s3:::your-bucket-name"
141
+ }
142
+ ]
143
+ }
144
+ ```
145
+
146
+ **2. Update gem configuration:**
147
+
148
+ Add the following configuration to the initializer (or environment files):
149
+
150
+ ```ruby
151
+ LetterOpenerWeb.configure do |config|
152
+ config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID']
153
+ config.aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
154
+ config.aws_region = ENV['AWS_REGION']
155
+ config.aws_bucket = ENV['AWS_BUCKET']
156
+ config.letters_storage = :s3
157
+ config.letters_location = "any prefix you want"
158
+ end
159
+ ```
160
+
161
+ When you send e-mail with attachment(s), the presigned link is generated to attachment that is valid for 1 week.
162
+
163
+ ## Acknowledgements
164
+
165
+ Special thanks to [@alexrothenberg](https://github.com/alexrothenberg) for some
166
+ ideas on [this pull request](https://github.com/ryanb/letter_opener/pull/12) and
167
+ [@pseudomuto](https://github.com/pseudomuto) for keeping the project alive for a
168
+ few years.
169
+
170
+ ## Contributing
171
+
172
+ 1. Fork it and run `bin/setup`
173
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
174
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
175
+ 4. Push to the branch (`git push origin my-new-feature`)
176
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env rake
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/gem_tasks'
5
+ require 'rspec/core/rake_task'
6
+ require 'rubocop/rake_task'
7
+
8
+ RuboCop::RakeTask.new
9
+ RSpec::Core::RakeTask.new(:spec)
10
+ task default: %i[spec rubocop]
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LetterOpenerWeb
4
+ class ApplicationController < ActionController::Base
5
+ protect_from_forgery with: :exception, unless: -> { Rails.configuration.try(:api_only) }
6
+ end
7
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ unless Rails.respond_to?(:autoloaders) && Rails.autoloaders.zeitwerk_enabled?
4
+ require_dependency 'letter_opener_web/application_controller'
5
+ end
6
+
7
+ module LetterOpenerWeb
8
+ class LettersController < ApplicationController
9
+ before_action :check_style, only: :show
10
+ before_action :load_letter, only: %i[show attachment destroy]
11
+ before_action :letter_params, only: %i[show attachment]
12
+
13
+ def index
14
+ @letters = letter_model.search
15
+ end
16
+
17
+ def show
18
+ text = @letter.send("#{letter_params[:style]}_text")
19
+ .gsub('"plain.html"', "\"#{routes.letter_path(id: @letter.id, style: 'plain')}\"")
20
+ .gsub('"rich.html"', "\"#{routes.letter_path(id: @letter.id, style: 'rich')}\"")
21
+
22
+ render html: text.html_safe
23
+ end
24
+
25
+ def attachment
26
+ filename = "#{letter_params[:file]}.#{letter_params[:format]}"
27
+ file = @letter.attachments[filename]
28
+
29
+ return render plain: 'Attachment not found!', status: 404 unless file.present?
30
+ return redirect_to(file, allow_other_host: true) if LetterOpenerWeb.config.letters_storage == :s3
31
+
32
+ send_file(file, filename:, disposition: 'inline')
33
+ end
34
+
35
+ def clear
36
+ letter_model.destroy_all
37
+ redirect_to routes.letters_path
38
+ end
39
+
40
+ def destroy
41
+ @letter.delete
42
+ respond_to do |format|
43
+ format.html { redirect_to routes.letters_path }
44
+ format.js { render js: "window.location='#{routes.letters_path}'" }
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def letter_params
51
+ params.permit(:style, :file, :format, :id)
52
+ end
53
+
54
+ def check_style
55
+ letter_params[:style] = 'rich' unless %w[plain rich].include?(letter_params[:style])
56
+ end
57
+
58
+ def load_letter
59
+ @letter = letter_model.find(letter_params[:id])
60
+
61
+ head :not_found unless @letter.valid?
62
+ end
63
+
64
+ def routes
65
+ LetterOpenerWeb.railtie_routes_url_helpers
66
+ end
67
+
68
+ def letter_model
69
+ case LetterOpenerWeb.config.letters_storage
70
+ when :s3
71
+ LetterOpenerWeb::AwsLetter
72
+ else
73
+ LetterOpenerWeb::Letter
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LetterOpenerWeb
4
+ class AwsLetter < BaseLetter
5
+ def self.aws_list_letters(path = [], **)
6
+ LetterOpenerWeb
7
+ .aws_client
8
+ .list_objects_v2(
9
+ bucket: LetterOpenerWeb.config.aws_bucket,
10
+ prefix: File.join([letters_location, *path].compact),
11
+ **
12
+ )
13
+ end
14
+ delegate :aws_list_letters, to: :class
15
+
16
+ def self.search
17
+ letters = aws_list_letters(delimiter: '.html').common_prefixes.map do |prefix|
18
+ new(id: File.basename(File.dirname(prefix.prefix)))
19
+ end
20
+
21
+ letters.reverse
22
+ end
23
+
24
+ def self.destroy_all
25
+ letters = aws_list_letters.contents.map(&:key)
26
+
27
+ LetterOpenerWeb.aws_client.delete_objects(
28
+ bucket: LetterOpenerWeb.config.aws_bucket,
29
+ delete: {
30
+ objects: letters.map { |key| { key: } },
31
+ quiet: false
32
+ }
33
+ )
34
+ end
35
+
36
+ def attachments
37
+ @attachments ||= aws_list_letters([id, 'attachments/']).contents.each_with_object({}) do |file, hash|
38
+ hash[File.basename(file.key)] = attachment_url(file.key)
39
+ end
40
+ end
41
+
42
+ def delete
43
+ return unless valid?
44
+
45
+ letters = aws_list_letters([id]).contents.map(&:key)
46
+
47
+ LetterOpenerWeb.aws_client.delete_objects(
48
+ bucket: LetterOpenerWeb.config.aws_bucket,
49
+ delete: {
50
+ objects: letters.map { |key| { key: } },
51
+ quiet: false
52
+ }
53
+ )
54
+ end
55
+
56
+ def valid?
57
+ aws_list_letters([id]).contents.any?
58
+ end
59
+
60
+ private
61
+
62
+ def attachment_url(key)
63
+ bucket = Aws::S3::Bucket.new(
64
+ name: LetterOpenerWeb.config.aws_bucket, client: LetterOpenerWeb.aws_client
65
+ )
66
+
67
+ obj = bucket.object(key)
68
+ obj.presigned_url(:get, expires_in: 1.week.to_i)
69
+ end
70
+
71
+ def objects
72
+ @objects ||= {}
73
+ end
74
+
75
+ def read_file(style)
76
+ return objects[style] if objects.key?(style)
77
+
78
+ response = LetterOpenerWeb.aws_client
79
+ .get_object(
80
+ bucket: LetterOpenerWeb.config.aws_bucket,
81
+ key: File.join(letters_location, id, "#{style}.html")
82
+ )
83
+
84
+ response.body.read.tap do |value|
85
+ objects[style] = value
86
+ end
87
+ rescue Aws::S3::Errors::NoSuchKey
88
+ ''
89
+ end
90
+
91
+ def style_exists?(style)
92
+ return !objects[style].empty? if objects.key?(style)
93
+
94
+ objects[style] = read_file(style)
95
+ !objects[style].empty?
96
+ end
97
+ end
98
+ end