Current section
Files
Jump to
Current section
Files
lib/yodlee/utils.ex
defmodule Yodlee.Utils do
@moduledoc """
Utility functions.
"""
alias Yodlee.{Account, Money, Transaction, Refreshinfo, Cobrand, User, ProviderAccount, Provider, DataExtract, Webhook}
@spec locale() :: map
def locale do
%{locale: "en_US"}
end
@spec encode_params(map) :: String.t
def encode_params(params) do
params
|> Map.to_list()
|> Enum.map_join("&", fn x -> pair(x) end)
end
defp pair({key, value}) do
param_name = to_string(key) |> URI.encode_www_form()
param_value =
cond do
is_map(value) ->
Poison.encode!(value)
is_list(value) ->
Enum.map_join(value, "|", fn x -> x end) |> URI.encode_www_form()
true ->
to_string(value) |> URI.encode_www_form()
end
"#{param_name}=#{param_value}"
end
@doc """
Converts Yodlee camel case keys to Elixir friendly snake case.
"""
@spec normalize_keys(map) :: map
def normalize_keys(map) when is_binary(map), do: map
def normalize_keys(map) do
map
|> Map.to_list()
|> Enum.map(&recase/1)
|> Enum.into(%{})
end
defp recase({k, v}) do
cond do
is_map(v) ->
{Recase.to_snake(k), normalize_keys(v)}
is_list(v) ->
{Recase.to_snake(k), Enum.map(v, &normalize_keys/1)}
true ->
{Recase.to_snake(k), v}
end
end
@doc """
Handles Yodlee response and maps to the correct data structure.
"""
@spec handle_resp({:ok, HTTPoison.Response.t} | {:error, HTTPoison.Error.t}, atom) :: {:ok, any} | {:error, map | Yodlee.Error.t | HTTPoison.Error.t}
def handle_resp({:ok, %{body: {:invalid, body}}}, _schema) do
{:error, body}
end
def handle_resp({:ok, %{status_code: 200, body: body}}, schema) do
{:ok, map_body(body, schema)}
end
def handle_resp({:ok, %{status_code: code, body: _}}, _schema) when code in 201..299 do
{:ok, %{}}
end
def handle_resp({:ok, resp}, _schema) do
error =
resp.body
|> normalize_keys()
|> Poison.Decode.decode(as: %Yodlee.Error{})
{:error, error}
end
def handle_resp({:error, %HTTPoison.Error{} = error}, _schema) do
{:error, error}
end
defp map_body(body, _schema) when body == %{} do
body
end
defp map_body(cobrand, :cobrand) do
session = get_in(cobrand, ["session", "cobSession"])
Application.put_env(:yodlee, :cob_session, session)
cobrand
|> normalize_keys()
|> Map.put("session", session)
|> Poison.Decode.decode(as: %Cobrand{})
end
defp map_body(%{"user" => user}, :user) do
session = get_in(user, ["session", "userSession"])
user
|> normalize_keys()
|> Map.put("session", session)
|> Poison.Decode.decode(as: %User{})
end
defp map_body(%{"account" => accounts}, :account) do
accounts
|> Enum.map(&normalize_keys/1)
|> Poison.Decode.decode(as: [%Account{
amount_due: %Money{},
balance: %Money{},
last_payment_amount: %Money{},
minimum_amount_due: %Money{},
original_loan_amount: %Money{},
principal_balance: %Money{},
refreshinfo: %Refreshinfo{}
}])
end
defp map_body(%{"transaction" => trans}, :transaction) do
trans
|> Enum.map(&normalize_keys/1)
|> Poison.Decode.decode(as: [%Transaction{
amount: %Yodlee.Money{},
interest: %Yodlee.Money{},
principal: %Yodlee.Money{}
}])
end
defp map_body(%{"providerAccount" => provider_accounts}, :provider_account) when is_list(provider_accounts) do
provider_accounts
|> Enum.map(&normalize_keys/1)
|> Poison.Decode.decode(as: [%ProviderAccount{
refresh_info: %Refreshinfo{}
}])
end
defp map_body(%{"providerAccount" => provider_accounts}, :provider_account) do
provider_accounts
|> normalize_keys()
|> Poison.Decode.decode(as: %ProviderAccount{
refresh_info: %Refreshinfo{}
})
end
defp map_body(%{"provider" => providers}, :provider) do
providers
|> Enum.map(&normalize_keys/1)
|> Poison.Decode.decode(as: [%Provider{}])
end
defp map_body(%{"user" => %{"accessTokens" => [token | _]}}, :fastlink) do
token
|> normalize_keys()
|> Map.take(["app_id", "value", "url"])
|> Enum.reduce(%{}, fn {k, v}, acc ->
Map.put(acc, String.to_atom(k), v)
end)
end
defp map_body(%{"userData" => user_data}, :data_extract) do
user_data
|> Enum.map(&normalize_keys/1)
|> Poison.Decode.decode(as: [%DataExtract{
user: %User{},
provider_account: [%ProviderAccount{
refresh_info: %Refreshinfo{}
}],
account: [%Account{
amount_due: %Money{},
balance: %Money{},
last_payment_amount: %Money{},
minimum_amount_due: %Money{},
original_loan_amount: %Money{},
principal_balance: %Money{},
refreshinfo: %Refreshinfo{}
}],
transaction: [%Transaction{
amount: %Yodlee.Money{},
interest: %Yodlee.Money{},
principal: %Yodlee.Money{}
}]
}])
end
defp map_body(%{"event" => webhooks}, :webhook) do
webhooks
|> Enum.map(&normalize_keys/1)
|> Poison.Decode.decode(as: [%Webhook{}])
end
defp map_body(_, :webhook) do
[]
end
end