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,64 +0,0 @@
1
- module FlexmlsApi
2
- module FaradayExt
3
- #=Flexmls API Faraday middleware
4
- # HTTP Response after filter to package api responses and bubble up basic api errors.
5
- class FlexmlsMiddleware < Faraday::Response::ParseJson
6
- include FlexmlsApi::PaginateHelper
7
- # Handles pretty much all the api response parsing and error handling. All responses that
8
- # indicate a failure will raise a FlexmlsApi::ClientError exception
9
- def on_complete(finished_env)
10
- body = parse(finished_env[:body])
11
- FlexmlsApi.logger.debug("Response Body: #{body.inspect}")
12
- unless body.is_a?(Hash) && body.key?("D")
13
- raise InvalidResponse, "The server response could not be understood"
14
- end
15
- response = ApiResponse.new body
16
- paging = response.pagination
17
- if paging.nil?
18
- results = response
19
- else
20
- if finished_env[:url].query_values["_pagination"] == "count"
21
- results = paging['TotalRows']
22
- else
23
- results = paginate_response(response, paging)
24
- end
25
- end
26
- case finished_env[:status]
27
- when 400
28
- hash = {:message => response.message, :code => response.code, :status => finished_env[:status]}
29
-
30
- # constraint violation
31
- if response.code == 1053
32
- details = body['D']['Details']
33
- hash[:details] = details
34
- end
35
- raise BadResourceRequest,hash
36
- when 401
37
- # Handle the WWW-Authenticate Response Header Field if present. This can be returned by
38
- # OAuth2 implementations and wouldn't hurt to log.
39
- auth_header_error = finished_env[:request_headers]["WWW-Authenticate"]
40
- FlexmlsApi.logger.warn("Authentication error #{auth_header_error}") unless auth_header_error.nil?
41
- raise PermissionDenied, {:message => response.message, :code => response.code, :status => finished_env[:status]}
42
- when 404
43
- raise NotFound, {:message => response.message, :code => response.code, :status => finished_env[:status]}
44
- when 405
45
- raise NotAllowed, {:message => response.message, :code => response.code, :status => finished_env[:status]}
46
- when 409
47
- raise BadResourceRequest, {:message => response.message, :code => response.code, :status => finished_env[:status]}
48
- when 500
49
- raise ClientError, {:message => response.message, :code => response.code, :status => finished_env[:status]}
50
- when 200..299
51
- FlexmlsApi.logger.debug("Success!")
52
- else
53
- raise ClientError, {:message => response.message, :code => response.code, :status => finished_env[:status]}
54
- end
55
- finished_env[:body] = results
56
- end
57
-
58
- def initialize(app)
59
- super(app)
60
- end
61
-
62
- end
63
- end
64
- end
@@ -1,33 +0,0 @@
1
- require 'flexmls_api/models/base'
2
- require 'flexmls_api/models/constraint'
3
- require 'flexmls_api/models/finders'
4
- require 'flexmls_api/models/subresource'
5
-
6
- require 'flexmls_api/models/account'
7
- require 'flexmls_api/models/connect_prefs'
8
- require 'flexmls_api/models/contact'
9
- require 'flexmls_api/models/custom_fields'
10
- require 'flexmls_api/models/document'
11
- require 'flexmls_api/models/idx_link'
12
- require 'flexmls_api/models/listing'
13
- require 'flexmls_api/models/listing_cart'
14
- require 'flexmls_api/models/market_statistics'
15
- require 'flexmls_api/models/message'
16
- require 'flexmls_api/models/note'
17
- require 'flexmls_api/models/notification'
18
- require 'flexmls_api/models/open_house'
19
- require 'flexmls_api/models/photo'
20
- require 'flexmls_api/models/property_types'
21
- require 'flexmls_api/models/saved_search'
22
- require 'flexmls_api/models/shared_listing'
23
- require 'flexmls_api/models/standard_fields'
24
- require 'flexmls_api/models/system_info'
25
- require 'flexmls_api/models/tour_of_home'
26
- require 'flexmls_api/models/video'
27
- require 'flexmls_api/models/virtual_tour'
28
-
29
- module FlexmlsApi
30
- module Models
31
-
32
- end
33
- end
@@ -1,115 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class Account < Base
4
- extend Finders
5
- self.element_name="accounts"
6
-
7
- SUBELEMENTS = [:emails, :phones, :websites, :addresses, :images]
8
- attr_accessor :my_account, *SUBELEMENTS
9
-
10
- def initialize(attributes={})
11
- @emails = subresource(Email, "Emails", attributes)
12
- @phones = subresource(Phone, "Phones", attributes)
13
- @websites = subresource(Website, "Websites", attributes)
14
- @addresses = subresource(Address, "Addresses", attributes)
15
- if attributes["Images"]
16
- @images = []
17
- attributes["Images"].each { |i| @images << Image.new(i) }
18
- else
19
- @images = nil
20
- end
21
- @my_account = false
22
- super(attributes)
23
- end
24
-
25
- def self.my(arguments={})
26
- account = collect(connection.get("/my/account", arguments)).first
27
- account.my_account = true
28
- account
29
- end
30
-
31
- def my_account?
32
- @my_account
33
- end
34
-
35
- def self.by_office(office_id, arguments={})
36
- collect(connection.get("#{self.path()}/by/office/#{office_id}", arguments))
37
- end
38
-
39
- def primary_img(typ)
40
- if @images.is_a?(Array)
41
- matches = @images.select {|i| i.Type == typ}
42
- matches.sort {|a,b| a.Name <=> b.Name }.first
43
- else
44
- nil
45
- end
46
- end
47
-
48
- def save(arguments={})
49
- self.errors = [] # clear the errors hash
50
- begin
51
- return save!(arguments)
52
- rescue NotFound, BadResourceRequest => e
53
- self.errors << {:code => e.code, :message => e.message}
54
- FlexmlsApi.logger.error("Failed to save resource #{self}: #{e.message}")
55
- end
56
- false
57
- end
58
- def save!(arguments={})
59
- # The long-term idea is that any setting in the user's account could be updated by including
60
- # an attribute and calling PUT /my/account, but for now only the GetEmailUpdates attribute
61
- # is supported
62
-
63
- save_path = "/accounts/"+self.Id
64
-
65
- ojbsome = {}
66
- if attributes['GetEmailUpdates']
67
- save_path = my_account? ? "/my/account" : self.class.path
68
- ojbsome["GetEmailUpdates"] = attributes['GetEmailUpdates']
69
- end
70
- if attributes['PasswordValidation']
71
- ojbsome["PasswordValidation"] = attributes['PasswordValidation']
72
- end
73
- if attributes['Password']
74
- ojbsome["Password"] = attributes['Password']
75
- end
76
-
77
- results = connection.put save_path, ojbsome, arguments
78
- true
79
- end
80
-
81
-
82
- private
83
-
84
- def subresource(klass, key, attributes)
85
- return nil unless attributes.key?(key)
86
- array = attributes[key]
87
- result = PrimaryArray.new()
88
- array.each do |i|
89
- result << klass.new(i)
90
- end
91
- result
92
- end
93
-
94
- class Email < Base
95
- include Primary
96
- end
97
-
98
- class Phone < Base
99
- include Primary
100
- end
101
-
102
- class Website < Base
103
- include Primary
104
- end
105
-
106
- class Address < Base
107
- include Primary
108
- end
109
-
110
- class Image < Base
111
- end
112
- end
113
- end
114
-
115
- end
@@ -1,118 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- # =API Model Base class
4
- # Intended to be a lot like working with ActiveResource, this class adds most of the basic
5
- # active model type niceties.
6
- class Base
7
- extend Paginate
8
-
9
- attr_accessor :attributes, :errors
10
- attr_reader :changed
11
-
12
- # Name of the resource as related to the path name
13
- def self.element_name
14
- # TODO I'd love to pull in active model at this point to provide default naming
15
- @element_name ||= "resource"
16
- end
17
-
18
- def self.element_name=(name)
19
- @element_name = name
20
- end
21
-
22
- # Resource path prefix, prepended to the url
23
- def self.prefix
24
- @prefix ||= "/"
25
- end
26
- def self.prefix=(prefix)
27
- @prefix = prefix
28
- end
29
- def self.path
30
- "#{prefix}#{element_name}"
31
- end
32
-
33
- def self.connection
34
- FlexmlsApi.client
35
- end
36
- def connection
37
- self.class.connection
38
- end
39
-
40
- def initialize(attributes={})
41
- @attributes = {}
42
- @errors = []
43
- @changed = []
44
- load(attributes)
45
- end
46
-
47
- def load(attributes)
48
- attributes.each do |key,val|
49
- @attributes[key.to_s] = val
50
- end
51
- end
52
-
53
- def self.get(options={})
54
- collect(connection.get(path, options))
55
- end
56
-
57
- def self.first(options={})
58
- get(options).first
59
- end
60
-
61
- def self.count(options={})
62
- connection.get(path, options.merge({:_pagination=>"count"}))
63
- end
64
-
65
- def method_missing(method_symbol, *arguments)
66
- method_name = method_symbol.to_s
67
-
68
- if method_name =~ /(=|\?)$/
69
- case $1
70
- when "="
71
- write_attribute($`, arguments.first)
72
- # TODO figure out a nice way to present setters for the standard fields
73
- when "?"
74
- if attributes.include?($`)
75
- attributes[$`] ? true : false
76
- else
77
- raise NoMethodError
78
- end
79
- end
80
- else
81
- return attributes[method_name] if attributes.include?(method_name)
82
- super # GTFO
83
- end
84
- end
85
-
86
- def respond_to?(method_symbol, include_private=false)
87
- if super
88
- return true
89
- else
90
- method_name = method_symbol.to_s
91
-
92
- if method_name =~ /=$/
93
- true
94
- elsif method_name =~ /(\?)$/
95
- attributes.include?($`)
96
- else
97
- attributes.include?(method_name)
98
- end
99
-
100
- end
101
- end
102
-
103
- def parse_id(uri)
104
- uri[/\/.*\/(.+)$/, 1]
105
- end
106
-
107
- protected
108
-
109
- def write_attribute(attribute, value)
110
- unless attributes[attribute] == value
111
- attributes[attribute] = value
112
- @changed << attribute unless @changed.include?(attribute)
113
- end
114
- end
115
-
116
- end
117
- end
118
- end
@@ -1,10 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class Connect < Base
4
- self.element_name="connect"
5
- def self.prefs
6
- connection.get("#{path}/prefs")
7
- end
8
- end
9
- end
10
- end
@@ -1,16 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class Constraint
4
- ATTRIBUTES = ["RuleValue","Value","RuleFieldValue","RuleField","RuleName"]
5
- attr_accessor *ATTRIBUTES
6
- def initialize(args)
7
- ATTRIBUTES.each { |f| send("#{f}=", args[f]) if args.include?(f) || args.include?(f.to_sym) }
8
- end
9
-
10
- def to_s
11
- "#{self.RuleName}: Field(#{self.RuleField},#{self.RuleFieldValue}) Value(#{self.RuleValue},#{self.Value})"
12
- end
13
- end
14
- end
15
- end
16
-
@@ -1,49 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class Contact < Base
4
- extend Finders
5
- self.element_name="contacts"
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
- def save!(arguments={})
20
- results = connection.post self.class.path, {"Contacts" => [ attributes ], "Notify" => notify? }, arguments
21
- result = results.first
22
- attributes['ResourceUri'] = result['ResourceUri']
23
- attributes['Id'] = parse_id(result['ResourceUri'])
24
- true
25
- end
26
-
27
- def self.by_tag(tag_name, arguments={})
28
- collect(connection.get("#{path}/tags/#{tag_name}", arguments))
29
- end
30
-
31
- def self.tags(arguments={})
32
- connection.get("#{path}/tags", arguments)
33
- end
34
-
35
- def self.my(arguments={})
36
- new(connection.get('/my/contact', arguments).first)
37
- end
38
-
39
- # Notify the agent of contact creation via a flexmls message.
40
- def notify?
41
- @notify == true
42
- end
43
- def notify=(notify_me=true)
44
- @notify = notify_me
45
- end
46
-
47
- end
48
- end
49
- end
@@ -1,12 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class CustomFields < Base
4
- self.element_name="customfields"
5
-
6
-
7
- def self.find_by_property_type(card_fmt, arguments={})
8
- collect(connection.get("#{self.path}/#{card_fmt}", arguments))
9
- end
10
- end
11
- end
12
- end
@@ -1,11 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- class Document < Base
4
- extend Subresource
5
-
6
- self.element_name="documents"
7
-
8
-
9
- end
10
- end
11
- end
@@ -1,45 +0,0 @@
1
- module FlexmlsApi
2
- module Models
3
- # =Rails-like finders module
4
- # Adds the base set of finder class methods to the models that support them (not all of them do)
5
- module Finders
6
-
7
- def find(*arguments)
8
- scope = arguments.slice!(0)
9
- options = arguments.slice!(0) || {}
10
- case scope
11
- when :all then find_every(options)
12
- when :first then find_every(options).first
13
- when :last then find_every(options).last
14
- when :one then find_one(options)
15
- else find_single(scope, options)
16
- end
17
- end
18
-
19
- def first(*arguments)
20
- find(:first, *arguments)
21
- end
22
-
23
- def last(*arguments)
24
- find(:last, *arguments)
25
- end
26
-
27
- private
28
-
29
- def find_every(options)
30
- collect(connection.get("/#{element_name}", options))
31
- end
32
-
33
- def find_one(options)
34
- raise NotImplementedError # TODO um... what?
35
- end
36
-
37
- def find_single(scope, options)
38
- resp = connection.get("/#{element_name}/#{scope}", options)
39
- new(resp.first)
40
- end
41
-
42
- end
43
- end
44
- end
45
-