From b2f6658e0355ceb5b603edfb588f00ccd9a5602e Mon Sep 17 00:00:00 2001 From: floumicaza Date: Thu, 2 Jun 2022 12:03:20 -0400 Subject: [PATCH 1/4] feat(recipes/mailer.rb): add asset_host to mailer and new tests --- lib/potassium/assets/config/mailer.rb.erb | 2 - lib/potassium/recipes/mailer.rb | 32 +++++-- lib/potassium/templates/application.rb | 1 + spec/features/mailer_spec.rb | 112 +++++++++++++++------- spec/support/shared_examples.rb | 5 + 5 files changed, 107 insertions(+), 45 deletions(-) create mode 100644 spec/support/shared_examples.rb 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/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/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/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 From 7a79a61bfe57fd4d573bd44fe77ab16765673d5c Mon Sep 17 00:00:00 2001 From: floumicaza Date: Thu, 2 Jun 2022 12:03:50 -0400 Subject: [PATCH 2/4] feat(example_mailer): create example mailer --- .../assets/app/mailers/application_mailer.rb | 2 +- .../assets/app/mailers/example_mailer.rb | 6 +++ .../example_mailer/example_mail.html.mjml | 7 +++ .../app/views/layouts/default_mail.html.mjml | 49 ++++++++++++++++++ .../assets/public/mails/platanus-logo.png | Bin 0 -> 2967 bytes 5 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 lib/potassium/assets/app/mailers/example_mailer.rb create mode 100644 lib/potassium/assets/app/views/example_mailer/example_mail.html.mjml create mode 100644 lib/potassium/assets/app/views/layouts/default_mail.html.mjml create mode 100644 lib/potassium/assets/public/mails/platanus-logo.png 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/public/mails/platanus-logo.png b/lib/potassium/assets/public/mails/platanus-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..0864c69e52cb8859d0b845c0e979c62f0ef7557f GIT binary patch literal 2967 zcmV;I3uyF-P)8v-r4x)uLCU<|$x%!d&70tEfz7YBVf zro!MDAvRmB-N3sV039hTj$-%>tUqiFuN}WI@Zp%i2@RUS1lBONT5}@>*K>lK#CoB9 zw%J-fGW2fBMUHCm<>7thiSK=~0S7!-%%eY^x++C>7uAalQJ&)F<9AQJ4u`!$BLN6t z9ea#yj=PWEed_1194m!JA|nByCWHvqY`1LI`Dp+D!|7Et#7*o2Lg1BS7eC!|E4qkS zCA5c|E$$7yO_cP>*s*7U=96GYzKrI#e;ckF{_Ce0-v3qBrUMoYry@9Qri*!dHL3`FDXtC0X_(}EXR>91KMv`4pF%V6R%O5%O(WnlNe zVA7(|^6o!>68#|K&F6oSxxIjBKe~Oo1Iw^RXo7{-tP~_H3gYn~j5lcc^ZO&K#-z0) zi1S|K!QsxSv+!H#^VFa5HY!uarmHxT^q zAMn0(Zk)ID(ZcVKe>Ykeb{Mj0J^a0F(kT*hU-XV!|gZ2 zWnD-@3Xcfl?+~(h$DTnJ-jPP(x*b%SIOGVg!O5m&LE>Uxc@d4Tz8v~lBc$&|&i?TJ zug7V%-<8lpAB{rXl(JJVKsVKAV($n&HnCqJM;+QIwb1p1>tx1*~w zX63K@XS97rdQh`z*&`IJ8AlrmcFkk?Cf8|vEHOqlgN8QjF?{fLYL8Th1?(Cu! zk6-+EUk+SV-duTd(tTvn$eLv|n~Y)W=%r73uneniPC42P=-C=RD#UyC$D?I)UNnWl z&D%7ITkqm#GkEaM zOlua9$S!``g{4^gG@*xgPIWzoS{_qiyT}NuA6r$GWt)W)S%me^N2}^F2`TvG4~D&6 zhZCCO;qB8M&lA*?a+E`MIB@+~Ggzn22OJ?zXa=F+8se%Pb1Qb^2$L2pz*|mW={TWH zA-uc&aii^d!3u-d5=`*;$=r0*NJs-FuqCb6y|_E(6^Zazlo@@v_5FIUPjL_Eez@hjm!}VpvCgIH5Ue!3Lqx8%mUa zxFbUwj@q%|*&8G@>t6D;Xt<`+Q43CJj#_X+bJW5?@zHqvJ;35TGQAatMXJ+&k$Ehd zTEgWxEXCinj%#Tt178NZt&E;C*2msJWp`va6EAb)_kmFdAI0d(us!4VYbkkBJ=!vy zpHe5pb=rvQm0rSw~UX*<>IH zzg=LPK7FM5Xmn7O`5zdCoKGo)4(d+4O%-g#mAe(!L9Yi#WL@-=s7~w!F zvNJIDUpIA|m<>nL%y1i~bv+$90pqEe$Jw%-pomJEe$D}dwQJ^C> zuaD*dOlP2v$(^Ty+o+EsorbzlLqLiu z|9E{Qedapxjq>SF^g41DELS!d~EG|Asb*bwvBGy9Av$ z_=x<-K2pw2*||>hAIwn>HB>=8->aB?(m3ja>arbw^BL*(!^+eNop0(0rVV9rL_OT? z_?zoLF509zRWNNxz{l7p?4w?5Moq^7T|u(^t_-cR zLTelGKIVrT@h+;NOi$4KBVEVhWA1OATZRv32=gEw`77=}} zl;Ehhlj0*ei?LKjXk8<&CWTGRlQV6ntM0)nd?UVs{CsG{mvJz7&xo&~UVI}y^4-k| zTXO8C2|^7)nA`9v>6ejj0)8FECxi2(=SbFdnqbU<;WcBsyU6|n=#$giIqQ^XUx`g* zPka+?B=YgJxsqUH0>HHO0V{f@*`h{dcD+TU(2ZbEhMLepw+3Rr9F!z9FrpK zA^VC}!rTv5AT7~HWbOPouKrkOknH%R<-HSsZ(w}M6tuiJl9x3RqhlaSgdVc#PT6)n zXSzJ$#*FgY1@gITY`a#XPTN!J!wb}1XA}7>nkr)(^Vi*EdCq*gdM4(<$y32Rmn`e_ zkk6cVk#7fz2#x3~$?;fQvANy}ID()x&+ zgWimMI$E7nQ{m63(-zWu;w?=6$+nR1VuTJReZ(&Ev5N6=SM^r=t;$z*?jw1nhJv Date: Thu, 2 Jun 2022 12:16:05 -0400 Subject: [PATCH 3/4] feat(mjml.rb): create mjml recipe --- lib/potassium/recipes/mjml.rb | 31 ++++++++++++++++++++ spec/features/mjml_spec.rb | 53 +++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 lib/potassium/recipes/mjml.rb create mode 100644 spec/features/mjml_spec.rb 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/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 From 6e699d9a91c602ed62ad1b3c18bd48bb4d1097fa Mon Sep 17 00:00:00 2001 From: floumicaza Date: Thu, 2 Jun 2022 12:35:11 -0400 Subject: [PATCH 4/4] feat(README.md): add mjml to readme --- README.md | 1 + 1 file changed, 1 insertion(+) 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: