From b4d4f1ccc47464b0243fb880420252afd81a7dc5 Mon Sep 17 00:00:00 2001 From: Ed Bond Date: Thu, 12 Mar 2020 02:33:09 -0500 Subject: [PATCH 1/4] Adding the ability to set the API key for sendgrid in different ways --- lib/bamboo/adapters/send_grid_adapter.ex | 12 +++- .../adapters/send_grid_adapter_test.exs | 66 +++++++++++++------ 2 files changed, 55 insertions(+), 23 deletions(-) diff --git a/lib/bamboo/adapters/send_grid_adapter.ex b/lib/bamboo/adapters/send_grid_adapter.ex index 8b5874f1..8f776fb0 100644 --- a/lib/bamboo/adapters/send_grid_adapter.ex +++ b/lib/bamboo/adapters/send_grid_adapter.ex @@ -43,7 +43,7 @@ defmodule Bamboo.SendGridAdapter do import Bamboo.ApiError def deliver(email, config) do - api_key = get_key(config) + api_key = _get_key(config) body = email |> to_sendgrid_body(config) |> Bamboo.json_library().encode!() url = [base_uri(), @send_message_path] @@ -63,16 +63,22 @@ defmodule Bamboo.SendGridAdapter do @doc false def handle_config(config) do # build the api key - will raise if there are errors - Map.merge(config, %{api_key: get_key(config)}) + Map.merge(config, %{api_key: _get_key(config)}) end @doc false def supports_attachments?, do: true - defp get_key(config) do + @doc """ + Private function prefixed with `_` for testability. + This handles getting the config key. + """ + def _get_key(config) do api_key = case Map.get(config, :api_key) do {:system, var} -> System.get_env(var) + {module_name, method_name, args} -> apply(module_name, method_name, args) + fun when is_function(fun) -> fun.() key -> key end diff --git a/test/lib/bamboo/adapters/send_grid_adapter_test.exs b/test/lib/bamboo/adapters/send_grid_adapter_test.exs index e2ca07c5..77cd87ee 100644 --- a/test/lib/bamboo/adapters/send_grid_adapter_test.exs +++ b/test/lib/bamboo/adapters/send_grid_adapter_test.exs @@ -3,10 +3,20 @@ defmodule Bamboo.SendGridAdapterTest do alias Bamboo.Email alias Bamboo.SendGridAdapter - @config %{adapter: SendGridAdapter, api_key: "123_abc"} + @good_api_key "123_abc" + @config %{adapter: SendGridAdapter, api_key: @good_api_key} @config_with_bad_key %{adapter: SendGridAdapter, api_key: nil} @config_with_env_var_key %{adapter: SendGridAdapter, api_key: {:system, "SENDGRID_API"}} - @config_with_sandbox_enabled %{adapter: SendGridAdapter, api_key: "123_abc", sandbox: true} + @config_with_env_var_tuple %{ + adapter: SendGridAdapter, + api_key: {Bamboo.SendGridAdapterTest, :sendgrid_secret, []} + } + @config_with_env_var_tuple_direct %{ + adapter: SendGridAdapter, + api_key: &Bamboo.SendGridAdapterTest.sendgrid_secret/0 + } + + @config_with_sandbox_enabled %{adapter: SendGridAdapter, api_key: @good_api_key, sandbox: true} defmodule FakeSendgrid do use Plug.Router @@ -54,6 +64,11 @@ defmodule Bamboo.SendGridAdapterTest do end end + @doc """ + sendgrid secret example dynamic + """ + def sendgrid_secret(), do: @good_api_key + setup do FakeSendgrid.start_server(self()) @@ -64,33 +79,44 @@ defmodule Bamboo.SendGridAdapterTest do :ok end - test "raises if the api key is nil" do - assert_raise ArgumentError, ~r/no API key set/, fn -> - new_email(from: "foo@bar.com") |> SendGridAdapter.deliver(@config_with_bad_key) + describe "API key section" do + test "raises if the api key is nil" do + assert_raise ArgumentError, ~r/no API key set/, fn -> + new_email(from: "foo@bar.com") |> SendGridAdapter.deliver(@config_with_bad_key) + end + + assert_raise ArgumentError, ~r/no API key set/, fn -> + SendGridAdapter.handle_config(%{}) + end end - assert_raise ArgumentError, ~r/no API key set/, fn -> - SendGridAdapter.handle_config(%{}) + test "can have a tuple resolution" do + config = SendGridAdapter.handle_config(@config_with_env_var_tuple) + assert config[:api_key] == @good_api_key end - end - test "can read the api key from an ENV var" do - System.put_env("SENDGRID_API", "123_abc") + test "can have an anonymous function resolution" do + config = SendGridAdapter.handle_config(@config_with_env_var_tuple_direct) + assert config[:api_key] == @good_api_key + end - config = SendGridAdapter.handle_config(@config_with_env_var_key) + test "can read the api key from an ENV var" do + System.put_env("SENDGRID_API", @good_api_key) + config = SendGridAdapter.handle_config(@config_with_env_var_key) - assert config[:api_key] == "123_abc" - end + assert config[:api_key] == @good_api_key + end - test "raises if an invalid ENV var is used for the API key" do - System.delete_env("SENDGRID_API") + test "raises if an invalid ENV var is used for the API key" do + System.delete_env("SENDGRID_API") - assert_raise ArgumentError, ~r/no API key set/, fn -> - new_email(from: "foo@bar.com") |> SendGridAdapter.deliver(@config_with_env_var_key) - end + assert_raise ArgumentError, ~r/no API key set/, fn -> + new_email(from: "foo@bar.com") |> SendGridAdapter.deliver(@config_with_env_var_key) + end - assert_raise ArgumentError, ~r/no API key set/, fn -> - SendGridAdapter.handle_config(@config_with_env_var_key) + assert_raise ArgumentError, ~r/no API key set/, fn -> + SendGridAdapter.handle_config(@config_with_env_var_key) + end end end From 87e99e619f3a74780ce0d4ee2c4c3a23a007d79d Mon Sep 17 00:00:00 2001 From: Ed Bond Date: Thu, 12 Mar 2020 02:50:42 -0500 Subject: [PATCH 2/4] updating documentation --- lib/bamboo/adapters/send_grid_adapter.ex | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/bamboo/adapters/send_grid_adapter.ex b/lib/bamboo/adapters/send_grid_adapter.ex index 8f776fb0..c2a4a72d 100644 --- a/lib/bamboo/adapters/send_grid_adapter.ex +++ b/lib/bamboo/adapters/send_grid_adapter.ex @@ -19,7 +19,11 @@ defmodule Bamboo.SendGridAdapter do # In config/config.exs, or config.prod.exs, etc. config :my_app, MyApp.Mailer, adapter: Bamboo.SendGridAdapter, - api_key: "my_api_key" # or {:system, "SENDGRID_API_KEY"}, + api_key: "my_api_key" + # or {:system, "SENDGRID_API_KEY"}, + # or {ModuleName, :method_name, []} + # or fn -> "a resolveable function" end + # or &ModuleName.method_name/0 hackney_opts: [ recv_timeout: :timer.minutes(1) ] @@ -32,6 +36,7 @@ defmodule Bamboo.SendGridAdapter do defmodule MyApp.Mailer do use Bamboo.Mailer, otp_app: :my_app end + """ @service_name "SendGrid" From 61409d37a7e13e5072aa26d1cce28ed512092523 Mon Sep 17 00:00:00 2001 From: Ed Bond Date: Wed, 19 Aug 2020 20:50:54 -0500 Subject: [PATCH 3/4] feedback from PR changes to documentation and tests --- lib/bamboo/adapters/send_grid_adapter.ex | 1 - test/lib/bamboo/adapters/send_grid_adapter_test.exs | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/bamboo/adapters/send_grid_adapter.ex b/lib/bamboo/adapters/send_grid_adapter.ex index c2a4a72d..a4c9dc95 100644 --- a/lib/bamboo/adapters/send_grid_adapter.ex +++ b/lib/bamboo/adapters/send_grid_adapter.ex @@ -22,7 +22,6 @@ defmodule Bamboo.SendGridAdapter do api_key: "my_api_key" # or {:system, "SENDGRID_API_KEY"}, # or {ModuleName, :method_name, []} - # or fn -> "a resolveable function" end # or &ModuleName.method_name/0 hackney_opts: [ recv_timeout: :timer.minutes(1) diff --git a/test/lib/bamboo/adapters/send_grid_adapter_test.exs b/test/lib/bamboo/adapters/send_grid_adapter_test.exs index 77cd87ee..de95e1cd 100644 --- a/test/lib/bamboo/adapters/send_grid_adapter_test.exs +++ b/test/lib/bamboo/adapters/send_grid_adapter_test.exs @@ -65,7 +65,8 @@ defmodule Bamboo.SendGridAdapterTest do end @doc """ - sendgrid secret example dynamic + This is a private function that is referenced in `Bamboo.SendGridAdapterTest` + to test the config usage example of having a dynamic key """ def sendgrid_secret(), do: @good_api_key From 4a942977b7497e6690203b20311030292e8071f1 Mon Sep 17 00:00:00 2001 From: Ed Bond Date: Fri, 21 Aug 2020 15:51:01 -0500 Subject: [PATCH 4/4] more feedback --- lib/bamboo/adapters/send_grid_adapter.ex | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/lib/bamboo/adapters/send_grid_adapter.ex b/lib/bamboo/adapters/send_grid_adapter.ex index cb65fe71..ed378949 100644 --- a/lib/bamboo/adapters/send_grid_adapter.ex +++ b/lib/bamboo/adapters/send_grid_adapter.ex @@ -22,7 +22,6 @@ defmodule Bamboo.SendGridAdapter do api_key: "my_api_key" # or {:system, "SENDGRID_API_KEY"}, # or {ModuleName, :method_name, []} - # or &ModuleName.method_name/0 hackney_opts: [ recv_timeout: :timer.minutes(1) ] @@ -47,7 +46,7 @@ defmodule Bamboo.SendGridAdapter do import Bamboo.ApiError def deliver(email, config) do - api_key = _get_key(config) + api_key = get_key(config) body = email |> to_sendgrid_body(config) |> Bamboo.json_library().encode!() url = [base_uri(), @send_message_path] @@ -67,17 +66,13 @@ defmodule Bamboo.SendGridAdapter do @doc false def handle_config(config) do # build the api key - will raise if there are errors - Map.merge(config, %{api_key: _get_key(config)}) + Map.merge(config, %{api_key: get_key(config)}) end @doc false def supports_attachments?, do: true - @doc """ - Private function prefixed with `_` for testability. - This handles getting the config key. - """ - def _get_key(config) do + defp get_key(config) do api_key = case Map.get(config, :api_key) do {:system, var} -> System.get_env(var)