Current section
Files
Jump to
Current section
Files
lib/finicity.ex
defmodule Finicity do
use HTTPotion.Base
use GenServer
def start(args) do
GenServer.start(__MODULE__, args, name: Finicity)
end
def init(args) do
{:ok, []}
end
def handle_cast({:set_token, token}, state) do
state = Keyword.put(state, :token, token)
{:noreply, state}
end
def handle_call({:get_token}, caller, state) do
{:ok, state[:token], state}
end
def set_token(token) do
GenServer.cast(Finicity, {:set_token, token})
end
def get_token do
GenServer.call(Finicity, {:get_token})
end
def partner_authentication() do
partner_authentication([partner_id: partner_id(), partner_secret: partner_secret()])
end
def partner_authentication([partner_id: partner_id, partner_secret: partner_secret]) do
unless {:ok, token} = get_token do
data = {:credentials, nil, [
{:partnerId, nil, partner_id},
{:partnerSecret, nil, partner_secret}]}
|> XmlBuilder.generate
%{status_code: 200, body: body} = post("/v2/partners/authentication", [body: data, timeout: 20000])
token = body |> Floki.Finder.find("token") |> Floki.FlatText.get
end
{:ok, token}
end
def get_institutions(token, params) do
%{status_code: 200, body: body} = get("/v1/institutions?" <> URI.encode_query(params), [headers: app_token(token)])
t = body |> Floki.Finder.find("institutions") |> List.first
metadata = t |> elem(1) |> Enum.into(%{})
institutions = t |> node_to_map
{:ok, %{"metadata" => metadata, "institutions" => institutions}}
end
def get_institution_form(token, [institution_id: institution_id]) do
%{status_code: 200, body: body} = get("/v1/institutions/" <> institution_id <> "/loginForm", [headers: app_token(token)])
fields = body |> Floki.find("loginform") |> List.first |> node_to_map
{:ok, %{"fields" => fields}}
end
def add_all_accounts(token, [customer_id: customer_id, institution_id: institution_id]) do
end
def discover_customer_accounts(token, [customer_id: customer_id, institution_id: institution_id, credentials: credentials]) do
data = {:accounts, nil, [{:credentials, nil, credentials}]} |> XmlBuilder.generate
case post("/v1/customers/#{customer_id}/institutions/#{institution_id}/accounts") do
%{status_code: 200, body: body} ->
IO.inspect body
%{status_code: 203, body: body} ->
# TODO: handle mfa
IO.inspect body
_ ->
IO.puts "error discovering customer accounts"
end
end
def add_customer(token, [username: username, first_name: first_name, last_name: last_name]) do
data = {:customer, nil, [
{:username, nil, username},
{:firstName, nil, first_name},
{:lastName, nil, last_name}
]}
|> XmlBuilder.generate
%{status_code: 201, body: body} = post("/v1/customers/active", [body: data, timeout: 20000, headers: app_token(token)])
customer = body |> Floki.Finder.find("customer")
{:ok, customer}
end
def add_test_customer(token, [username: username, first_name: first_name, last_name: last_name]) do
data = {:customer, nil, [
{:username, nil, username},
{:firstName, nil, first_name},
{:lastName, nil, last_name}
]}
|> XmlBuilder.generate
%{status_code: 201, body: body} = post("/v1/customers/testing", [body: data, timeout: 20000, headers: app_token(token)])
customer = body |> Floki.Finder.find("customer")
{:ok, body}
end
defp process_url(url) do
"https://api.finicity.com/aggregation" <> url
end
defp process_request_headers(headers) do
headers
|> Dict.put(:"Content-Type", "application/xml")
|> Dict.put(:"Finicity-App-Key", app_key())
end
defp process_response_body(body) do
body |> Floki.parse
end
defp app_token(token) do
["Finicity-App-Token": token]
end
defp app_key do
System.get_env("FINICITY_APP_KEY") || Application.get_env(:finicity, :app_key)
end
defp partner_id do
System.get_env("FINICITY_PARTNER_ID") || Application.get_env(:finicity, :partner_id)
end
defp partner_secret do
System.get_env("FINICITY_PARTNER_SECRET") || Application.get_env(:finicity, :partner_secret)
end
defp node_to_map(node) do
node |> elem(2) |> Enum.map(fn(x) ->
x |> elem(2) |> Enum.reduce(%{}, fn(x, acc) ->
Map.put(acc, elem(x, 0), elem(x, 2) |> List.first)
end)
end)
end
end