basic printify integration
This commit is contained in:
124
lib/simpleshop/printify/client.ex
Normal file
124
lib/simpleshop/printify/client.ex
Normal file
@@ -0,0 +1,124 @@
|
||||
defmodule Simpleshop.Printify.Client do
|
||||
require Logger
|
||||
alias Simpleshop.Printify.TokenStore
|
||||
|
||||
@base_url "https://api.printify.com/v1"
|
||||
@user_agent "SimpleshopMVP"
|
||||
|
||||
def get_products do
|
||||
config = Application.get_env(:simpleshop, :printify)
|
||||
shop_id = Keyword.fetch!(config, :shop_id)
|
||||
url = "#{@base_url}/shops/#{shop_id}/products.json"
|
||||
|
||||
with_token(fn token ->
|
||||
case Req.get(url, headers: headers(token)) do
|
||||
{:ok, %{status: 200, body: response}} ->
|
||||
products = Map.get(response, "data") || response
|
||||
Logger.info("Successfully fetched #{length(products)} products")
|
||||
{:ok, products}
|
||||
|
||||
{:ok, %{status: status, body: body}} ->
|
||||
Logger.error("Failed to fetch products: #{status} - #{inspect(body)}")
|
||||
{:error, "Failed to fetch products: #{status}"}
|
||||
|
||||
{:error, error} ->
|
||||
Logger.error("HTTP error fetching products: #{inspect(error)}")
|
||||
{:error, "Network error: #{inspect(error)}"}
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
def get_product(product_id) do
|
||||
config = Application.get_env(:simpleshop, :printify)
|
||||
shop_id = Keyword.fetch!(config, :shop_id)
|
||||
url = "#{@base_url}/shops/#{shop_id}/products/#{product_id}.json"
|
||||
|
||||
with_token(fn token ->
|
||||
case Req.get(url, headers: headers(token)) do
|
||||
{:ok, %{status: 200, body: product}} ->
|
||||
Logger.info("Successfully fetched product #{product_id}")
|
||||
{:ok, product}
|
||||
|
||||
{:ok, %{status: status, body: body}} ->
|
||||
Logger.error("Failed to fetch product: #{status} - #{inspect(body)}")
|
||||
{:error, "Failed to fetch product: #{status}"}
|
||||
|
||||
{:error, error} ->
|
||||
Logger.error("HTTP error fetching product: #{inspect(error)}")
|
||||
{:error, "Network error: #{inspect(error)}"}
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
def create_order(product_id, variant_id, quantity \\ 1) do
|
||||
config = Application.get_env(:simpleshop, :printify)
|
||||
shop_id = Keyword.fetch!(config, :shop_id)
|
||||
url = "#{@base_url}/shops/#{shop_id}/orders.json"
|
||||
|
||||
order_data = %{
|
||||
external_id: "simpleshop-#{System.unique_integer([:positive])}",
|
||||
line_items: [
|
||||
%{
|
||||
product_id: product_id,
|
||||
variant_id: variant_id,
|
||||
quantity: quantity
|
||||
}
|
||||
],
|
||||
shipping_method: 1,
|
||||
address_to: test_shipping_address()
|
||||
}
|
||||
|
||||
with_token(fn token ->
|
||||
case Req.post(url, headers: headers(token), json: order_data) do
|
||||
{:ok, %{status: status, body: response}} when status in 200..299 ->
|
||||
Logger.info("Successfully created order: #{inspect(response)}")
|
||||
{:ok, response}
|
||||
|
||||
{:ok, %{status: status, body: body}} ->
|
||||
Logger.error("Failed to create order: #{status} - #{inspect(body)}")
|
||||
{:error, "Failed to create order: #{status} - #{inspect(body)}"}
|
||||
|
||||
{:error, error} ->
|
||||
Logger.error("HTTP error creating order: #{inspect(error)}")
|
||||
{:error, "Network error: #{inspect(error)}"}
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp with_token(fun) do
|
||||
case TokenStore.get_access_token() do
|
||||
{:ok, token} ->
|
||||
fun.(token)
|
||||
|
||||
{:error, :not_configured} ->
|
||||
Logger.error("Printify Personal Access Token not configured in config/dev.exs")
|
||||
{:error, :not_configured}
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.error("Failed to get access token: #{inspect(reason)}")
|
||||
{:error, :authentication_required}
|
||||
end
|
||||
end
|
||||
|
||||
defp headers(token) do
|
||||
[
|
||||
{"Authorization", "Bearer #{token}"},
|
||||
{"User-Agent", @user_agent},
|
||||
{"Content-Type", "application/json;charset=utf-8"}
|
||||
]
|
||||
end
|
||||
|
||||
defp test_shipping_address do
|
||||
%{
|
||||
first_name: "John",
|
||||
last_name: "Doe",
|
||||
email: "test@example.com",
|
||||
phone: "555-0123",
|
||||
country: "US",
|
||||
region: "CA",
|
||||
address1: "123 Test St",
|
||||
city: "San Francisco",
|
||||
zip: "94102"
|
||||
}
|
||||
end
|
||||
end
|
||||
92
lib/simpleshop/printify/oauth.ex
Normal file
92
lib/simpleshop/printify/oauth.ex
Normal file
@@ -0,0 +1,92 @@
|
||||
defmodule Simpleshop.Printify.OAuth do
|
||||
require Logger
|
||||
alias Simpleshop.Printify.TokenStore
|
||||
|
||||
@printify_auth_url "https://printify.com/app/authorize"
|
||||
@printify_token_url "https://api.printify.com/v1/app/oauth/tokens"
|
||||
@printify_refresh_url "https://api.printify.com/v1/app/oauth/tokens/refresh"
|
||||
|
||||
def authorization_url do
|
||||
config = Application.get_env(:simpleshop, :printify)
|
||||
app_id = Keyword.fetch!(config, :app_id)
|
||||
redirect_uri = Keyword.fetch!(config, :redirect_uri)
|
||||
|
||||
query =
|
||||
URI.encode_query(%{
|
||||
app_id: app_id,
|
||||
accept_url: redirect_uri,
|
||||
decline_url: redirect_uri <> "?error=access_denied"
|
||||
})
|
||||
|
||||
"#{@printify_auth_url}?#{query}"
|
||||
end
|
||||
|
||||
def exchange_code(code) do
|
||||
config = Application.get_env(:simpleshop, :printify)
|
||||
app_id = Keyword.fetch!(config, :app_id)
|
||||
|
||||
body = %{
|
||||
app_id: app_id,
|
||||
code: code
|
||||
}
|
||||
|
||||
case Req.post(@printify_token_url, json: body) do
|
||||
{:ok, %{status: 200, body: response}} ->
|
||||
Logger.info("Successfully exchanged OAuth code for tokens")
|
||||
store_token_response(response)
|
||||
|
||||
{:ok, %{status: status, body: body}} ->
|
||||
Logger.error("Failed to exchange OAuth code: #{status} - #{inspect(body)}")
|
||||
{:error, "Failed to get access token: #{inspect(body)}"}
|
||||
|
||||
{:error, error} ->
|
||||
Logger.error("HTTP error during token exchange: #{inspect(error)}")
|
||||
{:error, "Network error: #{inspect(error)}"}
|
||||
end
|
||||
end
|
||||
|
||||
def refresh_access_token do
|
||||
case TokenStore.get_refresh_token() do
|
||||
{:ok, refresh_token} ->
|
||||
config = Application.get_env(:simpleshop, :printify)
|
||||
app_id = Keyword.fetch!(config, :app_id)
|
||||
|
||||
body = %{
|
||||
app_id: app_id,
|
||||
refresh_token: refresh_token
|
||||
}
|
||||
|
||||
case Req.post(@printify_refresh_url, json: body) do
|
||||
{:ok, %{status: 200, body: response}} ->
|
||||
Logger.info("Successfully refreshed access token")
|
||||
store_token_response(response)
|
||||
|
||||
{:ok, %{status: status, body: body}} ->
|
||||
Logger.error("Failed to refresh access token: #{status} - #{inspect(body)}")
|
||||
{:error, "Failed to refresh token: #{inspect(body)}"}
|
||||
|
||||
{:error, error} ->
|
||||
Logger.error("HTTP error during token refresh: #{inspect(error)}")
|
||||
{:error, "Network error: #{inspect(error)}"}
|
||||
end
|
||||
|
||||
{:error, :not_found} ->
|
||||
Logger.error("No refresh token found")
|
||||
{:error, :no_refresh_token}
|
||||
end
|
||||
end
|
||||
|
||||
defp store_token_response(response) do
|
||||
access_token = Map.get(response, "access_token") || Map.get(response, :access_token)
|
||||
refresh_token = Map.get(response, "refresh_token") || Map.get(response, :refresh_token)
|
||||
expires_in = Map.get(response, "expires_in") || Map.get(response, :expires_in) || 21_600
|
||||
|
||||
if access_token && refresh_token do
|
||||
TokenStore.store_tokens(access_token, refresh_token, expires_in)
|
||||
{:ok, access_token}
|
||||
else
|
||||
Logger.error("Missing tokens in response: #{inspect(response)}")
|
||||
{:error, "Invalid token response"}
|
||||
end
|
||||
end
|
||||
end
|
||||
24
lib/simpleshop/printify/token_store.ex
Normal file
24
lib/simpleshop/printify/token_store.ex
Normal file
@@ -0,0 +1,24 @@
|
||||
defmodule Simpleshop.Printify.TokenStore do
|
||||
@moduledoc """
|
||||
Simple module to retrieve the Printify Personal Access Token from config.
|
||||
No GenServer or ETS needed - just reads from application config.
|
||||
"""
|
||||
|
||||
def get_access_token do
|
||||
config = Application.get_env(:simpleshop, :printify)
|
||||
|
||||
case Keyword.get(config, :access_token) do
|
||||
nil -> {:error, :not_configured}
|
||||
"" -> {:error, :not_configured}
|
||||
"your_personal_access_token_here" -> {:error, :not_configured}
|
||||
token -> {:ok, token}
|
||||
end
|
||||
end
|
||||
|
||||
def has_tokens? do
|
||||
case get_access_token() do
|
||||
{:ok, _} -> true
|
||||
_ -> false
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user