your_membership 1.1.0 → 1.1.1
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.
- checksums.yaml +4 -4
- data/.env +5 -0
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +10 -0
- data/README.md +12 -10
- data/lib/httparty/patch.rb +33 -33
- data/lib/your_membership/base.rb +197 -197
- data/lib/your_membership/commerce.rb +25 -25
- data/lib/your_membership/config.rb +41 -41
- data/lib/your_membership/convert.rb +24 -24
- data/lib/your_membership/error.rb +21 -21
- data/lib/your_membership/events.rb +60 -60
- data/lib/your_membership/feeds.rb +37 -37
- data/lib/your_membership/member.rb +399 -397
- data/lib/your_membership/members.rb +124 -124
- data/lib/your_membership/people.rb +38 -38
- data/lib/your_membership/profile.rb +92 -85
- data/lib/your_membership/sa.rb +6 -6
- data/lib/your_membership/sa_auth.rb +34 -34
- data/lib/your_membership/sa_certifications.rb +22 -22
- data/lib/your_membership/sa_commerce.rb +22 -22
- data/lib/your_membership/sa_events.rb +66 -66
- data/lib/your_membership/sa_export.rb +195 -195
- data/lib/your_membership/sa_groups.rb +30 -30
- data/lib/your_membership/sa_member.rb +49 -49
- data/lib/your_membership/sa_members.rb +180 -179
- data/lib/your_membership/sa_nonmembers.rb +41 -41
- data/lib/your_membership/sa_people.rb +92 -92
- data/lib/your_membership/session.rb +148 -152
- data/lib/your_membership/version.rb +1 -1
- data/spec/fixtures/vcr_cassettes/sa_members_all_getids_timestamp_multiple.yml +51 -0
- data/spec/fixtures/vcr_cassettes/sa_members_all_getids_timestamp_none.yml +51 -0
- data/spec/fixtures/vcr_cassettes/sa_members_all_getids_timestamp_single.yml +51 -0
- data/spec/lib/{profile_spec.rb → your_membership/profile_spec.rb} +232 -197
- data/spec/lib/your_membership/sa_members_spec.rb +38 -0
- data/spec/spec_helper.rb +101 -78
- data/your_membership.gemspec +4 -0
- metadata +85 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a2114fa42d26afb1c73747800e9aba7e90513d97
|
4
|
+
data.tar.gz: bf1322fe1e0c1e8493b90d082062ae4e0d8af826
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58f41d9ba44581eb27c2e97d0927766fd21c6ca6772a098a44962b9f084c71b5f5c85c3cdb73afa32a6f7d9b71af7c4de88ae358c183754b30d0c5c5a363517c
|
7
|
+
data.tar.gz: 524ff0de4cc6d178a4e2823ed316e8a928768fcfcda3f4134d60ae9e9a0a8b93236626d6d703e5c317e46347a950e60cb43304a43ee63d00cacfeef751a57eea
|
data/.env
ADDED
data/.gitignore
CHANGED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# Change Log
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
This project adheres to [Semantic Versioning](http://semver.org/).
|
4
|
+
|
5
|
+
## [Unreleased]
|
6
|
+
|
7
|
+
## [1.1.1] - 2016-03-23
|
8
|
+
### Fixed
|
9
|
+
- Crash in `Profile#parse_custom_field_responses` when there are no
|
10
|
+
CustomFieldResponses present.
|
data/README.md
CHANGED
@@ -23,7 +23,7 @@ Or install it yourself as:
|
|
23
23
|
|
24
24
|
## Usage
|
25
25
|
|
26
|
-
Every effort has been made to expose the YourMembership.com API as transparently as possible while still providing a natively Ruby interface.
|
26
|
+
Every effort has been made to expose the YourMembership.com API as transparently as possible while still providing a natively Ruby interface.
|
27
27
|
|
28
28
|
### Scope and Naming
|
29
29
|
|
@@ -94,7 +94,7 @@ You can pass strings as keys if you do not prefer to use Symbols.
|
|
94
94
|
|
95
95
|
##### SDK-Specific Implementation of Argument Types
|
96
96
|
|
97
|
-
You should use the standard Ruby types to represent data, for instance:
|
97
|
+
You should use the standard Ruby types to represent data, for instance:
|
98
98
|
|
99
99
|
`:Timestamp` and other date or time arguments should be passed as DateTime objects rather than formatted strings, the formatting will be done for you.
|
100
100
|
|
@@ -104,7 +104,7 @@ You should use the standard Ruby types to represent data, for instance:
|
|
104
104
|
|
105
105
|
#### Returned Values
|
106
106
|
|
107
|
-
The SDK translates the returned data into Ruby Objects of only a few types. Nearly all methods return an Array, this may be an Array of Strings or, more likely, it will be an Array of Hashes.
|
107
|
+
The SDK translates the returned data into Ruby Objects of only a few types. Nearly all methods return an Array, this may be an Array of Strings or, more likely, it will be an Array of Hashes.
|
108
108
|
|
109
109
|
If only a single record can ever be retrieved at a time through a method a Hash object will be returned instead of an Array.
|
110
110
|
|
@@ -162,7 +162,7 @@ The Member object builds upon the Session object to more fully represent an auth
|
|
162
162
|
##### Instantiation:
|
163
163
|
```RUBY
|
164
164
|
# Members can be created by authenticating directly with the YourMembership API,
|
165
|
-
# the session is automatically created and bound to the Member instance.
|
165
|
+
# the session is automatically created and bound to the Member instance.
|
166
166
|
member = YourMembership::Member.create_by_authentication 'username', 'password'
|
167
167
|
|
168
168
|
# Members can also be created by passing in an already existing Session instance
|
@@ -213,7 +213,7 @@ An *outdated* list of standard fields can be found here: https://api.yourmembers
|
|
213
213
|
|
214
214
|
##### Data Access
|
215
215
|
+ **Profile#data** `Hash` This internal hash can be read and written to and should contain only fields that are standard in the YourMembership system.
|
216
|
-
+ **Profile#custom_data** `Hash` This internal hash can be read and written to and should contain the fields that are specified as custom responses in a specific YourMembership community.
|
216
|
+
+ **Profile#custom_data** `Hash` This internal hash can be read and written to and should contain the fields that are specified as custom responses in a specific YourMembership community.
|
217
217
|
+ **Profile#to_h** `Hash` is a read-only method for returning a single nested hash of both standard and custom fields.
|
218
218
|
|
219
219
|
#### YourMembership::Export
|
@@ -238,7 +238,7 @@ when :complete
|
|
238
238
|
# Export is ready
|
239
239
|
donations.export_uri
|
240
240
|
end
|
241
|
-
```
|
241
|
+
```
|
242
242
|
|
243
243
|
## About The Author(s)
|
244
244
|
|
@@ -259,7 +259,9 @@ If you find a problem with this library or would like to contribute an improveme
|
|
259
259
|
If you're a developer that would like to help solve world hunger problems with some of your spare time, we are always looking for talented volunteers. Contact Nate Flood by email: nate [at] echonet [dot] org
|
260
260
|
|
261
261
|
1. Fork it ( https://github.com/ECHOInternational/your_membership/fork )
|
262
|
-
2.
|
263
|
-
3.
|
264
|
-
4.
|
265
|
-
5.
|
262
|
+
2. If you need to make real API calls while testing, see the .env file
|
263
|
+
3. Create your feature branch (`git checkout -b my-new-feature`)
|
264
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
265
|
+
5. Ensure the specs pass (`bundle exec rspec`)
|
266
|
+
6. Push to the branch (`git push origin my-new-feature`)
|
267
|
+
7. Create a new Pull Request
|
data/lib/httparty/patch.rb
CHANGED
@@ -1,33 +1,33 @@
|
|
1
|
-
require 'cgi'
|
2
|
-
|
3
|
-
# Monkey Patch for the HTTParty Gem
|
4
|
-
module HTTParty
|
5
|
-
# In order to parse the HTML encoded documents returned by the YourMembership
|
6
|
-
# API we need to HTML decode the <![CDATA[ tags. This is a bug workaround.
|
7
|
-
class Request
|
8
|
-
# This is the encode_body method from HTTParty's Request Class adding an additional method call to fix
|
9
|
-
# the CDATA elements that are improperly formatted in the YourMembership API's XML. This is done here to ensure that
|
10
|
-
# the fix is in place before the data is parsed.
|
11
|
-
def encode_body(body)
|
12
|
-
body = fix_cdata body
|
13
|
-
if ''.respond_to?(:encoding)
|
14
|
-
_encode_body(body)
|
15
|
-
else
|
16
|
-
body
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# Bug Fix for HTML encoded < and > in XML body.
|
21
|
-
# @param body [String] an XML document that needs to be checked for this specific issue.
|
22
|
-
# @return [String] If the HTML encoding issue is found it is repaired and the document is returned.
|
23
|
-
def fix_cdata(body)
|
24
|
-
# <![CDATA[ = <![CDATA[
|
25
|
-
# ]]> = ]]>
|
26
|
-
if body.include? '<![CDATA['
|
27
|
-
body.gsub! '<![CDATA[', '<![CDATA['
|
28
|
-
body.gsub! ']]>', ']]>'
|
29
|
-
end
|
30
|
-
body
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
# Monkey Patch for the HTTParty Gem
|
4
|
+
module HTTParty
|
5
|
+
# In order to parse the HTML encoded documents returned by the YourMembership
|
6
|
+
# API we need to HTML decode the <![CDATA[ tags. This is a bug workaround.
|
7
|
+
class Request
|
8
|
+
# This is the encode_body method from HTTParty's Request Class adding an additional method call to fix
|
9
|
+
# the CDATA elements that are improperly formatted in the YourMembership API's XML. This is done here to ensure that
|
10
|
+
# the fix is in place before the data is parsed.
|
11
|
+
def encode_body(body)
|
12
|
+
body = fix_cdata body
|
13
|
+
if ''.respond_to?(:encoding)
|
14
|
+
_encode_body(body)
|
15
|
+
else
|
16
|
+
body
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Bug Fix for HTML encoded < and > in XML body.
|
21
|
+
# @param body [String] an XML document that needs to be checked for this specific issue.
|
22
|
+
# @return [String] If the HTML encoding issue is found it is repaired and the document is returned.
|
23
|
+
def fix_cdata(body)
|
24
|
+
# <![CDATA[ = <![CDATA[
|
25
|
+
# ]]> = ]]>
|
26
|
+
if body.include? '<![CDATA['
|
27
|
+
body.gsub! '<![CDATA[', '<![CDATA['
|
28
|
+
body.gsub! ']]>', ']]>'
|
29
|
+
end
|
30
|
+
body
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/your_membership/base.rb
CHANGED
@@ -1,197 +1,197 @@
|
|
1
|
-
module YourMembership
|
2
|
-
# Base Class inherited by all Your Membership SDK Classes.
|
3
|
-
class Base
|
4
|
-
include HTTParty
|
5
|
-
|
6
|
-
base_uri YourMembership.config[:baseUri]
|
7
|
-
|
8
|
-
# rubocop:disable Style/ClassVars
|
9
|
-
|
10
|
-
# Call IDs are usually tied to sessions, this is a unique call id for use whenever a session is not needed.
|
11
|
-
@@genericCallID = nil
|
12
|
-
|
13
|
-
# @return [Integer] Auto Increments ad returns the genericCallID as required by the YourMembership.com API
|
14
|
-
def self.new_call_id
|
15
|
-
if @@genericCallID.nil?
|
16
|
-
# We start with a very high number to avoid conflicts when initiating a new session.
|
17
|
-
@@genericCallID = 10_000
|
18
|
-
else
|
19
|
-
@@genericCallID += 1
|
20
|
-
end
|
21
|
-
@@genericCallID
|
22
|
-
end
|
23
|
-
# rubocop:enable Style/ClassVars
|
24
|
-
|
25
|
-
# A Guard Method that returns true if the response from the API can be processed and raises an exception if not.
|
26
|
-
# @param [Hash] response
|
27
|
-
# @return [Boolean] true if no errors found.
|
28
|
-
# @raise [HTTParty::ResponseError] if a communication error is found.
|
29
|
-
def self.response_valid?(response)
|
30
|
-
if response.success?
|
31
|
-
!response_ym_error?(response)
|
32
|
-
else
|
33
|
-
raise HTTParty::ResponseError.new(response), 'Connection to YourMembership API failed.'
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
# Checks for error codes in the API response and raises an exception if an error is found.
|
38
|
-
# @param [Hash] response
|
39
|
-
# @return [Boolean] false if no error is found
|
40
|
-
# @raise [YourMembership::Error] if an error is found
|
41
|
-
def self.response_ym_error?(response)
|
42
|
-
if response['YourMembership_Response']['ErrCode'] != '0'
|
43
|
-
raise YourMembership::Error.new(
|
44
|
-
response['YourMembership_Response']['ErrCode'],
|
45
|
-
response['YourMembership_Response']['ErrDesc']
|
46
|
-
)
|
47
|
-
else
|
48
|
-
return false
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# Creates an XML string to send to the API
|
53
|
-
# @todo THIS SHOULD BE MARKED PRIVATE and refactored to DRY up the calls.
|
54
|
-
def self.build_XML_request(callMethod, session = nil, params = {}) # rubocop:disable Style/MethodLength, Style/MethodName
|
55
|
-
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
56
|
-
# Root Node Is always <YourMembership>
|
57
|
-
xml.YourMembership do
|
58
|
-
# API Version
|
59
|
-
xml.Version_ YourMembership.config[:version]
|
60
|
-
|
61
|
-
# API Key: For System Administrative tasks it is the private key and
|
62
|
-
# passcode, for all others it is the public key
|
63
|
-
if callMethod.downcase.start_with?('sa.')
|
64
|
-
xml.ApiKey_ YourMembership.config[:privateKey]
|
65
|
-
xml.SaPasscode_ YourMembership.config[:saPasscode]
|
66
|
-
else
|
67
|
-
xml.ApiKey_ YourMembership.config[:publicKey]
|
68
|
-
end
|
69
|
-
|
70
|
-
# Pass Session ID and Session Call ID unless there is no session, then
|
71
|
-
# send call id from class
|
72
|
-
if session
|
73
|
-
if session.is_a? YourMembership::Session
|
74
|
-
xml.SessionID_ session.session_id
|
75
|
-
else
|
76
|
-
xml.SessionID_ session
|
77
|
-
end
|
78
|
-
xml.CallID_ session.call_id
|
79
|
-
else
|
80
|
-
xml.CallID_ new_call_id
|
81
|
-
end
|
82
|
-
|
83
|
-
xml.Call(:Method => callMethod) do
|
84
|
-
params.each do |key, value|
|
85
|
-
xml_process(key, value, xml)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
builder.to_xml
|
92
|
-
end
|
93
|
-
|
94
|
-
# This is a helper method to always return an array (potentially empty) of responses (Hashes) for methods that can
|
95
|
-
# have multiple results. The default behavior of the API is to return a nil if no records are found, a hash if one
|
96
|
-
# record is found and an array if multiple records are found.
|
97
|
-
#
|
98
|
-
# @param [Hash] response_body This is the nodeset that returns nil if an empty data set is returned.
|
99
|
-
# @param [Array] keys This is a list of keys, in order that are nested inside the response body, these keys will be
|
100
|
-
# traversed in order before retrieving the data associated with the last key in the array
|
101
|
-
# @return [Array] A single dimension array of hashes.
|
102
|
-
def self.response_to_array_of_hashes(response_body, keys = [])
|
103
|
-
return_array = []
|
104
|
-
if response_body
|
105
|
-
# http://stackoverflow.com/questions/13259181/what-is-the-most-ruby-ish-way-of-accessing-nested-hash-values-at-arbitrary-depth
|
106
|
-
response_body_items = keys.reduce(response_body) { |h, key| h[key] }
|
107
|
-
if response_body_items.class == Array
|
108
|
-
response_body_items.each do |response_item|
|
109
|
-
return_array.push response_item
|
110
|
-
end
|
111
|
-
else
|
112
|
-
return_array.push response_body_items
|
113
|
-
end
|
114
|
-
end
|
115
|
-
return_array
|
116
|
-
end
|
117
|
-
|
118
|
-
# Converts the desired portion of the XML response to a single dimension array.
|
119
|
-
# This is useful when you don't have a need for key, value pairs and want a clean array of values to work with.
|
120
|
-
#
|
121
|
-
# @param [Hash] response_body This is the nodeset that returns nil if an empty data set is returned.
|
122
|
-
# @param [Array] keys This is a list of keys, in order that are nested inside the response body, these keys will be
|
123
|
-
# traversed in order before retrieving the data associated with the key_for_array
|
124
|
-
# @param [String] key_for_array this is the key that represents the list of items you want to turn into an array.
|
125
|
-
# @return [Array] A single dimension array of values.
|
126
|
-
def self.response_to_array(response_body, keys = [], key_for_array)
|
127
|
-
return_array = []
|
128
|
-
response_hash_array = response_to_array_of_hashes(response_body, keys)
|
129
|
-
response_hash_array.each do |item|
|
130
|
-
return_array.push item[key_for_array]
|
131
|
-
end
|
132
|
-
return_array
|
133
|
-
end
|
134
|
-
|
135
|
-
private
|
136
|
-
|
137
|
-
# Convenience method to convert Ruby DateTime objects into ODBC canonical strings as are expected by the API
|
138
|
-
# @param [DateTime] dateTime
|
139
|
-
# @return [String] An ODBC canonical string representation of a date as is expected by the API
|
140
|
-
def self.format_date_string(dateTime)
|
141
|
-
dateTime.strftime('%Y-%m-%d %H:%M:%S')
|
142
|
-
end
|
143
|
-
|
144
|
-
def self.xml_process(key, value, xml)
|
145
|
-
case value
|
146
|
-
when Array
|
147
|
-
xml_process_array(key, value, xml)
|
148
|
-
when Hash
|
149
|
-
xml_process_hash(key, value, xml)
|
150
|
-
when YourMembership::Profile
|
151
|
-
xml_process_profile(value, xml)
|
152
|
-
when DateTime
|
153
|
-
xml.send(key, format_date_string(value))
|
154
|
-
else
|
155
|
-
xml.send(key, value)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
def self.xml_process_profile(profile, xml)
|
160
|
-
profile.data.each do |k, v|
|
161
|
-
xml_process(k, v, xml)
|
162
|
-
end
|
163
|
-
xml.send('CustomFieldResponses') do
|
164
|
-
profile.custom_data.each do |k, v|
|
165
|
-
xml_process_custom_field_responses(k, v, xml)
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
def self.xml_process_hash(key, value, xml)
|
171
|
-
xml.send(key) do
|
172
|
-
value.each { |k, v| xml_process(k, v, xml) }
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def self.xml_process_array(key, value, xml)
|
177
|
-
xml.send(key) do
|
178
|
-
value.each { |tag| xml.send(tag[0], tag[1]) }
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
def self.xml_process_custom_field_responses(key, value, xml)
|
183
|
-
xml.send('CustomFieldResponse', :FieldCode => key) do
|
184
|
-
xml.send('Values') do
|
185
|
-
case value
|
186
|
-
when Array
|
187
|
-
value.each do | item |
|
188
|
-
xml.send('Value', item)
|
189
|
-
end
|
190
|
-
else
|
191
|
-
xml.send('Value', value)
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
1
|
+
module YourMembership
|
2
|
+
# Base Class inherited by all Your Membership SDK Classes.
|
3
|
+
class Base
|
4
|
+
include HTTParty
|
5
|
+
|
6
|
+
base_uri YourMembership.config[:baseUri]
|
7
|
+
|
8
|
+
# rubocop:disable Style/ClassVars
|
9
|
+
|
10
|
+
# Call IDs are usually tied to sessions, this is a unique call id for use whenever a session is not needed.
|
11
|
+
@@genericCallID = nil
|
12
|
+
|
13
|
+
# @return [Integer] Auto Increments ad returns the genericCallID as required by the YourMembership.com API
|
14
|
+
def self.new_call_id
|
15
|
+
if @@genericCallID.nil?
|
16
|
+
# We start with a very high number to avoid conflicts when initiating a new session.
|
17
|
+
@@genericCallID = 10_000
|
18
|
+
else
|
19
|
+
@@genericCallID += 1
|
20
|
+
end
|
21
|
+
@@genericCallID
|
22
|
+
end
|
23
|
+
# rubocop:enable Style/ClassVars
|
24
|
+
|
25
|
+
# A Guard Method that returns true if the response from the API can be processed and raises an exception if not.
|
26
|
+
# @param [Hash] response
|
27
|
+
# @return [Boolean] true if no errors found.
|
28
|
+
# @raise [HTTParty::ResponseError] if a communication error is found.
|
29
|
+
def self.response_valid?(response)
|
30
|
+
if response.success?
|
31
|
+
!response_ym_error?(response)
|
32
|
+
else
|
33
|
+
raise HTTParty::ResponseError.new(response), 'Connection to YourMembership API failed.'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Checks for error codes in the API response and raises an exception if an error is found.
|
38
|
+
# @param [Hash] response
|
39
|
+
# @return [Boolean] false if no error is found
|
40
|
+
# @raise [YourMembership::Error] if an error is found
|
41
|
+
def self.response_ym_error?(response)
|
42
|
+
if response['YourMembership_Response']['ErrCode'] != '0'
|
43
|
+
raise YourMembership::Error.new(
|
44
|
+
response['YourMembership_Response']['ErrCode'],
|
45
|
+
response['YourMembership_Response']['ErrDesc']
|
46
|
+
)
|
47
|
+
else
|
48
|
+
return false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Creates an XML string to send to the API
|
53
|
+
# @todo THIS SHOULD BE MARKED PRIVATE and refactored to DRY up the calls.
|
54
|
+
def self.build_XML_request(callMethod, session = nil, params = {}) # rubocop:disable Style/MethodLength, Style/MethodName
|
55
|
+
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
56
|
+
# Root Node Is always <YourMembership>
|
57
|
+
xml.YourMembership do
|
58
|
+
# API Version
|
59
|
+
xml.Version_ YourMembership.config[:version]
|
60
|
+
|
61
|
+
# API Key: For System Administrative tasks it is the private key and
|
62
|
+
# passcode, for all others it is the public key
|
63
|
+
if callMethod.downcase.start_with?('sa.')
|
64
|
+
xml.ApiKey_ YourMembership.config[:privateKey]
|
65
|
+
xml.SaPasscode_ YourMembership.config[:saPasscode]
|
66
|
+
else
|
67
|
+
xml.ApiKey_ YourMembership.config[:publicKey]
|
68
|
+
end
|
69
|
+
|
70
|
+
# Pass Session ID and Session Call ID unless there is no session, then
|
71
|
+
# send call id from class
|
72
|
+
if session
|
73
|
+
if session.is_a? YourMembership::Session
|
74
|
+
xml.SessionID_ session.session_id
|
75
|
+
else
|
76
|
+
xml.SessionID_ session
|
77
|
+
end
|
78
|
+
xml.CallID_ session.call_id
|
79
|
+
else
|
80
|
+
xml.CallID_ new_call_id
|
81
|
+
end
|
82
|
+
|
83
|
+
xml.Call(:Method => callMethod) do
|
84
|
+
params.each do |key, value|
|
85
|
+
xml_process(key, value, xml)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
builder.to_xml
|
92
|
+
end
|
93
|
+
|
94
|
+
# This is a helper method to always return an array (potentially empty) of responses (Hashes) for methods that can
|
95
|
+
# have multiple results. The default behavior of the API is to return a nil if no records are found, a hash if one
|
96
|
+
# record is found and an array if multiple records are found.
|
97
|
+
#
|
98
|
+
# @param [Hash] response_body This is the nodeset that returns nil if an empty data set is returned.
|
99
|
+
# @param [Array] keys This is a list of keys, in order that are nested inside the response body, these keys will be
|
100
|
+
# traversed in order before retrieving the data associated with the last key in the array
|
101
|
+
# @return [Array] A single dimension array of hashes.
|
102
|
+
def self.response_to_array_of_hashes(response_body, keys = [])
|
103
|
+
return_array = []
|
104
|
+
if response_body
|
105
|
+
# http://stackoverflow.com/questions/13259181/what-is-the-most-ruby-ish-way-of-accessing-nested-hash-values-at-arbitrary-depth
|
106
|
+
response_body_items = keys.reduce(response_body) { |h, key| h[key] }
|
107
|
+
if response_body_items.class == Array
|
108
|
+
response_body_items.each do |response_item|
|
109
|
+
return_array.push response_item
|
110
|
+
end
|
111
|
+
else
|
112
|
+
return_array.push response_body_items
|
113
|
+
end
|
114
|
+
end
|
115
|
+
return_array
|
116
|
+
end
|
117
|
+
|
118
|
+
# Converts the desired portion of the XML response to a single dimension array.
|
119
|
+
# This is useful when you don't have a need for key, value pairs and want a clean array of values to work with.
|
120
|
+
#
|
121
|
+
# @param [Hash] response_body This is the nodeset that returns nil if an empty data set is returned.
|
122
|
+
# @param [Array] keys This is a list of keys, in order that are nested inside the response body, these keys will be
|
123
|
+
# traversed in order before retrieving the data associated with the key_for_array
|
124
|
+
# @param [String] key_for_array this is the key that represents the list of items you want to turn into an array.
|
125
|
+
# @return [Array] A single dimension array of values.
|
126
|
+
def self.response_to_array(response_body, keys = [], key_for_array)
|
127
|
+
return_array = []
|
128
|
+
response_hash_array = response_to_array_of_hashes(response_body, keys)
|
129
|
+
response_hash_array.each do |item|
|
130
|
+
return_array.push item[key_for_array]
|
131
|
+
end
|
132
|
+
return_array
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
# Convenience method to convert Ruby DateTime objects into ODBC canonical strings as are expected by the API
|
138
|
+
# @param [DateTime] dateTime
|
139
|
+
# @return [String] An ODBC canonical string representation of a date as is expected by the API
|
140
|
+
def self.format_date_string(dateTime)
|
141
|
+
dateTime.strftime('%Y-%m-%d %H:%M:%S')
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.xml_process(key, value, xml)
|
145
|
+
case value
|
146
|
+
when Array
|
147
|
+
xml_process_array(key, value, xml)
|
148
|
+
when Hash
|
149
|
+
xml_process_hash(key, value, xml)
|
150
|
+
when YourMembership::Profile
|
151
|
+
xml_process_profile(value, xml)
|
152
|
+
when DateTime
|
153
|
+
xml.send(key, format_date_string(value))
|
154
|
+
else
|
155
|
+
xml.send(key, value)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def self.xml_process_profile(profile, xml)
|
160
|
+
profile.data.each do |k, v|
|
161
|
+
xml_process(k, v, xml)
|
162
|
+
end
|
163
|
+
xml.send('CustomFieldResponses') do
|
164
|
+
profile.custom_data.each do |k, v|
|
165
|
+
xml_process_custom_field_responses(k, v, xml)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def self.xml_process_hash(key, value, xml)
|
171
|
+
xml.send(key) do
|
172
|
+
value.each { |k, v| xml_process(k, v, xml) }
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.xml_process_array(key, value, xml)
|
177
|
+
xml.send(key) do
|
178
|
+
value.each { |tag| xml.send(tag[0], tag[1]) }
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.xml_process_custom_field_responses(key, value, xml)
|
183
|
+
xml.send('CustomFieldResponse', :FieldCode => key) do
|
184
|
+
xml.send('Values') do
|
185
|
+
case value
|
186
|
+
when Array
|
187
|
+
value.each do | item |
|
188
|
+
xml.send('Value', item)
|
189
|
+
end
|
190
|
+
else
|
191
|
+
xml.send('Value', value)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|