From d43daafdb7886554959a3ee18e580178dab2cb65 Mon Sep 17 00:00:00 2001 From: Adam Piontek Date: Sat, 13 Aug 2022 06:39:14 -0400 Subject: [PATCH] updated Bamboo references to Swoosh; added runtime.exs config file --- config/config.exs | 14 +++- config/runtime.exs | 83 +++++++++++++++++++ config/test.exs | 4 +- lib/shift73k/accounts/user_notifier.ex | 20 +++-- lib/shift73k/mailer.ex | 2 +- lib/shift73k/mailer/user_email.ex | 10 +-- lib/shift73k_web/endpoint.ex | 5 -- lib/shift73k_web/live/user/registration.ex | 2 +- .../live/user_management/form_component.ex | 2 +- lib/shift73k_web/router.ex | 37 +++------ test/support/fixtures/accounts_fixtures.ex | 7 +- 11 files changed, 131 insertions(+), 55 deletions(-) create mode 100644 config/runtime.exs diff --git a/config/config.exs b/config/config.exs index 94871922..2880dad3 100644 --- a/config/config.exs +++ b/config/config.exs @@ -18,14 +18,26 @@ config :shift73k, :app_global_vars, mailer_reply_to: "reply_to@example.com", mailer_from: "app_name@example.com" + # Configures the endpoint config :shift73k, Shift73kWeb.Endpoint, url: [host: "localhost"], - secret_key_base: "LdIQmzV5UCWSbB2SdiWFHLgxYNObKq9Za/VyguoILxfOAMDb5IsptKCKtXTRn+Tf", render_errors: [view: Shift73kWeb.ErrorView, accepts: ~w(html json), layout: false], pubsub_server: Shift73k.PubSub, live_view: [signing_salt: "2D4GC4ac"] +# Configures the mailer +# +# By default it uses the "Local" adapter which stores the emails +# locally. You can see the emails in your browser, at "/dev/mailbox". +# +# For production it's recommended to configure a different adapter +# at the `config/runtime.exs`. +config :shift73k, Shift73k.Mailer, adapter: Swoosh.Adapters.Local + +# Swoosh API client is needed for adapters other than SMTP. +config :swoosh, :api_client, false + # Configures Elixir's Logger config :logger, :console, format: "$time $metadata[$level] $message\n", diff --git a/config/runtime.exs b/config/runtime.exs new file mode 100644 index 00000000..029407bf --- /dev/null +++ b/config/runtime.exs @@ -0,0 +1,83 @@ +import Config + +# config/runtime.exs is executed for all environments, including +# during releases. It is executed after compilation and before the +# system starts, so it is typically used to load production configuration +# and secrets from environment variables or elsewhere. Do not define +# any compile-time configuration in here, as it won't be applied. +# The block below contains prod specific runtime configuration. + +# ## Using releases +# +# If you use `mix release`, you need to explicitly enable the server +# by passing the PHX_SERVER=true when you start it: +# +# PHX_SERVER=true bin/shift73k start +# +# Alternatively, you can use `mix phx.gen.release` to generate a `bin/server` +# script that automatically sets the env var above. +if System.get_env("PHX_SERVER") do + config :shift73k, Shift73kWeb.Endpoint, server: true +end + +if config_env() == :prod do + database_url = + System.get_env("DATABASE_URL") || + raise """ + environment variable DATABASE_URL is missing. + For example: ecto://USER:PASS@HOST/DATABASE + """ + + maybe_ipv6 = if System.get_env("ECTO_IPV6"), do: [:inet6], else: [] + + config :shift73k, Shift73k.Repo, + # ssl: true, + url: database_url, + pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"), + socket_options: maybe_ipv6 + + # The secret key base is used to sign/encrypt cookies and other secrets. + # A default value is used in config/dev.exs and config/test.exs but you + # want to use a different value for prod and you most likely don't want + # to check this value into version control, so we use an environment + # variable instead. + secret_key_base = + System.get_env("SECRET_KEY_BASE") || + raise """ + environment variable SECRET_KEY_BASE is missing. + You can generate one by calling: mix phx.gen.secret + """ + + host = System.get_env("PHX_HOST") || "example.com" + port = String.to_integer(System.get_env("PORT") || "4000") + + config :shift73k, Shift73kWeb.Endpoint, + url: [host: host, port: 443, scheme: "https"], + http: [ + # Enable IPv6 and bind on all interfaces. + # Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access. + # See the documentation on https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html + # for details about using IPv6 vs IPv4 and loopback vs public addresses. + ip: {0, 0, 0, 0, 0, 0, 0, 0}, + port: port + ], + secret_key_base: secret_key_base + + # ## Configuring the mailer + # + # In production you need to configure the mailer to use a different adapter. + # Also, you may need to configure the Swoosh API client of your choice if you + # are not using SMTP. Here is an example of the configuration: + # + # config :shift73k, Shift73k.Mailer, + # adapter: Swoosh.Adapters.Mailgun, + # api_key: System.get_env("MAILGUN_API_KEY"), + # domain: System.get_env("MAILGUN_DOMAIN") + # + # For this example you need include a HTTP client required by Swoosh API client. + # Swoosh supports Hackney and Finch out of the box: + # + # config :swoosh, :api_client, Swoosh.ApiClient.Hackney + # + # See https://hexdocs.pm/swoosh/Swoosh.html#module-installation for details. +end diff --git a/config/test.exs b/config/test.exs index dd0166a9..836d7509 100644 --- a/config/test.exs +++ b/config/test.exs @@ -25,8 +25,8 @@ config :shift73k, Shift73kWeb.Endpoint, # Print only warnings and errors during test config :logger, level: :warn -# Bamboo test mailer config -config :shift73k, Shift73k.Mailer, adapter: Bamboo.TestAdapter +# Swoosh test mailer config +config :shift73k, Shift73k.Mailer, adapter: Swoosh.Adapters.Test # Import secret config # import_config "test.secret.exs" diff --git a/lib/shift73k/accounts/user_notifier.ex b/lib/shift73k/accounts/user_notifier.ex index 9c2f03f2..47b891a9 100644 --- a/lib/shift73k/accounts/user_notifier.ex +++ b/lib/shift73k/accounts/user_notifier.ex @@ -2,12 +2,19 @@ defmodule Shift73k.Accounts.UserNotifier do alias Shift73k.Mailer alias Shift73k.Mailer.UserEmail + def deliver(user_email, subject, body) do + %Swoosh.Email{} = email = UserEmail.compose(user_email, subject, body) + case Mailer.deliver(email) do + {:ok, msg} -> {:ok, msg, email} + err -> err + end + end + @doc """ Deliver instructions to confirm account. """ def deliver_confirmation_instructions(user, url) do - user - |> UserEmail.compose("Confirm Your Account", """ + deliver(user.email, "Confirmation instructions", """ ============================== @@ -21,15 +28,13 @@ defmodule Shift73k.Accounts.UserNotifier do ============================== """) - |> Mailer.deliver_later() end @doc """ Deliver instructions to reset a user password. """ def deliver_reset_password_instructions(user, url) do - user - |> UserEmail.compose("Reset Your Password", """ + deliver(user.email, "Reset password instructions", """ ============================== @@ -43,15 +48,13 @@ defmodule Shift73k.Accounts.UserNotifier do ============================== """) - |> Mailer.deliver_later() end @doc """ Deliver instructions to update a user email. """ def deliver_update_email_instructions(user, url) do - user - |> UserEmail.compose("Change Your E-mail", """ + deliver(user.email, "Update email instructions", """ ============================== @@ -65,6 +68,5 @@ defmodule Shift73k.Accounts.UserNotifier do ============================== """) - |> Mailer.deliver_later() end end diff --git a/lib/shift73k/mailer.ex b/lib/shift73k/mailer.ex index 589b722e..368ffe1d 100644 --- a/lib/shift73k/mailer.ex +++ b/lib/shift73k/mailer.ex @@ -1,3 +1,3 @@ defmodule Shift73k.Mailer do - use Bamboo.Mailer, otp_app: :shift73k + use Swoosh.Mailer, otp_app: :shift73k end diff --git a/lib/shift73k/mailer/user_email.ex b/lib/shift73k/mailer/user_email.ex index d5a7bc01..c5904e8b 100644 --- a/lib/shift73k/mailer/user_email.ex +++ b/lib/shift73k/mailer/user_email.ex @@ -1,16 +1,16 @@ defmodule Shift73k.Mailer.UserEmail do - import Bamboo.Email + import Swoosh.Email @mailer_vars Application.compile_env(:shift73k, :app_global_vars, mailer_reply_to: "admin@example.com", mailer_from: {"Shift73k", "shift73k@example.com"} ) - def compose(user, subject, body_text) do - new_email() + def compose(user_email, subject, body_text) do + new() |> from(@mailer_vars[:mailer_from]) - |> to(user.email) - |> put_header("Reply-To", @mailer_vars[:mailer_reply_to]) + |> to(user_email) + |> header("Reply-To", @mailer_vars[:mailer_reply_to]) |> subject(subject) |> text_body(body_text) end diff --git a/lib/shift73k_web/endpoint.ex b/lib/shift73k_web/endpoint.ex index 54596874..cf633bcf 100644 --- a/lib/shift73k_web/endpoint.ex +++ b/lib/shift73k_web/endpoint.ex @@ -39,11 +39,6 @@ defmodule Shift73kWeb.Endpoint do plug(Phoenix.Ecto.CheckRepoStatus, otp_app: :shift73k) end - plug(Phoenix.LiveDashboard.RequestLogger, - param_key: "request_logger", - cookie_key: "request_logger" - ) - plug(Plug.RequestId) plug(Plug.Telemetry, event_prefix: [:phoenix, :endpoint]) diff --git a/lib/shift73k_web/live/user/registration.ex b/lib/shift73k_web/live/user/registration.ex index e9d8976a..8b86b0fe 100644 --- a/lib/shift73k_web/live/user/registration.ex +++ b/lib/shift73k_web/live/user/registration.ex @@ -40,7 +40,7 @@ defmodule Shift73kWeb.UserLive.Registration do |> Accounts.register_user() |> case do {:ok, user} -> - {:ok, %Bamboo.Email{}} = + {:ok, _, %Swoosh.Email{} = _captured_email} = Accounts.deliver_user_confirmation_instructions( user, &Routes.user_confirmation_url(socket, :confirm, &1) diff --git a/lib/shift73k_web/live/user_management/form_component.ex b/lib/shift73k_web/live/user_management/form_component.ex index 2a6f7512..aa79b622 100644 --- a/lib/shift73k_web/live/user_management/form_component.ex +++ b/lib/shift73k_web/live/user_management/form_component.ex @@ -33,7 +33,7 @@ defmodule Shift73kWeb.UserManagement.FormComponent do defp save_user(%{assigns: %{action: :new}} = socket, user_params) do case Accounts.register_user(user_params) do {:ok, user} -> - {:ok, %Bamboo.Email{}} = + {:ok, _, %Swoosh.Email{} = _captured_email} = Accounts.deliver_user_confirmation_instructions( user, &Routes.user_confirmation_url(socket, :confirm, &1) diff --git a/lib/shift73k_web/router.ex b/lib/shift73k_web/router.ex index 1cdf67b0..b45acda4 100644 --- a/lib/shift73k_web/router.ex +++ b/lib/shift73k_web/router.ex @@ -13,10 +13,6 @@ defmodule Shift73kWeb.Router do plug(:fetch_current_user) end - pipeline :api do - plug(:accepts, ["json"]) - end - pipeline :user do plug(EnsureRolePlug, [:admin, :manager, :user]) end @@ -29,33 +25,24 @@ defmodule Shift73kWeb.Router do plug(EnsureRolePlug, :admin) end + # Enables the Swoosh mailbox preview in development. + # + # Note that preview only shows emails that were sent by the same + # node running the Phoenix server. + if Mix.env() == :dev do + scope "/dev" do + pipe_through :browser + + forward "/mailbox", Plug.Swoosh.MailboxPreview + end + end + scope "/", Shift73kWeb do pipe_through([:browser]) get("/", Redirector, to: "/assign") end - # Other scopes may use custom stacks. - # scope "/api", Shift73kWeb do - # pipe_through :api - # end - - # Enables LiveDashboard only for development - # - # If you want to use the LiveDashboard in production, you should put - # it behind authentication and allow only admins to access it. - # If your application does not have an admins-only section yet, - # you can use Plug.BasicAuth to set up some basic authentication - # as long as you are also using SSL (which you should anyway). - if Mix.env() in [:dev, :test] do - import Phoenix.LiveDashboard.Router - - scope "/" do - pipe_through(:browser) - live_dashboard("/dashboard", metrics: Shift73kWeb.Telemetry) - end - end - scope "/", Shift73kWeb do pipe_through([:browser, :redirect_if_user_is_authenticated]) diff --git a/test/support/fixtures/accounts_fixtures.ex b/test/support/fixtures/accounts_fixtures.ex index e8b49dfe..18a8264c 100644 --- a/test/support/fixtures/accounts_fixtures.ex +++ b/test/support/fixtures/accounts_fixtures.ex @@ -33,11 +33,8 @@ defmodule Shift73k.AccountsFixtures do end def extract_user_token(fun) do - # {:ok, captured} = fun.(&"[TOKEN]#{&1}[TOKEN]") - # [_, token, _] = String.split(captured.body, "[TOKEN]") - # token - {:ok, %Bamboo.Email{} = email} = fun.(&"[TOKEN]#{&1}[TOKEN]") - [_, token, _] = String.split(email.text_body, "[TOKEN]") + {:ok, _, %Swoosh.Email{} = captured_email} = fun.(&"[TOKEN]#{&1}[TOKEN]") + [_, token | _] = String.split(captured_email.text_body, "[TOKEN]") token end