From a454bb2c49c3fc507862b5f2402916bd48d85df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Veikko=20Lintuj=C3=A4rvi?= Date: Sun, 16 Mar 2025 20:22:48 +0200 Subject: [PATCH] Working test version of confirmation email delivery --- .gitignore | 3 +++ config/runtime.exs | 24 ++++++++++++++----- lib/osuuspuutarha/confirmation_sender.ex | 15 ++++++++++++ lib/osuuspuutarha/orders.ex | 24 ++++++++++++++++--- .../live/order_live/form_component.ex | 2 +- .../templates/emails/confirmation.html.heex | 3 +++ .../templates/layout/email.html.heex | 8 +++++++ mix.exs | 5 ++-- mix.lock | 2 ++ test/osuuspuutarha/orders_test.exs | 8 +++---- .../live/order_live_test.exs | 6 ++--- test/support/fixtures/orders_fixtures.ex | 2 +- 12 files changed, 82 insertions(+), 20 deletions(-) create mode 100644 lib/osuuspuutarha/confirmation_sender.ex create mode 100644 lib/osuuspuutarha_web/templates/emails/confirmation.html.heex create mode 100644 lib/osuuspuutarha_web/templates/layout/email.html.heex diff --git a/.gitignore b/.gitignore index d4c4bd6..f618ba2 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,6 @@ run.sh # Prod db variable script prod_db_vars + +# DKIM private key +/priv/keys/dkim_private.pem \ No newline at end of file diff --git a/config/runtime.exs b/config/runtime.exs index ffb8a19..089aaa6 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -68,12 +68,24 @@ if config_env() == :prod do # 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 :osuuspuutarha, Osuuspuutarha.Mailer, - # adapter: Swoosh.Adapters.Mailgun, - # api_key: System.get_env("MAILGUN_API_KEY"), - # domain: System.get_env("MAILGUN_DOMAIN") - # + + config :osuuspuutarha, Osuuspuutarha.Mailer, + adapter: Swoosh.Adapters.SMTP, + relay: "mail.tietokonepaja.fi", + username: System.get_env("SMTP_USERNAME"), + password: System.get_env("SMTP_PASSWORD"), + ssl: false, + tls: :never, + auth: :never, + port: 25, + dkim: [ + s: "email", + d: "livonsaarenosuuspuutarha.fi", + private_key: {:pem_plain, File.read!("priv/keys/domain.private")} + ], + retries: 2, + no_mx_lookups: false + # For this example you need include a HTTP client required by Swoosh API client. # Swoosh supports Hackney and Finch out of the box: # diff --git a/lib/osuuspuutarha/confirmation_sender.ex b/lib/osuuspuutarha/confirmation_sender.ex new file mode 100644 index 0000000..88c884f --- /dev/null +++ b/lib/osuuspuutarha/confirmation_sender.ex @@ -0,0 +1,15 @@ +defmodule Osuuspuutarha.ConfirmationSender do + @moduledoc """ + This module is responsible for sending confirmation emails. + """ + import Swoosh.Email + + def send_confirmation_email(order) do + new() + |> to({"Testi Testinen", "livonsaaren.tietokonepaja@gmail.com"}) + |> from({"Livonsaaren Osuuspuutarha", "noreply@livonsaarenosuuspuutarha.fi"}) + |> subject("Kiitokset tilauksesta!") + |> html_body("

Hello #{order.fname}

") + |> text_body("Hello #{order.fname}\n") + end +end diff --git a/lib/osuuspuutarha/orders.ex b/lib/osuuspuutarha/orders.ex index 57786d4..1825ef8 100644 --- a/lib/osuuspuutarha/orders.ex +++ b/lib/osuuspuutarha/orders.ex @@ -8,6 +8,9 @@ defmodule Osuuspuutarha.Orders do alias Osuuspuutarha.Orders.Order + alias Osuuspuutarha.ConfirmationSender + alias Osuuspuutarha.Mailer + @doc """ Returns the list of orders. @@ -42,19 +45,34 @@ defmodule Osuuspuutarha.Orders do ## Examples - iex> create_order(%{field: value}) + iex> process_order(%{field: value}) {:ok, %Order{}} - iex> create_order(%{field: bad_value}) + iex> process_order(%{field: bad_value}) {:error, %Ecto.Changeset{}} """ - def create_order(attrs \\ %{}) do + def process_order(attrs \\ %{}) do + case insert_order(attrs) do + {:ok, order} -> + send_confirmation_email_and_deliver(order) + + {:error, changeset} -> + {:error, changeset} + end + end + + defp insert_order(attrs) do %Order{} |> Order.changeset(attrs) |> Repo.insert() end + defp send_confirmation_email_and_deliver(order) do + ConfirmationSender.send_confirmation_email(order) + |> Mailer.deliver() + end + @doc """ Updates a order. diff --git a/lib/osuuspuutarha_web/live/order_live/form_component.ex b/lib/osuuspuutarha_web/live/order_live/form_component.ex index 1c8f94c..2148772 100644 --- a/lib/osuuspuutarha_web/live/order_live/form_component.ex +++ b/lib/osuuspuutarha_web/live/order_live/form_component.ex @@ -41,7 +41,7 @@ defmodule OsuuspuutarhaWeb.OrderLive.FormComponent do end defp save_order(socket, :new, order_params) do - case Orders.create_order(order_params) do + case Orders.process_order(order_params) do {:ok, _order} -> {:noreply, socket diff --git a/lib/osuuspuutarha_web/templates/emails/confirmation.html.heex b/lib/osuuspuutarha_web/templates/emails/confirmation.html.heex new file mode 100644 index 0000000..5cbae3b --- /dev/null +++ b/lib/osuuspuutarha_web/templates/emails/confirmation.html.heex @@ -0,0 +1,3 @@ +
+

Osuuspuutarhan testimaili, <%= @variable %>!

+
diff --git a/lib/osuuspuutarha_web/templates/layout/email.html.heex b/lib/osuuspuutarha_web/templates/layout/email.html.heex new file mode 100644 index 0000000..fa27822 --- /dev/null +++ b/lib/osuuspuutarha_web/templates/layout/email.html.heex @@ -0,0 +1,8 @@ + + + <%= @email.subject %> + + + <%= @inner_content %> + + \ No newline at end of file diff --git a/mix.exs b/mix.exs index 56aa09e..6b28521 100644 --- a/mix.exs +++ b/mix.exs @@ -42,14 +42,15 @@ defmodule Osuuspuutarha.MixProject do {:floki, ">= 0.30.0", only: :test}, {:phoenix_live_dashboard, "~> 0.6"}, {:esbuild, "~> 0.4", runtime: Mix.env() == :dev}, - {:swoosh, "~> 1.3"}, + {:swoosh, "~> 1.6"}, {:telemetry_metrics, "~> 0.6"}, {:telemetry_poller, "~> 1.0"}, {:gettext, "~> 0.18"}, {:jason, "~> 1.2"}, {:plug_cowboy, "~> 2.5"}, {:elixlsx, "~> 0.5.1"}, - {:credo, "~> 1.7", only: [:dev, :test], runtime: false} + {:credo, "~> 1.7", only: [:dev, :test], runtime: false}, + {:gen_smtp, "~> 1.0"} ] end diff --git a/mix.lock b/mix.lock index e179df7..23d65f5 100644 --- a/mix.lock +++ b/mix.lock @@ -15,6 +15,7 @@ "expo": {:hex, :expo, "0.4.0", "bbe4bf455e2eb2ebd2f1e7d83530ce50fb9990eb88fc47855c515bfdf1c6626f", [:mix], [], "hexpm", "a8ed1683ec8b7c7fa53fd7a41b2c6935f539168a6bb0616d7fd6b58a36f3abf2"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, "floki": {:hex, :floki, "0.34.2", "5fad07ef153b3b8ec110b6b155ec3780c4b2c4906297d0b4be1a7162d04a7e02", [:mix], [], "hexpm", "26b9d50f0f01796bc6be611ca815c5e0de034d2128e39cc9702eee6b66a4d1c8"}, + "gen_smtp": {:hex, :gen_smtp, "1.2.0", "9cfc75c72a8821588b9b9fe947ae5ab2aed95a052b81237e0928633a13276fd3", [:rebar3], [{:ranch, ">= 1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "5ee0375680bca8f20c4d85f58c2894441443a743355430ff33a783fe03296779"}, "gettext": {:hex, :gettext, "0.22.1", "e7942988383c3d9eed4bdc22fc63e712b655ae94a672a27e4900e3d4a2c43581", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "ad105b8dab668ee3f90c0d3d94ba75e9aead27a62495c101d94f2657a190ac5d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, @@ -25,6 +26,7 @@ "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.1", "2aff698f5e47369decde4357ba91fc9c37c6487a512b41732818f2204a8ef1d3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "9bffb834e7ddf08467fe54ae58b5785507aaba6255568ae22b4d46e2bb3615ab"}, "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.14", "5ec615d4d61bf9d4755f158bd6c80372b715533fe6d6219e12d74fb5eedbeac1", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.0 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "afeb6ba43ce329a6f7fc1c9acdfc6d3039995345f025febb7f409a92f6faebd3"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, + "phoenix_swoosh": {:hex, :phoenix_swoosh, "1.2.1", "b74ccaa8046fbc388a62134360ee7d9742d5a8ae74063f34eb050279de7a99e1", [:mix], [{:finch, "~> 0.8", [hex: :finch, repo: "hexpm", optional: true]}, {:hackney, "~> 1.10", [hex: :hackney, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.5", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "4000eeba3f9d7d1a6bf56d2bd56733d5cadf41a7f0d8ffe5bb67e7d667e204a2"}, "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, "phoenix_view": {:hex, :phoenix_view, "2.0.4", "b45c9d9cf15b3a1af5fb555c674b525391b6a1fe975f040fb4d913397b31abf4", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "4e992022ce14f31fe57335db27a28154afcc94e9983266835bb3040243eb620b"}, "plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"}, diff --git a/test/osuuspuutarha/orders_test.exs b/test/osuuspuutarha/orders_test.exs index c16c236..3df6bdc 100644 --- a/test/osuuspuutarha/orders_test.exs +++ b/test/osuuspuutarha/orders_test.exs @@ -34,7 +34,7 @@ defmodule Osuuspuutarha.OrdersTest do assert Orders.get_order!(order.id) == order end - test "create_order/1 with valid data creates a order" do + test "process_order/1 with valid data creates a order" do valid_attrs = %{ address: "some address", city: "some city", @@ -51,7 +51,7 @@ defmodule Osuuspuutarha.OrdersTest do early_bird: true } - assert {:ok, %Order{} = order} = Orders.create_order(valid_attrs) + assert {:ok, %Order{} = order} = Orders.process_order(valid_attrs) assert order.address == "some address" assert order.city == "some city" assert order.email == "some email" @@ -67,8 +67,8 @@ defmodule Osuuspuutarha.OrdersTest do assert order.early_bird == true end - test "create_order/1 with invalid data returns error changeset" do - assert {:error, %Ecto.Changeset{}} = Orders.create_order(@invalid_attrs) + test "process_order/1 with invalid data returns error changeset" do + assert {:error, %Ecto.Changeset{}} = Orders.process_order(@invalid_attrs) end test "update_order/2 with valid data updates the order" do diff --git a/test/osuuspuutarha_web/live/order_live_test.exs b/test/osuuspuutarha_web/live/order_live_test.exs index 7f334f3..f15a1f4 100644 --- a/test/osuuspuutarha_web/live/order_live_test.exs +++ b/test/osuuspuutarha_web/live/order_live_test.exs @@ -50,13 +50,13 @@ defmodule OsuuspuutarhaWeb.OrderLiveTest do early_bird: false } - defp create_order(_) do + defp process_order(_) do order = order_fixture() %{order: order} end describe "Index" do - setup [:create_order] + setup [:process_order] test "lists all orders", %{conn: conn, order: order} do {:ok, _index_live, html} = live(conn, Routes.order_index_path(conn, :index)) @@ -118,7 +118,7 @@ defmodule OsuuspuutarhaWeb.OrderLiveTest do end describe "Show" do - setup [:create_order] + setup [:process_order] test "displays order", %{conn: conn, order: order} do {:ok, _show_live, html} = live(conn, Routes.order_show_path(conn, :show, order)) diff --git a/test/support/fixtures/orders_fixtures.ex b/test/support/fixtures/orders_fixtures.ex index 14abf29..1666105 100644 --- a/test/support/fixtures/orders_fixtures.ex +++ b/test/support/fixtures/orders_fixtures.ex @@ -25,7 +25,7 @@ defmodule Osuuspuutarha.OrdersFixtures do split_invoice: true, early_bird: true }) - |> Osuuspuutarha.Orders.create_order() + |> Osuuspuutarha.Orders.process_order() order end