etsy 0.3.0 → 0.3.1
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 +4 -4
- data/.travis.yml +1 -2
- data/README.md +49 -6
- data/lib/etsy.rb +1 -0
- data/lib/etsy/image.rb +2 -2
- data/lib/etsy/listing.rb +61 -4
- data/lib/etsy/receipt.rb +3 -3
- data/lib/etsy/secure_client.rb +1 -1
- data/lib/etsy/variation/property_set.rb +71 -0
- data/lib/etsy/version.rb +1 -1
- data/test/fixtures/receipt/findAllShopReceipts.json +4 -4
- data/test/unit/etsy/image_test.rb +11 -3
- data/test/unit/etsy/listing_test.rb +31 -5
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd7112229ce87257b5ea66ca6eddafe82d07bacc
|
4
|
+
data.tar.gz: e8f34ab7f54ee0675a26d387c77b337ca10ec2db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad057b670ae67786f6c4093218dfb615ede31d5c005b8e19c753f3a776fcb1b77e0cf3e1dbf5f7227ad303ab6320ae7d5c4d014be48684d2c8490279e1992a73
|
7
|
+
data.tar.gz: 50108ef28fcd663125db0787a1127d6a5ee8587f5b1c35cf7aee4776f6f503fb2995af90a595d8f1577b8a4e228c02c06adce626e45fa468629f49c395423f1c
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -26,6 +26,32 @@ It will likely work with higher versions, but this is unproven.
|
|
26
26
|
|
27
27
|
## Usage
|
28
28
|
|
29
|
+
In order to try this out you'll need to create an app on [etsy.com/your/apps](https://www.etsy.com/your/apps).
|
30
|
+
|
31
|
+
This will give you an api key and secret.
|
32
|
+
|
33
|
+
Paste the following into IRB, replacing the api key and secret with the ones you got on Etsy:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
require 'etsy'
|
37
|
+
Etsy.protocol = "https"
|
38
|
+
Etsy.api_key = 'YOUR API KEY'
|
39
|
+
Etsy.api_secret = 'YOUR SECRET'
|
40
|
+
request = Etsy.request_token
|
41
|
+
Etsy.verification_url
|
42
|
+
```
|
43
|
+
|
44
|
+
Paste the verification URL into your browser, and authorize the application. That will give you a page
|
45
|
+
with a code on it. Paste the following into IRB, replacing the code:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
access = Etsy.access_token(request.token, request.secret, 'CODE')
|
49
|
+
Etsy.myself(access.token, access.secret)
|
50
|
+
```
|
51
|
+
|
52
|
+
If you've received a 401 unauthorized error, then you likely don't have a valid api key and secret, or
|
53
|
+
perhaps the verification url timed out.
|
54
|
+
|
29
55
|
### Public Mode
|
30
56
|
|
31
57
|
The Etsy API has two modes: public, and authenticated. Public mode only requires an
|
@@ -67,6 +93,11 @@ Authenticated calls can now be made by passing an access token and secret:
|
|
67
93
|
|
68
94
|
Etsy.myself(access.token, access.secret)
|
69
95
|
|
96
|
+
The key and secret have to be passed in for the authenticated calls.
|
97
|
+
|
98
|
+
auth = {:access_token=>access.token, :access_secret=>access.secret}
|
99
|
+
Etsy::Transaction.find_all_by_shop_id(shop_id, auth.merge(options))
|
100
|
+
|
70
101
|
### Web Application
|
71
102
|
|
72
103
|
The process for authenticating via a web application is similar, but requires the configuration of a callback URL:
|
@@ -278,16 +309,28 @@ I ask that you not submit patches that include changes to the version or gemspec
|
|
278
309
|
These people have helped make the Etsy gem what it is today:
|
279
310
|
|
280
311
|
* [Patrick Reagan](https://github.com/reagent)
|
281
|
-
* [Katrina Owen](
|
312
|
+
* [Katrina Owen](https://github.com/kytrinyx)
|
313
|
+
* [Trae Robrock](https://github.com/trobrock)
|
314
|
+
* [Roger Smith](https://github.com/rogsmith)
|
315
|
+
* [Jimmy Tang](https://github.com/jimmytang)
|
282
316
|
* [Mak Nazečić-Andrlon](https://github.com/Muon)
|
317
|
+
* [Daniel Szmulewicz](https://github.com/danielsz)
|
283
318
|
* [Patrick Schless](https://github.com/plainlystated)
|
319
|
+
* [Martin Popelak](https://github.com/pupca)
|
320
|
+
* [Julio Santos](https://github.com/julio)
|
284
321
|
* [Matt Fields](https://github.com/mfields106)
|
322
|
+
* [Mike Taylor](https://github.com/sealabcore)
|
323
|
+
* [Mason Stewart](https://github.com/masondesu)
|
324
|
+
* [Sasha Gerrand](https://github.com/sgerrand)
|
285
325
|
* [Jake Boxer](https://github.com/jakeboxer)
|
286
|
-
* [
|
287
|
-
* [
|
288
|
-
* [
|
289
|
-
* [
|
290
|
-
* [
|
326
|
+
* [Sunwoo Yang](https://github.com/sunwooz)
|
327
|
+
* [Isaac Rosenberg](https://github.com/irosenb)
|
328
|
+
* [Carson Gross](https://github.com/carsongross)
|
329
|
+
* [John Amicangelo](https://github.com/JohnAmican)
|
330
|
+
* [Max Gulyaev](https://github.com/maxilev)
|
331
|
+
* [fbehrens](https://github.com/fbehrens)
|
332
|
+
* [William Jeffries](https://github.com/williamcodes)
|
333
|
+
* [Jack Guoyuan Zhao](https://github.com/zhaoguoyuan)
|
291
334
|
|
292
335
|
### Github Flow
|
293
336
|
|
data/lib/etsy.rb
CHANGED
data/lib/etsy/image.rb
CHANGED
@@ -21,8 +21,8 @@ module Etsy
|
|
21
21
|
|
22
22
|
# Fetch all images for a given listing.
|
23
23
|
#
|
24
|
-
def self.find_all_by_listing_id(listing_id)
|
25
|
-
get_all("/listings/#{listing_id}/images")
|
24
|
+
def self.find_all_by_listing_id(listing_id, options = {})
|
25
|
+
get_all("/listings/#{listing_id}/images", options)
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.create(listing, image_path, options = {})
|
data/lib/etsy/listing.rb
CHANGED
@@ -33,7 +33,7 @@ module Etsy
|
|
33
33
|
include Etsy::Model
|
34
34
|
|
35
35
|
STATES = %w(active removed sold_out expired alchemy)
|
36
|
-
VALID_STATES = [:active, :expired, :inactive, :sold, :featured]
|
36
|
+
VALID_STATES = [:active, :expired, :inactive, :sold, :featured, :draft, :sold_out]
|
37
37
|
|
38
38
|
attribute :id, :from => :listing_id
|
39
39
|
attribute :view_count, :from => :views
|
@@ -44,7 +44,8 @@ module Etsy
|
|
44
44
|
|
45
45
|
attributes :title, :description, :state, :url, :price, :quantity,
|
46
46
|
:tags, :materials, :hue, :saturation, :brightness, :is_black_and_white,
|
47
|
-
:featured_rank, :occasion, :num_favorers, :user_id
|
47
|
+
:featured_rank, :occasion, :num_favorers, :user_id,
|
48
|
+
:shipping_template_id, :who_made, :when_made
|
48
49
|
|
49
50
|
association :image, :from => 'Images'
|
50
51
|
|
@@ -79,7 +80,7 @@ module Etsy
|
|
79
80
|
# By default, pulls back the first 25 active listings.
|
80
81
|
# Defaults can be overridden using :limit, :offset, and :state
|
81
82
|
#
|
82
|
-
# Available states are :active, :expired, :inactive, :sold, and :featured
|
83
|
+
# Available states are :active, :expired, :inactive, :sold, and :featured, :draft, :sold_out
|
83
84
|
# where :featured is a subset of the others.
|
84
85
|
#
|
85
86
|
# options = {
|
@@ -123,7 +124,7 @@ module Etsy
|
|
123
124
|
# The collection of images associated with this listing.
|
124
125
|
#
|
125
126
|
def images
|
126
|
-
@images ||= Image.find_all_by_listing_id(id)
|
127
|
+
@images ||= Image.find_all_by_listing_id(id, oauth)
|
127
128
|
end
|
128
129
|
|
129
130
|
# The primary image for this listing.
|
@@ -132,6 +133,53 @@ module Etsy
|
|
132
133
|
images.first
|
133
134
|
end
|
134
135
|
|
136
|
+
def variations
|
137
|
+
self.class.get_all("/listings/#{id}/variations")
|
138
|
+
end
|
139
|
+
|
140
|
+
# If these are your desired variations:
|
141
|
+
# - Dimensions: 1 x 2 inches
|
142
|
+
# - Dimensions: 2 x 4 inches
|
143
|
+
#
|
144
|
+
# Then you first have to find the property ID of the property you want to vary. Eg:
|
145
|
+
# Etsy::Variation::PropertySet.find_property_by_name("Dimensions").fetch("property_id")
|
146
|
+
#
|
147
|
+
# Then you can decide which options you want to set for this property.
|
148
|
+
# Eg:
|
149
|
+
# Etsy::Variation::PropertySet.qualifying_properties_for_property("Dimension")
|
150
|
+
# => [{
|
151
|
+
# "param"=>"dimensions_scale",
|
152
|
+
# "description"=>"Sizing Scale",
|
153
|
+
# "options"=>{
|
154
|
+
# "Inches" => 344,
|
155
|
+
# "Centimeters" => 345,
|
156
|
+
# "Other" => 346
|
157
|
+
# }
|
158
|
+
# }]
|
159
|
+
#
|
160
|
+
# Put it all together for a call to add_variations:
|
161
|
+
|
162
|
+
# property_id = Etsy::Variation::PropertySet.find_property_by_name("Dimensions").fetch("property_id")
|
163
|
+
# scale = Etsy::Variation::PropertySet.qualifying_properties_for_property("Dimensions").detect {|qp| qp.fetch("description") == "Sizing Scale"}
|
164
|
+
# my_listing.add_variations(
|
165
|
+
# :variations => [
|
166
|
+
# {"property_id" => property_id, "value" => "1 x 2", "is_available" => true, "price" => 1.23},
|
167
|
+
# {"property_id" => property_id, "value" => "2 x 4", "is_available" => true, "price" => 2.34}
|
168
|
+
# ],
|
169
|
+
# scale.fetch("param") => scale.fetch("options").fetch("Inches")
|
170
|
+
# )
|
171
|
+
def add_variations(options)
|
172
|
+
options[:variations] = JSON.dump(options.delete(:variations))
|
173
|
+
options[:require_secure] = true
|
174
|
+
self.class.post("/listings/#{id}/variations", options)
|
175
|
+
end
|
176
|
+
|
177
|
+
def update_variations(options)
|
178
|
+
options[:variations] = JSON.dump(options.delete(:variations))
|
179
|
+
options[:require_secure] = true
|
180
|
+
self.class.put("/listings/#{id}/variations", options)
|
181
|
+
end
|
182
|
+
|
135
183
|
def black_and_white?
|
136
184
|
is_black_and_white
|
137
185
|
end
|
@@ -169,6 +217,10 @@ module Etsy
|
|
169
217
|
(user_ids.size > 0) ? Array(Etsy::User.find(user_ids, options)) : []
|
170
218
|
end
|
171
219
|
|
220
|
+
def is_supply
|
221
|
+
!!@result.fetch("is_supply")
|
222
|
+
end
|
223
|
+
|
172
224
|
private
|
173
225
|
|
174
226
|
def self.valid?(state)
|
@@ -209,5 +261,10 @@ module Etsy
|
|
209
261
|
(listing_ids.size > 0) ? Array(find(listing_ids, options)) : []
|
210
262
|
end
|
211
263
|
|
264
|
+
private
|
265
|
+
|
266
|
+
def oauth
|
267
|
+
oauth = (token && secret) ? {:access_token => token, :access_secret => secret} : {}
|
268
|
+
end
|
212
269
|
end
|
213
270
|
end
|
data/lib/etsy/receipt.rb
CHANGED
@@ -6,14 +6,14 @@ module Etsy
|
|
6
6
|
attribute :buyer_id, :from => :buyer_user_id
|
7
7
|
|
8
8
|
attributes :quantity, :listing_id, :name, :first_line, :second_line, :city, :state, :zip, :country_id,
|
9
|
-
:payment_email, :buyer_email, :
|
9
|
+
:payment_email, :buyer_email, :creation_tsz
|
10
10
|
|
11
11
|
def self.find_all_by_shop_id(shop_id, options = {})
|
12
12
|
get_all("/shops/#{shop_id}/receipts", options)
|
13
13
|
end
|
14
14
|
|
15
15
|
def created_at
|
16
|
-
Time.at(
|
16
|
+
Time.at(creation_tsz)
|
17
17
|
end
|
18
18
|
|
19
19
|
def buyer
|
@@ -21,4 +21,4 @@ module Etsy
|
|
21
21
|
end
|
22
22
|
|
23
23
|
end
|
24
|
-
end
|
24
|
+
end
|
data/lib/etsy/secure_client.rb
CHANGED
@@ -107,7 +107,7 @@ module Etsy
|
|
107
107
|
if value.respond_to?(:read)
|
108
108
|
body << "Content-Disposition: form-data; name=\"#{esc_key}\"; filename=\"#{File.basename(value.path)}\"#{crlf}"
|
109
109
|
body << "Content-Type: image/jpeg#{crlf*2}"
|
110
|
-
body << value.read
|
110
|
+
body << open(value.path, "rb") {|io| io.read}
|
111
111
|
else
|
112
112
|
body << "Content-Disposition: form-data; name=\"#{esc_key}\"#{crlf*2}#{value}"
|
113
113
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Etsy
|
2
|
+
module Variation
|
3
|
+
class PropertySet
|
4
|
+
# Used to find properties which the seller can vary (eg Size, Color, etc), and options associated with those properties (eg Inches)
|
5
|
+
#
|
6
|
+
# The variations stuff is complex. See https://www.etsy.com/developers/documentation/getting_started/variations for more info.
|
7
|
+
#
|
8
|
+
# Probably the most useful method here is qualifying_properties_for_property. This method pulls in data from a few sources to get
|
9
|
+
# you everything you need to set up your variation options.
|
10
|
+
#
|
11
|
+
# Eg: I want to have a few Length options on my listings, and I want to use the unit Inches, then:
|
12
|
+
# Etsy::Variation::PropertySet.qualifying_properties_for_property("Length")
|
13
|
+
# => [{
|
14
|
+
# "param"=>"sizing_scale",
|
15
|
+
# "description"=>"Sizing Scale",
|
16
|
+
# "options"=>{
|
17
|
+
# "Alpha" => 301,
|
18
|
+
# "Inches" => 327,
|
19
|
+
# "Centimeters" => 328,
|
20
|
+
# "Fluid Ounces" => 335,
|
21
|
+
# "Millilitres" => 336,
|
22
|
+
# "Litres" => 337,
|
23
|
+
# "Other => 329
|
24
|
+
# }
|
25
|
+
# }]
|
26
|
+
#
|
27
|
+
# This tells me I want to set the parameter sizing_scale to 327 when calling Etsy::Listing.add_variations.
|
28
|
+
|
29
|
+
include Etsy::Model
|
30
|
+
|
31
|
+
|
32
|
+
attributes :properties, :category_id, :options, :qualifiers,
|
33
|
+
:qualifying_properties
|
34
|
+
|
35
|
+
def self.all
|
36
|
+
@all ||= get("/property_sets")
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.find_property_by_name(name)
|
40
|
+
property = all.properties.detect {|prop_id, prop| prop["name"] == name}
|
41
|
+
if property
|
42
|
+
property_id, property_data = property
|
43
|
+
property_data
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.qualifying_properties_for_property(name)
|
48
|
+
property = find_property_by_name(name)
|
49
|
+
return nil unless property
|
50
|
+
property_id = property["property_id"]
|
51
|
+
|
52
|
+
qualifiers = all.qualifiers[property_id.to_s]
|
53
|
+
return [] unless qualifiers
|
54
|
+
|
55
|
+
qualifiers.map do |qualifier|
|
56
|
+
qualifying_properties = all.qualifying_properties[qualifier.fetch("property_id").to_s]
|
57
|
+
options = qualifier.fetch("options").inject({}) do |acc, opt_id|
|
58
|
+
acc.merge({
|
59
|
+
all.options.fetch(opt_id.to_s) => opt_id
|
60
|
+
})
|
61
|
+
end
|
62
|
+
{
|
63
|
+
"param" => qualifying_properties.fetch("param"),
|
64
|
+
"description" => qualifying_properties.fetch("description"),
|
65
|
+
"options" => options
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/etsy/version.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
{
|
1
|
+
{
|
2
2
|
"count":1,
|
3
3
|
"results":
|
4
4
|
[
|
5
5
|
{
|
6
6
|
"receipt_id":27230877,
|
7
7
|
"buyer_user_id":12345,
|
8
|
-
"
|
8
|
+
"creation_tsz":1412206858,
|
9
9
|
"quantity":5,
|
10
10
|
"listing_id":123456,
|
11
11
|
"name":"Mike Taylor",
|
@@ -19,10 +19,10 @@
|
|
19
19
|
"buyer_email":"bar@example.com"
|
20
20
|
}
|
21
21
|
],
|
22
|
-
"params": {
|
22
|
+
"params": {
|
23
23
|
"shop_id":"5818087",
|
24
24
|
"limit":25,
|
25
25
|
"offset":0
|
26
26
|
},
|
27
27
|
"type":"Receipt"
|
28
|
-
}
|
28
|
+
}
|
@@ -5,11 +5,19 @@ module Etsy
|
|
5
5
|
|
6
6
|
context "The Image class" do
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
context "without oauth" do
|
9
|
+
should "be able to find all images for a listing" do
|
10
|
+
images = mock_request('/listings/1/images', {}, 'Image', 'findAllListingImages.json')
|
11
|
+
Image.find_all_by_listing_id(1, {}).should == images
|
12
|
+
end
|
11
13
|
end
|
12
14
|
|
15
|
+
context "with options" do
|
16
|
+
should "be able to find all images for a listing with options in request" do
|
17
|
+
images = mock_request('/listings/1/images', {foo: "bar"}, 'Image', 'findAllListingImages.json')
|
18
|
+
Image.find_all_by_listing_id(1, {foo: "bar"}).should == images
|
19
|
+
end
|
20
|
+
end
|
13
21
|
end
|
14
22
|
|
15
23
|
context "An instance of the Image class" do
|
@@ -32,6 +32,16 @@ module Etsy
|
|
32
32
|
Listing.find_all_by_shop_id(1, :state => :inactive).should == listings
|
33
33
|
end
|
34
34
|
|
35
|
+
should "be able to find draft listings" do
|
36
|
+
listings = mock_request('/shops/1/listings/draft', {}, 'Listing', 'findAllShopListings.json')
|
37
|
+
Listing.find_all_by_shop_id(1, :state => :draft).should == listings
|
38
|
+
end
|
39
|
+
|
40
|
+
should "be able to find sold_out listings" do
|
41
|
+
listings = mock_request('/shops/1/listings/sold_out', {}, 'Listing', 'findAllShopListings.json')
|
42
|
+
Listing.find_all_by_shop_id(1, :state => :sold_out).should == listings
|
43
|
+
end
|
44
|
+
|
35
45
|
should "be able to find featured listings" do
|
36
46
|
listings = mock_request('/shops/1/listings/featured', {}, 'Listing', 'findAllShopListings.json')
|
37
47
|
Listing.find_all_by_shop_id(1, :state => :featured).should == listings
|
@@ -196,15 +206,31 @@ module Etsy
|
|
196
206
|
end
|
197
207
|
end
|
198
208
|
|
199
|
-
|
200
|
-
|
201
|
-
|
209
|
+
context "with oauth" do
|
210
|
+
should "have a collection of images" do
|
211
|
+
listing = Listing.new
|
212
|
+
listing.stubs(:id).with().returns(1)
|
213
|
+
listing.stubs(:token).with().returns("token")
|
214
|
+
listing.stubs(:secret).with().returns("secret")
|
215
|
+
|
216
|
+
Image.stubs(:find_all_by_listing_id).with(1, {access_token: "token", access_secret: "secret"}).returns('images')
|
202
217
|
|
203
|
-
|
218
|
+
listing.images.should == 'images'
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
context "without oauth" do
|
223
|
+
should "have a collection of images" do
|
224
|
+
listing = Listing.new
|
225
|
+
listing.stubs(:id).with().returns(1)
|
204
226
|
|
205
|
-
|
227
|
+
Image.stubs(:find_all_by_listing_id).with(1, {}).returns('images')
|
228
|
+
|
229
|
+
listing.images.should == 'images'
|
230
|
+
end
|
206
231
|
end
|
207
232
|
|
233
|
+
|
208
234
|
should "have a default image" do
|
209
235
|
listing = Listing.new
|
210
236
|
listing.stubs(:images).with().returns(%w(image_1 image_2))
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: etsy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Patrick Reagan
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2015-09-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
@@ -144,6 +144,7 @@ files:
|
|
144
144
|
- lib/etsy/shop.rb
|
145
145
|
- lib/etsy/transaction.rb
|
146
146
|
- lib/etsy/user.rb
|
147
|
+
- lib/etsy/variation/property_set.rb
|
147
148
|
- lib/etsy/verification_request.rb
|
148
149
|
- lib/etsy/version.rb
|
149
150
|
- test/fixtures/address/getUserAddresses.json
|