ruby_shopify_api 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.github/CODEOWNERS +1 -0
- data/.github/ISSUE_TEMPLATE.md +36 -0
- data/.github/probots.yml +2 -0
- data/.github/workflows/build.yml +43 -0
- data/.gitignore +15 -0
- data/.rubocop.yml +28 -0
- data/.rubocop_todo.yml +75 -0
- data/CHANGELOG-OLD.md +501 -0
- data/CHANGELOG.md +5 -0
- data/CONTRIBUTING.md +8 -0
- data/CONTRIBUTORS +3 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +151 -0
- data/Gemfile_ar41 +5 -0
- data/Gemfile_ar50 +5 -0
- data/Gemfile_ar51 +5 -0
- data/Gemfile_ar60 +5 -0
- data/Gemfile_ar_main +5 -0
- data/LICENSE +20 -0
- data/README.md +649 -0
- data/RELEASING +17 -0
- data/Rakefile +55 -0
- data/SECURITY.md +59 -0
- data/dev.yml +11 -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 +11 -0
- data/lib/active_resource/detailed_log_subscriber.rb +55 -0
- data/lib/active_resource/json_errors.rb +37 -0
- data/lib/shopify_api/api_access.rb +57 -0
- data/lib/shopify_api/api_version.rb +206 -0
- data/lib/shopify_api/connection.rb +36 -0
- data/lib/shopify_api/countable.rb +15 -0
- data/lib/shopify_api/disable_prefix_check.rb +31 -0
- data/lib/shopify_api/events.rb +8 -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/graphql.rb +103 -0
- data/lib/shopify_api/hmac_params.rb +33 -0
- data/lib/shopify_api/limits.rb +77 -0
- data/lib/shopify_api/message_enricher.rb +25 -0
- data/lib/shopify_api/meta.rb +14 -0
- data/lib/shopify_api/metafields.rb +21 -0
- data/lib/shopify_api/paginated_collection.rb +69 -0
- data/lib/shopify_api/pagination_link_headers.rb +34 -0
- 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 +9 -0
- data/lib/shopify_api/resources/address.rb +5 -0
- data/lib/shopify_api/resources/announcement.rb +5 -0
- data/lib/shopify_api/resources/api_permission.rb +9 -0
- data/lib/shopify_api/resources/application_charge.rb +16 -0
- data/lib/shopify_api/resources/application_credit.rb +5 -0
- data/lib/shopify_api/resources/array_base.rb +13 -0
- data/lib/shopify_api/resources/article.rb +22 -0
- data/lib/shopify_api/resources/asset.rb +101 -0
- data/lib/shopify_api/resources/assigned_fulfillment_order.rb +16 -0
- data/lib/shopify_api/resources/base.rb +166 -0
- data/lib/shopify_api/resources/billing_address.rb +5 -0
- data/lib/shopify_api/resources/blog.rb +11 -0
- data/lib/shopify_api/resources/carrier_service.rb +5 -0
- data/lib/shopify_api/resources/cart.rb +5 -0
- data/lib/shopify_api/resources/checkout.rb +30 -0
- data/lib/shopify_api/resources/collect.rb +7 -0
- data/lib/shopify_api/resources/collection.rb +14 -0
- data/lib/shopify_api/resources/collection_listing.rb +19 -0
- data/lib/shopify_api/resources/collection_publication.rb +10 -0
- data/lib/shopify_api/resources/comment.rb +24 -0
- data/lib/shopify_api/resources/country.rb +5 -0
- data/lib/shopify_api/resources/currency.rb +6 -0
- data/lib/shopify_api/resources/custom_collection.rb +20 -0
- data/lib/shopify_api/resources/customer.rb +30 -0
- data/lib/shopify_api/resources/customer_group.rb +6 -0
- data/lib/shopify_api/resources/customer_invite.rb +5 -0
- data/lib/shopify_api/resources/customer_saved_search.rb +12 -0
- data/lib/shopify_api/resources/discount_code.rb +10 -0
- data/lib/shopify_api/resources/discount_code_batch.rb +34 -0
- data/lib/shopify_api/resources/draft_order.rb +15 -0
- data/lib/shopify_api/resources/draft_order_invoice.rb +5 -0
- data/lib/shopify_api/resources/event.rb +9 -0
- data/lib/shopify_api/resources/fulfillment.rb +56 -0
- data/lib/shopify_api/resources/fulfillment_event.rb +16 -0
- 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 +16 -0
- data/lib/shopify_api/resources/fulfillment_service.rb +5 -0
- data/lib/shopify_api/resources/fulfillment_v2.rb +21 -0
- data/lib/shopify_api/resources/gift_card.rb +8 -0
- data/lib/shopify_api/resources/image.rb +17 -0
- 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 +15 -0
- data/lib/shopify_api/resources/location.rb +8 -0
- data/lib/shopify_api/resources/marketing_event.rb +11 -0
- data/lib/shopify_api/resources/metafield.rb +14 -0
- data/lib/shopify_api/resources/note_attribute.rb +5 -0
- data/lib/shopify_api/resources/option.rb +5 -0
- data/lib/shopify_api/resources/order.rb +44 -0
- data/lib/shopify_api/resources/order_risk.rb +9 -0
- data/lib/shopify_api/resources/page.rb +7 -0
- data/lib/shopify_api/resources/payment.rb +7 -0
- data/lib/shopify_api/resources/payment_details.rb +5 -0
- data/lib/shopify_api/resources/ping.rb +3 -0
- data/lib/shopify_api/resources/policy.rb +8 -0
- data/lib/shopify_api/resources/price_rule.rb +8 -0
- data/lib/shopify_api/resources/product.rb +59 -0
- data/lib/shopify_api/resources/product_listing.rb +17 -0
- data/lib/shopify_api/resources/product_publication.rb +10 -0
- data/lib/shopify_api/resources/province.rb +6 -0
- data/lib/shopify_api/resources/publication.rb +5 -0
- data/lib/shopify_api/resources/receipt.rb +5 -0
- data/lib/shopify_api/resources/recurring_application_charge.rb +34 -0
- data/lib/shopify_api/resources/redirect.rb +5 -0
- data/lib/shopify_api/resources/refund.rb +15 -0
- data/lib/shopify_api/resources/report.rb +5 -0
- data/lib/shopify_api/resources/resource_feedback.rb +19 -0
- data/lib/shopify_api/resources/rule.rb +5 -0
- data/lib/shopify_api/resources/script_tag.rb +5 -0
- data/lib/shopify_api/resources/shipping_address.rb +5 -0
- data/lib/shopify_api/resources/shipping_line.rb +5 -0
- data/lib/shopify_api/resources/shipping_rate.rb +7 -0
- data/lib/shopify_api/resources/shipping_zone.rb +5 -0
- data/lib/shopify_api/resources/shop.rb +26 -0
- data/lib/shopify_api/resources/smart_collection.rb +15 -0
- data/lib/shopify_api/resources/storefront_access_token.rb +5 -0
- data/lib/shopify_api/resources/tax_line.rb +5 -0
- data/lib/shopify_api/resources/tax_service.rb +5 -0
- data/lib/shopify_api/resources/tender_transaction.rb +6 -0
- data/lib/shopify_api/resources/theme.rb +5 -0
- data/lib/shopify_api/resources/transaction.rb +6 -0
- data/lib/shopify_api/resources/usage_charge.rb +6 -0
- data/lib/shopify_api/resources/user.rb +5 -0
- data/lib/shopify_api/resources/variant.rb +43 -0
- data/lib/shopify_api/resources/webhook.rb +5 -0
- data/lib/shopify_api/resources.rb +4 -0
- data/lib/shopify_api/session.rb +203 -0
- data/lib/shopify_api/version.rb +4 -0
- data/lib/shopify_api.rb +45 -0
- data/lib/verify_docs.rb +8 -0
- data/service.yml +2 -0
- data/shipit.rubygems.yml +1 -0
- data/shopify_api.gemspec +47 -0
- data/test/abandoned_checkouts_test.rb +29 -0
- data/test/access_scope_test.rb +23 -0
- data/test/access_token_test.rb +20 -0
- data/test/active_resource/json_errors_test.rb +19 -0
- 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 +82 -0
- data/test/application_credit_test.rb +36 -0
- data/test/article_test.rb +72 -0
- data/test/asset_test.rb +26 -0
- data/test/assigned_fulfillment_order_test.rb +78 -0
- data/test/base_test.rb +213 -0
- data/test/blog_test.rb +9 -0
- data/test/carrier_service_test.rb +18 -0
- data/test/cart_test.rb +14 -0
- data/test/checkouts_test.rb +77 -0
- data/test/collect_test.rb +10 -0
- data/test/collection_listing_test.rb +84 -0
- data/test/collection_publication_test.rb +40 -0
- data/test/collection_test.rb +50 -0
- data/test/countable_test.rb +14 -0
- data/test/currency_test.rb +21 -0
- data/test/custom_collection_test.rb +10 -0
- data/test/customer_saved_search_test.rb +37 -0
- data/test/customer_test.rb +58 -0
- data/test/detailed_log_subscriber_test.rb +143 -0
- data/test/discount_code_batch_test.rb +41 -0
- data/test/discount_code_test.rb +59 -0
- data/test/draft_order_test.rb +167 -0
- 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/access_token_delegate.json +4 -0
- data/test/fixtures/api_versions.json +38 -0
- data/test/fixtures/apis.json +42 -0
- data/test/fixtures/application_charge.json +16 -0
- data/test/fixtures/application_charges.json +57 -0
- data/test/fixtures/application_credit.json +12 -0
- data/test/fixtures/application_credits.json +24 -0
- data/test/fixtures/article.json +15 -0
- data/test/fixtures/articles.json +39 -0
- data/test/fixtures/asset.json +9 -0
- data/test/fixtures/assets.json +136 -0
- data/test/fixtures/assigned_fulfillment_orders.json +80 -0
- data/test/fixtures/authors.json +1 -0
- data/test/fixtures/blog.json +13 -0
- data/test/fixtures/blogs.json +13 -0
- data/test/fixtures/carrier_service.json +9 -0
- data/test/fixtures/carts.json +43 -0
- data/test/fixtures/checkout.json +160 -0
- data/test/fixtures/checkouts.json +162 -0
- data/test/fixtures/collect.json +12 -0
- data/test/fixtures/collection.json +17 -0
- data/test/fixtures/collection_listing.json +11 -0
- data/test/fixtures/collection_listing_product_ids.json +1 -0
- data/test/fixtures/collection_listing_product_ids2.json +1 -0
- data/test/fixtures/collection_listings.json +13 -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/custom_collection.json +17 -0
- data/test/fixtures/customer_invite.json +9 -0
- data/test/fixtures/customer_saved_search.json +9 -0
- data/test/fixtures/customer_saved_search_customers.json +60 -0
- data/test/fixtures/customers.json +59 -0
- data/test/fixtures/customers_account_activation_url.json +3 -0
- data/test/fixtures/customers_search.json +60 -0
- data/test/fixtures/discount_code.json +10 -0
- data/test/fixtures/discount_code_batch.json +14 -0
- data/test/fixtures/discount_code_batch_discount_codes.json +21 -0
- data/test/fixtures/discount_codes.json +12 -0
- data/test/fixtures/draft_order.json +159 -0
- data/test/fixtures/draft_order_completed.json +159 -0
- data/test/fixtures/draft_order_invoice.json +9 -0
- data/test/fixtures/draft_orders.json +161 -0
- data/test/fixtures/engagement.json +15 -0
- data/test/fixtures/events.json +31 -0
- data/test/fixtures/fulfillment.json +49 -0
- data/test/fixtures/fulfillment_event.json +12 -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/fulfillment_request.json +28 -0
- data/test/fixtures/fulfillment_service.json +10 -0
- data/test/fixtures/fulfillments.json +53 -0
- data/test/fixtures/gift_card.json +20 -0
- data/test/fixtures/gift_card_disabled.json +20 -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/image.json +10 -0
- data/test/fixtures/images.json +20 -0
- data/test/fixtures/inventory_level.json +7 -0
- data/test/fixtures/inventory_levels.json +24 -0
- data/test/fixtures/marketing_event.json +28 -0
- data/test/fixtures/marketing_events.json +54 -0
- data/test/fixtures/metafield.json +12 -0
- data/test/fixtures/metafields.json +34 -0
- data/test/fixtures/order.json +297 -0
- data/test/fixtures/order_risk.json +14 -0
- data/test/fixtures/order_risks.json +28 -0
- data/test/fixtures/order_with_properties.json +373 -0
- data/test/fixtures/orders.json +299 -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/policies.json +8 -0
- data/test/fixtures/price_rule.json +27 -0
- data/test/fixtures/price_rules.json +28 -0
- data/test/fixtures/product.json +116 -0
- data/test/fixtures/product_listing.json +86 -0
- data/test/fixtures/product_listing_product_ids.json +1 -0
- data/test/fixtures/product_listing_product_ids2.json +1 -0
- data/test/fixtures/product_listings.json +174 -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/recurring_application_charge.json +22 -0
- data/test/fixtures/recurring_application_charge_adjustment.json +5 -0
- data/test/fixtures/recurring_application_charges.json +106 -0
- data/test/fixtures/redirect.json +7 -0
- data/test/fixtures/refund.json +112 -0
- data/test/fixtures/report.json +9 -0
- data/test/fixtures/reports.json +11 -0
- data/test/fixtures/script_tag.json +10 -0
- data/test/fixtures/script_tags.json +18 -0
- data/test/fixtures/shipping_rates.json +12 -0
- data/test/fixtures/shipping_zones.json +315 -0
- data/test/fixtures/shop.json +26 -0
- data/test/fixtures/smart_collection.json +21 -0
- data/test/fixtures/smart_collection_products.json +155 -0
- data/test/fixtures/storefront_access_token.json +9 -0
- data/test/fixtures/storefront_access_tokens.json +18 -0
- data/test/fixtures/tags.json +1 -0
- data/test/fixtures/tax_service.json +9 -0
- data/test/fixtures/tender_transactions.json +52 -0
- data/test/fixtures/transaction.json +29 -0
- data/test/fixtures/usage_charge.json +11 -0
- data/test/fixtures/usage_charges.json +23 -0
- data/test/fixtures/user.json +21 -0
- data/test/fixtures/users.json +42 -0
- data/test/fixtures/variant.json +23 -0
- data/test/fixtures/variants.json +88 -0
- data/test/fixtures/webhook.json +10 -0
- data/test/fixtures/webhooks.json +18 -0
- data/test/fulfillment_event_test.rb +74 -0
- data/test/fulfillment_order_test.rb +530 -0
- data/test/fulfillment_order_test_helper.rb +8 -0
- data/test/fulfillment_request_test.rb +35 -0
- data/test/fulfillment_service_test.rb +18 -0
- data/test/fulfillment_test.rb +239 -0
- data/test/fulfillment_v2_test.rb +66 -0
- data/test/gift_card_test.rb +24 -0
- data/test/graphql/http_client_test.rb +26 -0
- data/test/graphql_test.rb +190 -0
- data/test/hmac_params_test.rb +25 -0
- data/test/image_test.rb +41 -0
- data/test/inventory_level_test.rb +68 -0
- data/test/lib/webmock_extensions/last_request.rb +16 -0
- data/test/limits_test.rb +39 -0
- data/test/location_test.rb +15 -0
- data/test/marketing_event_test.rb +68 -0
- data/test/message_enricher_test.rb +45 -0
- data/test/meta_test.rb +47 -0
- data/test/metafield_test.rb +56 -0
- data/test/order_risk_test.rb +47 -0
- data/test/order_test.rb +140 -0
- data/test/pagination_test.rb +290 -0
- data/test/payment_test.rb +19 -0
- data/test/policy_test.rb +20 -0
- data/test/price_rule_test.rb +70 -0
- data/test/product_listing_test.rb +97 -0
- data/test/product_publication_test.rb +40 -0
- data/test/product_test.rb +111 -0
- data/test/publication_test.rb +12 -0
- data/test/recurring_application_charge_test.rb +204 -0
- data/test/redirect_test.rb +10 -0
- data/test/refund_test.rb +37 -0
- data/test/report_test.rb +37 -0
- data/test/resource_feedback_test.rb +43 -0
- data/test/script_tag_test.rb +31 -0
- data/test/session_test.rb +640 -0
- data/test/shipping_rate_test.rb +17 -0
- data/test/shipping_zone_test.rb +11 -0
- data/test/shop_test.rb +82 -0
- data/test/smart_collection_test.rb +11 -0
- data/test/storefront_access_token_test.rb +30 -0
- data/test/tax_service_test.rb +12 -0
- data/test/tender_transaction_test.rb +18 -0
- data/test/test_helper.rb +126 -0
- data/test/transaction_test.rb +18 -0
- data/test/usage_charge_test.rb +25 -0
- data/test/user_test.rb +18 -0
- data/test/variant_test.rb +73 -0
- data/test/webhook_test.rb +24 -0
- metadata +555 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'openssl'
|
|
3
|
+
require 'rack'
|
|
4
|
+
|
|
5
|
+
module ShopifyAPI
|
|
6
|
+
class ValidationException < StandardError
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class Session
|
|
10
|
+
SECONDS_IN_A_DAY = 24 * 60 * 60
|
|
11
|
+
|
|
12
|
+
cattr_accessor :api_key, :secret, :myshopify_domain
|
|
13
|
+
self.myshopify_domain = 'myshopify.com'
|
|
14
|
+
|
|
15
|
+
attr_accessor :domain, :token, :name, :extra
|
|
16
|
+
attr_reader :api_version, :access_scopes
|
|
17
|
+
alias_method :url, :domain
|
|
18
|
+
|
|
19
|
+
class << self
|
|
20
|
+
def setup(params)
|
|
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)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def with_session(session, &_block)
|
|
31
|
+
original_session = extract_current_session
|
|
32
|
+
original_user = ShopifyAPI::Base.user
|
|
33
|
+
original_password = ShopifyAPI::Base.password
|
|
34
|
+
|
|
35
|
+
begin
|
|
36
|
+
ShopifyAPI::Base.clear_session
|
|
37
|
+
ShopifyAPI::Base.activate_session(session)
|
|
38
|
+
yield
|
|
39
|
+
ensure
|
|
40
|
+
ShopifyAPI::Base.activate_session(original_session)
|
|
41
|
+
ShopifyAPI::Base.user = original_user
|
|
42
|
+
ShopifyAPI::Base.password = original_password
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
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?
|
|
55
|
+
# remove http:// or https://
|
|
56
|
+
domain = domain.strip.gsub(%r{\Ahttps?://}, '')
|
|
57
|
+
# extract host, removing any username, password or path
|
|
58
|
+
shop = URI.parse("https://#{domain}").host
|
|
59
|
+
# extract subdomain of .myshopify.com
|
|
60
|
+
if (idx = shop.index("."))
|
|
61
|
+
shop = shop.slice(0, idx)
|
|
62
|
+
end
|
|
63
|
+
return nil if shop.empty?
|
|
64
|
+
"#{shop}.#{myshopify_domain}"
|
|
65
|
+
rescue URI::InvalidURIError
|
|
66
|
+
nil
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def validate_signature(params)
|
|
70
|
+
params = (params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params).with_indifferent_access
|
|
71
|
+
return false unless (signature = params[:hmac])
|
|
72
|
+
|
|
73
|
+
calculated_signature = OpenSSL::HMAC.hexdigest(
|
|
74
|
+
OpenSSL::Digest.new('SHA256'), secret, ShopifyAPI::HmacParams.encode(params)
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
Rack::Utils.secure_compare(calculated_signature, signature)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
def extract_current_session
|
|
83
|
+
site = ShopifyAPI::Base.site.to_s
|
|
84
|
+
token = ShopifyAPI::Base.headers['X-Shopify-Access-Token']
|
|
85
|
+
version = ShopifyAPI::Base.api_version
|
|
86
|
+
new(domain: site, token: token, api_version: version)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def initialize(domain:, token:, access_scopes: nil, api_version: ShopifyAPI::Base.api_version, extra: {})
|
|
91
|
+
self.domain = self.class.prepare_domain(domain)
|
|
92
|
+
self.api_version = api_version
|
|
93
|
+
self.token = token
|
|
94
|
+
self.access_scopes = access_scopes
|
|
95
|
+
self.extra = extra
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def create_permission_url(scope, redirect_uri, options = {})
|
|
99
|
+
params = { client_id: api_key, scope: ShopifyAPI::ApiAccess.new(scope).to_s, redirect_uri: redirect_uri }
|
|
100
|
+
params[:state] = options[:state] if options[:state]
|
|
101
|
+
params["grant_options[]".to_sym] = options[:grant_options] if options[:grant_options]
|
|
102
|
+
construct_oauth_url("authorize", params)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def request_token(params)
|
|
106
|
+
return token if token
|
|
107
|
+
|
|
108
|
+
twenty_four_hours_ago = Time.now.utc.to_i - SECONDS_IN_A_DAY
|
|
109
|
+
unless self.class.validate_signature(params) && params[:timestamp].to_i > twenty_four_hours_ago
|
|
110
|
+
raise ShopifyAPI::ValidationException, "Invalid Signature: Possible malicious login"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
response = access_token_request(params[:code])
|
|
114
|
+
if response.code == "200"
|
|
115
|
+
self.extra = JSON.parse(response.body)
|
|
116
|
+
self.token = extra.delete('access_token')
|
|
117
|
+
|
|
118
|
+
if (expires_in = extra.delete('expires_in'))
|
|
119
|
+
extra['expires_at'] = Time.now.utc.to_i + expires_in
|
|
120
|
+
end
|
|
121
|
+
token
|
|
122
|
+
else
|
|
123
|
+
raise response.msg
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def shop
|
|
128
|
+
Shop.current
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def site
|
|
132
|
+
"https://#{domain}"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def api_version=(version)
|
|
136
|
+
@api_version = if ApiVersion::NullVersion.matches?(version)
|
|
137
|
+
ApiVersion::NullVersion
|
|
138
|
+
else
|
|
139
|
+
ApiVersion.find_version(version)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def valid?
|
|
144
|
+
domain.present? && token.present? && api_version.is_a?(ApiVersion)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def expires_in
|
|
148
|
+
return unless expires_at.present?
|
|
149
|
+
[0, expires_at.to_i - Time.now.utc.to_i].max
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def expires_at
|
|
153
|
+
return unless extra.present?
|
|
154
|
+
@expires_at ||= Time.at(extra['expires_at']).utc
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def expired?
|
|
158
|
+
return false if expires_in.nil?
|
|
159
|
+
expires_in <= 0
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def hash
|
|
163
|
+
state.hash
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def ==(other)
|
|
167
|
+
self.class == other.class && state == other.state
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
alias_method :eql?, :==
|
|
171
|
+
|
|
172
|
+
protected
|
|
173
|
+
|
|
174
|
+
def state
|
|
175
|
+
[domain, token, api_version, extra]
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
private
|
|
179
|
+
|
|
180
|
+
def access_scopes=(access_scopes)
|
|
181
|
+
return unless access_scopes
|
|
182
|
+
@access_scopes = ShopifyAPI::ApiAccess.new(access_scopes)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def parameterize(params)
|
|
186
|
+
URI.encode_www_form(params)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def access_token_request(code)
|
|
190
|
+
uri = URI.parse(construct_oauth_url('access_token'))
|
|
191
|
+
https = Net::HTTP.new(uri.host, uri.port)
|
|
192
|
+
https.use_ssl = true
|
|
193
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
|
194
|
+
request.set_form_data('client_id' => api_key, 'client_secret' => secret, 'code' => code)
|
|
195
|
+
https.request(request)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def construct_oauth_url(path, query_params = {})
|
|
199
|
+
query_string = "?#{parameterize(query_params)}" unless query_params.empty?
|
|
200
|
+
"https://#{domain}/admin/oauth/#{path}#{query_string}"
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
data/lib/shopify_api.rb
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
$:.unshift(File.dirname(__FILE__))
|
|
3
|
+
require 'active_resource'
|
|
4
|
+
require 'active_support/core_ext/class/attribute_accessors'
|
|
5
|
+
require 'digest/md5'
|
|
6
|
+
require 'base64'
|
|
7
|
+
require 'active_resource/detailed_log_subscriber'
|
|
8
|
+
require 'shopify_api/limits'
|
|
9
|
+
require 'shopify_api/api_version'
|
|
10
|
+
require 'shopify_api/meta'
|
|
11
|
+
require 'active_resource/json_errors'
|
|
12
|
+
require 'shopify_api/paginated_collection'
|
|
13
|
+
require 'shopify_api/disable_prefix_check'
|
|
14
|
+
|
|
15
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.6")
|
|
16
|
+
puts("\nshopify_api: NOTE: Support for Ruby #{RUBY_VERSION} will be dropped in the next major release. Please update to Ruby 2.6 or newer before updating this gem.\n\n")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
module ShopifyAPI
|
|
20
|
+
include Limits
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
require 'shopify_api/events'
|
|
24
|
+
require 'shopify_api/metafields'
|
|
25
|
+
require 'shopify_api/countable'
|
|
26
|
+
require 'shopify_api/resources'
|
|
27
|
+
require 'shopify_api/session'
|
|
28
|
+
require 'shopify_api/hmac_params'
|
|
29
|
+
require 'shopify_api/api_access'
|
|
30
|
+
require 'shopify_api/message_enricher'
|
|
31
|
+
require 'shopify_api/connection'
|
|
32
|
+
require 'shopify_api/pagination_link_headers'
|
|
33
|
+
require 'shopify_api/graphql'
|
|
34
|
+
require 'shopify_api/graphql/railtie' if defined?(Rails)
|
|
35
|
+
|
|
36
|
+
if ShopifyAPI::Base.respond_to?(:connection_class)
|
|
37
|
+
ShopifyAPI::Base.connection_class = ShopifyAPI::Connection
|
|
38
|
+
else
|
|
39
|
+
require 'active_resource/connection_ext'
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
if ENV["SHOPIFY_LOG_PATH"]
|
|
43
|
+
ActiveResource::Base.logger = Logger.new(ENV["SHOPIFY_LOG_PATH"])
|
|
44
|
+
ActiveResource::DetailedLogSubscriber.attach_to(:active_resource_detailed)
|
|
45
|
+
end
|
data/lib/verify_docs.rb
ADDED
data/service.yml
ADDED
data/shipit.rubygems.yml
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# using the default shipit config
|
data/shopify_api.gemspec
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
$:.push(File.expand_path("../lib", __FILE__))
|
|
3
|
+
require "shopify_api/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = %q{ruby_shopify_api}
|
|
7
|
+
s.version = ShopifyAPI::VERSION
|
|
8
|
+
s.authors = ["Hopper Gee"]
|
|
9
|
+
s.email = ["hopper.gee@hey.com"]
|
|
10
|
+
|
|
11
|
+
s.summary = %q{The Shopify API gem is a lightweight gem for accessing the Shopify admin REST web services}
|
|
12
|
+
s.description = <<~HERE
|
|
13
|
+
The Shopify API gem allows Ruby developers to programmatically access the admin
|
|
14
|
+
section of Shopify stores. The API is implemented as JSON or XML over HTTP using
|
|
15
|
+
all four verbs (GET/POST/PUT/DELETE). Each resource, like Order, Product, or
|
|
16
|
+
Collection, has its own URL and is manipulated in isolation.
|
|
17
|
+
HERE
|
|
18
|
+
s.homepage = %q{https://github.com/RetroShopifyDev/ruby-shopify-api}
|
|
19
|
+
|
|
20
|
+
s.metadata['allowed_push_host'] = 'https://rubygems.org'
|
|
21
|
+
|
|
22
|
+
s.extra_rdoc_files = [
|
|
23
|
+
"LICENSE",
|
|
24
|
+
"README.md",
|
|
25
|
+
]
|
|
26
|
+
s.files = `git ls-files`.split("\n")
|
|
27
|
+
s.test_files = `git ls-files -- {test}/*`.split("\n")
|
|
28
|
+
|
|
29
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
|
30
|
+
s.summary = %q{ShopifyAPI is a lightweight gem for accessing the Shopify admin REST web services}
|
|
31
|
+
s.license = "MIT"
|
|
32
|
+
|
|
33
|
+
s.required_ruby_version = ">= 2.4"
|
|
34
|
+
|
|
35
|
+
s.add_runtime_dependency("activeresource", ">= 4.1.0")
|
|
36
|
+
s.add_runtime_dependency("rack")
|
|
37
|
+
s.add_runtime_dependency("graphql-client")
|
|
38
|
+
|
|
39
|
+
s.add_development_dependency("mocha", ">= 1.4.0")
|
|
40
|
+
s.add_development_dependency("webmock")
|
|
41
|
+
s.add_development_dependency("minitest", ">= 5.14")
|
|
42
|
+
s.add_development_dependency("rake")
|
|
43
|
+
s.add_development_dependency("timecop")
|
|
44
|
+
s.add_development_dependency("rubocop-shopify")
|
|
45
|
+
s.add_development_dependency("pry")
|
|
46
|
+
s.add_development_dependency("pry-byebug")
|
|
47
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'test_helper'
|
|
3
|
+
|
|
4
|
+
class AbandonedCheckoutsTest < Test::Unit::TestCase
|
|
5
|
+
def setup
|
|
6
|
+
super
|
|
7
|
+
|
|
8
|
+
@expected_checkouts = JSON.parse(load_fixture('abandoned_checkouts'))['checkouts']
|
|
9
|
+
@expected_checkout_id = JSON.parse(load_fixture('abandoned_checkout'))['checkout']['id']
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
test ":create creates a checkout" do
|
|
13
|
+
fake 'checkouts', method: :post, status: 201, body: load_fixture('abandoned_checkout')
|
|
14
|
+
|
|
15
|
+
checkout = ShopifyAPI::AbandonedCheckout.create
|
|
16
|
+
|
|
17
|
+
assert_equal @expected_checkout_id, checkout.id
|
|
18
|
+
assert_equal true, checkout.attributes.include?(:abandoned_checkout_url)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
test "get all checkouts indexed by token" do
|
|
22
|
+
fake 'checkouts', method: :get, status: 200, body: load_fixture('abandoned_checkouts')
|
|
23
|
+
|
|
24
|
+
checkouts = ShopifyAPI::AbandonedCheckout.all
|
|
25
|
+
|
|
26
|
+
assert_equal @expected_checkout_id, checkouts.first.id
|
|
27
|
+
assert_equal @expected_checkouts.size, checkouts.size
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'test_helper'
|
|
3
|
+
|
|
4
|
+
class AccessScopeTest < Test::Unit::TestCase
|
|
5
|
+
test 'access scope does not use the versioned resource urls' do
|
|
6
|
+
fake(
|
|
7
|
+
'access_scopes',
|
|
8
|
+
url: 'https://shop2.myshopify.com/admin/oauth/access_scopes.json',
|
|
9
|
+
method: :get,
|
|
10
|
+
status: 201,
|
|
11
|
+
body: load_fixture('access_scopes'),
|
|
12
|
+
extension: false
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
unstable_version = ShopifyAPI::Session.new(domain: 'shop2.myshopify.com', token: 'token2', api_version: :unstable)
|
|
16
|
+
|
|
17
|
+
ShopifyAPI::Base.activate_session(unstable_version)
|
|
18
|
+
|
|
19
|
+
scope_handles = ShopifyAPI::AccessScope.find(:all).map(&:handle)
|
|
20
|
+
|
|
21
|
+
assert_equal(['write_product_listings', 'read_shipping'], scope_handles)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'test_helper'
|
|
3
|
+
|
|
4
|
+
class AccessTokenTest < Test::Unit::TestCase
|
|
5
|
+
def test_delegate_access_token
|
|
6
|
+
fake(
|
|
7
|
+
"access_tokens/delegate.json?delegate_access_scope%5B%5D=write_orders&" \
|
|
8
|
+
"delegate_access_scope%5B%5D=read_products&expires_in=",
|
|
9
|
+
method: :post,
|
|
10
|
+
status: 201,
|
|
11
|
+
body: load_fixture('access_token_delegate'),
|
|
12
|
+
extension: false
|
|
13
|
+
)
|
|
14
|
+
delegate_scope = ['write_orders', 'read_products']
|
|
15
|
+
token = ShopifyAPI::AccessToken.delegate(delegate_scope)
|
|
16
|
+
|
|
17
|
+
assert_equal('abracadabra', token.access_token)
|
|
18
|
+
assert_equal('write_orders,read_products', token.scope)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'test_helper'
|
|
3
|
+
|
|
4
|
+
module ActiveResource
|
|
5
|
+
class JsonErrorsTest < Test::Unit::TestCase
|
|
6
|
+
def test_parsing_of_error_json_hash
|
|
7
|
+
@model = ShopifyAPI::Order.new
|
|
8
|
+
@model.errors.from_json({ errors: { name: ['missing'] } }.to_json)
|
|
9
|
+
assert_equal(['missing'], @model.errors[:name])
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def test_parsing_of_error_json_plain_string
|
|
13
|
+
@model = ShopifyAPI::Order.new
|
|
14
|
+
@model.errors.from_json({ errors: 'some generic error' }.to_json)
|
|
15
|
+
assert_equal(['some generic error'], @model.errors[:base])
|
|
16
|
+
assert_equal('some generic error', @model.errors.full_messages.to_sentence)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'test_helper'
|
|
3
|
+
|
|
4
|
+
class ApiAccessTest < Minitest::Test
|
|
5
|
+
def test_write_is_the_same_access_as_read_write_on_the_same_resource
|
|
6
|
+
read_write_orders = ShopifyAPI::ApiAccess.new(%w(read_orders write_orders))
|
|
7
|
+
write_orders = ShopifyAPI::ApiAccess.new(%w(write_orders))
|
|
8
|
+
|
|
9
|
+
assert_equal write_orders, read_write_orders
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def test_write_is_the_same_access_as_read_write_on_the_same_unauthenticated_resource
|
|
13
|
+
unauthenticated_read_write_orders = ShopifyAPI::ApiAccess.new(%w(unauthenticated_read_orders unauthenticated_write_orders))
|
|
14
|
+
unauthenticated_write_orders = ShopifyAPI::ApiAccess.new(%w(unauthenticated_write_orders))
|
|
15
|
+
|
|
16
|
+
assert_equal unauthenticated_write_orders, unauthenticated_read_write_orders
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_read_is_not_the_same_as_read_write_on_the_same_resource
|
|
20
|
+
read_orders = ShopifyAPI::ApiAccess.new(%w(read_orders))
|
|
21
|
+
read_write_orders = ShopifyAPI::ApiAccess.new(%w(write_orders read_orders))
|
|
22
|
+
|
|
23
|
+
refute_equal read_write_orders, read_orders
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_two_different_resources_are_not_equal
|
|
27
|
+
read_orders = ShopifyAPI::ApiAccess.new(%w(read_orders))
|
|
28
|
+
read_products = ShopifyAPI::ApiAccess.new(%w(read_products))
|
|
29
|
+
|
|
30
|
+
refute_equal read_orders, read_products
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_two_identical_scopes_are_equal
|
|
34
|
+
read_orders = ShopifyAPI::ApiAccess.new(%w(read_orders))
|
|
35
|
+
read_orders_identical = ShopifyAPI::ApiAccess.new(%w(read_orders))
|
|
36
|
+
|
|
37
|
+
assert_equal read_orders_identical, read_orders
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_unauthenticated_is_not_implied_by_authenticated_access
|
|
41
|
+
unauthenticated_orders = ShopifyAPI::ApiAccess.new(%w(unauthenticated_read_orders))
|
|
42
|
+
authenticated_read_orders = ShopifyAPI::ApiAccess.new(%w(read_orders))
|
|
43
|
+
authenticated_write_orders = ShopifyAPI::ApiAccess.new(%w(write_orders))
|
|
44
|
+
|
|
45
|
+
refute_equal unauthenticated_orders, authenticated_read_orders
|
|
46
|
+
refute_equal unauthenticated_orders, authenticated_write_orders
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def test_scopes_covers_is_truthy_for_same_scopes
|
|
50
|
+
read_orders = ShopifyAPI::ApiAccess.new(%w(read_orders))
|
|
51
|
+
read_orders_identical = ShopifyAPI::ApiAccess.new(%w(read_orders))
|
|
52
|
+
|
|
53
|
+
assert read_orders.covers?(read_orders_identical)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def test_covers_is_falsy_for_different_scopes
|
|
57
|
+
read_orders = ShopifyAPI::ApiAccess.new(%w(read_orders))
|
|
58
|
+
read_products = ShopifyAPI::ApiAccess.new(%w(read_products))
|
|
59
|
+
|
|
60
|
+
refute read_orders.covers?(read_products)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_covers_is_truthy_for_read_when_the_set_has_read_write
|
|
64
|
+
write_products = ShopifyAPI::ApiAccess.new(%w(write_products))
|
|
65
|
+
read_products = ShopifyAPI::ApiAccess.new(%w(read_products))
|
|
66
|
+
|
|
67
|
+
assert write_products.covers?(read_products)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_covers_is_truthy_for_read_when_the_set_has_read_write_for_that_resource_and_others
|
|
71
|
+
write_products_and_orders = ShopifyAPI::ApiAccess.new(%w(write_products, write_orders))
|
|
72
|
+
read_orders = ShopifyAPI::ApiAccess.new(%w(read_orders))
|
|
73
|
+
|
|
74
|
+
assert write_products_and_orders.covers?(read_orders)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def test_covers_is_truthy_for_write_when_the_set_has_read_write_for_that_resource_and_others
|
|
78
|
+
write_products_and_orders = ShopifyAPI::ApiAccess.new(%w(write_products, write_orders))
|
|
79
|
+
write_orders = ShopifyAPI::ApiAccess.new(%w(write_orders))
|
|
80
|
+
|
|
81
|
+
assert write_products_and_orders.covers?(write_orders)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def test_covers_is_truthy_for_subset_of_scopes
|
|
85
|
+
write_products_orders_customers = ShopifyAPI::ApiAccess.new(%w(write_products write_orders write_customers))
|
|
86
|
+
write_orders_products = ShopifyAPI::ApiAccess.new(%w(write_orders read_products))
|
|
87
|
+
|
|
88
|
+
assert write_products_orders_customers.covers?(write_orders_products)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def test_covers_is_falsy_for_sets_of_scopes_that_have_no_common_elements
|
|
92
|
+
write_products_orders_customers = ShopifyAPI::ApiAccess.new(%w(write_products write_orders write_customers))
|
|
93
|
+
write_images_read_content = ShopifyAPI::ApiAccess.new(%w(write_images read_content))
|
|
94
|
+
|
|
95
|
+
refute write_products_orders_customers.covers?(write_images_read_content)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def test_covers_is_falsy_for_sets_of_scopes_that_have_only_some_common_access
|
|
99
|
+
write_products_orders_customers = ShopifyAPI::ApiAccess.new(%w(write_products write_orders write_customers))
|
|
100
|
+
write_products_read_content = ShopifyAPI::ApiAccess.new(%w(write_products read_content))
|
|
101
|
+
|
|
102
|
+
refute write_products_orders_customers.covers?(write_products_read_content)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def test_duplicate_scopes_resolve_to_one_scope
|
|
106
|
+
read_orders_duplicated = ShopifyAPI::ApiAccess.new(%w(read_orders read_orders read_orders read_orders))
|
|
107
|
+
read_orders = ShopifyAPI::ApiAccess.new(%w(read_orders))
|
|
108
|
+
|
|
109
|
+
assert_equal read_orders, read_orders_duplicated
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def test_to_s_outputs_scopes_as_a_comma_separated_list_without_implied_read_scopes
|
|
113
|
+
serialized_read_products_write_orders = "read_products,write_orders"
|
|
114
|
+
read_products_write_orders = ShopifyAPI::ApiAccess.new(%w(read_products read_orders write_orders))
|
|
115
|
+
|
|
116
|
+
assert_equal read_products_write_orders.to_s, serialized_read_products_write_orders
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def test_to_a_outputs_scopes_as_an_array_of_strings_without_implied_read_scopes
|
|
120
|
+
serialized_read_products_write_orders = %w(write_orders read_products)
|
|
121
|
+
read_products_write_orders = ShopifyAPI::ApiAccess.new(%w(read_products read_orders write_orders))
|
|
122
|
+
|
|
123
|
+
assert_equal read_products_write_orders.to_a.sort, serialized_read_products_write_orders.sort
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def test_creating_scopes_removes_extra_whitespace_from_scope_name_and_blank_scope_names
|
|
127
|
+
deserialized_read_products_write_orders = ShopifyAPI::ApiAccess.new([' read_products', ' ', 'write_orders '])
|
|
128
|
+
serialized_read_products_write_orders = deserialized_read_products_write_orders.to_s
|
|
129
|
+
expected_read_products_write_orders = ShopifyAPI::ApiAccess.new(%w(read_products write_orders))
|
|
130
|
+
|
|
131
|
+
assert_equal expected_read_products_write_orders, ShopifyAPI::ApiAccess.new(serialized_read_products_write_orders)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def test_creating_scopes_from_a_string_works_with_a_comma_separated_list
|
|
135
|
+
deserialized_read_products_write_orders = ShopifyAPI::ApiAccess.new("read_products,write_orders")
|
|
136
|
+
serialized_read_products_write_orders = deserialized_read_products_write_orders.to_s
|
|
137
|
+
expected_read_products_write_orders = ShopifyAPI::ApiAccess.new(%w(read_products write_orders))
|
|
138
|
+
|
|
139
|
+
assert_equal expected_read_products_write_orders, ShopifyAPI::ApiAccess.new(serialized_read_products_write_orders)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def test_using_to_s_from_one_scopes_to_construct_another_will_be_equal
|
|
143
|
+
read_products_write_orders = ShopifyAPI::ApiAccess.new(%w(read_products write_orders))
|
|
144
|
+
|
|
145
|
+
assert_equal read_products_write_orders, ShopifyAPI::ApiAccess.new(read_products_write_orders.to_s)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def test_using_to_a_from_one_scopes_to_construct_another_will_be_equal
|
|
149
|
+
read_products_write_orders = ShopifyAPI::ApiAccess.new(%w(read_products write_orders))
|
|
150
|
+
|
|
151
|
+
assert_equal read_products_write_orders, ShopifyAPI::ApiAccess.new(read_products_write_orders.to_a)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'test_helper'
|
|
3
|
+
|
|
4
|
+
class ApiPermissionTest < Test::Unit::TestCase
|
|
5
|
+
test "revoke access token" do
|
|
6
|
+
fake "api_permissions/current", method: :delete, status: 200, body: "{}"
|
|
7
|
+
assert ShopifyAPI::ApiPermission.destroy
|
|
8
|
+
end
|
|
9
|
+
end
|