shopify_api 4.9.0 → 9.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/CODEOWNERS +1 -0
- data/.github/ISSUE_TEMPLATE.md +36 -0
- data/.github/probots.yml +2 -0
- data/.github/workflows/build.yml +41 -0
- data/.gitignore +5 -1
- data/.rubocop.yml +28 -0
- data/.rubocop_todo.yml +75 -0
- data/CHANGELOG.md +491 -0
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +6 -2
- data/Gemfile.lock +151 -0
- data/Gemfile_ar41 +5 -0
- data/Gemfile_ar50 +5 -0
- data/Gemfile_ar51 +5 -0
- data/Gemfile_ar_master +0 -1
- data/README.md +492 -100
- data/RELEASING +10 -9
- data/Rakefile +21 -5
- data/SECURITY.md +59 -0
- data/docker-compose.yml +13 -0
- data/docs/_config.yml +1 -0
- data/docs/_includes/footer.html +28 -0
- data/docs/_includes/head.html +28 -0
- data/docs/_layouts/index.html +57 -0
- data/docs/graphql.md +241 -0
- data/docs/index.md +639 -0
- data/lib/active_resource/connection_ext.rb +1 -0
- data/lib/active_resource/detailed_log_subscriber.rb +43 -7
- data/lib/active_resource/json_errors.rb +8 -2
- data/lib/shopify_api.rb +16 -6
- data/lib/shopify_api/api_access.rb +57 -0
- data/lib/shopify_api/api_version.rb +206 -0
- data/lib/shopify_api/connection.rb +7 -4
- data/lib/shopify_api/countable.rb +3 -2
- data/lib/shopify_api/disable_prefix_check.rb +31 -0
- data/lib/shopify_api/events.rb +2 -1
- data/lib/shopify_api/graphql.rb +103 -0
- data/lib/shopify_api/graphql/http_client.rb +22 -0
- data/lib/shopify_api/graphql/railtie.rb +17 -0
- data/lib/shopify_api/graphql/task.rake +100 -0
- data/lib/shopify_api/limits.rb +9 -9
- data/lib/shopify_api/message_enricher.rb +25 -0
- data/lib/shopify_api/meta.rb +14 -0
- data/lib/shopify_api/metafields.rb +5 -4
- data/lib/shopify_api/paginated_collection.rb +69 -0
- data/lib/shopify_api/pagination_link_headers.rb +34 -0
- data/lib/shopify_api/resources.rb +3 -1
- data/lib/shopify_api/resources/abandoned_checkout.rb +7 -0
- data/lib/shopify_api/resources/access_scope.rb +10 -0
- data/lib/shopify_api/resources/access_token.rb +1 -0
- data/lib/shopify_api/resources/address.rb +1 -0
- data/lib/shopify_api/resources/announcement.rb +2 -1
- data/lib/shopify_api/resources/api_permission.rb +9 -0
- data/lib/shopify_api/resources/application_charge.rb +1 -0
- data/lib/shopify_api/resources/application_credit.rb +1 -0
- data/lib/shopify_api/resources/array_base.rb +13 -0
- data/lib/shopify_api/resources/article.rb +3 -2
- data/lib/shopify_api/resources/asset.rb +28 -23
- data/lib/shopify_api/resources/assigned_fulfillment_order.rb +16 -0
- data/lib/shopify_api/resources/base.rb +101 -24
- data/lib/shopify_api/resources/billing_address.rb +2 -1
- data/lib/shopify_api/resources/blog.rb +2 -1
- data/lib/shopify_api/resources/carrier_service.rb +1 -0
- data/lib/shopify_api/resources/cart.rb +2 -1
- data/lib/shopify_api/resources/checkout.rb +27 -1
- data/lib/shopify_api/resources/collect.rb +2 -0
- data/lib/shopify_api/resources/collection.rb +14 -0
- data/lib/shopify_api/resources/collection_listing.rb +11 -1
- data/lib/shopify_api/resources/collection_publication.rb +10 -0
- data/lib/shopify_api/resources/comment.rb +20 -5
- data/lib/shopify_api/resources/country.rb +1 -0
- data/lib/shopify_api/resources/currency.rb +6 -0
- data/lib/shopify_api/resources/custom_collection.rb +7 -6
- data/lib/shopify_api/resources/customer.rb +2 -1
- data/lib/shopify_api/resources/customer_group.rb +1 -0
- data/lib/shopify_api/resources/{customer_invite_message.rb → customer_invite.rb} +1 -0
- data/lib/shopify_api/resources/customer_saved_search.rb +4 -1
- data/lib/shopify_api/resources/discount_code.rb +1 -0
- data/lib/shopify_api/resources/discount_code_batch.rb +34 -0
- data/lib/shopify_api/resources/draft_order.rb +1 -0
- data/lib/shopify_api/resources/draft_order_invoice.rb +1 -0
- data/lib/shopify_api/resources/event.rb +2 -0
- data/lib/shopify_api/resources/fulfillment.rb +46 -3
- data/lib/shopify_api/resources/fulfillment_event.rb +2 -1
- data/lib/shopify_api/resources/fulfillment_order.rb +151 -0
- data/lib/shopify_api/resources/fulfillment_order_locations_for_move.rb +5 -0
- data/lib/shopify_api/resources/fulfillment_request.rb +1 -0
- data/lib/shopify_api/resources/fulfillment_service.rb +1 -0
- data/lib/shopify_api/resources/fulfillment_v2.rb +21 -0
- data/lib/shopify_api/resources/gift_card.rb +1 -0
- data/lib/shopify_api/resources/image.rb +4 -3
- data/lib/shopify_api/resources/inventory_item.rb +6 -0
- data/lib/shopify_api/resources/inventory_level.rb +54 -0
- data/lib/shopify_api/resources/line_item.rb +10 -1
- data/lib/shopify_api/resources/location.rb +4 -0
- data/lib/shopify_api/resources/marketing_event.rb +3 -0
- data/lib/shopify_api/resources/metafield.rb +2 -0
- data/lib/shopify_api/resources/note_attribute.rb +1 -0
- data/lib/shopify_api/resources/option.rb +1 -0
- data/lib/shopify_api/resources/order.rb +25 -5
- data/lib/shopify_api/resources/order_risk.rb +1 -0
- data/lib/shopify_api/resources/page.rb +1 -0
- data/lib/shopify_api/resources/payment.rb +7 -0
- data/lib/shopify_api/resources/payment_details.rb +1 -0
- data/lib/shopify_api/resources/ping.rb +3 -0
- data/lib/shopify_api/resources/policy.rb +1 -0
- data/lib/shopify_api/resources/price_rule.rb +1 -1
- data/lib/shopify_api/resources/product.rb +33 -7
- data/lib/shopify_api/resources/product_listing.rb +9 -1
- data/lib/shopify_api/resources/product_publication.rb +10 -0
- data/lib/shopify_api/resources/province.rb +1 -0
- data/lib/shopify_api/resources/publication.rb +5 -0
- data/lib/shopify_api/resources/receipt.rb +1 -0
- data/lib/shopify_api/resources/recurring_application_charge.rb +4 -1
- data/lib/shopify_api/resources/redirect.rb +1 -0
- data/lib/shopify_api/resources/refund.rb +6 -4
- data/lib/shopify_api/resources/report.rb +1 -0
- data/lib/shopify_api/resources/resource_feedback.rb +1 -1
- data/lib/shopify_api/resources/rule.rb +1 -0
- data/lib/shopify_api/resources/script_tag.rb +1 -0
- data/lib/shopify_api/resources/shipping_address.rb +1 -0
- data/lib/shopify_api/resources/shipping_line.rb +2 -1
- data/lib/shopify_api/resources/shipping_rate.rb +7 -0
- data/lib/shopify_api/resources/shipping_zone.rb +1 -0
- data/lib/shopify_api/resources/shop.rb +10 -7
- data/lib/shopify_api/resources/smart_collection.rb +3 -3
- data/lib/shopify_api/resources/storefront_access_token.rb +1 -0
- data/lib/shopify_api/resources/tax_line.rb +1 -0
- data/lib/shopify_api/resources/tax_service.rb +1 -0
- data/lib/shopify_api/resources/tender_transaction.rb +6 -0
- data/lib/shopify_api/resources/theme.rb +1 -0
- data/lib/shopify_api/resources/transaction.rb +1 -0
- data/lib/shopify_api/resources/usage_charge.rb +1 -0
- data/lib/shopify_api/resources/user.rb +1 -0
- data/lib/shopify_api/resources/variant.rb +35 -0
- data/lib/shopify_api/resources/webhook.rb +1 -0
- data/lib/shopify_api/session.rb +109 -45
- data/lib/shopify_api/version.rb +2 -1
- data/lib/verify_docs.rb +8 -0
- data/service.yml +8 -0
- data/shopify_api.gemspec +19 -8
- data/test/abandoned_checkouts_test.rb +29 -0
- data/test/access_scope_test.rb +23 -0
- data/test/access_token_test.rb +6 -5
- data/test/active_resource/json_errors_test.rb +6 -6
- data/test/api_access_test.rb +153 -0
- data/test/api_permission_test.rb +9 -0
- data/test/api_version_test.rb +157 -0
- data/test/application_charge_test.rb +30 -27
- data/test/application_credit_test.rb +10 -9
- data/test/article_test.rb +34 -35
- data/test/asset_test.rb +14 -6
- data/test/assigned_fulfillment_order_test.rb +78 -0
- data/test/base_test.rb +147 -59
- data/test/blog_test.rb +4 -3
- data/test/carrier_service_test.rb +7 -6
- data/test/cart_test.rb +2 -1
- data/test/checkouts_test.rb +72 -4
- data/test/collect_test.rb +4 -3
- data/test/collection_listing_test.rb +56 -13
- data/test/collection_publication_test.rb +40 -0
- data/test/collection_test.rb +50 -0
- data/test/countable_test.rb +3 -2
- data/test/currency_test.rb +21 -0
- data/test/custom_collection_test.rb +4 -3
- data/test/customer_saved_search_test.rb +18 -8
- data/test/customer_test.rb +22 -14
- data/test/detailed_log_subscriber_test.rb +113 -19
- data/test/discount_code_batch_test.rb +41 -0
- data/test/discount_code_test.rb +22 -16
- data/test/draft_order_test.rb +68 -52
- data/test/fixtures/abandoned_checkout.json +184 -0
- data/test/fixtures/abandoned_checkouts.json +186 -0
- data/test/fixtures/access_scopes.json +10 -0
- data/test/fixtures/api_versions.json +38 -0
- data/test/fixtures/apis.json +42 -0
- data/test/fixtures/assigned_fulfillment_orders.json +80 -0
- data/test/fixtures/checkout.json +160 -0
- data/test/fixtures/checkouts.json +25 -49
- data/test/fixtures/collection.json +17 -0
- data/test/fixtures/collection_listing_product_ids2.json +1 -0
- data/test/fixtures/collection_products.json +47 -0
- data/test/fixtures/collection_publication.json +11 -0
- data/test/fixtures/collection_publications.json +13 -0
- data/test/fixtures/currencies.json +25 -0
- data/test/fixtures/discount_code_batch.json +14 -0
- data/test/fixtures/discount_code_batch_discount_codes.json +21 -0
- data/test/fixtures/fulfillment_order.json +39 -0
- data/test/fixtures/fulfillment_order_locations_for_move.json +18 -0
- data/test/fixtures/fulfillment_orders.json +80 -0
- data/test/fixtures/fulfillments.json +53 -0
- data/test/fixtures/graphql/2019-10.json +1083 -0
- data/test/fixtures/graphql/dummy_schema.rb +16 -0
- data/test/fixtures/graphql/unstable.json +1083 -0
- data/test/fixtures/inventory_level.json +7 -0
- data/test/fixtures/inventory_levels.json +24 -0
- data/test/fixtures/order_with_properties.json +373 -0
- data/test/fixtures/payment.json +7 -0
- data/test/fixtures/payments.json +9 -0
- data/test/fixtures/ping/conversation.json +1 -0
- data/test/fixtures/ping/failed_delivery_confirmation.json +1 -0
- data/test/fixtures/ping/message.json +1 -0
- data/test/fixtures/ping/successful_delivery_confirmation.json +1 -0
- data/test/fixtures/product_listing_product_ids.json +1 -1
- data/test/fixtures/product_listing_product_ids2.json +1 -0
- data/test/fixtures/product_publication.json +11 -0
- data/test/fixtures/product_publications.json +13 -0
- data/test/fixtures/publications.json +9 -0
- data/test/fixtures/shipping_rates.json +12 -0
- data/test/fixtures/smart_collection_products.json +155 -0
- data/test/fixtures/tender_transactions.json +52 -0
- data/test/fulfillment_event_test.rb +31 -26
- data/test/fulfillment_order_test.rb +530 -0
- data/test/fulfillment_order_test_helper.rb +8 -0
- data/test/fulfillment_request_test.rb +10 -8
- data/test/fulfillment_service_test.rb +13 -12
- data/test/fulfillment_test.rb +198 -20
- data/test/fulfillment_v2_test.rb +66 -0
- data/test/gift_card_test.rb +6 -4
- data/test/graphql/http_client_test.rb +26 -0
- data/test/graphql_test.rb +190 -0
- data/test/image_test.rb +19 -17
- data/test/inventory_level_test.rb +68 -0
- data/test/lib/webmock_extensions/last_request.rb +16 -0
- data/test/limits_test.rb +4 -3
- data/test/location_test.rb +15 -0
- data/test/marketing_event_test.rb +21 -21
- data/test/message_enricher_test.rb +45 -0
- data/test/meta_test.rb +47 -0
- data/test/metafield_test.rb +30 -20
- data/test/order_risk_test.rb +17 -16
- data/test/order_test.rb +110 -17
- data/test/pagination_test.rb +290 -0
- data/test/payment_test.rb +19 -0
- data/test/policy_test.rb +6 -5
- data/test/price_rule_test.rb +20 -15
- data/test/product_listing_test.rb +72 -15
- data/test/product_publication_test.rb +40 -0
- data/test/product_test.rb +80 -19
- data/test/publication_test.rb +12 -0
- data/test/recurring_application_charge_test.rb +105 -50
- data/test/redirect_test.rb +4 -3
- data/test/refund_test.rb +22 -17
- data/test/report_test.rb +12 -10
- data/test/resource_feedback_test.rb +14 -13
- data/test/script_tag_test.rb +10 -9
- data/test/session_test.rb +497 -111
- data/test/shipping_rate_test.rb +17 -0
- data/test/shipping_zone_test.rb +4 -3
- data/test/shop_test.rb +47 -33
- data/test/smart_collection_test.rb +5 -4
- data/test/storefront_access_token_test.rb +13 -15
- data/test/tax_service_test.rb +7 -3
- data/test/tender_transaction_test.rb +18 -0
- data/test/test_helper.rb +98 -67
- data/test/transaction_test.rb +4 -3
- data/test/usage_charge_test.rb +12 -8
- data/test/user_test.rb +4 -3
- data/test/variant_test.rb +50 -20
- data/test/webhook_test.rb +10 -7
- metadata +196 -37
- data/.travis.yml +0 -36
- data/CHANGELOG +0 -292
- data/Gemfile_ar30 +0 -6
- data/Gemfile_ar31 +0 -6
- data/Gemfile_ar32 +0 -6
- data/Gemfile_ar40 +0 -6
- data/bin/shopify +0 -3
- data/lib/active_resource/base_ext.rb +0 -21
- data/lib/active_resource/disable_prefix_check.rb +0 -36
- data/lib/active_resource/to_query.rb +0 -10
- data/lib/shopify_api/json_format.rb +0 -18
- data/lib/shopify_api/resources/discount.rb +0 -11
- data/lib/shopify_api/resources/o_auth.rb +0 -9
- data/test/discount_test.rb +0 -52
- data/test/fixtures/discount.json +0 -17
- data/test/fixtures/discount_disabled.json +0 -17
- data/test/fixtures/discounts.json +0 -34
- data/test/fixtures/o_auth_revoke.json +0 -5
- data/test/o_auth_test.rb +0 -8
@@ -1,23 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ShopifyAPI
|
2
|
-
# Shop object. Use Shop.current to receive
|
3
|
+
# Shop object. Use Shop.current to receive
|
3
4
|
# the shop.
|
4
5
|
class Shop < Base
|
5
|
-
|
6
|
-
|
6
|
+
include ActiveResource::Singleton
|
7
|
+
|
8
|
+
def self.current(options = {})
|
9
|
+
find(options)
|
7
10
|
end
|
8
11
|
|
9
12
|
def metafields(**options)
|
10
|
-
Metafield.find
|
13
|
+
Metafield.find(:all, params: options)
|
11
14
|
end
|
12
15
|
|
13
16
|
def add_metafield(metafield)
|
14
|
-
raise ArgumentError, "You can only add metafields to resource that has been saved" if new?
|
17
|
+
raise ArgumentError, "You can only add metafields to resource that has been saved" if new?
|
15
18
|
metafield.save
|
16
19
|
metafield
|
17
20
|
end
|
18
|
-
|
21
|
+
|
19
22
|
def events
|
20
23
|
Event.find(:all)
|
21
24
|
end
|
22
|
-
end
|
25
|
+
end
|
23
26
|
end
|
@@ -1,15 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ShopifyAPI
|
2
3
|
class SmartCollection < Base
|
3
4
|
include Events
|
4
5
|
include Metafields
|
5
6
|
|
6
7
|
def products
|
7
|
-
Product.find(:all, :
|
8
|
+
Product.find(:all, params: { collection_id: id })
|
8
9
|
end
|
9
10
|
|
10
|
-
def order(options={})
|
11
|
+
def order(options = {})
|
11
12
|
load_attributes_from_response(put(:order, options, only_id))
|
12
13
|
end
|
13
|
-
|
14
14
|
end
|
15
15
|
end
|
@@ -1,8 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ShopifyAPI
|
2
3
|
class Variant < Base
|
3
4
|
include Metafields
|
4
5
|
include DisablePrefixCheck
|
5
6
|
|
6
7
|
conditional_prefix :product
|
8
|
+
|
9
|
+
def initialize(*)
|
10
|
+
super
|
11
|
+
attributes.except!('old_inventory_quantity')
|
12
|
+
end
|
13
|
+
|
14
|
+
def inventory_quantity_adjustment=(new_value)
|
15
|
+
raise_deprecated_inventory_call('inventory_quantity_adjustment')
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
def inventory_quantity=(new_value)
|
20
|
+
raise_deprecated_inventory_call('inventory_quantity')
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
def old_inventory_quantity=(new_value)
|
25
|
+
raise_deprecated_inventory_call('old_inventory_quantity')
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
def save
|
30
|
+
attributes.except!('inventory_quantity')
|
31
|
+
super
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def raise_deprecated_inventory_call(parameter)
|
37
|
+
raise(
|
38
|
+
ShopifyAPI::ValidationException,
|
39
|
+
"'#{parameter}' is deprecated - see https://help.shopify.com/en/api/guides/inventory-migration-guide",
|
40
|
+
)
|
41
|
+
end
|
7
42
|
end
|
8
43
|
end
|
data/lib/shopify_api/session.rb
CHANGED
@@ -1,60 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'openssl'
|
2
3
|
require 'rack'
|
3
4
|
|
4
5
|
module ShopifyAPI
|
5
|
-
|
6
6
|
class ValidationException < StandardError
|
7
7
|
end
|
8
8
|
|
9
9
|
class Session
|
10
|
-
|
11
|
-
|
10
|
+
SECONDS_IN_A_DAY = 24 * 60 * 60
|
11
|
+
|
12
|
+
cattr_accessor :api_key, :secret, :myshopify_domain
|
12
13
|
self.myshopify_domain = 'myshopify.com'
|
13
14
|
|
14
|
-
attr_accessor :
|
15
|
+
attr_accessor :domain, :token, :name, :extra
|
16
|
+
attr_reader :api_version, :access_scopes
|
17
|
+
alias_method :url, :domain
|
15
18
|
|
16
19
|
class << self
|
17
|
-
|
18
20
|
def setup(params)
|
19
|
-
params.each { |k,value| public_send("#{k}=", value) }
|
21
|
+
params.each { |k, value| public_send("#{k}=", value) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def temp(domain:, token:, api_version: ShopifyAPI::Base.api_version, &block)
|
25
|
+
session = new(domain: domain, token: token, api_version: api_version)
|
26
|
+
|
27
|
+
with_session(session, &block)
|
20
28
|
end
|
21
29
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
original_session = new(original_site, original_token)
|
30
|
+
def with_session(session, &_block)
|
31
|
+
original_session = extract_current_session
|
32
|
+
original_user = ShopifyAPI::Base.user
|
33
|
+
original_password = ShopifyAPI::Base.password
|
27
34
|
|
28
35
|
begin
|
36
|
+
ShopifyAPI::Base.clear_session
|
29
37
|
ShopifyAPI::Base.activate_session(session)
|
30
38
|
yield
|
31
39
|
ensure
|
32
40
|
ShopifyAPI::Base.activate_session(original_session)
|
41
|
+
ShopifyAPI::Base.user = original_user
|
42
|
+
ShopifyAPI::Base.password = original_password
|
33
43
|
end
|
34
44
|
end
|
35
45
|
|
36
|
-
def
|
37
|
-
|
46
|
+
def with_version(api_version, &block)
|
47
|
+
original_session = extract_current_session
|
48
|
+
session = new(domain: original_session.site, token: original_session.token, api_version: api_version)
|
49
|
+
|
50
|
+
with_session(session, &block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def prepare_domain(domain)
|
54
|
+
return nil if domain.blank?
|
38
55
|
# remove http:// or https://
|
39
|
-
|
56
|
+
domain = domain.strip.gsub(%r{\Ahttps?://}, '')
|
40
57
|
# extract host, removing any username, password or path
|
41
|
-
shop = URI.parse("https://#{
|
58
|
+
shop = URI.parse("https://#{domain}").host
|
42
59
|
# extract subdomain of .myshopify.com
|
43
|
-
if idx = shop.index(".")
|
60
|
+
if (idx = shop.index("."))
|
44
61
|
shop = shop.slice(0, idx)
|
45
62
|
end
|
46
63
|
return nil if shop.empty?
|
47
|
-
|
48
|
-
port ? "#{shop}:#{port}" : shop
|
64
|
+
"#{shop}.#{myshopify_domain}"
|
49
65
|
rescue URI::InvalidURIError
|
50
66
|
nil
|
51
67
|
end
|
52
68
|
|
53
69
|
def validate_signature(params)
|
54
|
-
params = params.with_indifferent_access
|
55
|
-
return false unless signature = params[:hmac]
|
70
|
+
params = (params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params).with_indifferent_access
|
71
|
+
return false unless (signature = params[:hmac])
|
56
72
|
|
57
|
-
calculated_signature = OpenSSL::HMAC.hexdigest(
|
73
|
+
calculated_signature = OpenSSL::HMAC.hexdigest(
|
74
|
+
OpenSSL::Digest.new('SHA256'), secret, encoded_params_for_signature(params)
|
75
|
+
)
|
58
76
|
|
59
77
|
Rack::Utils.secure_compare(calculated_signature, signature)
|
60
78
|
end
|
@@ -63,40 +81,51 @@ module ShopifyAPI
|
|
63
81
|
|
64
82
|
def encoded_params_for_signature(params)
|
65
83
|
params = params.except(:signature, :hmac, :action, :controller)
|
66
|
-
params.map{|k,v| "#{URI.escape(k.to_s, '&=%')}=#{URI.escape(v.to_s, '&%')}"}.sort.join('&')
|
84
|
+
params.map { |k, v| "#{URI.escape(k.to_s, '&=%')}=#{URI.escape(v.to_s, '&%')}" }.sort.join('&')
|
85
|
+
end
|
86
|
+
|
87
|
+
def extract_current_session
|
88
|
+
site = ShopifyAPI::Base.site.to_s
|
89
|
+
token = ShopifyAPI::Base.headers['X-Shopify-Access-Token']
|
90
|
+
version = ShopifyAPI::Base.api_version
|
91
|
+
new(domain: site, token: token, api_version: version)
|
67
92
|
end
|
68
93
|
end
|
69
94
|
|
70
|
-
def initialize(
|
71
|
-
self.
|
95
|
+
def initialize(domain:, token:, access_scopes: nil, api_version: ShopifyAPI::Base.api_version, extra: {})
|
96
|
+
self.domain = self.class.prepare_domain(domain)
|
97
|
+
self.api_version = api_version
|
72
98
|
self.token = token
|
99
|
+
self.access_scopes = access_scopes
|
73
100
|
self.extra = extra
|
74
101
|
end
|
75
102
|
|
76
|
-
def create_permission_url(scope, redirect_uri =
|
77
|
-
params = {:
|
78
|
-
params[:
|
79
|
-
|
103
|
+
def create_permission_url(scope, redirect_uri, options = {})
|
104
|
+
params = { client_id: api_key, scope: ShopifyAPI::ApiAccess.new(scope).to_s, redirect_uri: redirect_uri }
|
105
|
+
params[:state] = options[:state] if options[:state]
|
106
|
+
params["grant_options[]".to_sym] = options[:grant_options] if options[:grant_options]
|
107
|
+
construct_oauth_url("authorize", params)
|
80
108
|
end
|
81
109
|
|
82
110
|
def request_token(params)
|
83
111
|
return token if token
|
84
112
|
|
85
|
-
|
113
|
+
twenty_four_hours_ago = Time.now.utc.to_i - SECONDS_IN_A_DAY
|
114
|
+
unless self.class.validate_signature(params) && params[:timestamp].to_i > twenty_four_hours_ago
|
86
115
|
raise ShopifyAPI::ValidationException, "Invalid Signature: Possible malicious login"
|
87
116
|
end
|
88
117
|
|
89
|
-
response = access_token_request(params[
|
118
|
+
response = access_token_request(params[:code])
|
90
119
|
if response.code == "200"
|
91
120
|
self.extra = JSON.parse(response.body)
|
92
121
|
self.token = extra.delete('access_token')
|
93
122
|
|
94
|
-
if expires_in = extra.delete('expires_in')
|
123
|
+
if (expires_in = extra.delete('expires_in'))
|
95
124
|
extra['expires_at'] = Time.now.utc.to_i + expires_in
|
96
125
|
end
|
97
126
|
token
|
98
127
|
else
|
99
|
-
raise
|
128
|
+
raise response.msg
|
100
129
|
end
|
101
130
|
end
|
102
131
|
|
@@ -105,11 +134,19 @@ module ShopifyAPI
|
|
105
134
|
end
|
106
135
|
|
107
136
|
def site
|
108
|
-
"
|
137
|
+
"https://#{domain}"
|
138
|
+
end
|
139
|
+
|
140
|
+
def api_version=(version)
|
141
|
+
@api_version = if ApiVersion::NullVersion.matches?(version)
|
142
|
+
ApiVersion::NullVersion
|
143
|
+
else
|
144
|
+
ApiVersion.find_version(version)
|
145
|
+
end
|
109
146
|
end
|
110
147
|
|
111
148
|
def valid?
|
112
|
-
|
149
|
+
domain.present? && token.present? && api_version.is_a?(ApiVersion)
|
113
150
|
end
|
114
151
|
|
115
152
|
def expires_in
|
@@ -127,18 +164,45 @@ module ShopifyAPI
|
|
127
164
|
expires_in <= 0
|
128
165
|
end
|
129
166
|
|
167
|
+
def hash
|
168
|
+
state.hash
|
169
|
+
end
|
170
|
+
|
171
|
+
def ==(other)
|
172
|
+
self.class == other.class && state == other.state
|
173
|
+
end
|
174
|
+
|
175
|
+
alias_method :eql?, :==
|
176
|
+
|
177
|
+
protected
|
178
|
+
|
179
|
+
def state
|
180
|
+
[domain, token, api_version, extra]
|
181
|
+
end
|
182
|
+
|
130
183
|
private
|
131
|
-
def parameterize(params)
|
132
|
-
URI.escape(params.collect{|k,v| "#{k}=#{v}"}.join('&'))
|
133
|
-
end
|
134
184
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
185
|
+
def access_scopes=(access_scopes)
|
186
|
+
return unless access_scopes
|
187
|
+
@access_scopes = ShopifyAPI::ApiAccess.new(access_scopes)
|
188
|
+
end
|
189
|
+
|
190
|
+
def parameterize(params)
|
191
|
+
URI.escape(params.collect { |k, v| "#{k}=#{v}" }.join('&'))
|
192
|
+
end
|
193
|
+
|
194
|
+
def access_token_request(code)
|
195
|
+
uri = URI.parse(construct_oauth_url('access_token'))
|
196
|
+
https = Net::HTTP.new(uri.host, uri.port)
|
197
|
+
https.use_ssl = true
|
198
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
199
|
+
request.set_form_data('client_id' => api_key, 'client_secret' => secret, 'code' => code)
|
200
|
+
https.request(request)
|
201
|
+
end
|
202
|
+
|
203
|
+
def construct_oauth_url(path, query_params = {})
|
204
|
+
query_string = "?#{parameterize(query_params)}" unless query_params.empty?
|
205
|
+
"https://#{domain}/admin/oauth/#{path}#{query_string}"
|
206
|
+
end
|
143
207
|
end
|
144
208
|
end
|