diff --git a/README.md b/README.md index 01ffab34..39db1208 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ Potassium Rails apps includes the following gems and technologies: - [Tzinfo-Data](https://github.com/tzinfo/tzinfo-data) for updating timezone information - [Faker](https://github.com/stympy/faker) for creating development data - [Scout](https://github.com/scoutapp/scout_apm_ruby) for monitoring performance +- [Mjml](https://github.com/sighmon/mjml-rails) for mails style The following optional integrations are also added: diff --git a/lib/potassium/assets/app/mailers/application_mailer.rb b/lib/potassium/assets/app/mailers/application_mailer.rb index d8bd387b..474c7b92 100644 --- a/lib/potassium/assets/app/mailers/application_mailer.rb +++ b/lib/potassium/assets/app/mailers/application_mailer.rb @@ -1,3 +1,3 @@ class ApplicationMailer < ActionMailer::Base - layout 'mailer' + layout 'default_mail' end diff --git a/lib/potassium/assets/app/mailers/example_mailer.rb b/lib/potassium/assets/app/mailers/example_mailer.rb new file mode 100644 index 00000000..4a19707c --- /dev/null +++ b/lib/potassium/assets/app/mailers/example_mailer.rb @@ -0,0 +1,6 @@ +class ExampleMailer < ApplicationMailer + def example_mail + @email = params[:email] + mail(from: 'admin@example.com', to: @email, subject: 'Welcome to Potassium') + end +end diff --git a/lib/potassium/assets/app/views/example_mailer/example_mail.html.mjml b/lib/potassium/assets/app/views/example_mailer/example_mail.html.mjml new file mode 100644 index 00000000..b6b01a3d --- /dev/null +++ b/lib/potassium/assets/app/views/example_mailer/example_mail.html.mjml @@ -0,0 +1,7 @@ + + + + Hello <%= @email %>, welcome to Potassium + + + diff --git a/lib/potassium/assets/app/views/layouts/default_mail.html.mjml b/lib/potassium/assets/app/views/layouts/default_mail.html.mjml new file mode 100644 index 00000000..3d466077 --- /dev/null +++ b/lib/potassium/assets/app/views/layouts/default_mail.html.mjml @@ -0,0 +1,49 @@ + + + + + + + + .body-section { + -webkit-box-shadow: 1px 4px 11px 0px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 1px 4px 11px 0px rgba(0, 0, 0, 0.15); + box-shadow: 1px 4px 11px 0px rgba(0, 0, 0, 0.15); + } + + + .text-link { + color: #5e6ebf + } + + + .footer-link { + color: #888888 + } + + + + + + + + + + + + + + + + + + + <%= yield %> + + + + + + + + diff --git a/lib/potassium/assets/config/mailer.rb.erb b/lib/potassium/assets/config/mailer.rb.erb index 3a3b2927..3badab43 100644 --- a/lib/potassium/assets/config/mailer.rb.erb +++ b/lib/potassium/assets/config/mailer.rb.erb @@ -7,8 +7,6 @@ Rails.application.config.action_mailer.default_url_options = { } Rails.application.config.action_mailer.default_options = { from: ENV['DEFAULT_EMAIL_ADDRESS'] } -ASSET_HOST = ENV.fetch("ASSET_HOST", ENV.fetch("APPLICATION_HOST")) -Rails.application.config.action_mailer.asset_host = ASSET_HOST if ENV["EMAIL_RECIPIENTS"].present? Mail.register_interceptor RecipientInterceptor.new( diff --git a/lib/potassium/assets/public/mails/platanus-logo.png b/lib/potassium/assets/public/mails/platanus-logo.png new file mode 100644 index 00000000..0864c69e Binary files /dev/null and b/lib/potassium/assets/public/mails/platanus-logo.png differ diff --git a/lib/potassium/recipes/mailer.rb b/lib/potassium/recipes/mailer.rb index 47dcbbfb..9d7cb561 100644 --- a/lib/potassium/recipes/mailer.rb +++ b/lib/potassium/recipes/mailer.rb @@ -63,20 +63,32 @@ def dependencies(service) gather_gem 'recipient_interceptor' end + def config_environments + gsub_file 'config/environments/production.rb', /$\s*config.action_mailer.*/, '' + asset_host_dev = <<~RUBY + config.action_mailer.asset_host = "http://\#{ENV.fetch('APPLICATION_HOST')}" + RUBY + application asset_host_dev, env: "development" + asset_host_prod = <<~RUBY + config.action_mailer.asset_host = "https://\#{ENV.fetch('APPLICATION_HOST')}" + RUBY + application asset_host_prod, env: "production" + mailer_config = <<~RUBY + require Rails.root.join("config", "mailer") + RUBY + + prepend_file "config/environments/production.rb", mailer_config + end + def config(service) template "../assets/config/mailer.rb.erb", 'config/mailer.rb' - gsub_file 'config/environments/production.rb', /$\s*config.action_mailer.*/, '' + append_to_file '.env.development', "APPLICATION_HOST=localhost:3000\n" append_to_file '.env.development', "EMAIL_RECIPIENTS=\n" - mailer_config = - <<~RUBY - require Rails.root.join("config", "mailer") - RUBY - - prepend_file "config/environments/production.rb", mailer_config - copy_file '../assets/app/mailers/application_mailer.rb', 'app/mailers/application_mailer.rb', force: true - + copy_file '../assets/app/mailers/application_mailer.rb', 'app/mailers/application_mailer.rb', + force: true + config_environments send(service[:name]) end @@ -88,7 +100,7 @@ def sendgrid } RUBY inject_into_file 'config/mailer.rb', sendgrid_settings, - after: "Rails.application.config.action_mailer.delivery_method = :sendgrid\n" + after: "Rails.application.config.action_mailer.delivery_method = :sendgrid\n" sendgrid_dev_settings = <<~RUBY Rails.application.config.action_mailer.sendgrid_dev_settings = { api_key: ENV['SENDGRID_API_KEY'] diff --git a/lib/potassium/recipes/mjml.rb b/lib/potassium/recipes/mjml.rb new file mode 100644 index 00000000..81f1504b --- /dev/null +++ b/lib/potassium/recipes/mjml.rb @@ -0,0 +1,31 @@ +class Recipes::Mjml < Rails::AppBuilder + def create + return if get(:email_service).to_s.downcase.to_sym == :none + + gather_gem 'mjml-rails' + after(:gem_install) do + run 'bin/yarn add mjml' + mjml_config + end + end + + def installed? + gem_exists?(/mjml-rails/) + end + + def install + create + end +end + +private + +def mjml_config + copy_file '../assets/app/views/layouts/default_mail.html.mjml', + 'app/views/layouts/default_mail.html.mjml', force: true + copy_file '../assets/app/mailers/example_mailer.rb', 'app/mailers/example_mailer.rb', force: true + copy_file '../assets/app/views/example_mailer/example_mail.html.mjml', + 'app/views/example_mailer/example_mail.html.mjml', force: true + copy_file '../assets/public/mails/platanus-logo.png', + 'public/mails/platanus-logo.png', force: true +end diff --git a/lib/potassium/templates/application.rb b/lib/potassium/templates/application.rb index 27399f15..8358ba37 100644 --- a/lib/potassium/templates/application.rb +++ b/lib/potassium/templates/application.rb @@ -81,6 +81,7 @@ create :admin create :vue_admin create :google_tag_manager + create :mjml end info "Gathered enough information. Applying the template. Wait a minute." diff --git a/spec/features/mailer_spec.rb b/spec/features/mailer_spec.rb index eb49f5fa..cc3681e1 100644 --- a/spec/features/mailer_spec.rb +++ b/spec/features/mailer_spec.rb @@ -1,58 +1,104 @@ +# rubocop:disable Rspec/MultipleMemoizedHelpers require "spec_helper" RSpec.describe "Mailer" do let(:gemfile) { IO.read("#{project_path}/Gemfile") } - let(:mailer_config) { IO.read("#{project_path}/config/mailer.rb") } + let(:env) { IO.read("#{project_path}/.env.development") } let(:dev_config) { IO.read("#{project_path}/config/environments/development.rb") } - let(:sidekiq_config) { IO.read("#{project_path}/config/sidekiq.yml") } + let(:prod_config) { IO.read("#{project_path}/config/environments/production.rb") } + let(:asset_host_dev) do + <<~RUBY + config.action_mailer.asset_host = "http://\#{ENV.fetch('APPLICATION_HOST')}" + RUBY + end + let(:asset_host_prod) do + <<~RUBY + config.action_mailer.asset_host = "https://\#{ENV.fetch('APPLICATION_HOST')}" + RUBY + end + let(:mailer_config_text) do + <<~RUBY + require Rails.root.join("config", "mailer") + RUBY + end before(:all) { drop_dummy_database } - context "when selecting sendgrid as mailer" do - before(:all) do - remove_project_directory - create_dummy_project("email_service" => "sendgrid") - end + describe 'with mailer' do + let(:mailer_config) { IO.read("#{project_path}/config/mailer.rb") } + let(:sidekiq_config) { IO.read("#{project_path}/config/sidekiq.yml") } + + context "when selecting sendgrid as mailer" do + before(:all) do + remove_project_directory + create_dummy_project("email_service" => "sendgrid") + end + + it_behaves_like "name" + it { expect(gemfile).to include("send_grid_mailer") } - it { expect(gemfile).to include("send_grid_mailer") } + it "adds configuration to mailer.rb" do + expect(mailer_config).to include("delivery_method = :sendgrid") + expect(mailer_config).to include("sendgrid_settings = {") + expect(mailer_config).to include("api_key: ENV['SENDGRID_API_KEY']") + end - it "adds configuration to mailer.rb" do - expect(mailer_config).to include("delivery_method = :sendgrid") - expect(mailer_config).to include("sendgrid_settings = {") - expect(mailer_config).to include("api_key: ENV['SENDGRID_API_KEY']") + it "adds configuration to development.rb" do + expect(dev_config).to include("delivery_method = :sendgrid_dev") + expect(dev_config).to include("sendgrid_dev_settings = {") + expect(dev_config).to include("api_key: ENV['SENDGRID_API_KEY']") + end + + it "adds configuration to production" do + expect(prod_config).to include(mailer_config_text) + expect(prod_config).to include(asset_host_prod) + end end - it "adds configuration to development.rb" do - expect(dev_config).to include("delivery_method = :sendgrid_dev") - expect(dev_config).to include("sendgrid_dev_settings = {") - expect(dev_config).to include("api_key: ENV['SENDGRID_API_KEY']") + context "when selecting aws_ses as mailer" do + before(:all) do + remove_project_directory + create_dummy_project("email_service" => "aws_ses") + end + + it_behaves_like "name" + it { expect(gemfile).to include("aws-sdk-rails") } + it { expect(gemfile).to include("letter_opener") } + it { expect(mailer_config).to include("delivery_method = :aws_sdk") } + it { expect(dev_config).to include("delivery_method = :letter_opener") } end - it { expect(sidekiq_config).to include("- mailers") } + context "when selecting a mailer and sidekiq" do + before :all do + drop_dummy_database + remove_project_directory + create_dummy_project( + "background_processor" => true, "email_service" => 'sendgrid' + ) + end + + it { expect(sidekiq_config).to include("- mailers") } + end end - context "when selecting aws_ses as mailer" do + context "when there is no mailer" do before(:all) do remove_project_directory - create_dummy_project("email_service" => "aws_ses") + create_dummy_project end - it { expect(gemfile).to include("aws-sdk-rails") } - it { expect(gemfile).to include("letter_opener") } - it { expect(mailer_config).to include("delivery_method = :aws_sdk") } - it { expect(dev_config).to include("delivery_method = :letter_opener") } - it { expect(sidekiq_config).to include("- mailers") } - end + it { expect(gemfile).not_to include("letter_opener") } + it { expect(File.exists?("#{project_path}/config/mailer.rb")).to eq(false) } + it { expect(env).not_to include("EMAIL_RECIPIENTS") } - context "when selecting a mailer and sidekiq" do - before :all do - drop_dummy_database - remove_project_directory - create_dummy_project( - "background_processor" => true, "email_service" => 'sendgrid' - ) + it "adds configuration to development" do + expect(dev_config).not_to include(asset_host_dev) + expect(dev_config).not_to include("delivery_method") end - it { expect(sidekiq_config).to include("- mailers") } + it "adds configuration to production" do + expect(prod_config).not_to include(mailer_config_text) + expect(prod_config).not_to include(asset_host_prod) + end end end diff --git a/spec/features/mjml_spec.rb b/spec/features/mjml_spec.rb new file mode 100644 index 00000000..2289fe41 --- /dev/null +++ b/spec/features/mjml_spec.rb @@ -0,0 +1,53 @@ +require "spec_helper" + +RSpec.describe "Mjml" do + let(:gemfile) { IO.read("#{project_path}/Gemfile") } + let(:mailer_config) { IO.read("#{project_path}/config/mailer.rb") } + let(:dev_config) { IO.read("#{project_path}/config/environments/development.rb") } + let(:sidekiq_config) { IO.read("#{project_path}/config/sidekiq.yml") } + let(:yarn_lock) { IO.read("#{project_path}/yarn.lock") } + + before(:all) { drop_dummy_database } + + context "when selecting a mailer" do + before(:all) do + remove_project_directory + create_dummy_project("email_service" => "sendgrid") + end + + it 'adds gems and packages' do + expect(yarn_lock).to include("mjml") + expect(gemfile).to include("mjml-rails") + end + + it 'creates example mailer' do + expect(File.exists?("#{project_path}/app/views/layouts/default_mail.html.mjml")).to eq(true) + expect(File.exists?("#{project_path}/app/mailers/example_mailer.rb")).to eq(true) + expect(File.exists?("#{project_path}/app/views/example_mailer/example_mail.html.mjml")) + .to eq(true) + expect(File.exists?("#{project_path}/public/mails/platanus-logo.png")).to eq(true) + end + end + + context "when there is no mailer selected" do + before(:all) do + remove_project_directory + create_dummy_project + end + + it 'adds gems and packages' do + expect(yarn_lock).not_to include("mjml") + expect(gemfile).not_to include("mjml-rails") + end + + it 'creates example mailer' do + expect(File.exists?("#{project_path}/app/views/layouts/default_mail.html.mjml")) + .not_to eq(true) + expect(File.exists?("#{project_path}/app/mailers/example_mailer.rb")) + .not_to eq(true) + expect(File.exists?("#{project_path}/app/views/example_mailer/example_mail.html.mjml")) + .not_to eq(true) + expect(File.exists?("#{project_path}/public/mails/platanus-logo.png")).not_to eq(true) + end + end +end diff --git a/spec/support/shared_examples.rb b/spec/support/shared_examples.rb new file mode 100644 index 00000000..4828e4e4 --- /dev/null +++ b/spec/support/shared_examples.rb @@ -0,0 +1,5 @@ +RSpec.shared_examples "name" do + it { expect(sidekiq_config).to include("- mailers") } + it { expect(env).to include("EMAIL_RECIPIENTS") } + it { expect(dev_config).to include(asset_host_dev) } +end