From cabec0826c12532298b06f606fe42b0b48eba61b Mon Sep 17 00:00:00 2001 From: Josh Smith Date: Thu, 10 Nov 2016 18:11:41 -0800 Subject: [PATCH] Add Stripe.Account Fix usage of lists for hackney opts Add retrieving your own account --- .gitignore | 2 +- config/config.exs | 5 +++ lib/stripe.ex | 19 ++++++----- lib/stripe/account.ex | 78 +++++++++++++++++++++++++++++++++++++++++++ lib/stripe/connect.ex | 1 - lib/stripe/util.ex | 66 +++++------------------------------- mix.exs | 37 ++++++++++---------- 7 files changed, 120 insertions(+), 88 deletions(-) create mode 100644 config/config.exs create mode 100644 lib/stripe/account.ex diff --git a/.gitignore b/.gitignore index 927646d5..205d4c80 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,5 @@ /deps erl_crash.dump *.ez -config +config/config.secret.exs /doc diff --git a/config/config.exs b/config/config.exs new file mode 100644 index 00000000..09fa7812 --- /dev/null +++ b/config/config.exs @@ -0,0 +1,5 @@ +use Mix.Config + +if File.exists?("config/config.secret.exs") do + import_config "config.secret.exs" +end diff --git a/lib/stripe.ex b/lib/stripe.ex index ef9be368..2aeab29c 100644 --- a/lib/stripe.ex +++ b/lib/stripe.ex @@ -5,7 +5,7 @@ defmodule Stripe do ## Configuration ### API Key - + You need to set your API key in your application configuration. Typically this is done in `config/config.exs` or a similar file. For example: @@ -18,7 +18,7 @@ defmodule Stripe do config :stripity_stripe, api_key: System.get_env("STRIPE_API_KEY") ### HTTP Connection Pool - + Stripity Stripe is set up to use an HTTP connection pool by default. This means that it will reuse already opened HTTP connections in order to minimize the overhead of establishing connections. Two configuration @@ -203,15 +203,15 @@ defmodule Stripe do Map.put(existing_headers, "Stripe-Account", account_id) end - @spec add_default_options(Keyword.t) :: Keyword.t + @spec add_default_options(list) :: list defp add_default_options(opts) do - Keyword.merge(opts, [with_body: opts]) + [ :with_body | opts ] end - @spec add_pool_option(Keyword.t) :: Keyword.t + @spec add_pool_option(list) :: list defp add_pool_option(opts) do if use_pool?() do - Keyword.put(opts, :pool, @pool_name) + [ {:pool, @pool_name} | opts ] else opts end @@ -229,11 +229,12 @@ defmodule Stripe do request(:get, "/customers", %{}, %{}, connect_account: "acc_134151") """ - @spec request(method, String.t, map, headers, Keyword.t) :: {:ok, map} | {:error, Exception.t} + @spec request(method, String.t, map, headers, list) :: {:ok, map} | {:error, Exception.t} def request(method, endpoint, body, headers, opts) do - {connect_account_id, opts} = Keyword.pop(opts, :connection_account) + {connect_account_id, opts} = Keyword.pop(opts, :connect_account) - req_url = get_base_url() <> endpoint + base_url = get_base_url() + req_url = base_url <> endpoint req_body = Stripe.URI.encode_query(body) req_headers = headers diff --git a/lib/stripe/account.ex b/lib/stripe/account.ex new file mode 100644 index 00000000..849da94f --- /dev/null +++ b/lib/stripe/account.ex @@ -0,0 +1,78 @@ +defmodule Stripe.Account do + @moduledoc """ + Work with Stripe account objects. + + You can: + + - Retrieve your own account + - Retrieve an account with a specified `id` + + This module does not yet support managed accounts. + + Stripe API reference: https://stripe.com/docs/api#account + """ + + alias Stripe.Util + + @type t :: %__MODULE__{} + + defstruct [ + :id, :business_name, :business_primary_color, :business_url, + :charges_enabled, :country, :default_currency, :details_submitted, + :display_name, :email, :managed, :metadata, :statement_descriptor, + :support_email, :support_phone, :support_url, :timezone, + :transfers_enabled + ] + + @singular_endpoint "account" + @plural_endpoint "accounts" + + @doc """ + Retrieve your own account without options. + """ + @spec retrieve :: {:ok, t} | {:error, Exception.t} + def retrieve, do: retrieve([]) + + @doc """ + Retrieve your own account with options. + """ + @spec retrieve(Keyword.t) :: {:ok, t} | {:error, Exception.t} + def retrieve(opts), do: do_retrieve(@singular_endpoint, opts) + + @doc """ + Retrieve an account with a specified `id`. + """ + @spec retrieve(binary, Keyword.t) :: {:ok, t} | {:error, Exception.t} + def retrieve(id, opts \\ []), do: do_retrieve(@plural_endpoint <> "/" <> id, opts) + + @spec do_retrieve(String.t, Keyword.t) :: {:ok, t} | {:error, Exception.t} + defp do_retrieve(endpoint, opts) do + case Stripe.request(:get, endpoint, %{}, %{}, opts) do + {:ok, result} -> {:ok, to_struct(result)} + {:error, error} -> {:error, error} + end + end + + defp to_struct(response) do + %__MODULE__{ + id: Map.get(response, "id"), + business_name: Map.get(response, "business_name"), + business_primary_color: Map.get(response, "business_primary_color"), + business_url: Map.get(response, "business_url"), + charges_enabled: Map.get(response, "charges_enabled"), + country: Map.get(response, "country"), + default_currency: Map.get(response, "default_currency"), + details_submitted: Map.get(response, "details_submitted"), + display_name: Map.get(response, "display_name"), + email: Map.get(response, "email"), + managed: Map.get(response, "managed"), + metadata: Map.get(response, "metadata"), + statement_descriptor: Map.get(response, "statement_descriptor"), + support_email: Map.get(response, "support_email"), + support_phone: Map.get(response, "support_phone"), + support_url: Map.get(response, "support_url"), + timezone: Map.get(response, "timezone"), + transfers_enabled: Map.get(response, "transfers_enabled") + } + end +end diff --git a/lib/stripe/connect.ex b/lib/stripe/connect.ex index 99908234..990b5e7a 100644 --- a/lib/stripe/connect.ex +++ b/lib/stripe/connect.ex @@ -19,7 +19,6 @@ defmodule Stripe.Connect do crsf token to be sent to stripe, which they send you back at the end of the workflow to further secure the interaction. Make sure you verify this token yourself on reception of the workflow callback. """ def generate_button_url(csrf_token) do - client_id = Stripe.config_or_env_platform_client_id url = base_url() <> "oauth/authorize?response_type=code" url = url <> "&scope=read_write" url = url <> "&client_id=#{Stripe.config_or_env_platform_client_id}" diff --git a/lib/stripe/util.ex b/lib/stripe/util.ex index 86ee41e4..5c5a9352 100644 --- a/lib/stripe/util.ex +++ b/lib/stripe/util.ex @@ -1,4 +1,13 @@ defmodule Stripe.Util do + + @spec get_date(map, atom | String.t) :: DateTime.t | nil + def get_date(m, k) do + case Map.get(m, k) do + nil -> nil + ts -> DateTime.from_unix!(ts) + end + end + def datetime_from_timestamp(ts) when is_binary ts do ts = case Integer.parse ts do :error -> 0 @@ -23,61 +32,4 @@ defmodule Stripe.Util do def string_map_to_atoms(string_key_map) do for {key, val} <- string_key_map, into: %{}, do: {String.to_atom(key), val} end - - def handle_stripe_response(res) do - cond do - res["error"] -> {:error, res} - res["data"] -> {:ok, Enum.map(res["data"], &Stripe.Util.string_map_to_atoms &1)} - true -> {:ok, Stripe.Util.string_map_to_atoms res} - end - end - - # returns the full response in {:ok, response} - # this is useful to access top-level properties - def handle_stripe_full_response(res) do - cond do - res["error"] -> {:error, res} - true -> {:ok, Stripe.Util.string_map_to_atoms res} - end - end - - def list_raw( endpoint, limit \\ 10, starting_after \\ "") do - list_raw endpoint, Stripe.config_or_env_key, limit, starting_after - end - - def list_raw( endpoint, key, limit, starting_after) do - q = "#{endpoint}?limit=#{limit}" - - q = - if String.length(starting_after) > 0 do - q <> "&starting_after=#{starting_after}" - else - q - end - - Stripe.make_request_with_key(:get, q, key ) - |> Stripe.Util.handle_stripe_full_response - end - - def list( endpoint, key, starting_after, limit) do - list_raw endpoint, key, limit, starting_after - end - - def list( endpoint, starting_after \\ "", limit \\ 10) do - list endpoint, Stripe.config_or_env_key, starting_after, limit - end - - # most stripe listing endpoints allow the total count to be included without any results - def count(endpoint) do - count endpoint, Stripe.config_or_env_key - end - - def count(endpoint, key) do - case Stripe.make_request_with_key(:get, "#{endpoint}?include[]=total_count&limit=0", key) - |> Stripe.Util.handle_stripe_full_response do - {:ok, res} -> - {:ok, res[:total_count]} - {:error, err} -> raise err - end -end end diff --git a/mix.exs b/mix.exs index 5e3c3a4a..57b585d0 100644 --- a/mix.exs +++ b/mix.exs @@ -4,47 +4,44 @@ defmodule Stripe.Mixfile do def project do [ app: :stripity_stripe, - version: "2.0.0", + deps: deps, description: description(), - package: package(), elixir: "~> 1.1", - test_coverage: [tool: ExCoveralls], + package: package(), preferred_cli_env: [ "coveralls": :test, "coveralls.detail": :test, "coveralls.post": :test, "coveralls.html": :test ], - deps: deps + test_coverage: [tool: ExCoveralls], + version: "2.0.0" ] end # Configuration for the OTP application def application do [ - mod: {Stripe, []}, + applications: apps(Mix.env), env: env(), - applications: apps(Mix.env) + mod: {Stripe, []} ] end defp env() do [ - stripity_stripe: [ - api_base_url: "https://api.stripe.com/v1/", - use_connection_pool: true, - pool_options: [ - timeout: 5_000, - max_connections: 10 - ] - ] + api_base_url: "https://api.stripe.com/v1/", + pool_options: [ + timeout: 5_000, + max_connections: 10 + ], + use_connection_pool: true ] end defp apps(:test), do: [:bypass | apps()] defp apps(_), do: apps() - - defp apps(), do: [:hackney, :poison, :logger] + defp apps(), do: [:hackney, :logger, :poison] defp deps do [ @@ -60,18 +57,18 @@ defmodule Stripe.Mixfile do defp description do """ - A Stripe Library for Elixir. + A Stripe client for Elixir. """ end defp package do [ - files: ["lib", "mix.exs", "README*", "LICENSE*"], - maintainers: ["Dan Matthews", "Josh Smith"], + files: ["lib", "LICENSE*", "mix.exs", "README*"], licenses: ["New BSD"], links: %{ "GitHub" => "https://github.com/code-corps/stripity-stripe" - } + }, + maintainers: ["Dan Matthews", "Josh Smith"] ] end end