shopify_api 3.2.1 → 3.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +5 -0
- data/Gemfile.lock +3 -2
- data/lib/shopify_api/cli.rb +20 -19
- data/lib/shopify_api/session.rb +4 -1
- data/lib/shopify_api/version.rb +1 -1
- data/shopify_api.gemspec +4 -2
- data/test/checkouts_test.rb +9 -0
- data/test/cli_test.rb +24 -24
- data/test/fixtures/checkouts.json +186 -0
- data/test/fixtures/order.json +297 -0
- data/test/fixtures/orders.json +299 -0
- data/test/fixtures/script_tag.json +10 -0
- data/test/fixtures/script_tags.json +18 -0
- data/test/fixtures/webhook.json +10 -0
- data/test/fixtures/webhooks.json +18 -0
- data/test/order_test.rb +24 -40
- data/test/script_tag_test.rb +30 -0
- data/test/session_test.rb +4 -4
- data/test/webhook_test.rb +21 -0
- metadata +31 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b7258c4c1368bc212523e4f8454567e21d46737
|
4
|
+
data.tar.gz: 3ab24e5dba88ffb8172b7b4b9f9b72029fefe208
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3f0a8efebafd6e97a057c5e87de87a1fc81be1a587c4471c5c2129589d0ecbae0ba2b7398b5ecc6e6b4986e2cd1a2f9c85bbb090209e7438d7c31d42b885ab8
|
7
|
+
data.tar.gz: e38505ed41e9ae8bd00377483b57cf8a8b62dfff37eb218193cc620665309e978668193ede11b824cb2e7bf3bcbd820e85b4b5eb88a49539c6167eef7bb6e22e
|
data/CHANGELOG
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
shopify_api (3.2.
|
4
|
+
shopify_api (3.2.2)
|
5
5
|
activeresource (>= 3.0.0)
|
6
|
-
thor (
|
6
|
+
thor (~> 0.18.1)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
@@ -44,6 +44,7 @@ PLATFORMS
|
|
44
44
|
DEPENDENCIES
|
45
45
|
activeresource (~> 4.0.0)
|
46
46
|
fakeweb
|
47
|
+
minitest (~> 4.0)
|
47
48
|
mocha (>= 0.9.8)
|
48
49
|
rake
|
49
50
|
shopify_api!
|
data/lib/shopify_api/cli.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
require 'thor'
|
2
2
|
require 'abbrev'
|
3
|
+
require 'yaml'
|
3
4
|
|
4
5
|
module ShopifyAPI
|
5
6
|
class Cli < Thor
|
6
7
|
include Thor::Actions
|
7
|
-
|
8
|
+
|
8
9
|
class ConfigFileError < StandardError
|
9
10
|
end
|
10
11
|
|
@@ -15,7 +16,7 @@ module ShopifyAPI
|
|
15
16
|
puts prefix + c
|
16
17
|
end
|
17
18
|
end
|
18
|
-
|
19
|
+
|
19
20
|
desc "add CONNECTION", "create a config file for a connection named CONNECTION"
|
20
21
|
def add(connection)
|
21
22
|
file = config_file(connection)
|
@@ -35,7 +36,7 @@ module ShopifyAPI
|
|
35
36
|
default(connection)
|
36
37
|
end
|
37
38
|
end
|
38
|
-
|
39
|
+
|
39
40
|
desc "remove CONNECTION", "remove the config file for CONNECTION"
|
40
41
|
def remove(connection)
|
41
42
|
file = config_file(connection)
|
@@ -46,7 +47,7 @@ module ShopifyAPI
|
|
46
47
|
no_config_file_error(file)
|
47
48
|
end
|
48
49
|
end
|
49
|
-
|
50
|
+
|
50
51
|
desc "edit [CONNECTION]", "open the config file for CONNECTION with your default editor"
|
51
52
|
def edit(connection=nil)
|
52
53
|
file = config_file(connection)
|
@@ -60,7 +61,7 @@ module ShopifyAPI
|
|
60
61
|
no_config_file_error(file)
|
61
62
|
end
|
62
63
|
end
|
63
|
-
|
64
|
+
|
64
65
|
desc "show [CONNECTION]", "output the location and contents of the CONNECTION's config file"
|
65
66
|
def show(connection=nil)
|
66
67
|
connection ||= default_connection
|
@@ -72,7 +73,7 @@ module ShopifyAPI
|
|
72
73
|
no_config_file_error(file)
|
73
74
|
end
|
74
75
|
end
|
75
|
-
|
76
|
+
|
76
77
|
desc "default [CONNECTION]", "show the default connection, or make CONNECTION the default"
|
77
78
|
def default(connection=nil)
|
78
79
|
if connection
|
@@ -90,15 +91,15 @@ module ShopifyAPI
|
|
90
91
|
puts "There is no default connection set"
|
91
92
|
end
|
92
93
|
end
|
93
|
-
|
94
|
+
|
94
95
|
desc "console [CONNECTION]", "start an API console for CONNECTION"
|
95
96
|
def console(connection=nil)
|
96
97
|
file = config_file(connection)
|
97
|
-
|
98
|
+
|
98
99
|
config = YAML.load(File.read(file))
|
99
100
|
puts "using #{config['domain']}"
|
100
101
|
ShopifyAPI::Base.site = site_from_config(config)
|
101
|
-
|
102
|
+
|
102
103
|
require 'irb'
|
103
104
|
require 'irb/completion'
|
104
105
|
ARGV.clear
|
@@ -110,15 +111,15 @@ module ShopifyAPI
|
|
110
111
|
end
|
111
112
|
|
112
113
|
private
|
113
|
-
|
114
|
+
|
114
115
|
def shop_config_dir
|
115
116
|
@shop_config_dir ||= File.join(ENV['HOME'], '.shopify', 'shops')
|
116
117
|
end
|
117
|
-
|
118
|
+
|
118
119
|
def default_symlink
|
119
120
|
@default_symlink ||= File.join(shop_config_dir, 'default')
|
120
121
|
end
|
121
|
-
|
122
|
+
|
122
123
|
def config_file(connection)
|
123
124
|
if connection
|
124
125
|
File.join(shop_config_dir, "#{connection}.yml")
|
@@ -126,35 +127,35 @@ module ShopifyAPI
|
|
126
127
|
default_symlink
|
127
128
|
end
|
128
129
|
end
|
129
|
-
|
130
|
+
|
130
131
|
def site_from_config(config)
|
131
132
|
protocol = config['protocol'] || 'https'
|
132
133
|
api_key = config['api_key']
|
133
134
|
password = config['password']
|
134
135
|
domain = config['domain']
|
135
|
-
|
136
|
+
|
136
137
|
ShopifyAPI::Base.site = "#{protocol}://#{api_key}:#{password}@#{domain}/admin"
|
137
138
|
end
|
138
|
-
|
139
|
+
|
139
140
|
def available_connections
|
140
141
|
@available_connections ||= begin
|
141
142
|
pattern = File.join(shop_config_dir, "*.yml")
|
142
143
|
Dir.glob(pattern).map { |f| File.basename(f, ".yml") }
|
143
144
|
end
|
144
145
|
end
|
145
|
-
|
146
|
+
|
146
147
|
def default_connection_target
|
147
148
|
@default_connection_target ||= File.readlink(default_symlink)
|
148
149
|
end
|
149
|
-
|
150
|
+
|
150
151
|
def default_connection
|
151
152
|
@default_connection ||= File.basename(default_connection_target, ".yml")
|
152
153
|
end
|
153
|
-
|
154
|
+
|
154
155
|
def default?(connection)
|
155
156
|
default_connection == connection
|
156
157
|
end
|
157
|
-
|
158
|
+
|
158
159
|
def no_config_file_error(filename)
|
159
160
|
raise ConfigFileError, "There is no config file at #{filename}"
|
160
161
|
end
|
data/lib/shopify_api/session.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
|
2
2
|
module ShopifyAPI
|
3
3
|
|
4
|
+
class ValidationException < StandardError
|
5
|
+
end
|
6
|
+
|
4
7
|
class Session
|
5
8
|
cattr_accessor :api_key
|
6
9
|
cattr_accessor :secret
|
@@ -74,7 +77,7 @@ module ShopifyAPI
|
|
74
77
|
return token if token
|
75
78
|
|
76
79
|
unless self.class.validate_signature(params) && params[:timestamp].to_i > 24.hours.ago.utc.to_i
|
77
|
-
raise "Invalid Signature: Possible malicious login"
|
80
|
+
raise ShopifyAPI::ValidationException, "Invalid Signature: Possible malicious login"
|
78
81
|
end
|
79
82
|
|
80
83
|
code = params['code']
|
data/lib/shopify_api/version.rb
CHANGED
data/shopify_api.gemspec
CHANGED
@@ -25,15 +25,17 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.license = 'MIT'
|
26
26
|
|
27
27
|
s.add_dependency("activeresource", [">= 3.0.0"])
|
28
|
-
s.add_dependency("thor", ["
|
29
|
-
|
28
|
+
s.add_dependency("thor", ["~> 0.18.1"])
|
29
|
+
|
30
30
|
if s.respond_to?(:add_development_dependency)
|
31
31
|
s.add_development_dependency("mocha", ">= 0.9.8")
|
32
32
|
s.add_development_dependency("fakeweb")
|
33
|
+
s.add_development_dependency("minitest", "~> 4.0")
|
33
34
|
s.add_development_dependency("rake")
|
34
35
|
else
|
35
36
|
s.add_dependency("mocha", ">= 0.9.8")
|
36
37
|
s.add_dependency("fakeweb")
|
38
|
+
s.add_dependency("minitest", "~> 4.0")
|
37
39
|
s.add_dependency("rake")
|
38
40
|
end
|
39
41
|
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class CheckoutsTest < Test::Unit::TestCase
|
4
|
+
test "get all should get all orders" do
|
5
|
+
fake 'checkouts', :method => :get, :status => 200, :body => load_fixture('checkouts')
|
6
|
+
checkout = ShopifyAPI::Checkout.all
|
7
|
+
assert_equal 450789469, checkout.first.id
|
8
|
+
end
|
9
|
+
end
|
data/test/cli_test.rb
CHANGED
@@ -10,7 +10,7 @@ class CliTest < Test::Unit::TestCase
|
|
10
10
|
`rm -rf #{@test_home}`
|
11
11
|
ENV['HOME'] = @test_home
|
12
12
|
@cli = ShopifyAPI::Cli.new
|
13
|
-
|
13
|
+
|
14
14
|
FileUtils.mkdir_p(@shop_config_dir)
|
15
15
|
File.open(config_file('foo'), 'w') do |file|
|
16
16
|
file.puts valid_options.merge('domain' => 'foo.myshopify.com').to_yaml
|
@@ -20,11 +20,11 @@ class CliTest < Test::Unit::TestCase
|
|
20
20
|
file.puts valid_options.merge('domain' => 'bar.myshopify.com').to_yaml
|
21
21
|
end
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def teardown
|
25
25
|
`rm -rf #{@test_home}`
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
test "add with blank domain" do
|
29
29
|
`rm -rf #{@shop_config_dir}/*`
|
30
30
|
$stdout.expects(:print).with("Domain? (leave blank for foo.myshopify.com) ")
|
@@ -33,9 +33,9 @@ class CliTest < Test::Unit::TestCase
|
|
33
33
|
$stdin.expects(:gets).times(3).returns("", "key", "pass")
|
34
34
|
@cli.expects(:puts).with("\nopen https://foo.myshopify.com/admin/api in your browser to get API credentials\n")
|
35
35
|
@cli.expects(:puts).with("Default connection is foo")
|
36
|
-
|
36
|
+
|
37
37
|
@cli.add('foo')
|
38
|
-
|
38
|
+
|
39
39
|
config = YAML.load(File.read(config_file('foo')))
|
40
40
|
assert_equal 'foo.myshopify.com', config['domain']
|
41
41
|
assert_equal 'key', config['api_key']
|
@@ -43,7 +43,7 @@ class CliTest < Test::Unit::TestCase
|
|
43
43
|
assert_equal 'https', config['protocol']
|
44
44
|
assert_equal config_file('foo'), File.readlink(@default_symlink)
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
test "add with explicit domain" do
|
48
48
|
`rm -rf #{@shop_config_dir}/*`
|
49
49
|
$stdout.expects(:print).with("Domain? (leave blank for foo.myshopify.com) ")
|
@@ -52,58 +52,58 @@ class CliTest < Test::Unit::TestCase
|
|
52
52
|
$stdin.expects(:gets).times(3).returns("bar.myshopify.com", "key", "pass")
|
53
53
|
@cli.expects(:puts).with("\nopen https://bar.myshopify.com/admin/api in your browser to get API credentials\n")
|
54
54
|
@cli.expects(:puts).with("Default connection is foo")
|
55
|
-
|
55
|
+
|
56
56
|
@cli.add('foo')
|
57
|
-
|
57
|
+
|
58
58
|
config = YAML.load(File.read(config_file('foo')))
|
59
59
|
assert_equal 'bar.myshopify.com', config['domain']
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
test "list" do
|
63
63
|
@cli.expects(:puts).with(" bar")
|
64
64
|
@cli.expects(:puts).with(" * foo")
|
65
|
-
|
65
|
+
|
66
66
|
@cli.list
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
test "show default" do
|
70
70
|
@cli.expects(:puts).with("Default connection is foo")
|
71
|
-
|
71
|
+
|
72
72
|
@cli.default
|
73
73
|
end
|
74
|
-
|
74
|
+
|
75
75
|
test "set default" do
|
76
76
|
@cli.expects(:puts).with("Default connection is bar")
|
77
|
-
|
77
|
+
|
78
78
|
@cli.default('bar')
|
79
|
-
|
79
|
+
|
80
80
|
assert_equal config_file('bar'), File.readlink(@default_symlink)
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
test "remove default connection" do
|
84
84
|
@cli.remove('foo')
|
85
|
-
|
85
|
+
|
86
86
|
assert !File.exist?(@default_symlink)
|
87
87
|
assert !File.exist?(config_file('foo'))
|
88
88
|
assert File.exist?(config_file('bar'))
|
89
89
|
end
|
90
|
-
|
90
|
+
|
91
91
|
test "remove non-default connection" do
|
92
92
|
@cli.remove('bar')
|
93
|
-
|
93
|
+
|
94
94
|
assert_equal config_file('foo'), File.readlink(@default_symlink)
|
95
95
|
assert File.exist?(config_file('foo'))
|
96
96
|
assert !File.exist?(config_file('bar'))
|
97
97
|
end
|
98
|
-
|
98
|
+
|
99
99
|
private
|
100
|
-
|
100
|
+
|
101
101
|
def valid_options
|
102
102
|
{'domain' => 'snowdevil.myshopify.com', 'api_key' => 'key', 'password' => 'pass', 'protocol' => 'https'}
|
103
103
|
end
|
104
|
-
|
104
|
+
|
105
105
|
def config_file(connection)
|
106
106
|
File.join(@shop_config_dir, "#{connection}.yml")
|
107
107
|
end
|
108
|
-
|
109
|
-
end
|
108
|
+
|
109
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
{
|
2
|
+
"checkouts": [
|
3
|
+
{
|
4
|
+
"buyer_accepts_marketing": false,
|
5
|
+
"cart_token": "68778783ad298f1c80c3bafcddeea02f",
|
6
|
+
"closed_at": null,
|
7
|
+
"completed_at": null,
|
8
|
+
"created_at": "2012-10-12T07:05:27-04:00",
|
9
|
+
"currency": "USD",
|
10
|
+
"email": "bob.norman@hostmail.com",
|
11
|
+
"gateway": null,
|
12
|
+
"id": 450789469,
|
13
|
+
"landing_site": null,
|
14
|
+
"note": null,
|
15
|
+
"referring_site": null,
|
16
|
+
"shipping_lines": [
|
17
|
+
{
|
18
|
+
"title": "Free Shipping",
|
19
|
+
"price": "0.00",
|
20
|
+
"code": "Free Shipping",
|
21
|
+
"source": "shopify"
|
22
|
+
}
|
23
|
+
],
|
24
|
+
"source": null,
|
25
|
+
"source_identifier": null,
|
26
|
+
"source_name": "web",
|
27
|
+
"source_url": null,
|
28
|
+
"subtotal_price": "398.00",
|
29
|
+
"taxes_included": false,
|
30
|
+
"token": "2a1ace52255252df566af0faaedfbfa7",
|
31
|
+
"total_discounts": "0.00",
|
32
|
+
"total_line_items_price": "398.00",
|
33
|
+
"total_price": "409.94",
|
34
|
+
"total_tax": "11.94",
|
35
|
+
"total_weight": 400,
|
36
|
+
"updated_at": "2012-10-12T07:05:27-04:00",
|
37
|
+
"line_items": [
|
38
|
+
{
|
39
|
+
"applied_discounts": [
|
40
|
+
|
41
|
+
],
|
42
|
+
"compare_at_price": null,
|
43
|
+
"fulfillment_service": "manual",
|
44
|
+
"gift_card": false,
|
45
|
+
"grams": 200,
|
46
|
+
"id": 49148385,
|
47
|
+
"line_price": "199.00",
|
48
|
+
"price": "199.00",
|
49
|
+
"product_id": 632910392,
|
50
|
+
"properties": null,
|
51
|
+
"quantity": 1,
|
52
|
+
"requires_shipping": true,
|
53
|
+
"sku": "IPOD2008RED",
|
54
|
+
"tax_lines": [
|
55
|
+
|
56
|
+
],
|
57
|
+
"taxable": true,
|
58
|
+
"title": "IPod Nano - 8GB",
|
59
|
+
"variant_id": 49148385,
|
60
|
+
"variant_title": "Red",
|
61
|
+
"vendor": "Apple"
|
62
|
+
},
|
63
|
+
{
|
64
|
+
"applied_discounts": [
|
65
|
+
|
66
|
+
],
|
67
|
+
"compare_at_price": null,
|
68
|
+
"fulfillment_service": "manual",
|
69
|
+
"gift_card": false,
|
70
|
+
"grams": 200,
|
71
|
+
"id": 808950810,
|
72
|
+
"line_price": "199.00",
|
73
|
+
"price": "199.00",
|
74
|
+
"product_id": 632910392,
|
75
|
+
"properties": null,
|
76
|
+
"quantity": 1,
|
77
|
+
"requires_shipping": true,
|
78
|
+
"sku": "IPOD2008PINK",
|
79
|
+
"tax_lines": [
|
80
|
+
|
81
|
+
],
|
82
|
+
"taxable": true,
|
83
|
+
"title": "IPod Nano - 8GB",
|
84
|
+
"variant_id": 808950810,
|
85
|
+
"variant_title": "Pink",
|
86
|
+
"vendor": "Apple"
|
87
|
+
}
|
88
|
+
],
|
89
|
+
"name": "#450789469",
|
90
|
+
"note_attributes": [
|
91
|
+
{
|
92
|
+
"name": "custom engraving",
|
93
|
+
"value": "Happy Birthday"
|
94
|
+
},
|
95
|
+
{
|
96
|
+
"name": "colour",
|
97
|
+
"value": "green"
|
98
|
+
}
|
99
|
+
],
|
100
|
+
"discount_codes": [
|
101
|
+
{
|
102
|
+
"code": "TENOFF",
|
103
|
+
"amount": "10.00"
|
104
|
+
}
|
105
|
+
],
|
106
|
+
"abandoned_checkout_url": "https://checkout.local/orders/690933842/2a1ace52255252df566af0faaedfbfa7?recovered=1",
|
107
|
+
"tax_lines": [
|
108
|
+
{
|
109
|
+
"price": "11.94",
|
110
|
+
"rate": 0.06,
|
111
|
+
"title": "State Tax"
|
112
|
+
}
|
113
|
+
],
|
114
|
+
"billing_address": {
|
115
|
+
"address1": "Chestnut Street 92",
|
116
|
+
"address2": "",
|
117
|
+
"city": "Louisville",
|
118
|
+
"company": null,
|
119
|
+
"country": "United States",
|
120
|
+
"first_name": "Bob",
|
121
|
+
"last_name": "Norman",
|
122
|
+
"latitude": "45.41634",
|
123
|
+
"longitude": "-75.6868",
|
124
|
+
"phone": "555-625-1199",
|
125
|
+
"province": "Kentucky",
|
126
|
+
"zip": "40202",
|
127
|
+
"name": "Bob Norman",
|
128
|
+
"country_code": "US",
|
129
|
+
"province_code": "KY"
|
130
|
+
},
|
131
|
+
"shipping_address": {
|
132
|
+
"address1": "Chestnut Street 92",
|
133
|
+
"address2": "",
|
134
|
+
"city": "Louisville",
|
135
|
+
"company": null,
|
136
|
+
"country": "United States",
|
137
|
+
"first_name": "Bob",
|
138
|
+
"last_name": "Norman",
|
139
|
+
"latitude": "45.41634",
|
140
|
+
"longitude": "-75.6868",
|
141
|
+
"phone": "555-625-1199",
|
142
|
+
"province": "Kentucky",
|
143
|
+
"zip": "40202",
|
144
|
+
"name": "Bob Norman",
|
145
|
+
"country_code": "US",
|
146
|
+
"province_code": "KY"
|
147
|
+
},
|
148
|
+
"customer": {
|
149
|
+
"accepts_marketing": false,
|
150
|
+
"created_at": "2014-03-07T16:12:37-05:00",
|
151
|
+
"email": "bob.norman@hostmail.com",
|
152
|
+
"first_name": "Bob",
|
153
|
+
"id": 207119551,
|
154
|
+
"last_name": "Norman",
|
155
|
+
"last_order_id": null,
|
156
|
+
"multipass_identifier": null,
|
157
|
+
"note": null,
|
158
|
+
"orders_count": 0,
|
159
|
+
"state": "disabled",
|
160
|
+
"total_spent": "0.00",
|
161
|
+
"updated_at": "2014-03-07T16:12:37-05:00",
|
162
|
+
"verified_email": true,
|
163
|
+
"tags": "",
|
164
|
+
"last_order_name": null,
|
165
|
+
"default_address": {
|
166
|
+
"address1": "Chestnut Street 92",
|
167
|
+
"address2": "",
|
168
|
+
"city": "Louisville",
|
169
|
+
"company": null,
|
170
|
+
"country": "United States",
|
171
|
+
"first_name": null,
|
172
|
+
"id": 207119551,
|
173
|
+
"last_name": null,
|
174
|
+
"phone": "555-625-1199",
|
175
|
+
"province": "Kentucky",
|
176
|
+
"zip": "40202",
|
177
|
+
"name": null,
|
178
|
+
"province_code": "KY",
|
179
|
+
"country_code": "US",
|
180
|
+
"country_name": "United States",
|
181
|
+
"default": true
|
182
|
+
}
|
183
|
+
}
|
184
|
+
}
|
185
|
+
]
|
186
|
+
}
|