spark_api 1.0.2 → 1.0.4

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.
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