Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic sendgrid key #523

Merged
merged 5 commits into from
Aug 24, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions lib/bamboo/adapters/send_grid_adapter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ 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 &ModuleName.method_name/0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw the discussion in #523 (comment), and I saw that you removed the anonymous function in 61409d3 (thank you!).

Is &ModuleName.method_name/0 technically an anonymous function as well? Doesn't the capture operator create an anonymous function? Do you know if this will work or should we remove it as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it is an anonymous function. and looking back at the the driving factor behind this, https://hexdocs.pm/stripity_stripe/readme.html#configuration

uses the anonymous function. It's syntaxtual at this point, so I don't mind just the first 2

I have been using

config :notification, Notification.Mailer,
  adapter: Bamboo.SendGridAdapter,
  api_key: {Notification.Secrets, :sendgrid_secret, []},
  hackney_opts: [
    recv_timeout: :timer.minutes(1)
  ]

for a while now without issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be updated now

hackney_opts: [
recv_timeout: :timer.minutes(1)
]
Expand All @@ -32,6 +35,7 @@ defmodule Bamboo.SendGridAdapter do
defmodule MyApp.Mailer do
use Bamboo.Mailer, otp_app: :my_app
end

"""

@service_name "SendGrid"
Expand All @@ -43,7 +47,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]

Expand All @@ -63,16 +67,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
spunkedy marked this conversation as resolved.
Show resolved Hide resolved
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

Expand Down
68 changes: 47 additions & 21 deletions test/lib/bamboo/adapters/send_grid_adapter_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,22 @@ defmodule Bamboo.SendGridAdapterTest do
use ExUnit.Case
alias Bamboo.Email
alias Bamboo.SendGridAdapter

alias Bamboo.Test.User

@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
Expand Down Expand Up @@ -56,6 +65,12 @@ defmodule Bamboo.SendGridAdapterTest do
end
end

@doc """
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

setup do
FakeSendgrid.start_server(self())

Expand All @@ -66,33 +81,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

Expand Down