feat: add Printify webhook endpoint for real-time product updates
- Add /webhooks/printify endpoint with HMAC-SHA256 signature verification - Add Webhooks context to handle product:updated, product:deleted events - Add ProductDeleteWorker for async product deletion - Add webhook API methods to Printify client (create, list, delete) - Add register_webhooks/2 to Printify provider - Add mix register_webhooks task for one-time webhook registration - Cache raw request body in endpoint for signature verification Usage: 1. Generate webhook secret: openssl rand -hex 20 2. Add to provider connection config as "webhook_secret" 3. Register with Printify: mix register_webhooks https://yourshop.com/webhooks/printify Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -114,6 +114,66 @@ defmodule SimpleshopTheme.Providers.Printify do
|
||||
end
|
||||
end
|
||||
|
||||
# =============================================================================
|
||||
# Webhook Registration
|
||||
# =============================================================================
|
||||
|
||||
@webhook_events ["product:updated", "product:deleted", "product:publish:started"]
|
||||
|
||||
@doc """
|
||||
Registers webhooks for product events with Printify.
|
||||
|
||||
Returns {:ok, results} or {:error, reason}.
|
||||
"""
|
||||
def register_webhooks(%ProviderConnection{config: config} = conn, webhook_url) do
|
||||
shop_id = config["shop_id"]
|
||||
secret = config["webhook_secret"]
|
||||
|
||||
cond do
|
||||
is_nil(shop_id) ->
|
||||
{:error, :no_shop_id}
|
||||
|
||||
is_nil(secret) or secret == "" ->
|
||||
{:error, :no_webhook_secret}
|
||||
|
||||
true ->
|
||||
with api_key when is_binary(api_key) <- ProviderConnection.get_api_key(conn),
|
||||
:ok <- set_api_key(api_key) do
|
||||
results =
|
||||
Enum.map(@webhook_events, fn event ->
|
||||
case Client.create_webhook(shop_id, webhook_url, event, secret) do
|
||||
{:ok, response} -> {:ok, event, response}
|
||||
{:error, reason} -> {:error, event, reason}
|
||||
end
|
||||
end)
|
||||
|
||||
{:ok, results}
|
||||
else
|
||||
nil -> {:error, :no_api_key}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Lists registered webhooks for the shop.
|
||||
"""
|
||||
def list_webhooks(%ProviderConnection{config: config} = conn) do
|
||||
shop_id = config["shop_id"]
|
||||
|
||||
if is_nil(shop_id) do
|
||||
{:error, :no_shop_id}
|
||||
else
|
||||
with api_key when is_binary(api_key) <- ProviderConnection.get_api_key(conn),
|
||||
:ok <- set_api_key(api_key),
|
||||
{:ok, webhooks} <- Client.list_webhooks(shop_id) do
|
||||
{:ok, webhooks}
|
||||
else
|
||||
nil -> {:error, :no_api_key}
|
||||
{:error, _} = error -> error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# =============================================================================
|
||||
# Data Normalization
|
||||
# =============================================================================
|
||||
|
||||
Reference in New Issue
Block a user