cardmagic-etsy 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +13 -0
  4. data/Gemfile +11 -0
  5. data/LICENSE +9 -0
  6. data/README.md +348 -0
  7. data/Rakefile +12 -0
  8. data/etsy.gemspec +34 -0
  9. data/lib/etsy.rb +223 -0
  10. data/lib/etsy/about.rb +15 -0
  11. data/lib/etsy/address.rb +47 -0
  12. data/lib/etsy/attribute_value.rb +46 -0
  13. data/lib/etsy/basic_client.rb +32 -0
  14. data/lib/etsy/category.rb +84 -0
  15. data/lib/etsy/country.rb +27 -0
  16. data/lib/etsy/favorite_listing.rb +26 -0
  17. data/lib/etsy/image.rb +44 -0
  18. data/lib/etsy/listing.rb +296 -0
  19. data/lib/etsy/model.rb +127 -0
  20. data/lib/etsy/payment_template.rb +33 -0
  21. data/lib/etsy/profile.rb +49 -0
  22. data/lib/etsy/receipt.rb +37 -0
  23. data/lib/etsy/request.rb +150 -0
  24. data/lib/etsy/response.rb +128 -0
  25. data/lib/etsy/section.rb +16 -0
  26. data/lib/etsy/secure_client.rb +131 -0
  27. data/lib/etsy/shipping_info.rb +27 -0
  28. data/lib/etsy/shipping_template.rb +41 -0
  29. data/lib/etsy/shop.rb +88 -0
  30. data/lib/etsy/transaction.rb +29 -0
  31. data/lib/etsy/user.rb +109 -0
  32. data/lib/etsy/variation/property_set.rb +71 -0
  33. data/lib/etsy/verification_request.rb +17 -0
  34. data/lib/etsy/version.rb +3 -0
  35. data/test/fixtures/about/getAbout.json +16 -0
  36. data/test/fixtures/address/getUserAddresses.json +12 -0
  37. data/test/fixtures/attribute_value/findAllListingPropertyValues.json +44 -0
  38. data/test/fixtures/category/findAllSubCategoryChildren.json +78 -0
  39. data/test/fixtures/category/findAllTopCategory.json +347 -0
  40. data/test/fixtures/category/findAllTopCategory.single.json +18 -0
  41. data/test/fixtures/category/findAllTopCategoryChildren.json +308 -0
  42. data/test/fixtures/category/getCategory.multiple.json +28 -0
  43. data/test/fixtures/category/getCategory.single.json +18 -0
  44. data/test/fixtures/country/getCountry.json +1 -0
  45. data/test/fixtures/favorite_listing/findAllFavoriteListings.json +1 -0
  46. data/test/fixtures/image/findAllListingImages.json +102 -0
  47. data/test/fixtures/listing/findAllListingActive.category.json +827 -0
  48. data/test/fixtures/listing/findAllShopListings.json +69 -0
  49. data/test/fixtures/listing/getListing.multiple.json +1 -0
  50. data/test/fixtures/listing/getListing.single.includeImages.json +1 -0
  51. data/test/fixtures/listing/getListing.single.json +1 -0
  52. data/test/fixtures/payment_template/getPaymentTemplate.json +1 -0
  53. data/test/fixtures/profile/new.json +28 -0
  54. data/test/fixtures/receipt/findAllShopReceipts.json +28 -0
  55. data/test/fixtures/section/getShopSection.json +18 -0
  56. data/test/fixtures/shipping_info/getShippingInfo.json +1 -0
  57. data/test/fixtures/shipping_template/getShippingTemplate.json +1 -0
  58. data/test/fixtures/shop/findAllShop.json +1 -0
  59. data/test/fixtures/shop/findAllShop.single.json +1 -0
  60. data/test/fixtures/shop/getShop.multiple.json +1 -0
  61. data/test/fixtures/shop/getShop.single.json +34 -0
  62. data/test/fixtures/transaction/findAllShopTransactions.json +1 -0
  63. data/test/fixtures/user/getUser.multiple.json +29 -0
  64. data/test/fixtures/user/getUser.single.json +13 -0
  65. data/test/fixtures/user/getUser.single.private.json +18 -0
  66. data/test/fixtures/user/getUser.single.withProfile.json +38 -0
  67. data/test/fixtures/user/getUser.single.withShops.json +41 -0
  68. data/test/test_helper.rb +45 -0
  69. data/test/unit/etsy/address_test.rb +61 -0
  70. data/test/unit/etsy/attribute_value_test.rb +67 -0
  71. data/test/unit/etsy/basic_client_test.rb +30 -0
  72. data/test/unit/etsy/category_test.rb +106 -0
  73. data/test/unit/etsy/country_test.rb +64 -0
  74. data/test/unit/etsy/favorite_listing_test.rb +44 -0
  75. data/test/unit/etsy/image_test.rb +51 -0
  76. data/test/unit/etsy/listing_test.rb +268 -0
  77. data/test/unit/etsy/model_test.rb +64 -0
  78. data/test/unit/etsy/payment_template_test.rb +68 -0
  79. data/test/unit/etsy/profile_test.rb +111 -0
  80. data/test/unit/etsy/receipt_test.rb +107 -0
  81. data/test/unit/etsy/request_test.rb +190 -0
  82. data/test/unit/etsy/response_test.rb +175 -0
  83. data/test/unit/etsy/section_test.rb +28 -0
  84. data/test/unit/etsy/secure_client_test.rb +132 -0
  85. data/test/unit/etsy/shipping_info_test.rb +24 -0
  86. data/test/unit/etsy/shipping_template_test.rb +24 -0
  87. data/test/unit/etsy/shop_about_test.rb +43 -0
  88. data/test/unit/etsy/shop_test.rb +116 -0
  89. data/test/unit/etsy/transaction_test.rb +61 -0
  90. data/test/unit/etsy/user_test.rb +250 -0
  91. data/test/unit/etsy/verification_request_test.rb +26 -0
  92. data/test/unit/etsy_test.rb +173 -0
  93. metadata +293 -0
@@ -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
@@ -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
@@ -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