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
@@ -1,52 +0,0 @@
|
|
1
|
-
module SparkApi
|
2
|
-
module Models
|
3
|
-
|
4
|
-
class Subscription < Base
|
5
|
-
extend Finders
|
6
|
-
include Concerns::Savable,
|
7
|
-
Concerns::Destroyable
|
8
|
-
|
9
|
-
self.element_name = "subscriptions"
|
10
|
-
|
11
|
-
# list subscribers (private role)
|
12
|
-
def subscribers
|
13
|
-
return {} unless persisted?
|
14
|
-
results = connection.get("#{self.class.path}/#{@attributes["Id"]}/subscribers")
|
15
|
-
@attributes['RecipientIds'] = results.first['RecipientIds']
|
16
|
-
results
|
17
|
-
end
|
18
|
-
|
19
|
-
# subscribe/unsubscribe contact (private role)
|
20
|
-
[:subscribe, :unsubscribe].each do |action|
|
21
|
-
method = (action == :subscribe ? :put : :delete)
|
22
|
-
define_method(action) do |contact|
|
23
|
-
return false unless persisted?
|
24
|
-
self.errors = []
|
25
|
-
contact_id = contact.is_a?(Contact) ? contact.Id : contact
|
26
|
-
begin
|
27
|
-
connection.send(method, "#{self.class.path}/#{@attributes["Id"]}/subscribers/#{contact_id}")
|
28
|
-
rescue BadResourceRequest, NotFound => e
|
29
|
-
self.errors << { :code => e.code, :message => e.message }
|
30
|
-
SparkApi.logger.error("Failed to #{action} contact #{contact}: #{e.message}")
|
31
|
-
return false
|
32
|
-
end
|
33
|
-
update_recipients(action, contact_id)
|
34
|
-
true
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def update_recipients(method, contact_id)
|
41
|
-
@attributes['RecipientIds'] = [] if @attributes['RecipientIds'].nil?
|
42
|
-
if method == :subscribe
|
43
|
-
@attributes['RecipientIds'] << contact_id
|
44
|
-
else
|
45
|
-
@attributes['RecipientIds'].delete contact_id
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"D": {
|
3
|
-
"Success": true,
|
4
|
-
"Results": [
|
5
|
-
{
|
6
|
-
"Id":"20101230223226074204000000",
|
7
|
-
"ResourceUri":"/v1/contacts/20101230223226074204000000",
|
8
|
-
"Name":"First subscription",
|
9
|
-
"RecipientIds": ["20101230223226074307000000"]
|
10
|
-
},
|
11
|
-
{
|
12
|
-
"Id":"20101230223226074205000000",
|
13
|
-
"ResourceUri":"/v1/contacts/20101230223226074205000000",
|
14
|
-
"Name":"Second subscription",
|
15
|
-
"RecipientIds": []
|
16
|
-
}
|
17
|
-
]
|
18
|
-
}
|
19
|
-
}
|
@@ -1,251 +0,0 @@
|
|
1
|
-
# Several workarounds to get our test setup working in multiple ruby environments credit is
|
2
|
-
# attributed to all the projects that found solutions to these test headaches!
|
3
|
-
|
4
|
-
|
5
|
-
module SparkApiTest
|
6
|
-
# directly taken from Rails 3.1's OrderedHash
|
7
|
-
# see https://github.com/rails/rails/blob/master/activesupport/lib/active_support/ordered_hash.rb
|
8
|
-
|
9
|
-
# The order of iteration over hashes in Ruby 1.8 is undefined. For example, you do not know the
|
10
|
-
# order in which +keys+ will return keys, or +each+ yield pairs. <tt>ActiveSupport::OrderedHash</tt>
|
11
|
-
# implements a hash that preserves insertion order, as in Ruby 1.9:
|
12
|
-
#
|
13
|
-
# oh = ActiveSupport::OrderedHash.new
|
14
|
-
# oh[:a] = 1
|
15
|
-
# oh[:b] = 2
|
16
|
-
# oh.keys # => [:a, :b], this order is guaranteed
|
17
|
-
#
|
18
|
-
# <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts with other implementations.
|
19
|
-
class OrderedHash < ::Hash #:nodoc:
|
20
|
-
def to_yaml_type
|
21
|
-
"!tag:yaml.org,2002:omap"
|
22
|
-
end
|
23
|
-
|
24
|
-
def encode_with(coder)
|
25
|
-
coder.represent_seq '!omap', map { |k,v| { k => v } }
|
26
|
-
end
|
27
|
-
|
28
|
-
def to_yaml(opts = {})
|
29
|
-
if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck?
|
30
|
-
return super
|
31
|
-
end
|
32
|
-
|
33
|
-
YAML.quick_emit(self, opts) do |out|
|
34
|
-
out.seq(taguri) do |seq|
|
35
|
-
each do |k, v|
|
36
|
-
seq.add(k => v)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def nested_under_indifferent_access
|
43
|
-
self
|
44
|
-
end
|
45
|
-
|
46
|
-
# Hash is ordered in Ruby 1.9!
|
47
|
-
if RUBY_VERSION < '1.9'
|
48
|
-
|
49
|
-
# In MRI the Hash class is core and written in C. In particular, methods are
|
50
|
-
# programmed with explicit C function calls and polymorphism is not honored.
|
51
|
-
#
|
52
|
-
# For example, []= is crucial in this implementation to maintain the @keys
|
53
|
-
# array but hash.c invokes rb_hash_aset() originally. This prevents method
|
54
|
-
# reuse through inheritance and forces us to reimplement stuff.
|
55
|
-
#
|
56
|
-
# For instance, we cannot use the inherited #merge! because albeit the algorithm
|
57
|
-
# itself would work, our []= is not being called at all by the C code.
|
58
|
-
|
59
|
-
def initialize(*args, &block)
|
60
|
-
super
|
61
|
-
@keys = []
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.[](*args)
|
65
|
-
ordered_hash = new
|
66
|
-
|
67
|
-
if (args.length == 1 && args.first.is_a?(Array))
|
68
|
-
args.first.each do |key_value_pair|
|
69
|
-
next unless (key_value_pair.is_a?(Array))
|
70
|
-
ordered_hash[key_value_pair[0]] = key_value_pair[1]
|
71
|
-
end
|
72
|
-
|
73
|
-
return ordered_hash
|
74
|
-
end
|
75
|
-
|
76
|
-
unless (args.size % 2 == 0)
|
77
|
-
raise ArgumentError.new("odd number of arguments for Hash")
|
78
|
-
end
|
79
|
-
|
80
|
-
args.each_with_index do |val, ind|
|
81
|
-
next if (ind % 2 != 0)
|
82
|
-
ordered_hash[val] = args[ind + 1]
|
83
|
-
end
|
84
|
-
|
85
|
-
ordered_hash
|
86
|
-
end
|
87
|
-
|
88
|
-
def initialize_copy(other)
|
89
|
-
super
|
90
|
-
# make a deep copy of keys
|
91
|
-
@keys = other.keys
|
92
|
-
end
|
93
|
-
|
94
|
-
def []=(key, value)
|
95
|
-
@keys << key unless has_key?(key)
|
96
|
-
super
|
97
|
-
end
|
98
|
-
|
99
|
-
def delete(key)
|
100
|
-
if has_key? key
|
101
|
-
index = @keys.index(key)
|
102
|
-
@keys.delete_at index
|
103
|
-
end
|
104
|
-
super
|
105
|
-
end
|
106
|
-
|
107
|
-
def delete_if
|
108
|
-
super
|
109
|
-
sync_keys!
|
110
|
-
self
|
111
|
-
end
|
112
|
-
|
113
|
-
def reject!
|
114
|
-
super
|
115
|
-
sync_keys!
|
116
|
-
self
|
117
|
-
end
|
118
|
-
|
119
|
-
def reject(&block)
|
120
|
-
dup.reject!(&block)
|
121
|
-
end
|
122
|
-
|
123
|
-
def keys
|
124
|
-
@keys.dup
|
125
|
-
end
|
126
|
-
|
127
|
-
def values
|
128
|
-
@keys.collect { |key| self[key] }
|
129
|
-
end
|
130
|
-
|
131
|
-
def to_hash
|
132
|
-
self
|
133
|
-
end
|
134
|
-
|
135
|
-
def to_a
|
136
|
-
@keys.map { |key| [ key, self[key] ] }
|
137
|
-
end
|
138
|
-
|
139
|
-
def each_key
|
140
|
-
return to_enum(:each_key) unless block_given?
|
141
|
-
@keys.each { |key| yield key }
|
142
|
-
self
|
143
|
-
end
|
144
|
-
|
145
|
-
def each_value
|
146
|
-
return to_enum(:each_value) unless block_given?
|
147
|
-
@keys.each { |key| yield self[key]}
|
148
|
-
self
|
149
|
-
end
|
150
|
-
|
151
|
-
def each
|
152
|
-
return to_enum(:each) unless block_given?
|
153
|
-
@keys.each {|key| yield [key, self[key]]}
|
154
|
-
self
|
155
|
-
end
|
156
|
-
|
157
|
-
alias_method :each_pair, :each
|
158
|
-
|
159
|
-
alias_method :select, :find_all
|
160
|
-
|
161
|
-
def clear
|
162
|
-
super
|
163
|
-
@keys.clear
|
164
|
-
self
|
165
|
-
end
|
166
|
-
|
167
|
-
def shift
|
168
|
-
k = @keys.first
|
169
|
-
v = delete(k)
|
170
|
-
[k, v]
|
171
|
-
end
|
172
|
-
|
173
|
-
def merge!(other_hash)
|
174
|
-
if block_given?
|
175
|
-
other_hash.each { |k, v| self[k] = key?(k) ? yield(k, self[k], v) : v }
|
176
|
-
else
|
177
|
-
other_hash.each { |k, v| self[k] = v }
|
178
|
-
end
|
179
|
-
self
|
180
|
-
end
|
181
|
-
|
182
|
-
alias_method :update, :merge!
|
183
|
-
|
184
|
-
def merge(other_hash, &block)
|
185
|
-
dup.merge!(other_hash, &block)
|
186
|
-
end
|
187
|
-
|
188
|
-
# When replacing with another hash, the initial order of our keys must come from the other hash -ordered or not.
|
189
|
-
def replace(other)
|
190
|
-
super
|
191
|
-
@keys = other.keys
|
192
|
-
self
|
193
|
-
end
|
194
|
-
|
195
|
-
def invert
|
196
|
-
OrderedHash[self.to_a.map!{|key_value_pair| key_value_pair.reverse}]
|
197
|
-
end
|
198
|
-
|
199
|
-
private
|
200
|
-
def sync_keys!
|
201
|
-
@keys.delete_if {|k| !has_key?(k)}
|
202
|
-
end
|
203
|
-
end
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
# Originally based on a fix found in Koala, a facebook client gem that has compatibile licensing.
|
208
|
-
# See: https://raw.github.com/arsduo/koala/master/spec/support/json_testing_fix.rb
|
209
|
-
#
|
210
|
-
# when testing across Ruby versions, we found that JSON string creation inconsistently ordered keys
|
211
|
-
# which is a problem because our mock testing service ultimately matches strings to see if requests are mocked
|
212
|
-
# this fix solves that problem by ensuring all hashes are created with a consistent key order every time
|
213
|
-
module MultiJson
|
214
|
-
|
215
|
-
class << self
|
216
|
-
def dump_with_ordering(object)
|
217
|
-
# if it's a hash, recreate it with k/v pairs inserted in sorted-by-key order
|
218
|
-
# (for some reason, REE fails if we don't assign the ternary result as a local variable
|
219
|
-
# separately from calling encode_original)
|
220
|
-
dump_original(sort_object(object))
|
221
|
-
end
|
222
|
-
|
223
|
-
alias_method :dump_original, :dump
|
224
|
-
alias_method :dump, :dump_with_ordering
|
225
|
-
|
226
|
-
def load_with_ordering(string)
|
227
|
-
sort_object(load_original(string))
|
228
|
-
end
|
229
|
-
|
230
|
-
alias_method :load_original, :load
|
231
|
-
alias_method :load, :load_with_ordering
|
232
|
-
|
233
|
-
private
|
234
|
-
|
235
|
-
def sort_object(object)
|
236
|
-
if object.is_a?(Hash)
|
237
|
-
sort_hash(object)
|
238
|
-
elsif object.is_a?(Array)
|
239
|
-
object.collect {|item| item.is_a?(Hash) ? sort_hash(item) : item}
|
240
|
-
else
|
241
|
-
object
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
def sort_hash(unsorted_hash)
|
246
|
-
sorted_hash = SparkApiTest::OrderedHash.new(sorted_hash)
|
247
|
-
unsorted_hash.keys.sort {|a, b| a.to_s <=> b.to_s}.inject(sorted_hash) {|hash, k| hash[k] = unsorted_hash[k]; hash}
|
248
|
-
end
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
data/spec/json_helper.rb
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
class ListingJson
|
2
|
-
@counter = 0
|
3
|
-
def self.next_tech_id()
|
4
|
-
"#{@counter + 20110101000000000000}000000"
|
5
|
-
end
|
6
|
-
def self.next_list_id()
|
7
|
-
"06-#{@counter + 1000}"
|
8
|
-
end
|
9
|
-
def self.bump()
|
10
|
-
@counter += 1
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.create
|
14
|
-
bump
|
15
|
-
json = <<-JSON
|
16
|
-
{
|
17
|
-
"ResourceUri": "/v1/listings/#{next_tech_id}",
|
18
|
-
"StandardFields": #{standard_fields},
|
19
|
-
"Id": "#{next_tech_id}"
|
20
|
-
}
|
21
|
-
JSON
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.create_all(count = 1)
|
26
|
-
listings = []
|
27
|
-
count.times { listings << create }
|
28
|
-
json = listings * ","
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
def self.standard_fields
|
33
|
-
json = <<-JSON
|
34
|
-
{
|
35
|
-
"StreetNumber": "7298",
|
36
|
-
"Longitude": "-116.3237",
|
37
|
-
"City": "Bonners Ferry",
|
38
|
-
"ListingId": "#{next_list_id}",
|
39
|
-
"PublicRemarks": "Afforadable home in town close to hospital,yet quiet country like setting. Good views. Must see",
|
40
|
-
"BuildingAreaTotal": 924.0,
|
41
|
-
"YearBuilt": 1977,
|
42
|
-
"StreetName": "BIRCH",
|
43
|
-
"ListPrice": 50000.0,
|
44
|
-
"PostalCode": 83805,
|
45
|
-
"Latitude": "48.7001",
|
46
|
-
"BathsThreeQuarter": null,
|
47
|
-
"BathsFull": 1.0,
|
48
|
-
"BathsTotal": 1.0,
|
49
|
-
"StateOrProvince": "ID",
|
50
|
-
"PropertyType": "A",
|
51
|
-
"StreetAdditionalInfo": null,
|
52
|
-
"StreetDirPrefix": null,
|
53
|
-
"BedsTotal": 3,
|
54
|
-
"StreetDirSuffix": null,
|
55
|
-
"ListingKey": "#{next_tech_id}",
|
56
|
-
"ListOfficeName": "Century 21 On The Lake",
|
57
|
-
"BathsHalf": null,
|
58
|
-
"ModificationTimestamp": "2010-11-22T20:47:21Z",
|
59
|
-
"CountyOrParish": "Boundary"
|
60
|
-
}
|
61
|
-
JSON
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
def paginate_json(current_page = 1)
|
67
|
-
json = <<-JSON
|
68
|
-
"Pagination": {
|
69
|
-
"TotalRows": 38,
|
70
|
-
"PageSize": 10,
|
71
|
-
"TotalPages": 4,
|
72
|
-
"CurrentPage": #{current_page}
|
73
|
-
}
|
74
|
-
JSON
|
75
|
-
end
|
76
|
-
|