WIP
This commit is contained in:
parent
617c2ab725
commit
c451662178
17 changed files with 602 additions and 2 deletions
|
|
@ -14,7 +14,8 @@ defmodule CampApi.Application do
|
|||
# Start a worker by calling: CampApi.Worker.start_link(arg)
|
||||
# {CampApi.Worker, arg},
|
||||
# Start to serve requests, typically the last entry
|
||||
CampApiWeb.Endpoint
|
||||
CampApiWeb.Endpoint,
|
||||
CampApi.PaymentLinks.Qonto
|
||||
]
|
||||
|
||||
# See https://hexdocs.pm/elixir/Supervisor.html
|
||||
|
|
|
|||
110
lib/camp_api/payment_links.ex
Normal file
110
lib/camp_api/payment_links.ex
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
defmodule CampApi.PaymentLinks do
|
||||
@moduledoc """
|
||||
The PaymentLinks context.
|
||||
"""
|
||||
|
||||
# import Ecto.Query, warn: false
|
||||
alias CampApi.Repo
|
||||
|
||||
alias CampApi.PaymentLinks.Link
|
||||
|
||||
alias CampApi.PaymentLinks.Qonto
|
||||
|
||||
def connect() do
|
||||
body = %{
|
||||
"partner_callback_url" => "http://localhost:4000",
|
||||
"user_bank_account_id" => "01982d1e-6813-7bdf-a96f-0c583e6fa063",
|
||||
"user_phone_number" => "+33612345678",
|
||||
"user_website_url" => "http://localhost:4000",
|
||||
"business_description" => "This needs a long long long description. This needs a long long long description."
|
||||
}
|
||||
Qonto.request(:post, "/v2/payment_links/connections", body)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the list of links.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> list_links()
|
||||
[%Link{}, ...]
|
||||
|
||||
"""
|
||||
def list_links do
|
||||
raise "TODO"
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single link.
|
||||
|
||||
Raises if the Link does not exist.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> get_link!(123)
|
||||
%Link{}
|
||||
|
||||
"""
|
||||
def get_link!(id), do: raise "TODO"
|
||||
|
||||
@doc """
|
||||
Creates a link.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> create_link(%{field: value})
|
||||
{:ok, %Link{}}
|
||||
|
||||
iex> create_link(%{field: bad_value})
|
||||
{:error, ...}
|
||||
|
||||
"""
|
||||
def create_link(attrs) do
|
||||
raise "TODO"
|
||||
end
|
||||
|
||||
@doc """
|
||||
Updates a link.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> update_link(link, %{field: new_value})
|
||||
{:ok, %Link{}}
|
||||
|
||||
iex> update_link(link, %{field: bad_value})
|
||||
{:error, ...}
|
||||
|
||||
"""
|
||||
def update_link(%Link{} = link, attrs) do
|
||||
raise "TODO"
|
||||
end
|
||||
|
||||
@doc """
|
||||
Deletes a Link.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> delete_link(link)
|
||||
{:ok, %Link{}}
|
||||
|
||||
iex> delete_link(link)
|
||||
{:error, ...}
|
||||
|
||||
"""
|
||||
def delete_link(%Link{} = link) do
|
||||
raise "TODO"
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns a data structure for tracking link changes.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> change_link(link)
|
||||
%Todo{...}
|
||||
|
||||
"""
|
||||
def change_link(%Link{} = link, _attrs \\ %{}) do
|
||||
raise "TODO"
|
||||
end
|
||||
end
|
||||
3
lib/camp_api/payment_links/link.ex
Normal file
3
lib/camp_api/payment_links/link.ex
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
defmodule CampApi.PaymentLinks.Link do
|
||||
defstruct name: "John", age: 27
|
||||
end
|
||||
151
lib/camp_api/payment_links/qonto.ex
Normal file
151
lib/camp_api/payment_links/qonto.ex
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
defmodule CampApi.PaymentLinks.Qonto do
|
||||
use GenServer
|
||||
|
||||
use CampApiWeb, :verified_routes
|
||||
|
||||
def base_url() do
|
||||
if Application.get_env(CampApi, :qonto, :staging) do
|
||||
"https://thirdparty-sandbox.staging.qonto.co"
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
def oauth_url() do
|
||||
if Application.get_env(CampApi, :qonto, :staging) do
|
||||
"https://oauth-sandbox.staging.qonto.co"
|
||||
else
|
||||
"https://oauth.qonto.com"
|
||||
end
|
||||
end
|
||||
|
||||
def client_id() do
|
||||
if Application.get_env(CampApi, :qonto, :staging) do
|
||||
"d78920aa-e35f-4bfd-97df-e457f8337e2d"
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
def client_secret() do
|
||||
if Application.get_env(CampApi, :qonto, :staging) do
|
||||
"EqrS29dZYPy1Nfg8V8Bt6aRR1u"
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
def start_link(_) do
|
||||
GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
|
||||
end
|
||||
|
||||
def request(method, url, body) do
|
||||
GenServer.call(__MODULE__, {:request, method, url, body})
|
||||
end
|
||||
|
||||
def init(%{}) do
|
||||
oauth_client =
|
||||
OAuth2.Client.new(
|
||||
strategy: OAuth2.Strategy.AuthCode,
|
||||
client_id: client_id(),
|
||||
client_secret: client_secret(),
|
||||
site: oauth_url(),
|
||||
redirect_uri: url(~p"/api/qonto_auth"),
|
||||
authorize_url: "/oauth2/auth",
|
||||
token_url: "/oauth2/token"
|
||||
)
|
||||
|> OAuth2.Client.put_serializer("application/json;charset=UTF-8", Jason)
|
||||
|> OAuth2.Client.put_serializer("application/json", Jason)
|
||||
|
||||
{:ok, %{status: :disconnected, auth_state: nil, oauth_client: oauth_client}, {:continue, nil}}
|
||||
end
|
||||
|
||||
def handle_continue(_, state) do
|
||||
auth_state = :crypto.strong_rand_bytes(24) |> Base.url_encode64(padding: false)
|
||||
|
||||
# auth_url = %URI{
|
||||
# # scheme: "https",
|
||||
# # host: oauth_url(),
|
||||
# URI.parse(oauth_url()) |
|
||||
# path: "/oauth2/auth",
|
||||
# query:
|
||||
# URI.encode_query(%{
|
||||
# client_id: client_id(),
|
||||
# redirect_uri: url(~p"/api/qonto_auth"),
|
||||
# scope: "payment_link.write payment_link.read",
|
||||
# response_type: "code",
|
||||
# state: auth_state
|
||||
# # organization_id: TODO
|
||||
# })
|
||||
# }
|
||||
|
||||
auth_url = OAuth2.Client.authorize_url!(state.oauth_client, state: auth_state, scope: "payment_link.write payment_link.read")
|
||||
|
||||
IO.puts("Plz go to the following URL:")
|
||||
IO.puts(auth_url)
|
||||
|
||||
{:noreply, %{state | status: :pending, auth_state: auth_state}}
|
||||
end
|
||||
|
||||
def create_token(code, auth_state) do
|
||||
GenServer.call(__MODULE__, {:create_token, code, auth_state})
|
||||
end
|
||||
|
||||
def handle_call({:create_token, code, auth_state}, _from, state) do
|
||||
# with state.status == :pending && state.auth_state == auth_state,
|
||||
# {:ok, %{body: %{"json" => %{"access_token" => access_token, "refresh_token" => refresh_token}}}} <- Req.post(base_url: oauth_url(), url: "/outh2/token",
|
||||
# {:reply, :ok, %{state | status: :connected,
|
||||
#
|
||||
headers =
|
||||
if Application.get_env(CampApi, :qonto, :staging) do
|
||||
[
|
||||
{"x-qonto-staging-token", "0CxYRit4ZV7uwjoUluN93XgQvOt7bke96Nn0x5MUg2w="},
|
||||
{"authorization", ""}
|
||||
]
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
with state.status == :pending && state.auth_state == auth_state,
|
||||
{:ok, oauth_client} <- OAuth2.Client.get_token(state.oauth_client, [code: code, client_secret: state.oauth_client.client_secret], headers) do
|
||||
{:reply, :ok, %{state | status: :connected, oauth_client: oauth_client}}
|
||||
else
|
||||
_ ->
|
||||
{:reply, :error, state}
|
||||
end
|
||||
end
|
||||
|
||||
# def handle_call({:request, method, url, body}, _from, state) do
|
||||
# access_token =
|
||||
# headers =
|
||||
# if Application.get_env(CampApi, :qonto, :staging) do
|
||||
# [
|
||||
# authorization: "Bearer #{state.access_token}",
|
||||
# x_qonto_staging_token: "0CxYRit4ZV7uwjoUluN93XgQvOt7bke96Nn0x5MUg2w="
|
||||
# ]
|
||||
# else
|
||||
# []
|
||||
# end
|
||||
#
|
||||
# Req.request(method: method, base_url: base_url(), url: url, headers: headers, json: body)
|
||||
# end
|
||||
|
||||
def handle_call({:request, method, url, body}, _from, state) do
|
||||
url = base_url() <> url
|
||||
|
||||
headers =
|
||||
if Application.get_env(CampApi, :qonto, :staging) do
|
||||
[
|
||||
# x_qonto_staging_token: "0CxYRit4ZV7uwjoUluN93XgQvOt7bke96Nn0x5MUg2w="
|
||||
{"x-qonto-staging-token", "0CxYRit4ZV7uwjoUluN93XgQvOt7bke96Nn0x5MUg2w="}
|
||||
]
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
case OAuth2.Request.request(method, state.oauth_client, url, Jason.encode!(body), headers, []) do
|
||||
{:ok, resp} -> {:reply, {:ok, resp}, state}
|
||||
_ -> {:reply, :error, state}
|
||||
end
|
||||
end
|
||||
end
|
||||
25
lib/camp_api_web/controllers/changeset_json.ex
Normal file
25
lib/camp_api_web/controllers/changeset_json.ex
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
defmodule CampApiWeb.ChangesetJSON do
|
||||
@doc """
|
||||
Renders changeset errors.
|
||||
"""
|
||||
def error(%{changeset: changeset}) do
|
||||
# When encoded, the changeset returns its errors
|
||||
# as a JSON object. So we just pass it forward.
|
||||
%{errors: Ecto.Changeset.traverse_errors(changeset, &translate_error/1)}
|
||||
end
|
||||
|
||||
defp translate_error({msg, opts}) do
|
||||
# You can make use of gettext to translate error messages by
|
||||
# uncommenting and adjusting the following code:
|
||||
|
||||
# if count = opts[:count] do
|
||||
# Gettext.dngettext(CampApiWeb.Gettext, "errors", msg, msg, count, opts)
|
||||
# else
|
||||
# Gettext.dgettext(CampApiWeb.Gettext, "errors", msg, opts)
|
||||
# end
|
||||
|
||||
Enum.reduce(opts, msg, fn {key, value}, acc ->
|
||||
String.replace(acc, "%{#{key}}", fn _ -> to_string(value) end)
|
||||
end)
|
||||
end
|
||||
end
|
||||
16
lib/camp_api_web/controllers/fallback_controller.ex
Normal file
16
lib/camp_api_web/controllers/fallback_controller.ex
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
defmodule CampApiWeb.FallbackController do
|
||||
@moduledoc """
|
||||
Translates controller action results into valid `Plug.Conn` responses.
|
||||
|
||||
See `Phoenix.Controller.action_fallback/1` for more details.
|
||||
"""
|
||||
use CampApiWeb, :controller
|
||||
|
||||
# This clause is an example of how to handle resources that cannot be found.
|
||||
def call(conn, {:error, :not_found}) do
|
||||
conn
|
||||
|> put_status(:not_found)
|
||||
|> put_view(html: CampApiWeb.ErrorHTML, json: CampApiWeb.ErrorJSON)
|
||||
|> render(:"404")
|
||||
end
|
||||
end
|
||||
58
lib/camp_api_web/controllers/payment_link_controller.ex
Normal file
58
lib/camp_api_web/controllers/payment_link_controller.ex
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
defmodule CampApiWeb.PaymentLinkController do
|
||||
use CampApiWeb, :controller
|
||||
|
||||
alias CampApi.PaymentLinks
|
||||
alias CampApi.PaymentLinks.Link
|
||||
alias CampApi.PaymentLinks.Qonto
|
||||
|
||||
action_fallback CampApiWeb.FallbackController
|
||||
|
||||
def qonto_auth(conn, %{"code" => code, "state" => state}) do
|
||||
case Qonto.create_token(code, state) do
|
||||
:ok ->
|
||||
conn
|
||||
# |> put_resp_content_type
|
||||
|> send_resp(200, "connected")
|
||||
|
||||
:error ->
|
||||
conn
|
||||
# |> put_resp_content_type
|
||||
|> send_resp(500, "error")
|
||||
end
|
||||
end
|
||||
|
||||
# def index(conn, _params) do
|
||||
# links = PaymentLinks.list_links()
|
||||
# render(conn, :index, links: links)
|
||||
# end
|
||||
|
||||
def create(conn, %{"link" => link_params}) do
|
||||
with {:ok, %Link{} = link} <- PaymentLinks.create_link(link_params) do
|
||||
conn
|
||||
|> put_status(:created)
|
||||
|> put_resp_header("location", ~p"/api/links/#{link}")
|
||||
|> render(:show, link: link)
|
||||
end
|
||||
end
|
||||
|
||||
# def show(conn, %{"id" => id}) do
|
||||
# link = PaymentLinks.get_link!(id)
|
||||
# render(conn, :show, link: link)
|
||||
# end
|
||||
|
||||
# def update(conn, %{"id" => id, "link" => link_params}) do
|
||||
# link = PaymentLinks.get_link!(id)
|
||||
#
|
||||
# with {:ok, %Link{} = link} <- PaymentLinks.update_link(link, link_params) do
|
||||
# render(conn, :show, link: link)
|
||||
# end
|
||||
# end
|
||||
|
||||
# def delete(conn, %{"id" => id}) do
|
||||
# link = PaymentLinks.get_link!(id)
|
||||
#
|
||||
# with {:ok, %Link{}} <- PaymentLinks.delete_link(link) do
|
||||
# send_resp(conn, :no_content, "")
|
||||
# end
|
||||
# end
|
||||
end
|
||||
24
lib/camp_api_web/controllers/payment_link_json.ex
Normal file
24
lib/camp_api_web/controllers/payment_link_json.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
defmodule CampApiWeb.PaymentLinkJSON do
|
||||
alias CampApi.PaymentLinks.Link
|
||||
|
||||
@doc """
|
||||
Renders a list of links.
|
||||
"""
|
||||
def index(%{links: links}) do
|
||||
%{data: for(link <- links, do: data(link))}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders a single link.
|
||||
"""
|
||||
def show(%{link: link}) do
|
||||
%{data: data(link)}
|
||||
end
|
||||
|
||||
defp data(%Link{} = link) do
|
||||
%{
|
||||
id: link.id,
|
||||
price: link.price
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
@ -7,6 +7,10 @@ defmodule CampApiWeb.Router do
|
|||
|
||||
scope "/api", CampApiWeb do
|
||||
pipe_through :api
|
||||
|
||||
resources "/payment_links", PaymentLinkController, only: [:create]
|
||||
|
||||
get "/qonto_auth", PaymentLinkController, :qonto_auth
|
||||
end
|
||||
|
||||
# Enable LiveDashboard in development
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue