Public Shopify Sinatra App
https://www.lukeko.com/39/public-shopify-sinatra-app 0require 'shopify_api'
require 'sinatra'
require 'httparty'
require 'dotenv'
Dotenv.load
class App < Sinatra::Base
attr_reader :tokens
API_KEY = ENV['API_KEY']
API_SECRET = ENV['API_SECRET']
APP_URL = "xxxx.ngrok.io"
def initialize
@tokens = {}
super
end
get '/shopify/install' do
shop = request.params['shop']
scopes = "read_orders,read_products,write_products"
redirect "http://#{shop}/admin/oauth/authorize?client_id=#{API_KEY}&scope=#{scopes}&redirect_uri=https://#{APP_URL}/shopify/auth"
end
get '/shopify/auth' do
shop = request.params['shop']
code = request.params['code']
hmac = request.params['hmac']
validate_hmac(hmac,request)
get_shop_access_token(shop,API_KEY,API_SECRET,code)
create_order_webhook
redirect bulk_edit_url
end
get '/rest' do
shop = 'xxxx.myshopify.com'
token = 'shpat_xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
session = ShopifyAPI::Session.new(domain: shop, token: token, api_version: "2021-04")
ShopifyAPI::Base.activate_session(session)
# products = ShopifyAPI::Product.find(:all, params: { limit: 3 })
# products.size
shop = ShopifyAPI::Shop.current
p1 = ShopifyAPI::Product.first
p2 = ShopifyAPI::Product.last
p1.title = "MMM"
p1.save
"#{shop.name} #{p1.title} #{p2.title} #{p2.variants.first.sku} #{p2.variants.first.inventory_quantity}"
end
get '/graphql' do
shop = 'xxxx.myshopify.com'
token = 'shpat_xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
session = ShopifyAPI::Session.new(domain: shop, token: token, api_version: "2021-04")
ShopifyAPI::Base.activate_session(session)
ShopifyAPI::GraphQL.initialize_clients
client = ShopifyAPI::GraphQL.client
query = client.parse <<-'GRAPHQL'
{
shop {
id
name
email
}
products(first:3) {
edges {
node {
id
variants(first:3) {
edges {
node {
id
displayName
sku
}
}
}
}
}
}
}
GRAPHQL
result = client.query(query)
s1 = result.data.products.edges.first.node.variants.edges.first.node.sku
s2 = result.data.products.edges.last.node.variants.edges.first.node.sku
"#{s1} #{s2}"
end
helpers do
def get_shop_access_token(shop,client_id,client_secret,code)
if @tokens[shop].nil?
url = "https://#{shop}/admin/oauth/access_token"
payload = {
client_id: client_id,
client_secret: client_secret,
code: code}
response = HTTParty.post(url, body: payload)
if response.code == 200
@tokens[shop] = response['access_token']
else
return [500, "Something went wrong."]
end
instantiate_session(shop)
end
end
def instantiate_session(shop)
session = ShopifyAPI::Session.new(domain: shop, token: @tokens[shop], api_version: "2021-04")
ShopifyAPI::Base.activate_session(session)
end
def validate_hmac(hmac,request)
h = request.params.reject{|k,_| k == 'hmac' || k == 'signature'}
query = URI.escape(h.sort.collect{|k,v| "#{k}=#{v}"}.join('&'))
digest = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), API_SECRET, query)
unless (hmac == digest)
return [403, "Authentication failed. Digest provided was: #{digest}"]
end
end
def verify_webhook(hmac, data)
digest = OpenSSL::Digest.new('sha256')
calculated_hmac = Base64.encode64(OpenSSL::HMAC.digest(digest, API_SECRET, data)).strip
hmac == calculated_hmac
end
def bulk_edit_url
bulk_edit_url = "https://www.shopify.com/admin/bulk"\
"?resource_name=ProductVariant"\
"&edit=metafields.test.ingredients:string"
return bulk_edit_url
end
def create_order_webhook
# create webhook for order creation if it doesn't exist
unless ShopifyAPI::Webhook.find(:all).any?
webhook = {
topic: 'orders/create',
address: "https://#{APP_URL}/shopify/webhook/order_create",
format: 'json'}
ShopifyAPI::Webhook.create(webhook)
end
end
end
end
run App.run!
https://github.com/Shopify/example-ruby-app/blob/master/02%20Charging%20For%20Your%20App/app.rb