Packages
shopifex
0.3.6
2.4.0
2.3.0
2.2.2
2.2.1
2.2.0
2.1.20
2.1.19
2.1.18
2.1.17
2.1.16
2.1.15
2.1.14
2.1.13
2.1.12
2.1.11
2.1.10
2.1.9
2.1.8
2.1.7
2.1.6
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.1
2.0.0
1.1.1
1.1.0
1.0.1
1.0.0
0.6.2
0.6.1
0.6.0
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Phoenix boilerplate for Shopify Embedded App SDK
Current section
Files
Jump to
Current section
Files
lib/shopifex_web/controllers/auth_controller.ex
defmodule ShopifexWeb.AuthController do
@moduledoc """
You can use this module inside of another controller to handle initial iFrame load and shop installation
Example:
```elixir
defmodule MyAppWeb.AuthController do
use MyAppWeb, :controller
use ShopifexWeb.AuthController
# Thats it! Validation, installation are now handled for you :)
end
```
"""
@doc """
An optional callback called after the installation is completed, the shop is
persisted in the database and webhooks are registered. By default, this function
redirects the user to the app within their Shopify admin panel.
## Example
def after_install(conn, shop) do
# send yourself an e-mail about shop installation
# follow default behaviour.
super(conn, shop)
end
"""
@callback after_install(Plug.Conn.t(), Ecto.Schema.t()) :: Plug.Conn.t()
@optional_callbacks after_install: 2
defmacro __using__(_opts) do
quote do
@behaviour ShopifexWeb.AuthController
require Logger
# get authorization token for the shop and save the shop in the DB
# The session parameter indicates that this is an entry point request
def auth(conn, %{"shop" => shop_url, "session" => _session}) do
if Regex.match?(~r/^.*\.myshopify\.com/, shop_url) do
conn = put_flash(conn, :shop_url, shop_url)
# check if store is in the system already:
case Shopifex.Shops.get_shop_by_url(shop_url) do
nil ->
# If not, prompt user for install
install_url =
"https://#{shop_url}/admin/oauth/authorize?client_id=#{
Application.fetch_env!(:shopifex, :api_key)
}&scope=#{Application.fetch_env!(:shopifex, :scopes)}&redirect_uri=#{
Application.fetch_env!(:shopifex, :redirect_uri)
}"
conn
|> redirect(external: install_url)
shop ->
# If so, place the shop in the session and proceed to the app index
# This should be an overridable function instead of hard-coded here
if conn.private.valid_hmac do
path_prefix = Application.get_env(:shopifex, :path_prefix, "")
conn
|> put_flash(:shop, shop)
|> redirect(to: path_prefix <> "/")
else
send_resp(
conn,
403,
"A store was found, but no valid HMAC parameter was provided. Please load this app within the #{
shop_url
} admin panel."
)
end
end
else
conn
|> put_view(ShopifexWeb.AuthView)
|> put_layout({ShopifexWeb.LayoutView, "app.html"})
|> put_flash(:error, "Invalid shop URL")
|> render("select-store.html")
end
end
def auth(conn, %{"shop" => shop_url}) do
if Regex.match?(~r/^.*\.myshopify\.com/, shop_url) do
conn = put_flash(conn, :shop_url, shop_url)
# check if store is in the system already:
case Shopifex.Shops.get_shop_by_url(shop_url) do
nil ->
Logger.info("Initiating shop installation for #{shop_url}")
install_url =
"https://#{shop_url}/admin/oauth/authorize?client_id=#{
Application.fetch_env!(:shopifex, :api_key)
}&scope=#{Application.fetch_env!(:shopifex, :scopes)}&redirect_uri=#{
Application.fetch_env!(:shopifex, :redirect_uri)
}"
conn
|> redirect(external: install_url)
shop ->
if conn.private.valid_hmac do
Logger.info("Initiating shop reinstallation for #{shop_url}")
reinstall_url =
"https://#{shop_url}/admin/oauth/request_grant?client_id=#{
Application.fetch_env!(:shopifex, :api_key)
}&scope=#{Application.fetch_env!(:shopifex, :scopes)}&redirect_uri=#{
Application.fetch_env!(:shopifex, :reinstall_uri)
}"
conn
|> redirect(external: reinstall_url)
else
send_resp(
conn,
403,
"A store was found, but no valid HMAC parameter was provided. Please load this app within the #{
shop_url
} admin panel."
)
end
end
else
conn
|> put_view(ShopifexWeb.AuthView)
|> put_layout({ShopifexWeb.LayoutView, "app.html"})
|> put_flash(:error, "Invalid shop URL")
|> render("select-store.html")
end
end
def auth(conn, _) do
conn
|> put_view(ShopifexWeb.AuthView)
|> put_layout({ShopifexWeb.LayoutView, "app.html"})
|> render("select-store.html")
end
@impl ShopifexWeb.AuthController
def after_install(conn, shop) do
redirect(conn,
external:
"https://#{shop.url}/admin/apps/#{Application.fetch_env!(:shopifex, :api_key)}"
)
end
def install(conn = %{private: %{valid_hmac: true}}, %{"code" => code, "shop" => shop_url}) do
url = "https://#{shop_url}/admin/oauth/access_token"
case(
HTTPoison.post(
url,
Jason.encode!(%{
client_id: Application.fetch_env!(:shopifex, :api_key),
client_secret: Application.fetch_env!(:shopifex, :secret),
code: code
}),
"Content-Type": "application/json",
Accept: "application/json"
)
) do
{:ok, response} ->
shop =
Jason.decode!(response.body, keys: :atoms)
|> Map.put(:url, shop_url)
|> Shopifex.Shops.create_shop()
Shopifex.Shops.configure_webhooks(shop)
after_install(conn, shop)
error ->
raise(Shopifex.InstallError, message: "Installation failed for shop #{shop_url}")
end
end
def update(conn = %{private: %{valid_hmac: true}}, %{"code" => code, "shop" => shop_url}) do
url = "https://#{shop_url}/admin/oauth/access_token"
case(
HTTPoison.post(
url,
Jason.encode!(%{
client_id: Application.fetch_env!(:shopifex, :api_key),
client_secret: Application.fetch_env!(:shopifex, :secret),
code: code
}),
"Content-Type": "application/json",
Accept: "application/json"
)
) do
{:ok, response} ->
params = Jason.decode!(response.body, keys: :atoms)
shop =
shop_url
|> Shopifex.Shops.get_shop_by_url()
|> Shopifex.Shops.update_shop(params)
|> Shopifex.Shops.configure_webhooks()
redirect(conn,
external:
"https://#{shop_url}/admin/apps/#{Application.fetch_env!(:shopifex, :api_key)}"
)
error ->
raise(Shopifex.UpdateError, message: "Update failed for shop #{shop_url}")
end
end
defoverridable after_install: 2
end
end
end