lib/mls.rb in mls-0.14.0 vs lib/mls.rb in mls-1.0.0
- old
+ new
@@ -1,456 +1,102 @@
-require 'uri'
-require 'cgi'
-require 'logger'
-require 'net/https'
-require 'singleton'
-require 'yajl'
-require 'bigdecimal'
-require 'bigdecimal/util'
-require 'active_support'
-require 'active_support/core_ext'
-require 'date'
-require 'time'
+require 'sunstone'
-class Decimal #:nodoc:
-end
+module MLS
-class Boolean #:nodoc:
-end
-
-# _MLS_ is a low-level API. It provides basic HTTP #get, #post, #put, and #delete
-# calls to the MLS. It can also provides basic error checking of responses.
-class MLS
- include Singleton
-
API_VERSION = '0.1.0'
- attr_reader :url, :user_agent
- attr_writer :asset_host, :image_host, :agent_profile
- attr_accessor :api_key, :cookie_jar, :logger, :branch, :server, :forwarded_for
-
- # Sets the API Token and Host of the MLS Server
- #
- # #!ruby
- # MLS.url = "https://mls.42floors.com/API_KEY"
- def url=(uri) # TODO: testme
- @url = URI.parse(uri)
- @api_key = CGI.unescape(@url.user)
- @host, @port = @url.host, @url.port
- @ssl = (url.scheme == 'https')
+ def request_headers
+ super
+ super.merge({
+ 'Api-Version' => API_VERSION
+ })
end
- # Sets the user agent so that MLS can distinguish between multiple users
- # with the same auth
- def user_agent=(user_agent)
- @user_agent = user_agent
+ def self.asset_host
+ MLS::Model.connection.server_config['asset_host']
end
- def logger # TODO: testme
- @logger ||= default_logger
+ def self.image_host
+ MLS::Model.connection.server_config['image_host']
end
+
+end
- # Returns the current connection to the MLS or if connection has been made
- # it returns a new connection
- def connection # TODO: testme
- return @connection if @connection
- @connection = Net::HTTP.new(@host, @port)
- @connection.use_ssl = @ssl
- @connection
- end
+class MLS::Model < ActiveRecord::Base
+ self.abstract_class = true
+end
- # provides the asset host, if asset_host is set then it is returned,
- # otherwise it queries the MLS for this configuration.
- def asset_host # TODO: testme
- @asset_host ||= get('/asset_host').body
- end
+module MLS::Slugger
+
+ extend ActiveSupport::Concern
+
+ module ClassMethods
+
+ def find(*args)
+ friendly = -> (arg) { arg.respond_to?(:to_i) && arg.to_i.to_s != arg.to_s }
- def image_host # TODO: testme
- raw_image_host % (rand(4))
- end
-
- def raw_image_host
- @image_host ||= get('/image_host').body
- end
-
- def agent_profile(id)
- @agent_profile = Yajl::Parser.new(:symbolize_keys => true)
- .parse(MLS.get("/agents/#{id}").body)
- end
-
- def headers # TODO: testme
- headers = {
- 'Content-Type' => 'application/json',
- 'User-Agent' => @user_agent,
- 'X-42Floors-API-Version' => API_VERSION,
- 'X-42Floors-API-Key' => api_key
- }
- headers['X-42Floors-Branch'] = branch if branch
- headers['X-42Floors-Server'] = server if server
- headers['X-Forwarded-For'] = forwarded_for if forwarded_for
- headers
- end
-
- def prepare_request(req) # TODO: testme
- headers.each { |k, v| req[k] = v }
- req['Cookie'] = cookie_jar[:api_session] if cookie_jar[:api_session]
- end
-
- # Gets to +url+ on the MLS Server. Automatically includes any headers returned
- # by the MLS#headers function.
- #
- # Paramaters::
- #
- # * +url+ - The +url+ on the server to Get to. To get to <tt>"/accounts"</tt>
- # pass <tt>"/accounts"</tt> as +url+
- # * +params+ - A Hash or Ruby Object that responds to #to_param. The result
- # of this method is appended on the URL as query params
- # * +valid_response_codes+ - An Array of HTTP response codes that should be
- # considered accepable and not raise exceptions. For example If you don't
- # want a MLS::Exception::NotFound to be raised when a GET request returns
- # a 404 pass in 404, and the response body will be returned if the status
- # code is a 404 as it does if the status code is in the 200..299 rage. Status
- # codes in the 200..299 range are *always* considred acceptable
- #
- # Return Value::
- #
- # Returns the return value of the <tt>&block</tt> if given, otherwise the response
- # object
- #
- # Examples:
- #
- # #!ruby
- # MLS.get('/example') # => #<Net::HTTP::Response>
- #
- # MLS.get('/example', {:body => 'stuff'}) # => #<Net::HTTP::Response>
- #
- # MLS.get('/404') # => raises MLS::Exception::NotFound
- #
- # MLS.get('/404', nil, 404, 450..499) # => #<Net::HTTP::Response>
- #
- # MLS.get('/404', nil, [404, 450..499]) # => #<Net::HTTP::Response>
- #
- # MLS.get('/404', nil, 404) # => #<Net::HTTP::Response>
- #
- # # this will still raise an exception if the response_code is not valid
- # # and the block will not be called
- # MLS.get('/act') do |response, response_code|
- # # ...
- # end
- def get(url, params={}, *valid_response_codes, &block)
- params ||= {}
-
- req = Net::HTTP::Get.new(url + '?' + params.to_param)
- prepare_request(req)
-
- response = connection.request(req)
- handle_response(response, valid_response_codes)
-
- response.body.force_encoding(Encoding::UTF_8)
- if block_given?
- yield(response, response.code.to_i)
- else
- response
+ if args.count == 1 && friendly.call(args.first)
+ find_by_slug!(args)
+ else
+ super
+ end
end
- end
- # Puts to +url+ on the MLS Server. Automatically includes any headers returned
- # by the MLS#headers function.
- #
- # Paramaters::
- #
- # * +url+ - The +url+ on the server to Put to. To put to <tt>"/accounts"</tt>
- # pass <tt>"/accounts"</tt> as +url+
- # * +body+ - A Ruby object which is converted into JSON and added in the request
- # Body.
- # * +valid_response_codes+ - An Array of HTTP response codes that should be
- # considered accepable and not raise exceptions. For example If you don't
- # want a MLS::Exception::NotFound to be raised when a PUT request returns
- # a 404 pass in 404, and the response body will be returned if the status
- # code is a 404 as it does if the status code is in the 200..299 rage. Status
- # codes in the 200..299 range are *always* considred acceptable
- #
- # Return Value::
- #
- # Returns the return value of the <tt>&block</tt> if given, otherwise the response
- # object
- #
- # Examples:
- #
- # #!ruby
- # MLS.put('/example') # => #<Net::HTTP::Response>
- #
- # MLS.put('/example', {:body => 'stuff'}) # => #<Net::HTTP::Response>
- #
- # MLS.put('/404') # => raises MLS::Exception::NotFound
- #
- # MLS.put('/404', nil, 404, 450..499) # => #<Net::HTTP::Response>
- #
- # MLS.put('/404', nil, [404, 450..499]) # => #<Net::HTTP::Response>
- #
- # MLS.put('/404', nil, 404) # => #<Net::HTTP::Response>
- #
- # # this will still raise an exception if the response_code is not valid
- # # and the block will not be called
- # MLS.put('/act') do |response, response_code|
- # # ...
- # end
- def put(url, body={}, *valid_response_codes, &block)
- body ||= {}
-
- req = Net::HTTP::Put.new(url)
- req.body = Yajl::Encoder.encode(body)
- prepare_request(req)
-
- response = connection.request(req)
- handle_response(response, valid_response_codes)
-
- if block_given?
- yield(response, response.code.to_i)
- else
- response
- end
end
-
- # Posts to +url+ on the MLS Server. Automatically includes any headers returned
- # by the MLS#headers function.
- #
- # Paramaters::
- #
- # * +url+ - The +url+ on the server to Post to. To post to <tt>"/accounts"</tt>
- # pass <tt>"/accounts"</tt> as +url+
- # * +body+ - A Ruby object which is converted into JSON and added in the request
- # Body.
- # * +valid_response_codes+ - An Array of HTTP response codes that should be
- # considered accepable and not raise exceptions. For example If you don't
- # want a MLS::Exception::NotFound to be raised when a POST request returns
- # a 404 pass in 404, and the response body will be returned if the status
- # code is a 404 as it does if the status code is in the 200..299 rage. Status
- # codes in the 200..299 range are *always* considred acceptable
- #
- # Return Value::
- #
- # Returns the return value of the <tt>&block</tt> if given, otherwise the response
- # object
- #
- # Examples:
- #
- # #!ruby
- # MLS.post('/example') # => #<Net::HTTP::Response>
- #
- # MLS.post('/example', {:body => 'stuff'}) # => #<Net::HTTP::Response>
- #
- # MLS.post('/404') # => raises MLS::Exception::NotFound
- #
- # MLS.post('/404', nil, 404, 450..499) # => #<Net::HTTP::Response>
- #
- # MLS.post('/404', nil, [404, 450..499]) # => #<Net::HTTP::Response>
- #
- # MLS.post('/404', nil, 404) # => #<Net::HTTP::Response>
- #
- # # this will still raise an exception if the response_code is not valid
- # # and the block will not be called
- # MLS.post('/act') do |response, response_code|
- # # ...
- # end
- def post(url, body={}, *valid_response_codes, &block)
- body ||= {}
-
- req = Net::HTTP::Post.new(url)
- req.body = Yajl::Encoder.encode(body)
- prepare_request(req)
-
- response = connection.request(req)
- handle_response(response, valid_response_codes)
-
- if block_given?
- yield(response, response.code.to_i)
- else
- response
- end
+
+ def to_param
+ slug
end
- # Deletes to +url+ on the MLS Server. Automatically includes any headers returned
- # by the MLS#headers function.
- #
- # Paramaters::
- #
- # * +url+ - The +url+ on the server to Post to. To delete to <tt>"/accounts"</tt>
- # pass <tt>"/accounts"</tt> as +url+
- # * +body+ - A Ruby object which is converted into JSON and added in the request
- # Body.
- # * +valid_response_codes+ - An Array of HTTP response codes that should be
- # considered accepable and not raise exceptions. For example If you don't
- # want a MLS::Exception::NotFound to be raised when a POST request returns
- # a 404 pass in 404, and the response body will be returned if the status
- # code is a 404 as it does if the status code is in the 200..299 rage. Status
- # codes in the 200..299 range are *always* considred acceptable
- #
- # Return Value::
- #
- # Returns the return value of the <tt>&block</tt> if given, otherwise the
- # response object
- #
- # Examples:
- #
- # #!ruby
- # MLS.delete('/example') # => #<Net::HTTP::Response>
- #
- # MLS.delete('/example', {:body => 'stuff'}) # => #<Net::HTTP::Response>
- #
- # MLS.delete('/404') # => raises MLS::Exception::NotFound
- #
- # MLS.delete('/404', nil, 404, 450..499) # => #<Net::HTTP::Response>
- #
- # MLS.delete('/404', nil, [404, 450..499]) # => #<Net::HTTP::Response>
- #
- # MLS.delete('/404', nil, 404) # => #<Net::HTTP::Response>
- #
- # # this will still raise an exception if the response_code is not valid
- # # and the block will not be called
- # MLS.delete('/act') do |response, response_code|
- # # ...
- # end
- def delete(url, body={}, *valid_response_codes, &block)
- body ||= {}
+end
- req = Net::HTTP::Delete.new(url)
- req.body = Yajl::Encoder.encode(body)
- prepare_request(req)
+module MLS::Avatar
- response = connection.request(req)
- handle_response(response, valid_response_codes)
- if block_given?
- yield(response, response.code.to_i)
- else
- response
- end
- end
+ extend ActiveSupport::Concern
- # Raise an MLS::Exception based on the response_code, unless the response_code
- # is include in the valid_response_codes Array
- #
- # Paramaters::
- #
- # * +response+ - The Net::HTTP::Response object
- # * +valid_response_codes+ - An Array, Integer, or Range. If it's Array the
- # Array can include both Integers or Ranges.
- #
- # Return Value::
- #
- # If an exception is not raised the +response+ is returned
- #
- # Examples:
- #
- # #!ruby
- # MLS.handle_response(<Net::HTTP::Response @code=200>) # => <Net::HTTP::Response @code=200>
- #
- # MLS.handle_response(<Net::HTTP::Response @code=404>) # => raises MLS::Exception::NotFound
- #
- # MLS.handle_response(<Net::HTTP::Response @code=500>) # => raises MLS::Exception
- #
- # MLS.handle_response(<Net::HTTP::Response @code=404>, 404) # => <Net::HTTP::Response @code=404>
- #
- # MLS.handle_response(<Net::HTTP::Response @code=500>, 404, 500) # => <Net::HTTP::Response @code=500>
- #
- # MLS.handle_response(<Net::HTTP::Response @code=405>, 300, 400..499) # => <Net::HTTP::Response @code=405>
- #
- # MLS.handle_response(<Net::HTTP::Response @code=405>, [300, 400..499]) # => <Net::HTTP::Response @code=405>
- def handle_response(response, *valid_response_codes)
- if response['X-42Floors-API-Version-Deprecated']
- logger.warn("DEPRECATION WARNING: API v#{API_VERSION} is being phased out")
- end
-
- code = response.code.to_i
- valid_response_codes.flatten!
- valid_response_codes << (200..299)
-
- if !valid_response_codes.detect{|i| i.is_a?(Range) ? i.include?(code) : i == code}
- case code
- when 400
- raise MLS::Exception::BadRequest, response.body
- when 401
- raise MLS::Exception::Unauthorized, response.body
- when 404
- raise MLS::Exception::NotFound
- when 410
- raise MLS::Exception::Gone
- when 422
- raise MLS::Exception::ApiVersionUnsupported, response.body
- when 503
- raise MLS::Exception::ServiceUnavailable, response.body
- when 301
- raise MLS::Exception::MovedPermanently, response.body
- when 300..599
- raise MLS::Exception, code
- end
- end
-
- cookie_jar[:api_session] = response['Set-Cookie'] if response['Set-Cookie']
- cookie_jar[:api_session_id] = response['X-42Floors-API-Session-Id'] if response['X-42Floors-API-Session-Id']
-
- response
+ included do
+ belongs_to :avatar, :class_name => 'Photo'
end
- # Ping the MLS. If everything is configured and operating correctly <tt>"pong"</tt>
- # will be returned. Otherwise and MLS::Exception should be thrown.
- #
- # #!ruby
- # MLS.ping # => "pong"
- #
- # MLS.ping # raises MLS::Exception::ServiceUnavailable if a 503 is returned
- def ping # TODO: testme
- get('/ping').body
- end
+ def avatar_url(options={})
+ options.reverse_merge!({
+ :style => nil,
+ :protocol => "http",
+ :bg => nil,
+ :format => "jpg"
+ });
- def auth_ping # TODO: testme
- post('/ping').body
- end
+ url_params = {s: options[:style], bg: options[:bg]}.select{ |k, v| v }
+ result = "#{options[:protocol]}://#{MLS.image_host}/#{avatar_digest}.#{options[:format]}"
+ result += "?#{url_params.to_param}" if url_params.size > 1
- def default_logger # TODO: testme
- logger = Logger.new(STDOUT)
- logger.level = Logger::INFO
- logger
+ result
end
- # Delegates all uncauge class method calls to the singleton
- def self.method_missing(method, *args, &block) #:nodoc: # TODO: testme
- instance.__send__(method, *args, &block)
- end
-
- def self.parse(json) # TODO: testme
- Yajl::Parser.new(:symbolize_keys => true).parse(json)
- end
-
end
-require 'mls/errors'
-require 'mls/resource'
-require 'mls/parser'
+require 'mls/photo'
+require 'mls/account'
+require 'mls/brokerage'
+require 'mls/property'
+require 'mls/region'
+require 'mls/listing'
+require 'mls/lease'
+require 'mls/sublease'
+require 'mls/space'
+require 'mls/sale'
+require 'mls/coworking_space'
+require 'mls/address'
+require 'mls/locality'
+require 'mls/flyer'
+require 'mls/agency'
+require 'mls/floorplan'
+require 'mls/use'
-# Attributes
-require 'mls/attribute'
-require 'mls/attributes/fixnum'
-require 'mls/attributes/boolean'
-require 'mls/attributes/decimal'
-require 'mls/attributes/datetime'
-require 'mls/attributes/string'
-require 'mls/attributes/hash'
-require 'mls/attributes/array'
-
# Models
-require 'mls/model'
-require 'mls/models/account'
-require 'mls/models/listing'
-require 'mls/models/address'
-require 'mls/models/property'
-require 'mls/models/photo'
-require 'mls/models/video'
-require 'mls/models/pdf'
-require 'mls/models/tour'
-require 'mls/models/flyer'
-require 'mls/models/floorplan'
-require 'mls/models/region'
-require 'mls/models/brokerage'
-
-#factories
-require 'mls/factories_helper'
+# # Helpers
+# class MLS
+#
+# def current_account
+# end
+#
+# end
\ No newline at end of file