spark_api 1.0.2 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/README.md +86 -3
  2. data/VERSION +1 -1
  3. data/lib/spark_api.rb +1 -0
  4. data/lib/spark_api/authentication/oauth2.rb +43 -2
  5. data/lib/spark_api/configuration/oauth2_configurable.rb +3 -1
  6. data/lib/spark_api/models.rb +1 -0
  7. data/lib/spark_api/models/listing.rb +17 -1
  8. data/lib/spark_api/models/rental_calendar.rb +26 -0
  9. data/lib/spark_api/options_hash.rb +18 -0
  10. data/script/combined_flow_example.rb +55 -0
  11. data/script/oauth2_example.rb +2 -2
  12. data/spec/fixtures/listings/rental_calendar.json +19 -0
  13. data/spec/fixtures/listings/with_rental_calendar.json +52 -0
  14. data/spec/unit/spark_api/authentication/oauth2_spec.rb +79 -1
  15. data/spec/unit/spark_api/models/listing_spec.rb +7 -0
  16. data/spec/unit/spark_api/models/rental_calendar_spec.rb +30 -0
  17. data/spec/unit/spark_api/options_hash_spec.rb +14 -0
  18. metadata +15 -96
  19. data/bin/spark_api~ +0 -8
  20. data/lib/spark_api/authentication/api_auth.rb~ +0 -104
  21. data/lib/spark_api/authentication/base_auth.rb~ +0 -47
  22. data/lib/spark_api/authentication/oauth2.rb~ +0 -199
  23. data/lib/spark_api/authentication/oauth2_impl/grant_type_base.rb~ +0 -87
  24. data/lib/spark_api/authentication/oauth2_impl/grant_type_code.rb~ +0 -49
  25. data/lib/spark_api/authentication/oauth2_impl/grant_type_password.rb~ +0 -45
  26. data/lib/spark_api/authentication/oauth2_impl/grant_type_refresh.rb~ +0 -36
  27. data/lib/spark_api/authentication/oauth2_impl/middleware.rb~ +0 -39
  28. data/lib/spark_api/authentication/oauth2_impl/password_provider.rb~ +0 -25
  29. data/lib/spark_api/cli.rb~ +0 -158
  30. data/lib/spark_api/cli/api_auth.rb~ +0 -8
  31. data/lib/spark_api/cli/oauth2.rb~ +0 -14
  32. data/lib/spark_api/cli/setup.rb~ +0 -47
  33. data/lib/spark_api/configuration.rb~ +0 -54
  34. data/lib/spark_api/configuration/yaml.rb~ +0 -101
  35. data/lib/spark_api/faraday.rb~ +0 -64
  36. data/lib/spark_api/models.rb~ +0 -33
  37. data/lib/spark_api/models/account.rb~ +0 -115
  38. data/lib/spark_api/models/base.rb~ +0 -118
  39. data/lib/spark_api/models/connect_prefs.rb~ +0 -10
  40. data/lib/spark_api/models/constraint.rb~ +0 -16
  41. data/lib/spark_api/models/contact.rb~ +0 -49
  42. data/lib/spark_api/models/custom_fields.rb~ +0 -12
  43. data/lib/spark_api/models/document.rb~ +0 -11
  44. data/lib/spark_api/models/finders.rb~ +0 -45
  45. data/lib/spark_api/models/idx_link.rb~ +0 -47
  46. data/lib/spark_api/models/listing.rb~ +0 -197
  47. data/lib/spark_api/models/listing_cart.rb~ +0 -72
  48. data/lib/spark_api/models/market_statistics.rb~ +0 -33
  49. data/lib/spark_api/models/message.rb~ +0 -21
  50. data/lib/spark_api/models/note.rb~ +0 -41
  51. data/lib/spark_api/models/notification.rb~ +0 -42
  52. data/lib/spark_api/models/open_house.rb~ +0 -24
  53. data/lib/spark_api/models/photo.rb~ +0 -70
  54. data/lib/spark_api/models/property_types.rb~ +0 -7
  55. data/lib/spark_api/models/saved_search.rb~ +0 -16
  56. data/lib/spark_api/models/shared_listing.rb~ +0 -35
  57. data/lib/spark_api/models/standard_fields.rb~ +0 -50
  58. data/lib/spark_api/models/subresource.rb~ +0 -19
  59. data/lib/spark_api/models/system_info.rb~ +0 -14
  60. data/lib/spark_api/models/tour_of_home.rb~ +0 -24
  61. data/lib/spark_api/models/video.rb~ +0 -16
  62. data/lib/spark_api/models/virtual_tour.rb~ +0 -18
  63. data/lib/spark_api/multi_client.rb~ +0 -59
  64. data/lib/spark_api/paginate.rb~ +0 -109
  65. data/lib/spark_api/primary_array.rb~ +0 -29
  66. data/lib/spark_api/request.rb~ +0 -96
  67. data/lib/spark_api/response.rb~ +0 -70
  68. data/lib/spark_api/version.rb~ +0 -4
  69. data/script/console~ +0 -6
  70. data/script/example.rb~ +0 -27
  71. data/spec/unit/flexmls_api_spec.rb~ +0 -23
  72. data/spec/unit/spark_api/authentication/api_auth_spec.rb~ +0 -169
  73. data/spec/unit/spark_api/authentication/base_auth_spec.rb~ +0 -10
  74. data/spec/unit/spark_api/authentication/oauth2_impl/grant_type_base_spec.rb~ +0 -10
  75. data/spec/unit/spark_api/authentication/oauth2_spec.rb~ +0 -205
  76. data/spec/unit/spark_api/authentication_spec.rb~ +0 -38
  77. data/spec/unit/spark_api/configuration/yaml_spec.rb~ +0 -72
  78. data/spec/unit/spark_api/configuration_spec.rb~ +0 -122
  79. data/spec/unit/spark_api/faraday_spec.rb~ +0 -90
  80. data/spec/unit/spark_api/models/contact_spec.rb~ +0 -108
  81. data/spec/unit/spark_api/models/listing_cart_spec.rb~ +0 -127
  82. data/spec/unit/spark_api/models/listing_spec.rb~ +0 -320
  83. data/spec/unit/spark_api/models/message_spec.rb~ +0 -47
  84. data/spec/unit/spark_api/models/note_spec.rb~ +0 -63
  85. data/spec/unit/spark_api/models/notification_spec.rb~ +0 -62
  86. data/spec/unit/spark_api/models/shared_listing_spec.rb~ +0 -45
  87. data/spec/unit/spark_api/multi_client_spec.rb~ +0 -56
  88. data/spec/unit/spark_api/paginate_spec.rb~ +0 -224
  89. data/spec/unit/spark_api/primary_array_spec.rb~ +0 -41
  90. data/spec/unit/spark_api/request_spec.rb~ +0 -344
@@ -1,24 +0,0 @@
1
- require 'date'
2
- require 'time'
3
-
4
- module FlexmlsApi
5
- module Models
6
- class OpenHouse < Base
7
- extend Subresource
8
-
9
- self.element_name = "openhouses"
10
-
11
- def initialize(attributes={})
12
- # Transform the date strings
13
- unless attributes['Date'].nil?
14
- date = Date.parse(attributes['Date'])
15
- attributes['Date'] = date
16
- attributes['StartTime'] = Time.parse("#{date}T#{attributes['StartTime']}") unless attributes['StartTime'].nil?
17
- attributes['EndTime'] = Time.parse("#{date}T#{attributes['EndTime']}") unless attributes['EndTime'].nil?
18
- end
19
- super(attributes)
20
- end
21
-
22
- end
23
- end
24
- end
@@ -1,70 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class Photo < Base
4
- extend Subresource
5
- self.element_name = "photos"
6
-
7
- attr_accessor :update_path
8
-
9
- EDITABLE_FIELDS = [:Picture, :FileName, :Name, :Caption, :Primary]
10
-
11
- def initialize(opts={})
12
- defaulted_opts = {}
13
- EDITABLE_FIELDS.each do |k|
14
- key = k.to_s()
15
- defaulted_opts[key] = opts[key] || nil
16
- end
17
- super(opts.merge(defaulted_opts))
18
- end
19
-
20
- def primary?
21
- @attributes["Primary"] == true
22
- end
23
-
24
- def save(arguments={})
25
- begin
26
- return save!(arguments)
27
- rescue NotFound, BadResourceRequest => e
28
- FlexmlsApi.logger.error("Failed to save resource #{self}: #{e.message}")
29
- end
30
- false
31
- end
32
- def save!(arguments={})
33
- payload = {"Photos" => [ build_photo_hash]}
34
- if exists?
35
- results = connection.put "#{update_path}/#{self.Id}", payload, arguments
36
- else
37
- results = connection.post update_path, payload, arguments
38
- end
39
- result = results.first
40
- load(result)
41
- true
42
- end
43
-
44
- def load_picture(file_name)
45
- self.Picture = Base64.encode64(File.open(file_name, 'rb').read).gsub(/\n/, '')
46
- self.FileName = File.basename(file_name)
47
- end
48
-
49
- def delete(args={})
50
- connection.delete("#{update_path}/#{self.Id}", args)
51
- end
52
-
53
- def exists?
54
- @attributes.include?("Id")
55
- end
56
-
57
- private
58
-
59
- def build_photo_hash
60
- results_hash = {}
61
- EDITABLE_FIELDS.each do |k|
62
- key = k.to_s
63
- results_hash[key] = @attributes[key] unless @attributes[key].nil?
64
- end
65
- results_hash
66
- end
67
-
68
- end
69
- end
70
- end
@@ -1,7 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class PropertyTypes < Base
4
- self.element_name="propertytypes"
5
- end
6
- end
7
- end
@@ -1,16 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class SavedSearch < Base
4
- extend Finders
5
- self.element_name="savedsearches"
6
-
7
- def self.provided()
8
- Class.new(self).tap do |provided|
9
- provided.element_name = '/savedsearches'
10
- provided.prefix = '/provided'
11
- FlexmlsApi.logger.info("#{self.name}.path: #{provided.path}")
12
- end
13
- end
14
- end
15
- end
16
- end
@@ -1,35 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class SharedListing < Base
4
- extend Finders
5
- self.element_name="sharedlistings"
6
-
7
- def ListingIds=(listing_ids)
8
- attributes["ListingIds"] = Array(listing_ids)
9
- end
10
- def ViewId=(id)
11
- attributes["ViewId"] = id
12
- end
13
- def ReportId=(id)
14
- attributes["ReportId"] = id
15
- end
16
-
17
- def save(arguments={})
18
- begin
19
- return save!(arguments)
20
- rescue BadResourceRequest => e
21
- rescue NotFound => e
22
- # log and leave
23
- FlexmlsApi.logger.error("Failed to save SharedListing #{self}: #{e.message}")
24
- end
25
- false
26
- end
27
- def save!(arguments={})
28
- results = connection.post self.class.path, attributes, arguments
29
- result = results.first
30
- attributes['ResourceUri'] = result['ResourceUri']
31
- true
32
- end
33
- end
34
- end
35
- end
@@ -1,50 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class StandardFields < Base
4
- extend Finders
5
- self.element_name="standardfields"
6
-
7
- # expand all fields passed in
8
- def self.find_and_expand_all(fields, arguments={}, max_list_size=1000)
9
- returns = {}
10
-
11
- # find all standard fields, but expand only the location fields
12
- # TODO: when _expand support is added to StandardFields API, use the following
13
- # standard_fields = find(:all, {:ApiUser => owner, :_expand => fields.join(",")})
14
- standard_fields = find(:all, arguments)
15
-
16
- # filter through the list and return only the location fields found
17
- fields.each do |field|
18
- # search for field in the payload
19
- if standard_fields.first.attributes.has_key?(field)
20
- returns[field] = standard_fields.first.attributes[field]
21
-
22
- # lookup fully _expand field, if the field has a list
23
- if returns[field]['HasList'] && returns[field]['MaxListSize'].to_i <= max_list_size
24
- returns[field] = connection.get("/standardfields/#{field}", arguments).first[field]
25
- end
26
-
27
- end
28
- end
29
-
30
- returns
31
- end
32
-
33
-
34
- # find_nearby: find fields nearby via lat/lon
35
- def self.find_nearby(prop_types = ["A"], arguments={})
36
- return_json = {"D" => {"Success" => true, "Results" => []} }
37
-
38
- # add _expand=1 so the fields are returned
39
- arguments.merge!({:_expand => 1})
40
-
41
- # find and return
42
- return_json["D"]["Results"] = connection.get("/standardfields/nearby/#{prop_types.join(',')}", arguments)
43
-
44
- # return
45
- return_json
46
- end
47
-
48
- end
49
- end
50
- end
@@ -1,19 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- module Subresource
4
-
5
- def build_subclass
6
- Class.new(self)
7
- end
8
-
9
- def find_by_listing_key(key, arguments={})
10
- collect(connection.get("/listings/#{key}#{self.path}", arguments))
11
- end
12
-
13
- def find_by_id(id, parent_id, arguments={})
14
- collect(connection.get("/listings/#{parent_id}#{self.path}/#{id}", arguments)).first
15
- end
16
-
17
- end
18
- end
19
- end
@@ -1,14 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class SystemInfo < Base
4
- self.element_name="system"
5
-
6
- def primary_logo
7
- logo = nil
8
- mls_logos = attributes['Configuration'].first['MlsLogos']
9
- logo = mls_logos.first if !mls_logos.nil? and !mls_logos.empty?
10
- logo
11
- end
12
- end
13
- end
14
- end
@@ -1,24 +0,0 @@
1
- require 'date'
2
- require 'time'
3
-
4
- module FlexmlsApi
5
- module Models
6
- class TourOfHome < Base
7
- extend Subresource
8
-
9
- self.element_name = "tourofhomes"
10
-
11
- def initialize(attributes={})
12
- # Transform the date strings
13
- unless attributes['Date'].nil?
14
- date = Date.parse(attributes['Date'])
15
- attributes['Date'] = date
16
- attributes['StartTime'] = Time.parse("#{date}T#{attributes['StartTime']}") unless attributes['StartTime'].nil?
17
- attributes['EndTime'] = Time.parse("#{date}T#{attributes['EndTime']}") unless attributes['EndTime'].nil?
18
- end
19
- super(attributes)
20
- end
21
-
22
- end
23
- end
24
- end
@@ -1,16 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class Video < Base
4
- extend Subresource
5
- self.element_name = 'videos'
6
-
7
- def branded?
8
- attributes['Type'] == 'branded'
9
- end
10
-
11
- def unbranded?
12
- attributes['Type'] == 'unbranded'
13
- end
14
- end
15
- end
16
- end
@@ -1,18 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class VirtualTour < Base
4
- extend Subresource
5
- self.element_name="virtualtours"
6
-
7
-
8
- def branded?
9
- attributes["Type"] == "branded"
10
- end
11
-
12
- def unbranded?
13
- attributes["Type"] == "unbranded"
14
- end
15
-
16
- end
17
- end
18
- end
@@ -1,59 +0,0 @@
1
- module FlexmlsApi
2
- #===Active support for multiple clients
3
- module MultiClient
4
- include FlexmlsApi::Configuration
5
-
6
- # Activate a specific instance of the client (with appropriate config settings). Each client
7
- # is lazily instanciated by calling the matching FlexmlsApi.symbol_name method on the
8
- # FlexmlsApi module. It's the developers responsibility to extend the module and provide this
9
- # method.
10
- # Parameters
11
- # @sym - the unique symbol identifier for a client configuration.
12
- # &block - a block of code to run with the specified client enabled, after which the original
13
- # client setting will be reenabled
14
- def activate(sym)
15
- if block_given?
16
- original_client = Thread.current[:flexmls_api_client]
17
- begin
18
- activate_client(sym)
19
- yield
20
- ensure
21
- Thread.current[:flexmls_api_client] = original_client
22
- end
23
- else
24
- activate_client(sym)
25
- end
26
- end
27
-
28
- private
29
-
30
- # set the active client for the symbol
31
- def activate_client(symbol)
32
- if !Thread.current[symbol].nil?
33
- active_client = Thread.current[symbol]
34
- elsif FlexmlsApi.respond_to? symbol
35
- active_client = FlexmlsApi.send(symbol)
36
- elsif YamlConfig.exists? symbol.to_s
37
- active_client = activate_client_from_config(symbol)
38
- else
39
- raise ArgumentError, "The symbol #{symbol} is not setup correctly as a multi client key."
40
- end
41
- Thread.current[symbol] = active_client
42
- Thread.current[:flexmls_api_client] = active_client
43
- end
44
-
45
- def activate_client_from_config(symbol)
46
- FlexmlsApi.logger.debug("Loading multiclient [#{symbol.to_s}] from config")
47
- yaml = YamlConfig.build(symbol.to_s)
48
- if(yaml.oauth2?)
49
- Client.new(yaml.client_keys.merge({
50
- :oauth2_provider => Authentication::OAuth2Impl.load_provider(yaml.oauth2_provider, yaml.oauth2_keys),
51
- :authentication_mode => FlexmlsApi::Authentication::OAuth2,
52
- }))
53
- else
54
- Client.new(yaml.client_keys)
55
- end
56
- end
57
-
58
- end
59
- end
@@ -1,109 +0,0 @@
1
- require 'will_paginate/collection'
2
-
3
- # =Pagination for api resource collections
4
- # Will paginate adapter for the api client. Utilizes the same interface as will paginate and returns the
5
- # same WillPaginate::Collection for finder results.
6
- module FlexmlsApi
7
- module Paginate
8
-
9
- DEFAULT_PAGE_SIZE = 25
10
-
11
- # == Replacement hook for will_paginate's class method
12
- # Does a best effort to mimic the will_paginate method of same name. All arguments are
13
- # passed on to the finder method except the special keys for the options hash listed below.
14
- #
15
- # == Special parameters for paginating finders
16
- # * <tt>:page</tt> -- REQUIRED, but defaults to 1 if false or nil
17
- # * <tt>:per_page</tt> -- defaults to <tt>CurrentModel.per_page</tt> (which is 25 if not overridden)
18
- # * <tt>:finder</tt> -- name of the finder used (default: "get"). This needs to be a class finder method on the class
19
- def paginate(*args)
20
- options = args.last.is_a?(::Hash) ? args.pop : {}
21
- page = options.delete(:page) || 1
22
- items_per_page = options.delete(:per_page) || self.per_page
23
- finder = (options.delete(:finder) || 'get').to_s
24
- page_options = {
25
- "_pagination" => 1,
26
- "_limit" => items_per_page,
27
- "_page" => page
28
- }
29
- options.merge!(page_options)
30
- args << options
31
- collection = send(finder,*args)
32
- end
33
-
34
- # == Instanciate class instances from array of hash representations.
35
- # Needs to be called by all finders that would like to support paging. Takes the hash result
36
- # set from the request layer and instanciates instances of the class called for the finder.
37
- #
38
- # * result_array -- the results object returned from the api request layer. An array of hashes.
39
- #
40
- # :returns:
41
- # An array of class instances for the Class of the calling finder
42
- def collect(result_array)
43
-
44
- # when conducting a count (pagination=count), the result_array is not an array
45
- # in those cases, simply return the Fixnum
46
- return result_array unless result_array.kind_of? Array
47
-
48
- collection = result_array.collect { |item| new(item)}
49
- result_array.replace(collection)
50
- result_array
51
- end
52
-
53
- # Default per_page limit set on all models. Override this method in the model such ala the
54
- # will_paginate gem to change
55
- def per_page
56
- DEFAULT_PAGE_SIZE
57
- end
58
-
59
-
60
- end
61
-
62
- # ==Paginate Api Responses
63
- # Module used by the request layer to decorate the response's results array with paging support.
64
- # Pagination only happens if the response includes the pagination information as specified by the
65
- # API.
66
- module PaginateResponse
67
- attr_accessor :results
68
- def method_missing(method_symbol, *arguments)
69
- if results.respond_to?(method_symbol)
70
- arguments.empty? ? self.results.send(method_symbol) : self.results.send(method_symbol, arguments)
71
- else
72
- super
73
- end
74
- end
75
- end
76
-
77
- # ==Pagination Helpers
78
- # Helpers to create the pagination collection
79
- module PaginateHelper
80
- # ==Enable pagination
81
- # * results -- array of hashes representing api resources
82
- # * paging_hash -- the pagination response information from the api representing paging state.
83
- #
84
- # :returns:
85
- # The result set decorated as a WillPaginate::Collection
86
- def paginate_response(results, paging_hash)
87
- pager = Pagination.new(paging_hash)
88
- paged_results = WillPaginate::Collection.create(pager.current_page, pager.page_size, pager.total_rows) do |p|
89
- p.replace(results)
90
- end
91
- paged_results.extend PaginateResponse
92
- paged_results.results = results
93
- paged_results
94
- end
95
- end
96
-
97
- # ==Pagination
98
- # Simple class representing the API's pagination response object
99
- class Pagination
100
- attr_accessor :total_rows, :page_size, :total_pages, :current_page
101
- def initialize(hash)
102
- @total_rows = hash["TotalRows"]
103
- @page_size = hash["PageSize"]
104
- @total_pages = hash["TotalPages"]
105
- @current_page = hash["CurrentPage"]
106
- end
107
- end
108
-
109
- end