app.rb (123 lines of code) (raw):
require 'shopify_api'
require 'sinatra'
require 'httparty'
def alternating_characters?(s)
type = [/[aeiou]/, /[^aeiou]/].cycle
if s.start_with?(/[^aeiou]/)
type.next
end
s.chars.all? { |ch| ch.match?(type.next) }
end
alternating_characters?("ateciyu")
class GiftBasket < Sinatra::Base
attr_reader :tokens
API_KEY = ENV['API_KEY']
API_SECRET = ENV['API_SECRET']
APP_URL = "jamie.ngrok.io"
def initialize
@tokens = {}
super
end
get '/giftbasket/install' do
shop = request.params['shop']
scopes = "read_orders,read_products,write_products"
# construct the installation URL and redirect the merchant
install_url = "http://#{shop}/admin/oauth/authorize?client_id=#{API_KEY}"\
"&scope=#{scopes}&redirect_uri=https://#{APP_URL}/giftbasket/auth"
# redirect to the install_url
redirect install_url
end
get '/giftbasket/auth' do
# extract shop data from request parameters
shop = request.params['shop']
code = request.params['code']
hmac = request.params['hmac']
# perform hmac validation to determine if the request is coming from Shopify
validate_hmac(hmac,request)
# if no access token for this particular shop exist,
# POST the OAuth request and receive the token in the response
get_shop_access_token(shop,API_KEY,API_SECRET,code)
# create webhook for order creation if it doesn't exist
create_order_webhook
# now that the session is activated, redirect to the bulk edit page
redirect bulk_edit_url
end
post '/giftbasket/webhook/order_create' do
# inspect hmac value in header and verify webhook
hmac = request.env['HTTP_X_SHOPIFY_HMAC_SHA256']
request.body.rewind
data = request.body.read
webhook_ok = verify_webhook(hmac, data)
if webhook_ok
shop = request.env['HTTP_X_SHOPIFY_SHOP_DOMAIN']
token = @tokens[shop]
unless token.nil?
session = ShopifyAPI::Session.new(shop, token)
ShopifyAPI::Base.activate_session(session)
else
return [403, "You're not authorized to perform this action."]
end
else
return [403, "You're not authorized to perform this action."]
end
# parse the request body as JSON data
json_data = JSON.parse data
line_items = json_data['line_items']
line_items.each do |line_item|
variant_id = line_item['variant_id']
variant = ShopifyAPI::Variant.find(variant_id)
variant.metafields.each do |field|
if field.key == 'ingredients'
items = field.value.split(',')
items.each do |item|
gift_item = ShopifyAPI::Variant.find(item)
gift_item.inventory_quantity = gift_item.inventory_quantity - 1
gift_item.save
end
end
end
end
return [200, "Webhook notification received successfully."]
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 the response is successful, obtain the token and store it in a hash
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)
# now that the token is available, instantiate a session
session = ShopifyAPI::Session.new(shop, @tokens[shop])
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}/giftbasket/webhook/order_create",
format: 'json'}
ShopifyAPI::Webhook.create(webhook)
end
end
end
end
run GiftBasket.run!