cardmagic-etsy 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +13 -0
- data/Gemfile +11 -0
- data/LICENSE +9 -0
- data/README.md +348 -0
- data/Rakefile +12 -0
- data/etsy.gemspec +34 -0
- data/lib/etsy.rb +223 -0
- data/lib/etsy/about.rb +15 -0
- data/lib/etsy/address.rb +47 -0
- data/lib/etsy/attribute_value.rb +46 -0
- data/lib/etsy/basic_client.rb +32 -0
- data/lib/etsy/category.rb +84 -0
- data/lib/etsy/country.rb +27 -0
- data/lib/etsy/favorite_listing.rb +26 -0
- data/lib/etsy/image.rb +44 -0
- data/lib/etsy/listing.rb +296 -0
- data/lib/etsy/model.rb +127 -0
- data/lib/etsy/payment_template.rb +33 -0
- data/lib/etsy/profile.rb +49 -0
- data/lib/etsy/receipt.rb +37 -0
- data/lib/etsy/request.rb +150 -0
- data/lib/etsy/response.rb +128 -0
- data/lib/etsy/section.rb +16 -0
- data/lib/etsy/secure_client.rb +131 -0
- data/lib/etsy/shipping_info.rb +27 -0
- data/lib/etsy/shipping_template.rb +41 -0
- data/lib/etsy/shop.rb +88 -0
- data/lib/etsy/transaction.rb +29 -0
- data/lib/etsy/user.rb +109 -0
- data/lib/etsy/variation/property_set.rb +71 -0
- data/lib/etsy/verification_request.rb +17 -0
- data/lib/etsy/version.rb +3 -0
- data/test/fixtures/about/getAbout.json +16 -0
- data/test/fixtures/address/getUserAddresses.json +12 -0
- data/test/fixtures/attribute_value/findAllListingPropertyValues.json +44 -0
- data/test/fixtures/category/findAllSubCategoryChildren.json +78 -0
- data/test/fixtures/category/findAllTopCategory.json +347 -0
- data/test/fixtures/category/findAllTopCategory.single.json +18 -0
- data/test/fixtures/category/findAllTopCategoryChildren.json +308 -0
- data/test/fixtures/category/getCategory.multiple.json +28 -0
- data/test/fixtures/category/getCategory.single.json +18 -0
- data/test/fixtures/country/getCountry.json +1 -0
- data/test/fixtures/favorite_listing/findAllFavoriteListings.json +1 -0
- data/test/fixtures/image/findAllListingImages.json +102 -0
- data/test/fixtures/listing/findAllListingActive.category.json +827 -0
- data/test/fixtures/listing/findAllShopListings.json +69 -0
- data/test/fixtures/listing/getListing.multiple.json +1 -0
- data/test/fixtures/listing/getListing.single.includeImages.json +1 -0
- data/test/fixtures/listing/getListing.single.json +1 -0
- data/test/fixtures/payment_template/getPaymentTemplate.json +1 -0
- data/test/fixtures/profile/new.json +28 -0
- data/test/fixtures/receipt/findAllShopReceipts.json +28 -0
- data/test/fixtures/section/getShopSection.json +18 -0
- data/test/fixtures/shipping_info/getShippingInfo.json +1 -0
- data/test/fixtures/shipping_template/getShippingTemplate.json +1 -0
- data/test/fixtures/shop/findAllShop.json +1 -0
- data/test/fixtures/shop/findAllShop.single.json +1 -0
- data/test/fixtures/shop/getShop.multiple.json +1 -0
- data/test/fixtures/shop/getShop.single.json +34 -0
- data/test/fixtures/transaction/findAllShopTransactions.json +1 -0
- data/test/fixtures/user/getUser.multiple.json +29 -0
- data/test/fixtures/user/getUser.single.json +13 -0
- data/test/fixtures/user/getUser.single.private.json +18 -0
- data/test/fixtures/user/getUser.single.withProfile.json +38 -0
- data/test/fixtures/user/getUser.single.withShops.json +41 -0
- data/test/test_helper.rb +45 -0
- data/test/unit/etsy/address_test.rb +61 -0
- data/test/unit/etsy/attribute_value_test.rb +67 -0
- data/test/unit/etsy/basic_client_test.rb +30 -0
- data/test/unit/etsy/category_test.rb +106 -0
- data/test/unit/etsy/country_test.rb +64 -0
- data/test/unit/etsy/favorite_listing_test.rb +44 -0
- data/test/unit/etsy/image_test.rb +51 -0
- data/test/unit/etsy/listing_test.rb +268 -0
- data/test/unit/etsy/model_test.rb +64 -0
- data/test/unit/etsy/payment_template_test.rb +68 -0
- data/test/unit/etsy/profile_test.rb +111 -0
- data/test/unit/etsy/receipt_test.rb +107 -0
- data/test/unit/etsy/request_test.rb +190 -0
- data/test/unit/etsy/response_test.rb +175 -0
- data/test/unit/etsy/section_test.rb +28 -0
- data/test/unit/etsy/secure_client_test.rb +132 -0
- data/test/unit/etsy/shipping_info_test.rb +24 -0
- data/test/unit/etsy/shipping_template_test.rb +24 -0
- data/test/unit/etsy/shop_about_test.rb +43 -0
- data/test/unit/etsy/shop_test.rb +116 -0
- data/test/unit/etsy/transaction_test.rb +61 -0
- data/test/unit/etsy/user_test.rb +250 -0
- data/test/unit/etsy/verification_request_test.rb +26 -0
- data/test/unit/etsy_test.rb +173 -0
- metadata +293 -0
data/lib/etsy.rb
ADDED
@@ -0,0 +1,223 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'json'
|
5
|
+
require 'oauth'
|
6
|
+
require 'uri'
|
7
|
+
|
8
|
+
require 'etsy/request'
|
9
|
+
require 'etsy/response'
|
10
|
+
|
11
|
+
require 'etsy/basic_client'
|
12
|
+
require 'etsy/secure_client'
|
13
|
+
require 'etsy/verification_request'
|
14
|
+
|
15
|
+
require 'etsy/model'
|
16
|
+
require 'etsy/user'
|
17
|
+
require 'etsy/profile'
|
18
|
+
require 'etsy/shop'
|
19
|
+
require 'etsy/listing'
|
20
|
+
require 'etsy/attribute_value'
|
21
|
+
require 'etsy/image'
|
22
|
+
require 'etsy/transaction'
|
23
|
+
require 'etsy/address'
|
24
|
+
require 'etsy/category'
|
25
|
+
require 'etsy/payment_template'
|
26
|
+
require 'etsy/country'
|
27
|
+
require 'etsy/shipping_template'
|
28
|
+
require 'etsy/shipping_info'
|
29
|
+
require 'etsy/section'
|
30
|
+
require 'etsy/favorite_listing'
|
31
|
+
require 'etsy/receipt'
|
32
|
+
require 'etsy/variation/property_set'
|
33
|
+
require 'etsy/about'
|
34
|
+
|
35
|
+
# = Etsy: A friendly Ruby interface to the Etsy API
|
36
|
+
#
|
37
|
+
# == Quick Start
|
38
|
+
#
|
39
|
+
# Getting started is easy. First, you will need a valid API key from the Etsy
|
40
|
+
# developer site (http://developer.etsy.com/).
|
41
|
+
#
|
42
|
+
# To start using the API, require the etsy gem and set it up to use your API key:
|
43
|
+
#
|
44
|
+
# require 'rubygems'
|
45
|
+
# require 'etsy'
|
46
|
+
#
|
47
|
+
# Etsy.api_key = 'itsasecret'
|
48
|
+
#
|
49
|
+
# Now you can make API calls that originate from an Etsy user:
|
50
|
+
#
|
51
|
+
# # Find a user by username
|
52
|
+
# user = Etsy.user('littletjane')
|
53
|
+
#
|
54
|
+
# # Grab that user's shop information
|
55
|
+
# user.shop
|
56
|
+
# user.shop.title
|
57
|
+
#
|
58
|
+
# # ... and the listings in the shop
|
59
|
+
# listing = user.shop.listings.first
|
60
|
+
# listing.title
|
61
|
+
# listing.description
|
62
|
+
#
|
63
|
+
# To see what else is available for a user, check out the full documentation for
|
64
|
+
# the Etsy::User class. Information about making authenticated calls is available
|
65
|
+
# in the README.
|
66
|
+
#
|
67
|
+
module Etsy
|
68
|
+
class Error < RuntimeError; end
|
69
|
+
|
70
|
+
class << self
|
71
|
+
attr_writer :callback_url
|
72
|
+
attr_writer :permission_scopes
|
73
|
+
end
|
74
|
+
|
75
|
+
# Make Etsy.api_key and Etsy.api_secret global but also local to threads
|
76
|
+
#
|
77
|
+
def self.api_key
|
78
|
+
Thread.current[:etsy_api_key] || @api_key
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.api_key=(key)
|
82
|
+
@api_key ||= key
|
83
|
+
Thread.current[:etsy_api_key] = key
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.api_secret
|
87
|
+
Thread.current[:etsy_api_secret] || @api_secret
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.api_secret=(secret)
|
91
|
+
@api_secret ||= secret
|
92
|
+
Thread.current[:etsy_api_secret] = secret
|
93
|
+
end
|
94
|
+
|
95
|
+
SANDBOX_HOST = 'sandbox.openapi.etsy.com'
|
96
|
+
PRODUCTION_HOST = 'openapi.etsy.com'
|
97
|
+
|
98
|
+
# Set the environment, accepts either :sandbox or :production. Defaults to :sandbox
|
99
|
+
# and will raise an exception when set to an unrecognized environment.
|
100
|
+
#
|
101
|
+
def self.environment=(environment)
|
102
|
+
unless [:sandbox, :production].include?(environment)
|
103
|
+
raise(ArgumentError, "environment must be set to either :sandbox or :production")
|
104
|
+
end
|
105
|
+
@environment = environment
|
106
|
+
@host = (environment == :sandbox) ? SANDBOX_HOST : PRODUCTION_HOST
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.protocol=(protocol)
|
110
|
+
unless ["http", "https"].include?(protocol.to_s)
|
111
|
+
raise(ArgumentError, "protocol must be set to either 'http' or 'https'")
|
112
|
+
end
|
113
|
+
@protocol = protocol.to_s
|
114
|
+
end
|
115
|
+
|
116
|
+
# Allow throwing API errors
|
117
|
+
#
|
118
|
+
def self.silent_errors=(bool)
|
119
|
+
unless [TrueClass, FalseClass].include?(bool.class)
|
120
|
+
raise(ArgumentError, "Silent errors must be set to either true or false'")
|
121
|
+
end
|
122
|
+
@silent_errors = bool
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.protocol
|
126
|
+
@protocol || "https"
|
127
|
+
end
|
128
|
+
|
129
|
+
# The currently configured environment.
|
130
|
+
#
|
131
|
+
def self.environment
|
132
|
+
@environment || :production
|
133
|
+
end
|
134
|
+
|
135
|
+
# The default will change to false for a 1.0 release (breaking changes)
|
136
|
+
#
|
137
|
+
def self.silent_errors
|
138
|
+
@silent_errors.nil? ? true : @silent_errors
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.host # :nodoc:
|
142
|
+
@host || PRODUCTION_HOST
|
143
|
+
end
|
144
|
+
|
145
|
+
# The configured callback URL or 'oob' if no callback URL is configured. This controls
|
146
|
+
# whether or not we need to pass the OAuth verifier by hand.
|
147
|
+
#
|
148
|
+
def self.callback_url
|
149
|
+
@callback_url || 'oob'
|
150
|
+
end
|
151
|
+
|
152
|
+
# OAuth permission scopes. Defines which private fields we can have access to.
|
153
|
+
#
|
154
|
+
def self.permission_scopes
|
155
|
+
@permission_scopes || []
|
156
|
+
end
|
157
|
+
|
158
|
+
# Find a user by username. See Etsy::User for more information.
|
159
|
+
#
|
160
|
+
def self.user(username)
|
161
|
+
User.find(username)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Convenience method for accessing the authenticated user's own user information. Requires
|
165
|
+
# authentication.
|
166
|
+
#
|
167
|
+
def self.myself(token, secret, options = {})
|
168
|
+
User.myself(token, secret, options)
|
169
|
+
end
|
170
|
+
|
171
|
+
# Generate a request token for authorization.
|
172
|
+
#
|
173
|
+
def self.request_token
|
174
|
+
clear_for_new_authorization
|
175
|
+
verification_request.request_token
|
176
|
+
end
|
177
|
+
|
178
|
+
# Generate an access token from the request token, secret, and verifier. The verifier can
|
179
|
+
# either be passed manually or from the params in the callback URL.
|
180
|
+
#
|
181
|
+
def self.access_token(request_token, request_secret, verifier)
|
182
|
+
@access_token = begin
|
183
|
+
client = Etsy::SecureClient.new({
|
184
|
+
:request_token => request_token,
|
185
|
+
:request_secret => request_secret,
|
186
|
+
:verifier => verifier
|
187
|
+
})
|
188
|
+
client.client
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# Generate the URL to begin the verification process for a user.
|
193
|
+
#
|
194
|
+
def self.verification_url
|
195
|
+
verification_request.url
|
196
|
+
end
|
197
|
+
|
198
|
+
def self.single_user(access_token, access_secret)
|
199
|
+
@credentials = {
|
200
|
+
:access_token => access_token,
|
201
|
+
:access_secret => access_secret
|
202
|
+
}
|
203
|
+
nil
|
204
|
+
end
|
205
|
+
|
206
|
+
def self.credentials
|
207
|
+
@credentials || {}
|
208
|
+
end
|
209
|
+
|
210
|
+
private
|
211
|
+
|
212
|
+
def self.verification_request
|
213
|
+
@verification_request ||= VerificationRequest.new
|
214
|
+
end
|
215
|
+
|
216
|
+
def self.clear_for_new_authorization
|
217
|
+
@verification_request = nil
|
218
|
+
end
|
219
|
+
|
220
|
+
def self.deprecate(message)
|
221
|
+
puts "DEPRECATED: #{message}."
|
222
|
+
end
|
223
|
+
end
|
data/lib/etsy/about.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Etsy
|
2
|
+
class About
|
3
|
+
include Etsy::Model
|
4
|
+
|
5
|
+
attributes :status, :story_headline, :story_leading_paragraph,
|
6
|
+
:story, :related_links, :url
|
7
|
+
attribute :id, :from => :shop_id
|
8
|
+
attribute :shop_id, :from => :shop_id
|
9
|
+
|
10
|
+
def self.find_by_shop(shop)
|
11
|
+
get("/shops/#{shop.id}/about")
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
data/lib/etsy/address.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
module Etsy
|
2
|
+
|
3
|
+
# = Address
|
4
|
+
#
|
5
|
+
# Represents a single Etsy Address. Users may or may not have associated addresses.
|
6
|
+
#
|
7
|
+
# An address has the following attributes:
|
8
|
+
#
|
9
|
+
# [first_line] Street address
|
10
|
+
# [second_line] Additional street information.
|
11
|
+
# [city]
|
12
|
+
# [state]
|
13
|
+
# [country]
|
14
|
+
# [country_id] The Etsy country id
|
15
|
+
#
|
16
|
+
class Address
|
17
|
+
|
18
|
+
include Etsy::Model
|
19
|
+
|
20
|
+
attributes :name, :first_line, :second_line, :city, :state, :zip, :country_id
|
21
|
+
|
22
|
+
attribute :id, :from => :user_address_id
|
23
|
+
attribute :country, :from => :country_name
|
24
|
+
|
25
|
+
# Retrieve all of a user's addresses by user name or ID:
|
26
|
+
#
|
27
|
+
# Etsy::Address.find('reagent')
|
28
|
+
#
|
29
|
+
def self.find(*identifiers_and_options)
|
30
|
+
self.append_to_endpoint('addresses', identifiers_and_options)
|
31
|
+
self.find_one_or_more('users', identifiers_and_options)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def oauth
|
36
|
+
oauth = (token && secret) ? {:access_token => token, :access_secret => secret} : {}
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.append_to_endpoint(suffix, arguments)
|
40
|
+
if arguments.last.class == Hash
|
41
|
+
arguments.last[:append_to_endpoint] = suffix
|
42
|
+
else
|
43
|
+
arguments << {:append_to_endpoint => suffix}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Etsy
|
2
|
+
|
3
|
+
# = AttributeValue
|
4
|
+
#
|
5
|
+
# An attribute of a listing according to its taxonomy.
|
6
|
+
#
|
7
|
+
# An attribute has the following attributes:
|
8
|
+
#
|
9
|
+
# [property_id] (INT) The numeric ID of this property.
|
10
|
+
# [property_name] (STRING) The name of the property, in the requested locale language.
|
11
|
+
# [scale_id] (INT) The numeric ID of the scale (if any).
|
12
|
+
# [scale_name] (STRING) The label used to describe the chosen scale (if any).
|
13
|
+
# [value_ids] (Array(INT)) The numeric IDs of the values.
|
14
|
+
# [values] (Array(STRING)) The literal values of the value
|
15
|
+
class AttributeValue
|
16
|
+
|
17
|
+
include Etsy::Model
|
18
|
+
|
19
|
+
attribute :id, :from => :property_id
|
20
|
+
attributes :property_name, :scale_id, :scale_name, :value_ids,
|
21
|
+
:values
|
22
|
+
|
23
|
+
# Fetch all property_values for a given listing.
|
24
|
+
#
|
25
|
+
def self.find_all_by_listing_id(listing_id, options = {})
|
26
|
+
get_all("/listings/#{listing_id}/attributes", options)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Adds a new attribute_value to the listing given
|
30
|
+
#
|
31
|
+
def self.create(listing, property_hash, options = {})
|
32
|
+
property_id = property_hash[:property_id]
|
33
|
+
options.merge!(:require_secure => true)
|
34
|
+
options.merge!(property_hash)
|
35
|
+
put("/listings/#{listing.id}/attributes/#{property_id}", options)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Delete attribute_value from listing
|
39
|
+
#
|
40
|
+
def self.destroy(listing, property_value, options = {})
|
41
|
+
options.merge!(:require_secure => true)
|
42
|
+
delete("/listings/#{listing.id}/attributes/#{property_value.id}", options)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Etsy
|
2
|
+
|
3
|
+
# = BasicClient
|
4
|
+
#
|
5
|
+
# Used for calling public API methods.
|
6
|
+
#
|
7
|
+
class BasicClient
|
8
|
+
|
9
|
+
# Create a new client that will connect to the specified host
|
10
|
+
#
|
11
|
+
def initialize
|
12
|
+
@host = Etsy.host
|
13
|
+
end
|
14
|
+
|
15
|
+
def client # :nodoc:
|
16
|
+
if @client
|
17
|
+
return @client
|
18
|
+
else
|
19
|
+
@client = Net::HTTP.new(@host, Etsy.protocol == "http" ? 80 : 443)
|
20
|
+
@client.use_ssl = true if Etsy.protocol == "https"
|
21
|
+
return @client
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Fetch a raw response from the specified endpoint
|
26
|
+
#
|
27
|
+
def get(endpoint)
|
28
|
+
client.get(endpoint)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Etsy
|
2
|
+
|
3
|
+
# = Category
|
4
|
+
#
|
5
|
+
# A category of listings for sale, formed from 1 to 3 tags.
|
6
|
+
#
|
7
|
+
# A category has the following attributes:
|
8
|
+
#
|
9
|
+
# [page_description] A short description of the category from the category's landing page
|
10
|
+
# [page_title] The title of the category's landing page
|
11
|
+
# [category_name] The category's string ID
|
12
|
+
# [short_name] A short display name for the category
|
13
|
+
# [long_name] A longer display name for the category
|
14
|
+
# [children_count] The number of subcategories below this one
|
15
|
+
#
|
16
|
+
class Category
|
17
|
+
|
18
|
+
include Etsy::Model
|
19
|
+
|
20
|
+
attribute :id, :from => :category_id
|
21
|
+
attribute :children_count, :from => :num_children
|
22
|
+
attributes :page_description, :page_title, :category_name, :short_name,
|
23
|
+
:long_name
|
24
|
+
|
25
|
+
# Retrieve one or more top-level categories by name:
|
26
|
+
#
|
27
|
+
# Etsy::Category.find('accessories')
|
28
|
+
#
|
29
|
+
# You can find multiple top-level categories by passing an array of identifiers:
|
30
|
+
#
|
31
|
+
# Etsy::Category.find(['accessories', 'art'])
|
32
|
+
#
|
33
|
+
def self.find_top(*identifiers_and_options)
|
34
|
+
self.find_one_or_more('categories', identifiers_and_options)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Retrieve a list of all subcategories of the specified category.
|
38
|
+
#
|
39
|
+
# Etsy::Category.find_all_subcategories('accessories')
|
40
|
+
#
|
41
|
+
# You can also find the subcategories of a subcategory.
|
42
|
+
#
|
43
|
+
# Etsy::Category.find_all_subcategories('accessories/apron')
|
44
|
+
#
|
45
|
+
# Etsy categories only go three levels deep, so this will return nil past the third level.
|
46
|
+
#
|
47
|
+
# Etsy::Category.find_all_subcategories('accessories/apron/women')
|
48
|
+
# => nil
|
49
|
+
#
|
50
|
+
def self.find_all_subcategories(category, options = {})
|
51
|
+
valid?(category) ? self.get_all("/taxonomy/categories/#{category}", options) : nil
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.find(tag)
|
55
|
+
get("/categories/#{tag}")
|
56
|
+
end
|
57
|
+
|
58
|
+
# Retrieve a list of all top-level categories.
|
59
|
+
#
|
60
|
+
# Etsy::Category.all
|
61
|
+
#
|
62
|
+
def self.all_top(options = {})
|
63
|
+
self.get_all("/taxonomy/categories", options)
|
64
|
+
end
|
65
|
+
|
66
|
+
# The collection of active listings associated with this category.
|
67
|
+
#
|
68
|
+
def active_listings
|
69
|
+
@active_listings ||= Listing.find_all_active_by_category(category_name)
|
70
|
+
end
|
71
|
+
|
72
|
+
# The collection of subcategories associated with this category.
|
73
|
+
#
|
74
|
+
def subcategories
|
75
|
+
@subcategories ||= Category.find_all_subcategories(category_name)
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def self.valid?(parent_category)
|
81
|
+
parent_category.count("/") < 2
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|