spark_api 1.2.1 → 1.3.0
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.
- data/History.txt +12 -0
- data/README.md +7 -0
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/lib/spark_api/authentication.rb +0 -3
- data/lib/spark_api/authentication/oauth2.rb +1 -1
- data/lib/spark_api/configuration.rb +6 -1
- data/lib/spark_api/models.rb +6 -2
- data/lib/spark_api/models/activity.rb +10 -0
- data/lib/spark_api/models/base.rb +25 -5
- data/lib/spark_api/models/comment.rb +9 -0
- data/lib/spark_api/models/concerns/destroyable.rb +1 -1
- data/lib/spark_api/models/concerns/savable.rb +3 -6
- data/lib/spark_api/models/contact.rb +38 -1
- data/lib/spark_api/models/dirty.rb +1 -1
- data/lib/spark_api/models/fields.rb +12 -0
- data/lib/spark_api/models/listing_cart.rb +6 -34
- data/lib/spark_api/models/portal.rb +37 -0
- data/lib/spark_api/models/saved_search.rb +36 -0
- data/lib/spark_api/models/vow_account.rb +44 -0
- data/lib/spark_api/request.rb +1 -1
- data/spec/fixtures/activities/get.json +22 -0
- data/spec/fixtures/base.json +2 -2
- data/spec/fixtures/comments/get.json +32 -0
- data/spec/fixtures/comments/new.json +7 -0
- data/spec/fixtures/comments/post.json +19 -0
- data/spec/fixtures/contacts/my.json +1 -0
- data/spec/fixtures/contacts/vow_accounts/edit.json +5 -0
- data/spec/fixtures/contacts/vow_accounts/get.json +15 -0
- data/spec/fixtures/contacts/vow_accounts/new.json +12 -0
- data/spec/fixtures/contacts/vow_accounts/post.json +10 -0
- data/spec/fixtures/fields/order.json +22 -0
- data/spec/fixtures/fields/order_a.json +39 -0
- data/spec/fixtures/portal/disable.json +5 -0
- data/spec/fixtures/portal/enable.json +5 -0
- data/spec/fixtures/portal/my.json +15 -0
- data/spec/fixtures/portal/my_non_existant.json +6 -0
- data/spec/fixtures/portal/new.json +7 -0
- data/spec/fixtures/portal/post.json +10 -0
- data/spec/fixtures/saved_searches/get.json +4 -1
- data/spec/spec_helper.rb +11 -7
- data/spec/unit/spark_api/authentication/oauth2_impl/faraday_middleware_spec.rb +2 -2
- data/spec/unit/spark_api/authentication/oauth2_impl/grant_type_base_spec.rb +1 -2
- data/spec/unit/spark_api/authentication/oauth2_spec.rb +3 -4
- data/spec/unit/spark_api/models/activity_spec.rb +29 -0
- data/spec/unit/spark_api/models/base_spec.rb +23 -0
- data/spec/unit/spark_api/models/concerns/destroyable_spec.rb +1 -1
- data/spec/unit/spark_api/models/concerns/savable_spec.rb +8 -4
- data/spec/unit/spark_api/models/contact_spec.rb +144 -21
- data/spec/unit/spark_api/models/fields_spec.rb +56 -0
- data/spec/unit/spark_api/models/listing_cart_spec.rb +1 -1
- data/spec/unit/spark_api/models/portal_spec.rb +50 -0
- data/spec/unit/spark_api/models/saved_search_spec.rb +60 -0
- data/spec/unit/spark_api/models/shared_listing_spec.rb +1 -1
- data/spec/unit/spark_api/models/vow_account_spec.rb +64 -0
- data/spec/unit/spark_api/request_spec.rb +1 -1
- data/spec/unit/spark_api_spec.rb +1 -1
- metadata +362 -360
- data/lib/spark_api/models/subscription.rb +0 -52
- data/spec/fixtures/subscriptions/get.json +0 -19
- data/spec/fixtures/subscriptions/new.json +0 -13
- data/spec/fixtures/subscriptions/post.json +0 -10
- data/spec/fixtures/subscriptions/put.json +0 -12
- data/spec/fixtures/subscriptions/subscribe.json +0 -5
- data/spec/fixtures/subscriptions/update.json +0 -6
- data/spec/json_hash_test_support.rb +0 -251
- data/spec/json_helper.rb +0 -76
- data/spec/mock_helper.rb +0 -132
- data/spec/oauth2_helper.rb +0 -70
- data/spec/unit/spark_api/models/subscription_spec.rb +0 -106
data/History.txt
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
== v1.3.0 2013-01-08
|
2
|
+
* yajl is no longer a dependency. To use it, make sure the gem is installed.
|
3
|
+
* JRuby support finalized
|
4
|
+
* Increased default OAuthSession timeout to 12 hours
|
5
|
+
* New API Support:
|
6
|
+
* field ordering service
|
7
|
+
* attaching/detaching contacts to saved searches,
|
8
|
+
* agent portal administration
|
9
|
+
* contact commenting
|
10
|
+
* contact export, export all
|
11
|
+
* contact vow accounts
|
12
|
+
* activity stream retrieval
|
1
13
|
== v1.2.0 2012-11-14
|
2
14
|
* SSL verification enabled by default
|
3
15
|
* Sparkbar token access support
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
Spark API
|
2
2
|
=====================
|
3
|
+
[](http://travis-ci.org/sparkapi/spark_api) [](https://codeclimate.com/github/sparkapi/spark_api)
|
4
|
+
|
3
5
|
A Ruby wrapper for the Spark REST API. Loosely based on ActiveResource to provide models to interact with remote services.
|
4
6
|
|
5
7
|
|
@@ -65,6 +67,11 @@ The client also provides ActiveModelesque interface for working with the api res
|
|
65
67
|
# Top list price: $199999.99
|
66
68
|
puts Account.find(:first, :_filter => "UserType Eq 'Member' And Name Eq 'John*'").Name
|
67
69
|
# John Doe
|
70
|
+
|
71
|
+
|
72
|
+
JSON Parsing
|
73
|
+
--------------
|
74
|
+
By default, this gem uses the pure ruby json gem for parsing API responses for cross platform compatibility. Projects that include the yajl-ruby gem will see noticeable speed improvements when installed.
|
68
75
|
|
69
76
|
|
70
77
|
Authentication Types
|
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.3.0
|
@@ -159,7 +159,7 @@ module SparkApi
|
|
159
159
|
@scope = options["scope"]
|
160
160
|
@refresh_token = options["refresh_token"]
|
161
161
|
@start_time = options.fetch("start_time", DateTime.now)
|
162
|
-
@refresh_timeout = options.fetch("refresh_timeout",
|
162
|
+
@refresh_timeout = options.fetch("refresh_timeout", 43200)
|
163
163
|
if @start_time.is_a? String
|
164
164
|
@start_time = DateTime.parse(@start_time)
|
165
165
|
end
|
@@ -1,7 +1,12 @@
|
|
1
1
|
module SparkApi
|
2
2
|
module Configuration
|
3
3
|
|
4
|
-
|
4
|
+
begin
|
5
|
+
require 'yajl'
|
6
|
+
MultiJson.engine = "yajl"
|
7
|
+
rescue LoadError => e
|
8
|
+
# Using pure ruby JSON parser
|
9
|
+
end
|
5
10
|
|
6
11
|
# valid configuration options
|
7
12
|
VALID_OPTION_KEYS = [:api_key, :api_secret, :api_user, :endpoint,
|
data/lib/spark_api/models.rb
CHANGED
@@ -6,10 +6,13 @@ require 'spark_api/models/subresource'
|
|
6
6
|
require 'spark_api/models/concerns'
|
7
7
|
|
8
8
|
require 'spark_api/models/account'
|
9
|
+
require 'spark_api/models/activity'
|
9
10
|
require 'spark_api/models/connect_prefs'
|
10
11
|
require 'spark_api/models/contact'
|
12
|
+
require 'spark_api/models/comment'
|
11
13
|
require 'spark_api/models/custom_fields'
|
12
14
|
require 'spark_api/models/document'
|
15
|
+
require 'spark_api/models/fields'
|
13
16
|
require 'spark_api/models/idx_link'
|
14
17
|
require 'spark_api/models/listing'
|
15
18
|
require 'spark_api/models/listing_cart'
|
@@ -19,7 +22,9 @@ require 'spark_api/models/note'
|
|
19
22
|
require 'spark_api/models/notification'
|
20
23
|
require 'spark_api/models/open_house'
|
21
24
|
require 'spark_api/models/photo'
|
25
|
+
require 'spark_api/models/portal'
|
22
26
|
require 'spark_api/models/property_types'
|
27
|
+
require 'spark_api/models/rental_calendar'
|
23
28
|
require 'spark_api/models/saved_search'
|
24
29
|
require 'spark_api/models/shared_listing'
|
25
30
|
require 'spark_api/models/standard_fields'
|
@@ -27,8 +32,7 @@ require 'spark_api/models/system_info'
|
|
27
32
|
require 'spark_api/models/tour_of_home'
|
28
33
|
require 'spark_api/models/video'
|
29
34
|
require 'spark_api/models/virtual_tour'
|
30
|
-
require 'spark_api/models/
|
31
|
-
require 'spark_api/models/subscription'
|
35
|
+
require 'spark_api/models/vow_account'
|
32
36
|
|
33
37
|
module SparkApi
|
34
38
|
module Models
|
@@ -7,14 +7,13 @@ module SparkApi
|
|
7
7
|
extend Paginate
|
8
8
|
include Dirty
|
9
9
|
|
10
|
-
attr_accessor :attributes, :errors
|
10
|
+
attr_accessor :attributes, :errors, :parent
|
11
11
|
|
12
12
|
# Name of the resource as related to the path name
|
13
13
|
def self.element_name
|
14
14
|
# TODO I'd love to pull in active model at this point to provide default naming
|
15
15
|
@element_name ||= "resource"
|
16
16
|
end
|
17
|
-
|
18
17
|
def self.element_name=(name)
|
19
18
|
@element_name = name
|
20
19
|
end
|
@@ -26,9 +25,25 @@ module SparkApi
|
|
26
25
|
def self.prefix=(prefix)
|
27
26
|
@prefix = prefix
|
28
27
|
end
|
28
|
+
|
29
|
+
def resource_uri
|
30
|
+
self.ResourceUri.sub(/^\/#{SparkApi.client.version}/, "") if persisted?
|
31
|
+
end
|
32
|
+
|
29
33
|
def self.path
|
30
34
|
"#{prefix}#{element_name}"
|
31
35
|
end
|
36
|
+
def path
|
37
|
+
if self.persisted?
|
38
|
+
resource_uri.sub(/\/[0-9]{26}$/, "")
|
39
|
+
else
|
40
|
+
if @parent
|
41
|
+
"#{@parent.class.path}/#{@parent.Id}#{self.class.path}"
|
42
|
+
else
|
43
|
+
self.class.path
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
32
47
|
|
33
48
|
def self.connection
|
34
49
|
SparkApi.client
|
@@ -61,6 +76,11 @@ module SparkApi
|
|
61
76
|
connection.get(path, options.merge({:_pagination=>"count"}))
|
62
77
|
end
|
63
78
|
|
79
|
+
# update/create hash (can be overridden)
|
80
|
+
def post_data
|
81
|
+
{ resource_pluralized => [ attributes ] }
|
82
|
+
end
|
83
|
+
|
64
84
|
def method_missing(method_symbol, *arguments)
|
65
85
|
method_name = method_symbol.to_s
|
66
86
|
|
@@ -82,7 +102,7 @@ module SparkApi
|
|
82
102
|
end
|
83
103
|
end
|
84
104
|
|
85
|
-
def respond_to?(method_symbol
|
105
|
+
def respond_to?(method_symbol)
|
86
106
|
if super
|
87
107
|
return true
|
88
108
|
else
|
@@ -105,8 +125,8 @@ module SparkApi
|
|
105
125
|
uri[/\/.*\/(.+)$/, 1]
|
106
126
|
end
|
107
127
|
|
108
|
-
def persisted
|
109
|
-
|
128
|
+
def persisted?;
|
129
|
+
!@attributes['Id'].nil? && !@attributes['ResourceUri'].nil?
|
110
130
|
end
|
111
131
|
|
112
132
|
protected
|
@@ -21,10 +21,7 @@ module SparkApi
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def create!(arguments = {})
|
24
|
-
results = connection.post self.
|
25
|
-
resource_pluralized => [ attributes ]
|
26
|
-
}.merge(params_for_save), arguments
|
27
|
-
|
24
|
+
results = connection.post self.path, post_data.merge(params_for_save), arguments
|
28
25
|
update_resource_identifiers(results.first)
|
29
26
|
reset_dirty
|
30
27
|
params_for_save.clear
|
@@ -32,8 +29,8 @@ module SparkApi
|
|
32
29
|
end
|
33
30
|
|
34
31
|
def update!(arguments = {})
|
35
|
-
return true unless changed?
|
36
|
-
connection.put
|
32
|
+
return true unless changed? && persisted?
|
33
|
+
connection.put resource_uri, dirty_attributes, arguments
|
37
34
|
reset_dirty
|
38
35
|
params_for_save.clear
|
39
36
|
true
|
@@ -6,7 +6,7 @@ module SparkApi
|
|
6
6
|
Concerns::Destroyable
|
7
7
|
|
8
8
|
self.element_name="contacts"
|
9
|
-
|
9
|
+
|
10
10
|
def self.by_tag(tag_name, arguments={})
|
11
11
|
collect(connection.get("#{path}/tags/#{tag_name}", arguments))
|
12
12
|
end
|
@@ -19,11 +19,48 @@ module SparkApi
|
|
19
19
|
new(connection.get('/my/contact', arguments).first)
|
20
20
|
end
|
21
21
|
|
22
|
+
def self.export(arguments={})
|
23
|
+
collect(connection.get("/contacts/export", arguments))
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.export_all(arguments={})
|
27
|
+
collect(connection.get("/contacts/export/all", arguments))
|
28
|
+
end
|
29
|
+
|
22
30
|
# Notify the agent of contact creation via a Spark notification.
|
23
31
|
def notify?; params_for_save[:Notify] == true end
|
24
32
|
def notify=(notify_me)
|
25
33
|
params_for_save[:Notify] = notify_me
|
26
34
|
end
|
35
|
+
|
36
|
+
def saved_searches(arguments = {})
|
37
|
+
@saved_searches ||= SavedSearch.collect(connection.get("/contacts/#{self.Id}/savedsearches", arguments))
|
38
|
+
end
|
39
|
+
|
40
|
+
def listing_carts(arguments = {})
|
41
|
+
@listing_carts ||= ListingCart.collect(connection.get("/contacts/#{self.Id}/listingcarts", arguments))
|
42
|
+
end
|
43
|
+
|
44
|
+
def comments(arguments = {})
|
45
|
+
@comments ||= Comment.collect(connection.get("/contacts/#{self.Id}/comments", arguments))
|
46
|
+
end
|
47
|
+
def comment(body)
|
48
|
+
comment = Comment.new({ :Comment => body })
|
49
|
+
comment.parent = self
|
50
|
+
comment.save
|
51
|
+
comment
|
52
|
+
end
|
53
|
+
|
54
|
+
def vow_account(arguments={})
|
55
|
+
return @vow_account if @vow_account
|
56
|
+
begin
|
57
|
+
@vow_account = VowAccount.new(connection.get("/contacts/#{self.Id}/portal", arguments).first)
|
58
|
+
@vow_account.parent = self
|
59
|
+
@vow_account
|
60
|
+
rescue NotFound
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
end
|
27
64
|
|
28
65
|
end
|
29
66
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module SparkApi
|
2
|
+
module Models
|
3
|
+
class Fields < Base
|
4
|
+
self.element_name="fields"
|
5
|
+
|
6
|
+
def self.order(property_type=nil, arguments={})
|
7
|
+
connection.get("#{self.path}/order#{"/"+property_type unless property_type.nil?}", arguments)
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -2,6 +2,9 @@ module SparkApi
|
|
2
2
|
module Models
|
3
3
|
class ListingCart < Base
|
4
4
|
extend Finders
|
5
|
+
include Concerns::Savable,
|
6
|
+
Concerns::Destroyable
|
7
|
+
|
5
8
|
self.element_name="listingcarts"
|
6
9
|
|
7
10
|
def ListingIds=(listing_ids)
|
@@ -10,19 +13,19 @@ module SparkApi
|
|
10
13
|
def Name=(name)
|
11
14
|
attributes["Name"] = name
|
12
15
|
end
|
13
|
-
|
16
|
+
|
14
17
|
def add_listing(listing)
|
15
18
|
id = listing.respond_to?(:Id) ? listing.Id : listing.to_s
|
16
19
|
results = connection.post("#{self.class.path}/#{self.Id}", {"ListingIds" => [ listing ]})
|
17
20
|
self.ListingCount = results.first["ListingCount"]
|
18
21
|
end
|
19
|
-
|
22
|
+
|
20
23
|
def remove_listing(listing)
|
21
24
|
id = listing.respond_to?(:Id) ? listing.Id : listing.to_s
|
22
25
|
results = connection.delete("#{self.class.path}/#{self.Id}/listings/#{id}")
|
23
26
|
self.ListingCount = results.first["ListingCount"]
|
24
27
|
end
|
25
|
-
|
28
|
+
|
26
29
|
def self.for(listings,arguments={})
|
27
30
|
keys = Array(listings).map { |l| l.respond_to?(:Id) ? l.Id : l.to_s }
|
28
31
|
collect(connection.get("/#{self.element_name}/for/#{keys.join(",")}", arguments))
|
@@ -35,37 +38,6 @@ module SparkApi
|
|
35
38
|
def self.portal(arguments={})
|
36
39
|
collect(connection.get("/#{self.element_name}/portal", arguments))
|
37
40
|
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
|
-
SparkApi.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" => [ {"ListingIds" => attributes["ListingIds"],"Name" => attributes["Name"]} ] }, arguments
|
67
|
-
true
|
68
|
-
end
|
69
41
|
|
70
42
|
end
|
71
43
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module SparkApi
|
2
|
+
module Models
|
3
|
+
|
4
|
+
class Portal < Base
|
5
|
+
extend Finders
|
6
|
+
include Concerns::Savable
|
7
|
+
|
8
|
+
self.element_name = "portal"
|
9
|
+
|
10
|
+
def self.my(arguments = {})
|
11
|
+
portal = collect(connection.get("/portal", arguments)).first
|
12
|
+
portal = Portal.new if portal.nil?
|
13
|
+
portal
|
14
|
+
end
|
15
|
+
|
16
|
+
def enabled?
|
17
|
+
@attributes['Enabled'] == true
|
18
|
+
end
|
19
|
+
|
20
|
+
def enable
|
21
|
+
attribute_will_change! "Enabled"
|
22
|
+
@attributes['Enabled'] = true
|
23
|
+
save
|
24
|
+
end
|
25
|
+
|
26
|
+
def disable
|
27
|
+
attribute_will_change! "Enabled"
|
28
|
+
@attributes['Enabled'] = false
|
29
|
+
save
|
30
|
+
end
|
31
|
+
|
32
|
+
def post_data; attributes end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -16,10 +16,46 @@ module SparkApi
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
# list contacts (private role)
|
20
|
+
def contacts
|
21
|
+
return [] unless persisted?
|
22
|
+
results = connection.get("#{self.class.path}/#{@attributes["Id"]}")
|
23
|
+
@attributes['ContactIds'] = results.first['ContactIds']
|
24
|
+
end
|
25
|
+
|
26
|
+
# attach/detach contact (private role)
|
27
|
+
[:attach, :detach].each do |action|
|
28
|
+
method = (action == :attach ? :put : :delete)
|
29
|
+
define_method(action) do |contact|
|
30
|
+
return false unless persisted?
|
31
|
+
self.errors = []
|
32
|
+
contact_id = contact.is_a?(Contact) ? contact.Id : contact
|
33
|
+
begin
|
34
|
+
connection.send(method, "#{self.class.path}/#{@attributes["Id"]}/contacts/#{contact_id}")
|
35
|
+
rescue BadResourceRequest, NotFound => e
|
36
|
+
self.errors << { :code => e.code, :message => e.message }
|
37
|
+
SparkApi.logger.error("Failed to #{action} contact #{contact}: #{e.message}")
|
38
|
+
return false
|
39
|
+
end
|
40
|
+
update_contacts(action, contact_id)
|
41
|
+
true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
19
45
|
private
|
20
46
|
|
21
47
|
def resource_pluralized; "SavedSearches" end
|
22
48
|
|
49
|
+
def update_contacts(method, contact_id)
|
50
|
+
@attributes['ContactIds'] = [] if @attributes['ContactIds'].nil?
|
51
|
+
case method
|
52
|
+
when :attach
|
53
|
+
@attributes['ContactIds'] << contact_id
|
54
|
+
when :detach
|
55
|
+
@attributes['ContactIds'].delete contact_id
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
23
59
|
end
|
24
60
|
|
25
61
|
end
|