simpleshop_theme/lib/mix/tasks/generate_mockups.ex
Jamey Greenwood c5c06d9979 feat: add Products context with provider integration (Phase 1)
Implement the schema foundation for syncing products from POD providers
like Printify. This includes encrypted credential storage, product/variant
schemas, and an Oban worker for background sync.

New modules:
- Vault: AES-256-GCM encryption for API keys
- Products context: CRUD and sync operations for products
- Provider behaviour: abstraction for POD provider implementations
- ProductSyncWorker: Oban job for async product sync

Schemas: ProviderConnection, Product, ProductImage, ProductVariant

Also reorganizes Printify client to lib/simpleshop_theme/clients/ and
mockup generator to lib/simpleshop_theme/mockups/ for better structure.

134 tests added covering all new functionality.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 20:32:20 +00:00

202 lines
5.7 KiB
Elixir

defmodule Mix.Tasks.GenerateMockups do
@moduledoc """
Generates product mockups using the Printify API.
This task automates the creation of product mockups for the SimpleshopTheme
sample content. It downloads artwork from Unsplash, uploads it to Printify,
creates products, and downloads the generated mockups.
## Requirements
- A Printify account with API access
- The PRINTIFY_API_TOKEN environment variable must be set
## Usage
# Generate mockups (keeps products in Printify)
mix generate_mockups
# Generate mockups and delete products afterwards
mix generate_mockups --cleanup
# Search for available blueprints
mix generate_mockups --search "poster"
# List all blueprints
mix generate_mockups --list-blueprints
## Output
Mockup images are saved to: priv/static/mockups/
"""
use Mix.Task
alias SimpleshopTheme.Mockups.Generator, as: MockupGenerator
@shortdoc "Generates product mockups using Printify API"
@impl Mix.Task
def run(args) do
# Start required applications
Mix.Task.run("app.start")
{opts, _, _} =
OptionParser.parse(args,
switches: [
cleanup: :boolean,
search: :string,
list_blueprints: :boolean,
help: :boolean
],
aliases: [
c: :cleanup,
s: :search,
l: :list_blueprints,
h: :help
]
)
cond do
opts[:help] ->
print_help()
opts[:list_blueprints] ->
list_blueprints()
opts[:search] ->
search_blueprints(opts[:search])
true ->
generate_mockups(opts)
end
end
defp print_help do
Mix.shell().info("""
Printify Mockup Generator
=========================
Generates product mockups using the Printify API.
Usage:
mix generate_mockups [options]
Options:
--cleanup, -c Delete created products from Printify after downloading mockups
--search, -s TERM Search for blueprints by name
--list-blueprints List all available blueprint IDs and names
--help, -h Show this help message
Environment:
PRINTIFY_API_TOKEN Required. Your Printify API token.
Examples:
# Generate all mockups
export PRINTIFY_API_TOKEN="your-token"
mix generate_mockups
# Generate and cleanup
mix generate_mockups --cleanup
# Find blueprint IDs
mix generate_mockups --search "poster"
""")
end
defp list_blueprints do
Mix.shell().info("Fetching blueprints from Printify...")
case MockupGenerator.list_blueprints() do
blueprints when is_list(blueprints) ->
Mix.shell().info("\nAvailable Blueprints:\n")
blueprints
|> Enum.each(fn {id, title} ->
Mix.shell().info(" #{id}: #{title}")
end)
Mix.shell().info("\nTotal: #{length(blueprints)} blueprints")
{:error, reason} ->
Mix.shell().error("Error fetching blueprints: #{inspect(reason)}")
end
end
defp search_blueprints(term) do
Mix.shell().info("Searching for blueprints matching '#{term}'...")
case MockupGenerator.search_blueprints(term) do
results when is_list(results) ->
if length(results) == 0 do
Mix.shell().info("No blueprints found matching '#{term}'")
else
Mix.shell().info("\nMatching Blueprints:\n")
results
|> Enum.each(fn {id, title} ->
Mix.shell().info(" #{id}: #{title}")
end)
Mix.shell().info("\nFound: #{length(results)} blueprints")
end
{:error, reason} ->
Mix.shell().error("Error searching blueprints: #{inspect(reason)}")
end
end
defp generate_mockups(opts) do
cleanup = Keyword.get(opts, :cleanup, false)
Mix.shell().info("""
╔═══════════════════════════════════════════╗
║ Printify Mockup Generator ║
╠═══════════════════════════════════════════╣
║ Cleanup mode: #{if cleanup, do: "ON ", else: "OFF"}
╚═══════════════════════════════════════════╝
""")
# Verify API token is set
case System.get_env("PRINTIFY_API_TOKEN") do
nil ->
Mix.shell().error("""
Error: PRINTIFY_API_TOKEN environment variable is not set.
To get your API token:
1. Log in to Printify
2. Go to Settings > API tokens
3. Create a new token with required permissions
Then run:
export PRINTIFY_API_TOKEN="your-token"
mix generate_mockups
""")
_token ->
results = MockupGenerator.generate_all(cleanup: cleanup)
# Summary
successful = Enum.count(results, &match?({:ok, _, _, _}, &1))
failed = Enum.count(results, &match?({:error, _, _}, &1))
Mix.shell().info("""
═══════════════════════════════════════════
Summary
═══════════════════════════════════════════
Successful: #{successful}
Failed: #{failed}
═══════════════════════════════════════════
""")
if failed > 0 do
Mix.shell().error("Some products failed to generate. Check the output above for details.")
end
end
end
end