cardmagic-etsy 0.3.2
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/.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
|