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,47 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class IdxLink < Base
4
- self.element_name="idxlinks"
5
-
6
- LINK_TYPES = ["QuickSearch", "SavedSearch", "MyListings", "Roster"]
7
-
8
- #TODO Work all below into common base class
9
- def self.find(*arguments)
10
- scope = arguments.slice!(0)
11
- options = arguments.slice!(0) || {}
12
-
13
- case scope
14
- when :all then find_every(options)
15
- when :first then find_every(options).first
16
- when :last then find_every(options).last
17
- when :one then find_one(options)
18
- else find_single(scope, options)
19
- end
20
- end
21
-
22
- def self.first(*arguments)
23
- find(:first, *arguments)
24
- end
25
-
26
- def self.last(*arguments)
27
- find(:last, *arguments)
28
- end
29
-
30
- private
31
-
32
- def self.find_every(options)
33
- raise NotImplementedError # TODO
34
- end
35
-
36
- def self.find_one(options)
37
- raise NotImplementedError # TODO
38
- end
39
-
40
- def self.find_single(scope, options)
41
- resp = FlexmlsApi.client.get("/idxlinks/#{scope}", options)
42
- new(resp.first)
43
- end
44
-
45
- end
46
- end
47
- end
@@ -1,197 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class Listing < Base
4
- extend Finders
5
- attr_accessor :photos, :videos, :virtual_tours, :documents
6
- attr_accessor :constraints
7
- self.element_name="listings"
8
- DATA_MASK = "********"
9
- WRITEABLE_FIELDS = ["ListPrice", "ExpirationDate"]
10
-
11
- def initialize(attributes={})
12
- @photos = []
13
- @videos = []
14
- @virtual_tours = []
15
- @documents = []
16
- @constraints = []
17
-
18
- if attributes.has_key?('StandardFields')
19
- pics, vids, tours, docs = attributes['StandardFields'].values_at('Photos','Videos', 'VirtualTours', 'Documents')
20
- end
21
-
22
- if pics != nil
23
- pics.collect { |pic| @photos.push(Photo.new(pic)) }
24
- attributes['StandardFields'].delete('Photos')
25
- end
26
-
27
- if vids != nil
28
- vids.collect { |vid| @videos.push(Video.new(vid)) }
29
- attributes['StandardFields'].delete('Videos')
30
- end
31
-
32
- if tours != nil
33
- tours.collect { |tour| @virtual_tours.push(VirtualTour.new(tour)) }
34
- attributes['StandardFields'].delete('VirtualTours')
35
- end
36
-
37
- if docs != nil
38
- docs.collect { |doc| @documents.push(Document.new(doc)) }
39
- attributes['StandardFields'].delete('Documents')
40
- end
41
-
42
- super(attributes)
43
- end
44
-
45
- def self.find_by_cart_id(cart_id, options={})
46
- query = {:_filter => "ListingCart Eq '#{cart_id}'"}
47
- find(:all, options.merge(query))
48
- end
49
-
50
- def self.my(arguments={})
51
- collect(connection.get("/my/listings", arguments))
52
- end
53
-
54
- def self.office(arguments={})
55
- collect(connection.get("/office/listings", arguments))
56
- end
57
-
58
- def self.company(arguments={})
59
- collect(connection.get("/company/listings", arguments))
60
- end
61
-
62
- def self.nearby(latitude, longitude, arguments={})
63
- nearby_args = {:Lat => latitude, :Lon => longitude}.merge(arguments)
64
- collect(connection.get("/listings/nearby", nearby_args))
65
- end
66
-
67
- def tour_of_homes(arguments={})
68
- return @tour_of_homes unless @tour_of_homes.nil?
69
- @tour_of_homes = TourOfHome.find_by_listing_key(self.Id, arguments)
70
- end
71
-
72
- def open_houses(arguments={})
73
- return @open_houses unless @open_houses.nil?
74
- @open_houses = OpenHouse.find_by_listing_key(self.Id, arguments)
75
- end
76
-
77
- def my_notes
78
- Note.build_subclass.tap do |note|
79
- note.prefix = "/listings/#{self.ListingKey}"
80
- note.element_name = "/my/notes"
81
- FlexmlsApi.logger.info("Note.path: #{note.path}")
82
- end
83
- end
84
-
85
- # 'fore' is required when accessing an agent's shared
86
- # notes for a specific contact. If the ApiUser /is/ the
87
- # contact, then it can be inferred by the api, so it's
88
- # unecessary
89
- def shared_notes(fore=nil)
90
- Note.build_subclass.tap do |note|
91
- note.prefix = "/listings/#{self.ListingKey}"
92
- if fore.nil?
93
- note.element_name = "/shared/notes"
94
- else
95
- note.element_name = "/shared/notes/contacts/#{fore}"
96
- end
97
- end
98
- end
99
-
100
- def street_address
101
- "#{self.StreetNumber} #{self.StreetDirPrefix} #{self.StreetName} #{self.StreetSuffix} #{self.StreetDirSuffix} #{self.StreetAdditionalInfo}".delete(DATA_MASK).strip().gsub(/\s{2,}/, ' ')
102
- end
103
-
104
- def region_address
105
- "#{self.City}, #{self.StateOrProvince} #{self.PostalCode}".delete(DATA_MASK).strip().gsub(/^,\s/, '').gsub(/,$/, '')
106
- end
107
-
108
- def full_address
109
- "#{self.street_address}, #{self.region_address}".strip().gsub(/^,\s/, '').gsub(/,$/, '')
110
- end
111
-
112
- def save(arguments={})
113
- self.errors = []
114
- begin
115
- return save!(arguments)
116
- rescue BadResourceRequest => e
117
- self.errors << {:code => e.code, :message => e.message}
118
- FlexmlsApi.logger.debug("BHDEBUG: #{e.inspect}")
119
- if e.code == 1053
120
- @constraints = []
121
- e.details.each do |detail|
122
- detail.each_pair do |k,v|
123
- v.each { |constraint| @constraints << Constraint.new(constraint)}
124
- end
125
- end
126
- end
127
- FlexmlsApi.logger.error("Failed to save resource #{self}: #{e.message}")
128
- rescue NotFound => e
129
- FlexmlsApi.logger.error("Failed to save resource #{self}: #{e.message}")
130
- end
131
- false
132
- end
133
- def save!(arguments={})
134
- writable_changed_keys = changed & WRITEABLE_FIELDS
135
- if writable_changed_keys.empty?
136
- FlexmlsApi.logger.warn("No supported listing change detected")
137
- else
138
- results = connection.put "#{self.class.path}/#{self.Id}", build_hash(writable_changed_keys), arguments
139
- @contstraints = []
140
- results.details.each do |detail|
141
- detail.each_pair do |k,v|
142
- v.each { |constraint| @constraints << Constraint.new(constraint)}
143
- end
144
- end
145
- end
146
- true
147
- end
148
-
149
- def editable?(editable_settings = [])
150
- settings = Array(editable_settings)
151
- editable = attributes.include?("Permissions") && self.Permissions["Editable"] == true
152
- if editable
153
- settings.each{ |setting| editable = false unless self.Permissions["EditableSettings"][setting.to_s] == true }
154
- end
155
- editable
156
- end
157
-
158
- def ExpirationDate
159
- attributes["ExpirationDate"]
160
- end
161
- def ExpirationDate=(value)
162
- write_attribute("ExpirationDate", value)
163
- end
164
-
165
-
166
- private
167
-
168
- # TODO trim this down so we're only overriding the StandardFields access
169
- def method_missing(method_symbol, *arguments)
170
- method_name = method_symbol.to_s
171
-
172
- if method_name =~ /(=|\?)$/
173
- case $1
174
- when "="
175
- write_attribute($`,arguments.first)
176
- # TODO figure out a nice way to present setters for the standard fields
177
- when "?"
178
- attributes[$`]
179
- end
180
- else
181
- return attributes[method_name] if attributes.include?(method_name)
182
- return @attributes['StandardFields'][method_name] if attributes['StandardFields'].include?(method_name)
183
- super # GTFO
184
- end
185
- end
186
-
187
- def build_hash(keys)
188
- hash = {}
189
- keys.each do |key|
190
- hash[key] = attributes[key]
191
- end
192
- hash
193
- end
194
-
195
- end
196
- end
197
- end
@@ -1,72 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class ListingCart < Base
4
- extend Finders
5
- self.element_name="listingcarts"
6
-
7
- def ListingIds=(listing_ids)
8
- attributes["ListingIds"] = Array(listing_ids)
9
- end
10
- def Name=(name)
11
- attributes["Name"] = name
12
- end
13
-
14
- def add_listing(listing)
15
- id = listing.respond_to?(:Id) ? listing.Id : listing.to_s
16
- results = connection.post("#{self.class.path}/#{self.Id}", {"ListingIds" => [ listing ]})
17
- self.ListingCount = results.first["ListingCount"]
18
- end
19
-
20
- def remove_listing(listing)
21
- id = listing.respond_to?(:Id) ? listing.Id : listing.to_s
22
- results = connection.delete("#{self.class.path}/#{self.Id}/listings/#{id}")
23
- self.ListingCount = results.first["ListingCount"]
24
- end
25
-
26
- def self.for(listings,arguments={})
27
- keys = Array(listings).map { |l| l.respond_to?(:Id) ? l.Id : l.to_s }
28
- collect(connection.get("/#{self.element_name}/for/#{keys.join(",")}", arguments))
29
- end
30
-
31
- def self.my(arguments={})
32
- collect(connection.get("/my/#{self.element_name}", arguments))
33
- end
34
-
35
- def self.portal(arguments={})
36
- collect(connection.get("/#{self.element_name}/portal", arguments))
37
- end
38
-
39
- def save(arguments={})
40
- begin
41
- return save!(arguments)
42
- rescue BadResourceRequest => e
43
- rescue NotFound => e
44
- # log and leave
45
- FlexmlsApi.logger.error("Failed to save contact #{self}: #{e.message}")
46
- end
47
- false
48
- end
49
- def save!(arguments={})
50
- attributes['Id'].nil? ? create!(arguments) : update!(arguments)
51
- end
52
-
53
- def delete(args={})
54
- connection.delete("#{self.class.path}/#{self.Id}", args)
55
- end
56
-
57
- private
58
- def create!(arguments={})
59
- results = connection.post self.class.path, {"ListingCarts" => [ attributes ]}, arguments
60
- result = results.first
61
- attributes['ResourceUri'] = result['ResourceUri']
62
- attributes['Id'] = parse_id(result['ResourceUri'])
63
- true
64
- end
65
- def update!(arguments={})
66
- results = connection.put "#{self.class.path}/#{self.Id}", {"ListingCarts" => [ {"Name" => attributes["Name"], "ListingIds" => attributes["ListingIds"]} ] }, arguments
67
- true
68
- end
69
-
70
- end
71
- end
72
- end
@@ -1,33 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class MarketStatistics < Base
4
- self.element_name="marketstatistics"
5
-
6
- def self.absorption(parameters={})
7
- self.stat('absorption',parameters)
8
- end
9
- def self.inventory(parameters={})
10
- self.stat('inventory',parameters)
11
- end
12
- def self.price(parameters={})
13
- self.stat('price',parameters)
14
- end
15
- def self.ratio(parameters={})
16
- self.stat('ratio',parameters)
17
- end
18
- def self.dom(parameters={})
19
- self.stat('dom',parameters)
20
- end
21
- def self.volume(parameters={})
22
- self.stat('volume',parameters)
23
- end
24
-
25
- private
26
- def self.stat(stat_name, parameters={})
27
- resp = connection.get("#{path}/#{stat_name}", parameters)
28
- new(resp.first)
29
- end
30
-
31
- end
32
- end
33
- end
@@ -1,21 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class Message < Base
4
- self.element_name="messages"
5
-
6
- def save(arguments={})
7
- begin
8
- return save!(arguments)
9
- rescue NotFound, BadResourceRequest => e
10
- FlexmlsApi.logger.error("Failed to save resource #{self}: #{e.message}")
11
- end
12
- false
13
- end
14
- def save!(arguments={})
15
- results = connection.post self.class.path, {"Messages" => [ attributes ]}, arguments
16
- true
17
- end
18
-
19
- end
20
- end
21
- end
@@ -1,41 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class Note < Base
4
- extend Subresource
5
- self.element_name = "notes" # not sure this is really of any use...
6
-
7
- def self.get(options={})
8
- ret = super(options)
9
- if ret.empty?
10
- return nil
11
- else
12
- return ret.first
13
- end
14
- end
15
-
16
- def save(arguments={})
17
- begin
18
- return save!(arguments)
19
- rescue BadResourceRequest => e
20
- rescue NotFound => e
21
- # log and leave
22
- FlexmlsApi.logger.error("Failed to save note #{self} (path: #{self.class.path}): #{e.message}")
23
- end
24
- false
25
- end
26
-
27
- def save!(args={})
28
- args.merge(:Notes => attributes['Note'])
29
- results = connection.put(self.class.path, {:Note => attributes['Note']}, args)
30
- result = results.first
31
- attributes['ResourceUri'] = result['ResourceUri']
32
- true
33
- end
34
-
35
- def delete(args={})
36
- connection.delete(self.class.path, args)
37
- end
38
-
39
- end
40
- end
41
- end
@@ -1,42 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class Notification < Base
4
-
5
- self.element_name = 'notifications'
6
-
7
- def save(arguments={})
8
- self.errors = [] # clear the errors hash
9
- begin
10
- return save!(arguments)
11
- rescue BadResourceRequest => e
12
- self.errors << {:code => e.code, :message => e.message}
13
- FlexmlsApi.logger.error("Failed to save resource #{self}: #{e.message}")
14
- rescue NotFound => e
15
- FlexmlsApi.logger.error("Failed to save resource #{self}: #{e.message}")
16
- end
17
- false
18
- end
19
-
20
- def save!(arguments={})
21
- results = connection.post self.class.path, attributes, arguments
22
- result = results.first
23
- attributes['ResourceUri'] = result['ResourceUri']
24
- true
25
- end
26
-
27
- def self.unread()
28
- # force pagination so response knows to deal with returned pagination info
29
- result = connection.get "#{self.path}/unread", {:_pagination => 'count'}
30
- result
31
- end
32
-
33
- def self.mark_read(notifications, arguments={})
34
- notifications = Array(notifications)
35
-
36
- ids = notifications.map { |n| n.respond_to?('Id') ? n.Id : n }
37
- result = connection.put "#{self.path}/#{ids.join(',')}", {'Read' => true}, arguments
38
- end
39
-
40
- end
41
- end
42
- end