Skip to content
This repository was archived by the owner on Jan 19, 2022. It is now read-only.

Get transactions #15

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ pluggy_elixir-*.tar

# Temporary files for e.g. tests
/tmp

.git
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Get all webhooks
- Get transactions by account

[unreleased]: https://github.com/brainnco/strong_params/compare/main
114 changes: 58 additions & 56 deletions lib/pluggy_elixir/http_adapter/tesla.ex
Original file line number Diff line number Diff line change
@@ -1,70 +1,72 @@
defmodule PluggyElixir.HttpAdapter.Tesla do
@moduledoc """
Implements `PluggyElixir.HttpAdapter` behaviour using `Tesla`.
"""
alias PluggyElixir.Config
alias PluggyElixir.HttpAdapter.Response
if Code.ensure_loaded?(Tesla) do
defmodule PluggyElixir.HttpAdapter.Tesla do
@moduledoc """
Implements `PluggyElixir.HttpAdapter` behaviour using `Tesla`.
"""
alias PluggyElixir.Config
alias PluggyElixir.HttpAdapter.Response

@behaviour PluggyElixir.HttpAdapter
@behaviour PluggyElixir.HttpAdapter

@impl true
def post(url, body, query \\ [], headers \\ [], %Config{} = config) do
config
|> build_client()
|> Tesla.post(url, body, build_options(query, headers, config))
|> format_response()
end
@impl true
def post(url, body, query \\ [], headers \\ [], %Config{} = config) do
config
|> build_client()
|> Tesla.post(url, body, build_options(query, headers, config))
|> format_response()
end

@impl true
def get(url, query \\ [], headers \\ [], %Config{} = config) do
config
|> build_client()
|> Tesla.get(url, build_options(query, headers, config))
|> format_response()
end
@impl true
def get(url, query \\ [], headers \\ [], %Config{} = config) do
config
|> build_client()
|> Tesla.get(url, build_options(query, headers, config))
|> format_response()
end

@impl true
def patch(url, body, query \\ [], headers \\ [], %Config{} = config) do
config
|> build_client()
|> Tesla.patch(url, body, build_options(query, headers, config))
|> format_response()
end
@impl true
def patch(url, body, query \\ [], headers \\ [], %Config{} = config) do
config
|> build_client()
|> Tesla.patch(url, body, build_options(query, headers, config))
|> format_response()
end

defp build_options(query, headers, %{sandbox: sandbox}) do
[
query: build_query(query, sandbox),
headers: headers
]
end
defp build_options(query, headers, %{sandbox: sandbox}) do
[
query: build_query(query, sandbox),
headers: headers
]
end

defp build_query(query, true), do: Keyword.merge(query, sandbox: true)
defp build_query(query, _false), do: query
defp build_query(query, true), do: Keyword.merge(query, sandbox: true)
defp build_query(query, _false), do: query

defp build_client(config) do
Tesla.client(
[
{Tesla.Middleware.BaseUrl, host_uri(config)},
{Tesla.Middleware.Headers, [{"content-type", "application/json"}]},
Tesla.Middleware.JSON
],
get_tesla_adapter(config)
)
end
defp build_client(config) do
Tesla.client(
[
{Tesla.Middleware.BaseUrl, host_uri(config)},
{Tesla.Middleware.Headers, [{"content-type", "application/json"}]},
Tesla.Middleware.JSON
],
get_tesla_adapter(config)
)
end

defp format_response({:ok, %Tesla.Env{body: body, headers: headers, status: status}}),
do: {:ok, %Response{body: body, headers: headers, status: status}}
defp format_response({:ok, %Tesla.Env{body: body, headers: headers, status: status}}),
do: {:ok, %Response{body: body, headers: headers, status: status}}

defp format_response({:error, reason}) when is_atom(reason),
do: {:error, Atom.to_string(reason)}
defp format_response({:error, reason}) when is_atom(reason),
do: {:error, Atom.to_string(reason)}

defp format_response({:error, {Tesla.Middleware.JSON, :decode, _error}}),
do: {:error, "response body is not a valid JSON"}
defp format_response({:error, {Tesla.Middleware.JSON, :decode, %{data: invalid_json}}}),
do: {:error, %{message: "response body is not a valid JSON", details: invalid_json}}

defp format_response({:error, reason}), do: {:error, inspect(reason)}
defp format_response({:error, reason}), do: {:error, inspect(reason)}

defp get_tesla_adapter(%{adapter: %{configs: adapter_config}}),
do: Keyword.fetch!(adapter_config, :adapter)
defp get_tesla_adapter(%{adapter: %{configs: adapter_config}}),
do: Keyword.fetch!(adapter_config, :adapter)

defp host_uri(%{host: host}), do: to_string(host)
defp host_uri(%{host: host}), do: to_string(host)
end
end
3 changes: 3 additions & 0 deletions lib/pluggy_elixir/http_client.ex
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,8 @@ defmodule PluggyElixir.HttpClient do
defp handle_result({:ok, %Response{} = response}),
do: {:error, Error.parse(response)}

defp handle_result({:error, %{message: message, details: details}}),
do: {:error, %Error{code: 500, message: message, details: details}}

defp handle_result({:error, _reason} = error), do: error
end
95 changes: 95 additions & 0 deletions lib/pluggy_elixir/test.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
defmodule PluggyElixir.Test do
@moduledoc """
Support module to crate test form `PluggyElixir`
"""
alias PluggyElixir.Auth.Guard

def create_and_save_api_key do
auth = %PluggyElixir.Auth{api_key: "generated_api_key_#{:rand.uniform()}"}

Guard.set_auth(auth)

auth.api_key
end

if Code.ensure_loaded?(Bypass) do
alias Plug.Conn

def bypass_expect(bypass, method, url, mock_func) do
caller = self()

Bypass.expect(bypass, method, url, fn conn ->
conn
|> validate_content_type()
|> Conn.read_body()
|> json_decode()
|> Conn.put_resp_header("content-type", "application/json")
|> notify_caller(caller)
|> mock_func.()
end)
end

defmacro assert_pluggy(value, timeout \\ 3000) do
assertion =
if(is_fn(value),
do: quote(do: unquote(value).(conn)),
else: quote(do: assert(unquote(value) = conn))
)

quote do
receive do
{:bypass, conn} ->
unquote(assertion)
after
unquote(timeout) -> raise("Bypass message not received")
end
end
end

defp is_fn({:fn, _line, _code}), do: true
defp is_fn(_any), do: false

defp validate_content_type(conn) do
conn
|> Conn.get_req_header("content-type")
|> case do
["application/json" <> _tail] -> conn
_other -> custom_raise("Pluggy API requires content-type: application/json header")
end
end

defp json_decode({:ok, body, conn}) do
body
|> case do
"" -> {:ok, %{}}
json -> Jason.decode(json)
end
|> add_body(conn)
end

defp add_body({:ok, body}, conn) when is_map(body) do
%{conn | body_params: body, params: Map.merge(conn.params, body)}
end

defp add_body({:error, reason}, _conn) do
custom_raise(
"Pluggy API just accept body with JSON format. The Jason.decode/1 failed with #{
inspect(reason)
}"
)
end

defp notify_caller(%Conn{} = conn, caller) do
Process.send(
caller,
{:bypass,
Map.take(conn, [:params, :body_params, :query_params, :path_params, :req_headers])},
[]
)

conn
end

defp custom_raise(msg), do: raise("\n\n\n>>>>>> Bypass error:\n\n#{msg}\n\n<<<<<<\n\n\n")
end
end
Empty file.
Loading