tailored-etsy 0.2.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.
- data/.gitignore +8 -0
 - data/.travis.yml +8 -0
 - data/Gemfile +3 -0
 - data/LICENSE +9 -0
 - data/README.md +280 -0
 - data/Rakefile +12 -0
 - data/etsy.gemspec +28 -0
 - data/lib/etsy.rb +172 -0
 - data/lib/etsy/address.rb +47 -0
 - data/lib/etsy/basic_client.rb +26 -0
 - data/lib/etsy/category.rb +84 -0
 - data/lib/etsy/country.rb +27 -0
 - data/lib/etsy/image.rb +34 -0
 - data/lib/etsy/listing.rb +178 -0
 - data/lib/etsy/model.rb +123 -0
 - data/lib/etsy/payment_template.rb +33 -0
 - data/lib/etsy/profile.rb +49 -0
 - data/lib/etsy/request.rb +148 -0
 - data/lib/etsy/response.rb +112 -0
 - data/lib/etsy/section.rb +16 -0
 - data/lib/etsy/secure_client.rb +128 -0
 - data/lib/etsy/shipping_template.rb +32 -0
 - data/lib/etsy/shop.rb +83 -0
 - data/lib/etsy/transaction.rb +18 -0
 - data/lib/etsy/user.rb +91 -0
 - data/lib/etsy/verification_request.rb +17 -0
 - data/lib/etsy/version.rb +3 -0
 - data/test/fixtures/address/getUserAddresses.json +12 -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/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.json +1 -0
 - data/test/fixtures/payment_template/getPaymentTemplate.json +1 -0
 - data/test/fixtures/profile/new.json +28 -0
 - data/test/fixtures/section/getShopSection.json +18 -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 +33 -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 +44 -0
 - data/test/unit/etsy/address_test.rb +61 -0
 - data/test/unit/etsy/basic_client_test.rb +28 -0
 - data/test/unit/etsy/category_test.rb +106 -0
 - data/test/unit/etsy/country_test.rb +64 -0
 - data/test/unit/etsy/image_test.rb +43 -0
 - data/test/unit/etsy/listing_test.rb +217 -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/request_test.rb +192 -0
 - data/test/unit/etsy/response_test.rb +164 -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_template_test.rb +24 -0
 - data/test/unit/etsy/shop_test.rb +104 -0
 - data/test/unit/etsy/transaction_test.rb +52 -0
 - data/test/unit/etsy/user_test.rb +218 -0
 - data/test/unit/etsy/verification_request_test.rb +26 -0
 - data/test/unit/etsy_test.rb +114 -0
 - metadata +269 -0
 
| 
         @@ -0,0 +1,33 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Etsy
         
     | 
| 
      
 2 
     | 
    
         
            +
              class PaymentTemplate
         
     | 
| 
      
 3 
     | 
    
         
            +
                include Etsy::Model
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                attribute :id, :from => :payment_template_id
         
     | 
| 
      
 6 
     | 
    
         
            +
                attributes :allow_check, :allow_mo, :allow_other, :allow_paypal, :allow_cc
         
     | 
| 
      
 7 
     | 
    
         
            +
                attributes :paypal_email, :name, :first_line, :second_line, :city, :state
         
     | 
| 
      
 8 
     | 
    
         
            +
                attributes :zip, :country_id
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def self.create(options = {})
         
     | 
| 
      
 11 
     | 
    
         
            +
                  options.merge!(:require_secure => true)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  post("/payments/templates", options)
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
         
     | 
| 
      
 15 
     | 
    
         
            +
                def self.find(id, credentials = {})
         
     | 
| 
      
 16 
     | 
    
         
            +
                  options = {
         
     | 
| 
      
 17 
     | 
    
         
            +
                    :access_token => credentials[:access_token],
         
     | 
| 
      
 18 
     | 
    
         
            +
                    :access_secret => credentials[:access_secret],
         
     | 
| 
      
 19 
     | 
    
         
            +
                    :require_secure => true
         
     | 
| 
      
 20 
     | 
    
         
            +
                  }
         
     | 
| 
      
 21 
     | 
    
         
            +
                  get("/payments/templates/#{id}", options)
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                def self.find_by_user(user, credentials = {})
         
     | 
| 
      
 25 
     | 
    
         
            +
                  options = {
         
     | 
| 
      
 26 
     | 
    
         
            +
                    :access_token => credentials[:access_token],
         
     | 
| 
      
 27 
     | 
    
         
            +
                    :access_secret => credentials[:access_secret],
         
     | 
| 
      
 28 
     | 
    
         
            +
                    :require_secure => true
         
     | 
| 
      
 29 
     | 
    
         
            +
                  }
         
     | 
| 
      
 30 
     | 
    
         
            +
                  get("/users/#{user.id}/payments/templates", options)
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/etsy/profile.rb
    ADDED
    
    | 
         @@ -0,0 +1,49 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Etsy
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              # = Profile
         
     | 
| 
      
 4 
     | 
    
         
            +
              #
         
     | 
| 
      
 5 
     | 
    
         
            +
              # Represents a profile resource of an Etsy user.
         
     | 
| 
      
 6 
     | 
    
         
            +
              #
         
     | 
| 
      
 7 
     | 
    
         
            +
              class Profile
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                include Etsy::Model
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                attribute :id, :from => :user_profile_id
         
     | 
| 
      
 12 
     | 
    
         
            +
                attribute :user_id
         
     | 
| 
      
 13 
     | 
    
         
            +
                attribute :bio
         
     | 
| 
      
 14 
     | 
    
         
            +
                attribute :username, :from => :login_name
         
     | 
| 
      
 15 
     | 
    
         
            +
                attribute :gender
         
     | 
| 
      
 16 
     | 
    
         
            +
                attribute :birth_day
         
     | 
| 
      
 17 
     | 
    
         
            +
                attribute :birth_month
         
     | 
| 
      
 18 
     | 
    
         
            +
                attribute :birth_year
         
     | 
| 
      
 19 
     | 
    
         
            +
                attribute :joined, :from => :join_tsz
         
     | 
| 
      
 20 
     | 
    
         
            +
                attribute :favorite_materials, :from => :materials
         
     | 
| 
      
 21 
     | 
    
         
            +
                attribute :country_id
         
     | 
| 
      
 22 
     | 
    
         
            +
                attribute :city
         
     | 
| 
      
 23 
     | 
    
         
            +
                attribute :location
         
     | 
| 
      
 24 
     | 
    
         
            +
                attribute :region
         
     | 
| 
      
 25 
     | 
    
         
            +
                attribute :avatar_id
         
     | 
| 
      
 26 
     | 
    
         
            +
                attribute :image, :from => :image_url_75x75
         
     | 
| 
      
 27 
     | 
    
         
            +
                attribute :lat
         
     | 
| 
      
 28 
     | 
    
         
            +
                attribute :lon
         
     | 
| 
      
 29 
     | 
    
         
            +
                attribute :transaction_buy_count
         
     | 
| 
      
 30 
     | 
    
         
            +
                attribute :transaction_sold_count
         
     | 
| 
      
 31 
     | 
    
         
            +
                attribute :is_seller
         
     | 
| 
      
 32 
     | 
    
         
            +
                attribute :first_name
         
     | 
| 
      
 33 
     | 
    
         
            +
                attribute :last_name
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def materials
         
     | 
| 
      
 36 
     | 
    
         
            +
                  favorite_materials ? favorite_materials.split(',') : []
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                # Time that this user joined Etsy
         
     | 
| 
      
 40 
     | 
    
         
            +
                #
         
     | 
| 
      
 41 
     | 
    
         
            +
                def joined_at
         
     | 
| 
      
 42 
     | 
    
         
            +
                  Time.at(joined)
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                def seller?
         
     | 
| 
      
 46 
     | 
    
         
            +
                  is_seller
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/etsy/request.rb
    ADDED
    
    | 
         @@ -0,0 +1,148 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Etsy
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              # = Request
         
     | 
| 
      
 4 
     | 
    
         
            +
              #
         
     | 
| 
      
 5 
     | 
    
         
            +
              # A basic wrapper around GET requests to the Etsy JSON API
         
     | 
| 
      
 6 
     | 
    
         
            +
              #
         
     | 
| 
      
 7 
     | 
    
         
            +
              class Request
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                # Perform a GET request for the resource with optional parameters - returns
         
     | 
| 
      
 10 
     | 
    
         
            +
                # A Response object with the payload data
         
     | 
| 
      
 11 
     | 
    
         
            +
                def self.get(resource_path, parameters = {})
         
     | 
| 
      
 12 
     | 
    
         
            +
                  request = Request.new(resource_path, parameters)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  Response.new(request.get)
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def self.post(resource_path, parameters = {})
         
     | 
| 
      
 17 
     | 
    
         
            +
                  request = Request.new(resource_path, parameters)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  Response.new(request.post)
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def self.put(resource_path, parameters = {})
         
     | 
| 
      
 22 
     | 
    
         
            +
                  request = Request.new(resource_path, parameters)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  Response.new(request.put)
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                def self.delete(resource_path, parameters = {})
         
     | 
| 
      
 27 
     | 
    
         
            +
                  request = Request.new(resource_path, parameters)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  Response.new(request.delete)
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                # Create a new request for the resource with optional parameters
         
     | 
| 
      
 32 
     | 
    
         
            +
                def initialize(resource_path, parameters = {})
         
     | 
| 
      
 33 
     | 
    
         
            +
                  parameters = parameters.dup
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @token = parameters.delete(:access_token) || Etsy.credentials[:access_token]
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @secret = parameters.delete(:access_secret) || Etsy.credentials[:access_secret]
         
     | 
| 
      
 36 
     | 
    
         
            +
                  raise("Secure connection required. Please provide your OAuth credentials via :access_token and :access_secret in the parameters") if parameters.delete(:require_secure) && !secure?
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @multipart_request = parameters.delete(:multipart)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  @resource_path = resource_path
         
     | 
| 
      
 39 
     | 
    
         
            +
                  @resources = parameters.delete(:includes)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  if @resources.class == String
         
     | 
| 
      
 41 
     | 
    
         
            +
                    @resources = @resources.split(',').map {|r| {:resource => r}}
         
     | 
| 
      
 42 
     | 
    
         
            +
                  elsif @resources.class == Array
         
     | 
| 
      
 43 
     | 
    
         
            +
                    @resources = @resources.map do |r|
         
     | 
| 
      
 44 
     | 
    
         
            +
                      if r.class == String
         
     | 
| 
      
 45 
     | 
    
         
            +
                        {:resource => r}
         
     | 
| 
      
 46 
     | 
    
         
            +
                      else
         
     | 
| 
      
 47 
     | 
    
         
            +
                        r
         
     | 
| 
      
 48 
     | 
    
         
            +
                      end
         
     | 
| 
      
 49 
     | 
    
         
            +
                    end
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
                  parameters = parameters.merge(:api_key => Etsy.api_key) unless secure?
         
     | 
| 
      
 52 
     | 
    
         
            +
                  @parameters = parameters
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                def base_path # :nodoc:
         
     | 
| 
      
 56 
     | 
    
         
            +
                  "/v2"
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                # Perform a GET request against the API endpoint and return the raw
         
     | 
| 
      
 60 
     | 
    
         
            +
                # response data
         
     | 
| 
      
 61 
     | 
    
         
            +
                def get
         
     | 
| 
      
 62 
     | 
    
         
            +
                  client.get(endpoint_url)
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                def post
         
     | 
| 
      
 66 
     | 
    
         
            +
                  if multipart?
         
     | 
| 
      
 67 
     | 
    
         
            +
                    client.post_multipart(endpoint_url(:include_query => false), @parameters)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  else
         
     | 
| 
      
 69 
     | 
    
         
            +
                    client.post(endpoint_url)
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                def put
         
     | 
| 
      
 74 
     | 
    
         
            +
                  client.put(endpoint_url)
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                def delete
         
     | 
| 
      
 78 
     | 
    
         
            +
                  client.delete(endpoint_url)
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                def client # :nodoc:
         
     | 
| 
      
 82 
     | 
    
         
            +
                  @client ||= secure? ? secure_client : basic_client
         
     | 
| 
      
 83 
     | 
    
         
            +
                end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                def parameters # :nodoc:
         
     | 
| 
      
 86 
     | 
    
         
            +
                  @parameters
         
     | 
| 
      
 87 
     | 
    
         
            +
                end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                def resources # :nodoc:
         
     | 
| 
      
 90 
     | 
    
         
            +
                  @resources
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                def query # :nodoc:
         
     | 
| 
      
 94 
     | 
    
         
            +
                  to_url(parameters.merge(:includes => resources.to_a.map { |r| association(r) }))
         
     | 
| 
      
 95 
     | 
    
         
            +
                end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                def to_url(val)
         
     | 
| 
      
 98 
     | 
    
         
            +
                  if val.is_a? Array
         
     | 
| 
      
 99 
     | 
    
         
            +
                    to_url(val.join(','))
         
     | 
| 
      
 100 
     | 
    
         
            +
                  elsif val.is_a? Hash
         
     | 
| 
      
 101 
     | 
    
         
            +
                    val.reject { |k, v|
         
     | 
| 
      
 102 
     | 
    
         
            +
                      k.nil? || v.nil? || (k.respond_to?(:empty?) && k.empty?) || (v.respond_to?(:empty?) && v.empty?)
         
     | 
| 
      
 103 
     | 
    
         
            +
                    }.map { |k, v| "#{to_url(k.to_s)}=#{to_url(v)}" }.join('&')
         
     | 
| 
      
 104 
     | 
    
         
            +
                  else
         
     | 
| 
      
 105 
     | 
    
         
            +
                    URI.escape(val.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
         
     | 
| 
      
 106 
     | 
    
         
            +
                  end
         
     | 
| 
      
 107 
     | 
    
         
            +
                end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                def association(options={}) # :nodoc:
         
     | 
| 
      
 110 
     | 
    
         
            +
                  s = options[:resource].dup
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                  if options.include? :fields
         
     | 
| 
      
 113 
     | 
    
         
            +
                    s << "(#{[options[:fields]].flatten.join(',')})"
         
     | 
| 
      
 114 
     | 
    
         
            +
                  end
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                  if options.include?(:limit) || options.include?(:offset)
         
     | 
| 
      
 117 
     | 
    
         
            +
                    s << ":#{options.fetch(:limit, 25)}:#{options.fetch(:offset, 0)}"
         
     | 
| 
      
 118 
     | 
    
         
            +
                  end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                  s
         
     | 
| 
      
 121 
     | 
    
         
            +
                end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                def endpoint_url(options = {}) # :nodoc:
         
     | 
| 
      
 124 
     | 
    
         
            +
                  url = "#{base_path}#{@resource_path}"
         
     | 
| 
      
 125 
     | 
    
         
            +
                  url += "?#{query}" if options.fetch(:include_query, true)
         
     | 
| 
      
 126 
     | 
    
         
            +
                  url
         
     | 
| 
      
 127 
     | 
    
         
            +
                end
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                def multipart?
         
     | 
| 
      
 130 
     | 
    
         
            +
                  !!@multipart_request
         
     | 
| 
      
 131 
     | 
    
         
            +
                end
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                private
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
                def secure_client
         
     | 
| 
      
 136 
     | 
    
         
            +
                  SecureClient.new(:access_token => @token, :access_secret => @secret)
         
     | 
| 
      
 137 
     | 
    
         
            +
                end
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                def basic_client
         
     | 
| 
      
 140 
     | 
    
         
            +
                  BasicClient.new(Etsy.host)
         
     | 
| 
      
 141 
     | 
    
         
            +
                end
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                def secure?
         
     | 
| 
      
 144 
     | 
    
         
            +
                  !@token.nil? && !@secret.nil?
         
     | 
| 
      
 145 
     | 
    
         
            +
                end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
              end
         
     | 
| 
      
 148 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,112 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Etsy
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              class OAuthTokenRevoked < StandardError; end
         
     | 
| 
      
 4 
     | 
    
         
            +
              class MissingShopID < StandardError; end
         
     | 
| 
      
 5 
     | 
    
         
            +
              class EtsyJSONInvalid < StandardError; end
         
     | 
| 
      
 6 
     | 
    
         
            +
              class TemporaryIssue < StandardError; end
         
     | 
| 
      
 7 
     | 
    
         
            +
              class InvalidUserID < StandardError; end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              # = Response
         
     | 
| 
      
 10 
     | 
    
         
            +
              #
         
     | 
| 
      
 11 
     | 
    
         
            +
              # Basic wrapper around the Etsy JSON response data
         
     | 
| 
      
 12 
     | 
    
         
            +
              #
         
     | 
| 
      
 13 
     | 
    
         
            +
              class Response
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                # Create a new response based on the raw HTTP response
         
     | 
| 
      
 16 
     | 
    
         
            +
                def initialize(raw_response)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  @raw_response = raw_response
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                # Convert the raw JSON data to a hash
         
     | 
| 
      
 21 
     | 
    
         
            +
                def to_hash
         
     | 
| 
      
 22 
     | 
    
         
            +
                  validate!
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @hash ||= json
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                def body
         
     | 
| 
      
 27 
     | 
    
         
            +
                  @raw_response.body
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def code
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @raw_response.code
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                # Number of records in the response results
         
     | 
| 
      
 35 
     | 
    
         
            +
                def count
         
     | 
| 
      
 36 
     | 
    
         
            +
                  if paginated?
         
     | 
| 
      
 37 
     | 
    
         
            +
                    to_hash['results'].nil? ? 0 : to_hash['results'].size
         
     | 
| 
      
 38 
     | 
    
         
            +
                  else
         
     | 
| 
      
 39 
     | 
    
         
            +
                    to_hash['count']
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                # Results of the API request
         
     | 
| 
      
 44 
     | 
    
         
            +
                def result
         
     | 
| 
      
 45 
     | 
    
         
            +
                  if success?
         
     | 
| 
      
 46 
     | 
    
         
            +
                    results = to_hash['results'] || []
         
     | 
| 
      
 47 
     | 
    
         
            +
                    count == 1 ? results.first : results
         
     | 
| 
      
 48 
     | 
    
         
            +
                  else
         
     | 
| 
      
 49 
     | 
    
         
            +
                    []
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                def success?
         
     | 
| 
      
 54 
     | 
    
         
            +
                  !!(code =~ /2\d\d/)
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                def paginated?
         
     | 
| 
      
 58 
     | 
    
         
            +
                  !!to_hash['pagination']
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                private
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                def data
         
     | 
| 
      
 64 
     | 
    
         
            +
                  @raw_response.body
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                def json
         
     | 
| 
      
 68 
     | 
    
         
            +
                  @hash ||= JSON.parse(data)
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                def validate!
         
     | 
| 
      
 72 
     | 
    
         
            +
                  raise OAuthTokenRevoked         if token_revoked?
         
     | 
| 
      
 73 
     | 
    
         
            +
                  raise MissingShopID             if missing_shop_id?
         
     | 
| 
      
 74 
     | 
    
         
            +
                  raise InvalidUserID             if invalid_user_id?
         
     | 
| 
      
 75 
     | 
    
         
            +
                  raise TemporaryIssue            if temporary_etsy_issue? || resource_unavailable? || exceeded_rate_limit?
         
     | 
| 
      
 76 
     | 
    
         
            +
                  raise EtsyJSONInvalid.new("CODE: #{code}, BODY: #{data}") unless valid_json?
         
     | 
| 
      
 77 
     | 
    
         
            +
                  true
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                def valid_json?
         
     | 
| 
      
 81 
     | 
    
         
            +
                  json
         
     | 
| 
      
 82 
     | 
    
         
            +
                  return true
         
     | 
| 
      
 83 
     | 
    
         
            +
                rescue JSON::ParserError
         
     | 
| 
      
 84 
     | 
    
         
            +
                  return false
         
     | 
| 
      
 85 
     | 
    
         
            +
                end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                def token_revoked?
         
     | 
| 
      
 88 
     | 
    
         
            +
                  data == "oauth_problem=token_revoked"
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                def missing_shop_id?
         
     | 
| 
      
 92 
     | 
    
         
            +
                  data =~ /Shop with PK shop_id/
         
     | 
| 
      
 93 
     | 
    
         
            +
                end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                def invalid_user_id?
         
     | 
| 
      
 96 
     | 
    
         
            +
                  data =~ /is not a valid user_id/
         
     | 
| 
      
 97 
     | 
    
         
            +
                end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                def temporary_etsy_issue?
         
     | 
| 
      
 100 
     | 
    
         
            +
                  data =~ /Temporary Etsy issue/
         
     | 
| 
      
 101 
     | 
    
         
            +
                end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                def resource_unavailable?
         
     | 
| 
      
 104 
     | 
    
         
            +
                  data =~ /Resource temporarily unavailable/
         
     | 
| 
      
 105 
     | 
    
         
            +
                end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                def exceeded_rate_limit?
         
     | 
| 
      
 108 
     | 
    
         
            +
                  data =~ /You have exceeded/
         
     | 
| 
      
 109 
     | 
    
         
            +
                end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
              end
         
     | 
| 
      
 112 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/etsy/section.rb
    ADDED
    
    | 
         @@ -0,0 +1,16 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Etsy
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Section
         
     | 
| 
      
 3 
     | 
    
         
            +
                include Etsy::Model
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                attributes :title, :rank, :user_id, :active_listing_count
         
     | 
| 
      
 6 
     | 
    
         
            +
                attribute :id, :from => :shop_section_id
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def self.find_by_shop(shop)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  get("/shops/#{shop.id}/sections")
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def self.find(shop, id)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  get("/shops/#{shop.id}/sections/#{id}")
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,128 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Etsy
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              # = SecureClient
         
     | 
| 
      
 4 
     | 
    
         
            +
              #
         
     | 
| 
      
 5 
     | 
    
         
            +
              # Used for generating tokens and calling API methods that require authentication.
         
     | 
| 
      
 6 
     | 
    
         
            +
              #
         
     | 
| 
      
 7 
     | 
    
         
            +
              class SecureClient
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                # Create a new client with the necessary parameters.  Accepts the following
         
     | 
| 
      
 10 
     | 
    
         
            +
                # key/value pairs:
         
     | 
| 
      
 11 
     | 
    
         
            +
                #
         
     | 
| 
      
 12 
     | 
    
         
            +
                #   :request_token
         
     | 
| 
      
 13 
     | 
    
         
            +
                #   :request_secret
         
     | 
| 
      
 14 
     | 
    
         
            +
                #   :access_token
         
     | 
| 
      
 15 
     | 
    
         
            +
                #   :access_secret
         
     | 
| 
      
 16 
     | 
    
         
            +
                #
         
     | 
| 
      
 17 
     | 
    
         
            +
                # The request token / secret is useful for generating the access token.  Pass
         
     | 
| 
      
 18 
     | 
    
         
            +
                # the access token / secret when initializing from stored credentials.
         
     | 
| 
      
 19 
     | 
    
         
            +
                #
         
     | 
| 
      
 20 
     | 
    
         
            +
                def initialize(attributes = {})
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @attributes = attributes
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                def consumer # :nodoc:
         
     | 
| 
      
 25 
     | 
    
         
            +
                  path = '/v2/oauth/'
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @consumer ||= OAuth::Consumer.new(Etsy.api_key, Etsy.api_secret, {
         
     | 
| 
      
 27 
     | 
    
         
            +
                    :site               => "http://#{Etsy.host}",
         
     | 
| 
      
 28 
     | 
    
         
            +
                    :request_token_path => "#{path}request_token?scope=#{Etsy.permission_scopes.join('+')}",
         
     | 
| 
      
 29 
     | 
    
         
            +
                    :access_token_path  => "#{path}access_token"
         
     | 
| 
      
 30 
     | 
    
         
            +
                  })
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                # Generate a request token.
         
     | 
| 
      
 34 
     | 
    
         
            +
                #
         
     | 
| 
      
 35 
     | 
    
         
            +
                def request_token
         
     | 
| 
      
 36 
     | 
    
         
            +
                  consumer.get_request_token(:oauth_callback => Etsy.callback_url)
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                # Access token for this request, either generated from the request token or taken
         
     | 
| 
      
 40 
     | 
    
         
            +
                # from the :access_token parameter.
         
     | 
| 
      
 41 
     | 
    
         
            +
                #
         
     | 
| 
      
 42 
     | 
    
         
            +
                def access_token
         
     | 
| 
      
 43 
     | 
    
         
            +
                  @attributes[:access_token] || client.token
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                # Access secret for this request, either generated from the request token or taken
         
     | 
| 
      
 47 
     | 
    
         
            +
                # from the :access_secret parameter.
         
     | 
| 
      
 48 
     | 
    
         
            +
                #
         
     | 
| 
      
 49 
     | 
    
         
            +
                def access_secret
         
     | 
| 
      
 50 
     | 
    
         
            +
                  @attributes[:access_secret] || client.secret
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                def client_from_request_data # :nodoc:
         
     | 
| 
      
 54 
     | 
    
         
            +
                  request_token = OAuth::RequestToken.new(consumer, @attributes[:request_token], @attributes[:request_secret])
         
     | 
| 
      
 55 
     | 
    
         
            +
                  request_token.get_access_token(:oauth_verifier => @attributes[:verifier])
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                def client_from_access_data # :nodoc:
         
     | 
| 
      
 59 
     | 
    
         
            +
                  OAuth::AccessToken.new(consumer, @attributes[:access_token], @attributes[:access_secret])
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                def client # :nodoc:
         
     | 
| 
      
 63 
     | 
    
         
            +
                  @client ||= has_access_data? ? client_from_access_data : client_from_request_data
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                # Fetch a raw response from the specified endpoint.
         
     | 
| 
      
 67 
     | 
    
         
            +
                #
         
     | 
| 
      
 68 
     | 
    
         
            +
                def get(endpoint)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  client.get(endpoint)
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                def post(endpoint)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  client.post(endpoint)
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                def put(endpoint)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  client.put(endpoint)
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                def delete(endpoint)
         
     | 
| 
      
 81 
     | 
    
         
            +
                  client.delete(endpoint)
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                def post_multipart(endpoint, params = {})
         
     | 
| 
      
 85 
     | 
    
         
            +
                  Net::HTTP.new(Etsy.host).start do |http|
         
     | 
| 
      
 86 
     | 
    
         
            +
                    req = Net::HTTP::Post.new(endpoint)
         
     | 
| 
      
 87 
     | 
    
         
            +
                    add_multipart_data(req, params)
         
     | 
| 
      
 88 
     | 
    
         
            +
                    add_oauth(req)
         
     | 
| 
      
 89 
     | 
    
         
            +
                    res = http.request(req)
         
     | 
| 
      
 90 
     | 
    
         
            +
                  end
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                private
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                # Encodes the request as multipart
         
     | 
| 
      
 96 
     | 
    
         
            +
                def add_multipart_data(req, params)
         
     | 
| 
      
 97 
     | 
    
         
            +
                  crlf = "\r\n"
         
     | 
| 
      
 98 
     | 
    
         
            +
                  boundary = Time.now.to_i.to_s(16)
         
     | 
| 
      
 99 
     | 
    
         
            +
                  req["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
         
     | 
| 
      
 100 
     | 
    
         
            +
                  body = ""
         
     | 
| 
      
 101 
     | 
    
         
            +
                  params.each do |key,value|
         
     | 
| 
      
 102 
     | 
    
         
            +
                    esc_key = CGI.escape(key.to_s)
         
     | 
| 
      
 103 
     | 
    
         
            +
                    body << "--#{boundary}#{crlf}"
         
     | 
| 
      
 104 
     | 
    
         
            +
                    if value.respond_to?(:read)
         
     | 
| 
      
 105 
     | 
    
         
            +
                      body << "Content-Disposition: form-data; name=\"#{esc_key}\"; filename=\"#{File.basename(value.path)}\"#{crlf}"
         
     | 
| 
      
 106 
     | 
    
         
            +
                      body << "Content-Type: image/jpeg#{crlf*2}"
         
     | 
| 
      
 107 
     | 
    
         
            +
                      body << value.read
         
     | 
| 
      
 108 
     | 
    
         
            +
                    else
         
     | 
| 
      
 109 
     | 
    
         
            +
                      body << "Content-Disposition: form-data; name=\"#{esc_key}\"#{crlf*2}#{value}"
         
     | 
| 
      
 110 
     | 
    
         
            +
                    end
         
     | 
| 
      
 111 
     | 
    
         
            +
                    body << crlf
         
     | 
| 
      
 112 
     | 
    
         
            +
                  end
         
     | 
| 
      
 113 
     | 
    
         
            +
                  body << "--#{boundary}--#{crlf*2}"
         
     | 
| 
      
 114 
     | 
    
         
            +
                  req.body = body
         
     | 
| 
      
 115 
     | 
    
         
            +
                  req["Content-Length"] = req.body.size
         
     | 
| 
      
 116 
     | 
    
         
            +
                end
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                # Uses the OAuth gem to add the signed Authorization header
         
     | 
| 
      
 119 
     | 
    
         
            +
                def add_oauth(req)
         
     | 
| 
      
 120 
     | 
    
         
            +
                  client.sign!(req)
         
     | 
| 
      
 121 
     | 
    
         
            +
                end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                def has_access_data?
         
     | 
| 
      
 124 
     | 
    
         
            +
                  !@attributes[:access_token].nil? && !@attributes[:access_secret].nil?
         
     | 
| 
      
 125 
     | 
    
         
            +
                end
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
              end
         
     | 
| 
      
 128 
     | 
    
         
            +
            end
         
     |