This repository has been archived by the owner on Aug 28, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from jshmrtn/payments
Add payments Endpoint
- Loading branch information
Showing
16 changed files
with
2,126 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
%{ | ||
configs: [ | ||
%{ | ||
name: "default", | ||
files: %{ | ||
included: ["lib/", "test", "mix.exs"], | ||
excluded: [] | ||
}, | ||
checks: [ | ||
# For others you can also set parameters | ||
{Credo.Check.Readability.MaxLineLength, priority: :low, max_length: 120}, | ||
# Allow Namespaces for broader Alias | ||
{Credo.Check.Design.AliasUsage, priority: :low, if_nested_deeper_than: 2} | ||
] | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,12 @@ | ||
# This file is responsible for configuring your application | ||
# and its dependencies with the aid of the Mix.Config module. | ||
use Mix.Config | ||
|
||
# This configuration is loaded before any dependency and is restricted | ||
# to this project. If another project depends on this project, this | ||
# file won't be loaded nor affect the parent project. For this reason, | ||
# if you want to provide default values for your application for | ||
# 3rd-party users, it should be done in your "mix.exs" file. | ||
|
||
# You can configure your application as: | ||
# | ||
# config :ex_wirecard, key: :value | ||
# | ||
# and access this configuration in your application as: | ||
# | ||
# Application.get_env(:ex_wirecard, :key) | ||
# | ||
# You can also configure a 3rd-party app: | ||
# | ||
# config :logger, level: :info | ||
# | ||
|
||
# It is also possible to import configuration files, relative to this | ||
# directory. For example, you can emulate configuration per environment | ||
# by uncommenting the line below and defining dev.exs, test.exs and such. | ||
# Configuration from the imported file will override the ones defined | ||
# here (which is why it is important to import them last). | ||
# | ||
# import_config "#{Mix.env}.exs" | ||
config :exvcr, | ||
vcr_cassette_library_dir: "priv/fixture/vcr_cassettes", | ||
custom_cassette_library_dir: "priv/fixture/custom_cassettes", | ||
filter_sensitive_data: [ | ||
[ | ||
pattern: "<merchant-account-id.+</merchant-account-id>", | ||
placeholder: "<merchant-account-id>Foo</merchant-account-id>" | ||
] | ||
], | ||
filter_request_headers: ["authorization"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,36 @@ | ||
defmodule ExWirecard do | ||
@moduledoc """ | ||
Documentation for ExWirecard. | ||
API Client for WireCard. | ||
""" | ||
|
||
@doc """ | ||
Hello world. | ||
defmacro __using__(opts) do | ||
base_uri = Keyword.get(opts, :base_uri, "https://api.wirecard.com/engine/rest/") | ||
schema_module = Keyword.fetch!(opts, :schema_module) | ||
|
||
## Examples | ||
quote bind_quoted: [ | ||
base_uri: base_uri, | ||
schema_module: schema_module | ||
] do | ||
use Tesla | ||
|
||
iex> ExWirecard.hello | ||
:world | ||
plug(Tesla.Middleware.Headers, %{"Accept" => "application/xml"}) | ||
@model schema_module.erlsom_model() | ||
plug(ExWirecard.Middleware.XML, model: @model) | ||
|
||
""" | ||
def hello do | ||
:world | ||
def new(opts \\ %{}) do | ||
Tesla.build_client([ | ||
{Tesla.Middleware.BaseUrl, | ||
Application.get_env(:ex_wirecard, :base_url, unquote(base_uri))}, | ||
{Tesla.Middleware.BasicAuth, | ||
Map.merge( | ||
%{ | ||
username: Application.fetch_env!(:ex_wirecard, :username), | ||
password: Application.fetch_env!(:ex_wirecard, :password) | ||
}, | ||
opts | ||
)} | ||
]) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
defmodule ExWirecard.Middleware.XML do | ||
@behaviour Tesla.Middleware | ||
|
||
alias Tesla.Middleware.Headers | ||
alias Tesla.Multipart | ||
|
||
@moduledoc """ | ||
Encode requests and decode responses as XML. | ||
This middleware requires [erlsom](https://hex.pm/packages/erlsom) as dependency. | ||
Remember to add `{:erlsom, "~> 1.4"}` to dependencies (and `:erlsom` to applications in `mix.exs`) | ||
Also, you need to recompile tesla after adding `:erlsom` dependency: | ||
``` | ||
mix deps.clean ex_wirecard | ||
mix deps.compile ex_wirecard | ||
``` | ||
### Example usage | ||
``` | ||
defmodule MyClient do | ||
use Tesla | ||
plug Tesla.Middleware.XML, model: :erlsom.compile_xsd_file("some.xsd") | ||
end | ||
``` | ||
### Options | ||
- `:engine_opts` - optional engine options | ||
- `:decode_content_types` - list of additional decodable content-types | ||
- `:model` - erlsom XML Model | ||
""" | ||
@default_content_types ["application/xml"] | ||
|
||
def call(env, next, opts) do | ||
opts = opts || [] | ||
|
||
env | ||
|> encode(opts) | ||
|> Tesla.run(next) | ||
|> decode(opts) | ||
end | ||
|
||
@doc """ | ||
Encode request body as XML. | ||
""" | ||
def encode(env, opts) do | ||
if encodable?(env) do | ||
env | ||
|> Map.update!(:body, &encode_body(&1, opts)) | ||
|> Headers.call([], %{"content-type" => "application/xml"}) | ||
else | ||
env | ||
end | ||
end | ||
|
||
defp encode_body(%Stream{} = body, opts), do: encode_stream(body, opts) | ||
defp encode_body(body, opts) when is_function(body), do: encode_stream(body, opts) | ||
defp encode_body(body, opts), do: process(body, :encode, opts) | ||
|
||
defp encode_stream(body, opts) do | ||
Stream.map(body, fn item -> encode_body(item, opts) <> "\n" end) | ||
end | ||
|
||
defp encodable?(%{body: nil}), do: false | ||
defp encodable?(%{body: body}) when is_binary(body), do: false | ||
defp encodable?(%{body: %Multipart{}}), do: false | ||
defp encodable?(_), do: true | ||
|
||
@doc """ | ||
Decode response body as XML. | ||
""" | ||
def decode(env, opts) do | ||
if decodable?(env, opts) do | ||
Map.update!(env, :body, &process(&1, :decode, opts)) | ||
else | ||
env | ||
end | ||
end | ||
|
||
defp decodable?(env, opts), do: decodable_body?(env) && decodable_content_type?(env, opts) | ||
|
||
defp decodable_body?(env) do | ||
(is_binary(env.body) && env.body != "") || (is_list(env.body) && env.body != []) | ||
end | ||
|
||
defp decodable_content_type?(env, opts) do | ||
case env.headers["content-type"] do | ||
nil -> false | ||
content_type -> Enum.any?(content_types(opts), &String.starts_with?(content_type, &1)) | ||
end | ||
end | ||
|
||
defp content_types(opts), | ||
do: @default_content_types ++ Keyword.get(opts, :decode_content_types, []) | ||
|
||
defp process(data, op, opts) do | ||
with {:ok, value} <- do_process(data, op, opts) do | ||
value | ||
else | ||
{:error, reason} -> | ||
raise %Tesla.Error{message: "XML #{op} error: #{inspect(reason)}", reason: reason} | ||
|
||
{:error, msg, position} -> | ||
reason = {msg, position} | ||
raise %Tesla.Error{message: "XML #{op} error: #{inspect(reason)}", reason: reason} | ||
end | ||
end | ||
|
||
defp do_process(data, :encode, opts) do | ||
{:ok, encoded} = :erlsom.write(data, Keyword.fetch!(opts, :model)) | ||
{:ok, to_string(encoded)} | ||
end | ||
|
||
defp do_process(data, :decode, opts) do | ||
case :erlsom.scan(data, Keyword.fetch!(opts, :model)) do | ||
{:ok, decoded, _} -> {:ok, decoded} | ||
{:error, error} -> {:error, error} | ||
end | ||
end | ||
end | ||
|
||
defmodule ExWirecard.Middleware.DecodeXML do | ||
@moduledoc """ | ||
Decode XML | ||
""" | ||
|
||
alias ExWirecard.Middleware.XML | ||
|
||
def call(env, next, opts) do | ||
opts = opts || [] | ||
|
||
env | ||
|> Tesla.run(next) | ||
|> XML.decode(opts) | ||
end | ||
end | ||
|
||
defmodule ExWirecard.Middleware.EncodeXML do | ||
@moduledoc """ | ||
Encode XML | ||
""" | ||
|
||
alias ExWirecard.Middleware.XML | ||
|
||
def call(env, next, opts) do | ||
opts = opts || [] | ||
|
||
env | ||
|> XML.encode(opts) | ||
|> Tesla.run(next) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
defmodule ExWirecard.Payment do | ||
@moduledoc """ | ||
Payments Endpoint Client | ||
""" | ||
|
||
use ExWirecard, | ||
base_uri: "https://api.wirecard.com/engine/rest/", | ||
schema_module: ExWirecard.Schema.Payment, | ||
name: "payment" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
defmodule ExWirecard.Schema do | ||
@moduledoc """ | ||
Base to add Schema | ||
""" | ||
|
||
defmacro __using__(opts) do | ||
quote bind_quoted: [name: Keyword.fetch!(opts, :name)] do | ||
hrl_path = Application.app_dir(:ex_wirecard, "priv/hrl/#{name}.hrl") | ||
xsd_path = Application.app_dir(:ex_wirecard, "priv/xsd/#{name}.xsd") | ||
|
||
require Record | ||
|
||
for {name, fields} <- Record.extract_all(from: hrl_path) do | ||
nice_name = | ||
name | ||
|> Atom.to_string() | ||
|> String.replace(~r/-/, "_") | ||
|> String.to_atom() | ||
|
||
Record.defrecord(nice_name, name, fields) | ||
end | ||
|
||
@erlsom_model :erlsom.compile_xsd_file(xsd_path) | ||
def erlsom_model do | ||
{:ok, model} = @erlsom_model | ||
model | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
defmodule ExWirecard.Schema.Payment do | ||
@moduledoc """ | ||
Schema for payments endpoint | ||
""" | ||
|
||
use ExWirecard.Schema, name: "payment" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
defmodule Mix.Tasks.ExWirecard.XsdToHrl do | ||
@moduledoc """ | ||
Convert all XSD Files in `priv/xsd` to HRL into `priv/hrl`. | ||
""" | ||
@shortdoc "Convert XSD to HRL" | ||
|
||
use Mix.Task | ||
|
||
@xsd_dir Application.app_dir(:ex_wirecard, "priv/xsd") | ||
@hrl_dir Application.app_dir(:ex_wirecard, "priv/hrl") | ||
|
||
def run(_) do | ||
for xsd <- xsds() do | ||
hrl = hrl_path(xsd) | ||
IO.puts("Converting #{xsd} to #{hrl}") | ||
:erlsom.write_xsd_hrl_file(xsd, hrl) | ||
end | ||
end | ||
|
||
defp xsds do | ||
@xsd_dir | ||
|> File.ls!() | ||
|> Enum.map(&Path.join(@xsd_dir, &1)) | ||
end | ||
|
||
defp hrl_path(xsd) do | ||
name = Path.basename(xsd, ".xsd") | ||
Path.join(@hrl_dir, name <> ".hrl") | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.