eloqua 1.1.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.
Files changed (72) hide show
  1. data/.gitignore +11 -0
  2. data/.yardopts +2 -0
  3. data/CHANGELOG.md +23 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +81 -0
  6. data/LICENSE +21 -0
  7. data/README.md +245 -0
  8. data/Rakefile +13 -0
  9. data/TODO.md +8 -0
  10. data/eloqua.gemspec +32 -0
  11. data/eloqua_initializer.tpl.rb +3 -0
  12. data/lib/eloqua.rb +51 -0
  13. data/lib/eloqua/api.rb +119 -0
  14. data/lib/eloqua/api/action.rb +41 -0
  15. data/lib/eloqua/api/service.rb +240 -0
  16. data/lib/eloqua/asset.rb +31 -0
  17. data/lib/eloqua/builder/templates.rb +31 -0
  18. data/lib/eloqua/builder/xml.rb +129 -0
  19. data/lib/eloqua/entity.rb +72 -0
  20. data/lib/eloqua/exceptions.rb +5 -0
  21. data/lib/eloqua/helper/attribute_map.rb +78 -0
  22. data/lib/eloqua/query.rb +291 -0
  23. data/lib/eloqua/remote_object.rb +274 -0
  24. data/lib/eloqua/version.rb +3 -0
  25. data/lib/eloqua/wsdl/action.wsdl +1 -0
  26. data/lib/eloqua/wsdl/data.wsdl +1 -0
  27. data/lib/eloqua/wsdl/email.wsdl +1 -0
  28. data/lib/eloqua/wsdl/service.wsdl +1 -0
  29. data/lib/tasks/test.rake +24 -0
  30. data/rspec.watchr +74 -0
  31. data/spec/fixtures/add_group_member/success.xml +18 -0
  32. data/spec/fixtures/create/contact_duplicate.xml +30 -0
  33. data/spec/fixtures/create/contact_success.xml +25 -0
  34. data/spec/fixtures/create_asset/failure.xml +30 -0
  35. data/spec/fixtures/create_asset/group_success.xml +25 -0
  36. data/spec/fixtures/delete_asset/access_deny.xml +31 -0
  37. data/spec/fixtures/describe_asset/success.xml +72 -0
  38. data/spec/fixtures/describe_asset_type/success.xml +23 -0
  39. data/spec/fixtures/describe_entity/success.xml +54 -0
  40. data/spec/fixtures/describe_entity_type/success.xml +45 -0
  41. data/spec/fixtures/get_member_count_in_step_by_status/success.xml +15 -0
  42. data/spec/fixtures/list_asset_types/success.xml +28 -0
  43. data/spec/fixtures/list_entity_types/success.xml +21 -0
  44. data/spec/fixtures/list_group_membership/success.xml +25 -0
  45. data/spec/fixtures/list_members_in_step_by_status/success.xml +15 -0
  46. data/spec/fixtures/query/contact_email_one.xml +38 -0
  47. data/spec/fixtures/query/contact_email_two.xml +56 -0
  48. data/spec/fixtures/query/contact_missing.xml +19 -0
  49. data/spec/fixtures/query/fault.xml +43 -0
  50. data/spec/fixtures/remove_group_member/success.xml +18 -0
  51. data/spec/fixtures/retrieve/contact_missing.xml +17 -0
  52. data/spec/fixtures/retrieve/contact_multiple.xml +3460 -0
  53. data/spec/fixtures/retrieve/contact_single.xml +38 -0
  54. data/spec/fixtures/retrieve_asset/failure.xml +17 -0
  55. data/spec/fixtures/retrieve_asset/success.xml +50 -0
  56. data/spec/fixtures/update/contact_success.xml +26 -0
  57. data/spec/lib/eloqua/api/action_spec.rb +36 -0
  58. data/spec/lib/eloqua/api/service_spec.rb +498 -0
  59. data/spec/lib/eloqua/api_spec.rb +133 -0
  60. data/spec/lib/eloqua/asset_spec.rb +63 -0
  61. data/spec/lib/eloqua/builder/templates_spec.rb +68 -0
  62. data/spec/lib/eloqua/builder/xml_spec.rb +254 -0
  63. data/spec/lib/eloqua/entity_spec.rb +224 -0
  64. data/spec/lib/eloqua/helper/attribute_map_spec.rb +14 -0
  65. data/spec/lib/eloqua/query_spec.rb +596 -0
  66. data/spec/lib/eloqua/remote_object_spec.rb +742 -0
  67. data/spec/lib/eloqua_spec.rb +171 -0
  68. data/spec/shared/attribute_map.rb +173 -0
  69. data/spec/shared/class_to_api_delegation.rb +50 -0
  70. data/spec/spec_helper.rb +48 -0
  71. data/spec/support/helper.rb +73 -0
  72. metadata +366 -0
@@ -0,0 +1,3 @@
1
+ Eloqua.configure do |config|
2
+ config.authenticate('Company\\User', 'Password')
3
+ end
@@ -0,0 +1,51 @@
1
+ require 'active_support/core_ext/class'
2
+ require 'active_support/core_ext/module'
3
+
4
+ module Eloqua
5
+
6
+ autoload :Api, 'eloqua/api'
7
+ autoload :Entity, 'eloqua/entity'
8
+ autoload :Asset, 'eloqua/asset'
9
+ autoload :RemoteObject, 'eloqua/remote_object'
10
+ autoload :Query, 'eloqua/query'
11
+
12
+ mattr_accessor :user, :password
13
+
14
+ def self.configure(&block)
15
+ yield self
16
+ end
17
+
18
+ def self.authenticate(user, password)
19
+ self.user = user
20
+ self.password = password
21
+ end
22
+
23
+ def self.format_results_for_array(results, *keys)
24
+ max_depth = keys.length
25
+ depth = 0
26
+ keys.each do |key|
27
+ if(results.has_key?(key))
28
+ depth += 1
29
+ results = results[key]
30
+ end
31
+ end
32
+ if(depth == max_depth && !results.is_a?(Array))
33
+ results = [results]
34
+ end
35
+ results
36
+ end
37
+
38
+ def self.delegate_with_args(from_klass, to_klass, methods, methods_to_argument)
39
+ argument_string = methods_to_argument.join(', ')
40
+ methods.each do |__method_name|
41
+ from_klass.module_eval(<<-RUBY)
42
+ def self.#{__method_name}(*args, &block)
43
+ #{to_klass}.__send__(#{__method_name.inspect}, #{argument_string}, *args, &block)
44
+ end
45
+ RUBY
46
+ end
47
+
48
+ end
49
+
50
+
51
+ end
@@ -0,0 +1,119 @@
1
+ require 'savon'
2
+
3
+ require 'active_support/core_ext/class'
4
+ require 'active_support/concern'
5
+ require 'active_support/core_ext/module/delegation'
6
+
7
+ require 'eloqua/builder/xml'
8
+ require 'eloqua/exceptions'
9
+
10
+ module Eloqua
11
+
12
+ class Api
13
+
14
+ autoload :Service, 'eloqua/api/service'
15
+ autoload :Action, 'eloqua/api/action'
16
+
17
+ # The namespace for Eloqua Array objects
18
+ XML_NS_ARRAY = 'http://schemas.microsoft.com/2003/10/Serialization/Arrays'
19
+
20
+ # WSDLs are from 3-30-2011
21
+ WSDL = {
22
+ :service => File.dirname(__FILE__) + '/wsdl/service.wsdl',
23
+ :data => File.dirname(__FILE__) + '/wsdl/data.wsdl',
24
+ :email => File.dirname(__FILE__) + '/wsdl/email.wsdl',
25
+ :action => File.dirname(__FILE__) + '/wsdl/action.wsdl'
26
+ }
27
+
28
+ class << self
29
+
30
+ delegate :define_builder_template, :to => Eloqua::Builder::Xml
31
+ delegate :builder_template, :to => Eloqua::Builder::Xml
32
+ delegate :builder_templates, :to => Eloqua::Builder::Xml
33
+
34
+ attr_accessor :last_request, :last_response, :soap_error, :http_error
35
+
36
+ @@clients = {}
37
+
38
+ def reset_clients
39
+ @@clients = {}
40
+ end
41
+
42
+ def clients
43
+ @@clients
44
+ end
45
+
46
+ # There are four currently supported wsdl types for eloqua
47
+ # 1. Service
48
+ # 2. Data
49
+ # 3. Email
50
+ # 4. External Action
51
+ def client(type)
52
+ if(!Eloqua.user || !Eloqua.password)
53
+ raise('Eloqua.user or Eloqua.password is not set see Eloqua.authenticate')
54
+ end
55
+ clients[type] ||= Savon::Client.new do
56
+ wsdl.document = WSDL[type]
57
+ wsse.credentials Eloqua.user, Eloqua.password
58
+ end
59
+ end
60
+
61
+ def builder(&block)
62
+ Eloqua::Builder::Xml.create(:namespace => :wsdl, &block)
63
+ end
64
+
65
+ def remote_type(name, type = 'Base', id = 0)
66
+ {
67
+ :name => name,
68
+ :type => type,
69
+ :id => id
70
+ }
71
+ end
72
+
73
+ def request(type, name, soap_body = nil, &block)
74
+ result = send_remote_request(type, name, soap_body, &block)
75
+
76
+ self.last_request = client(type).soap.to_xml if client(type).soap
77
+ self.last_response = result.to_xml if result.respond_to?(:to_xml)
78
+
79
+ if(result)
80
+ result = result.to_hash
81
+ response_key = "#{name}_response".to_sym
82
+ result_key = "#{name}_result".to_sym
83
+ if(result.has_key?(response_key))
84
+ result = result[response_key]
85
+ end
86
+ if(result.has_key?(result_key))
87
+ result = result[result_key]
88
+ end
89
+ end
90
+ result
91
+ end
92
+
93
+ # Sends remote request and returns a response object
94
+ def send_remote_request(type, name, soap_body = nil, &block)
95
+ @soap_error = nil
96
+ @http_error = nil
97
+
98
+ request = client(type).request(:wsdl, name) do
99
+ soap.namespaces["xmlns:arr"] = XML_NS_ARRAY
100
+ soap.element_form_default = :qualified
101
+ soap.body = soap_body if soap_body
102
+ instance_eval(&block) if block_given?
103
+ end
104
+ response_errors(request)
105
+ request
106
+ end
107
+
108
+ def response_errors(response)
109
+ @soap_error = Eloqua::SoapError.new(response.http)
110
+ @http_error = Eloqua::HTTPError.new(response.http)
111
+
112
+ raise @soap_error if @soap_error.present?
113
+ raise @http_error if @http_error.present?
114
+ end
115
+
116
+ end
117
+ end
118
+
119
+ end
@@ -0,0 +1,41 @@
1
+ require 'eloqua/api'
2
+
3
+ module Eloqua
4
+
5
+ class Api
6
+ class Action
7
+
8
+ cattr_reader :type_methods
9
+ @@type_methods = [:list_external_action_steps_by_type, :get_member_count_in_step_by_status, :list_members_in_step_by_status, :set_member_status]
10
+
11
+ class << self
12
+
13
+ delegate :builder, :remote_type, :to => Eloqua::Api
14
+
15
+ def get_member_count_in_step_by_status(stepId, status)
16
+ xml_query = builder do |xml|
17
+ xml.tag!(:stepId, stepId)
18
+ xml.tag!(:status, status)
19
+ end
20
+ results = request(:get_member_count_in_step_by_status, xml_query)
21
+ results = results.to_i
22
+ end
23
+
24
+ #still seems finicky, returns a funky hash table if there are no members in that step
25
+ def list_members_in_step_by_status(stepId, status, pageNumber, pageSize)
26
+ xml_query = builder do |xml|
27
+ xml.tag!(:stepId, stepId)
28
+ xml.tag!(:status, status)
29
+ xml.tag!(:pageNumber, pageNumber)
30
+ xml.tag!(:pageSize, pageSize)
31
+ end
32
+ results = request(:list_members_in_step_by_status, xml_query)
33
+ end
34
+
35
+ def request(*args)
36
+ Eloqua::Api.request(:action, *args)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,240 @@
1
+ require 'eloqua/api'
2
+
3
+ module Eloqua
4
+
5
+ class Api
6
+ class Service
7
+
8
+ cattr_reader :group_methods
9
+ cattr_reader :group_type_methods
10
+ cattr_reader :type_methods
11
+
12
+ @@group_methods = [:key_with_object, :object_method, :list_types, :describe_type]
13
+ @@type_methods = []
14
+ @@group_type_methods = [:create_object, :update_object, :delete_object, :find_object, :describe]
15
+
16
+ class << self
17
+
18
+ delegate :builder, :remote_type, :to => Eloqua::Api
19
+
20
+ def entity_association_xml(asset_type, asset_id, entity, entity_id)
21
+ xml_query = builder do |xml|
22
+ xml.template!(:object, :entity, entity, entity_id)
23
+ xml.template!(:object, :asset, asset_type, asset_id)
24
+ end
25
+ end
26
+
27
+ # Delegate Group
28
+ def key_with_object(group, name)
29
+ if (group == :entity)
30
+ name.to_sym
31
+ else
32
+ parts = name.to_s.split('_')
33
+ "#{parts[0]}_#{group}_#{parts[1]}".to_sym
34
+ end
35
+ end
36
+
37
+ # Delegate Group
38
+ def object_method(group, method)
39
+ if (group == :entity)
40
+ method.to_sym
41
+ else
42
+ "#{method}_#{group}".to_sym
43
+ end
44
+ end
45
+
46
+ def request(*args)
47
+ Eloqua::Api.request(:service, *args)
48
+ end
49
+
50
+ # Delegate, Group, Type
51
+ def create_object(group, type, attributes)
52
+ xml_query = builder do |xml|
53
+ xml.object_collection!(group) do
54
+ xml.dynamic_object!(group) do
55
+ xml.template!(:dynamic, group, type, nil, attributes)
56
+ end
57
+ end
58
+ end
59
+
60
+ result = request(object_method(group, :create), xml_query)
61
+ result = result[key_with_object(group, :create_result)]
62
+
63
+ if (result[:errors].nil? && result[:id])
64
+ {:id => result[:id].to_i}
65
+ else
66
+ handle_exception(result)
67
+ end
68
+ end
69
+
70
+ # Delegate Group, Type
71
+ def update_object(group, type, entity_id, attributes)
72
+ xml_query = builder do |xml|
73
+ xml.object_collection!(group) do
74
+ xml.dynamic_object!(group) do
75
+ xml.template!(:dynamic, group, type, entity_id, attributes)
76
+ end
77
+ end
78
+ end
79
+
80
+ result = request(object_method(group, :update), xml_query)
81
+ result = result[key_with_object(group, :update_result)]
82
+
83
+ if (result[:success] && result[:id].to_s == entity_id.to_s)
84
+ true
85
+ else
86
+ handle_exception(result)
87
+ end
88
+ end
89
+
90
+ # Delegate Group, Type
91
+ def delete_object(group, type, id)
92
+ xml_query = builder do |xml|
93
+ xml.object_type_lower!(group) do
94
+ xml.template!(:object_type, type)
95
+ end
96
+ xml.ids do
97
+ xml.template!(:int_array, [id])
98
+ end
99
+ end
100
+
101
+ result = request(object_method(group, :delete), xml_query)
102
+ result = result[key_with_object(group, :delete_result)]
103
+
104
+ if (result[:success] && result[:id].to_s == id.to_s)
105
+ [result[:id]]
106
+ else
107
+ handle_exception(result)
108
+ end
109
+ end
110
+
111
+ # Delegate Group, Type
112
+ def find_object(group, type, id)
113
+ xml_query = builder do |xml|
114
+ xml.object_type_lower!(group) do
115
+ xml.template!(:object_type, type)
116
+ end
117
+ xml.ids do
118
+ xml.template!(:int_array, [id])
119
+ end
120
+ end
121
+
122
+
123
+ result = request(object_method(group, :retrieve), xml_query)
124
+
125
+ field_key = "#{group}_fields".to_sym
126
+ dynamic_key = "dynamic_#{group}".to_sym
127
+
128
+ if (result[dynamic_key] && result[dynamic_key][:field_value_collection])
129
+ attribute_list = result[dynamic_key][:field_value_collection][field_key]
130
+ attributes = {:id => result[dynamic_key][:id].to_i}
131
+ attribute_list.each do |map|
132
+ attributes[map[:internal_name].to_sym] = map[:value]
133
+ end
134
+ attributes
135
+ else
136
+ false
137
+ end
138
+ end
139
+
140
+ # Delegate Type
141
+ def list_memberships(entity_type, entity_id)
142
+ xml_query = builder do |xml|
143
+ xml.template!(:object, :entity, entity_type, entity_id)
144
+ end
145
+ results = request(:list_group_membership, xml_query)
146
+ if(results.has_key?(:dynamic_asset))
147
+ results = Eloqua.format_results_for_array(results, :dynamic_asset)
148
+ results.inject([]) do |map, object|
149
+ map << object[:asset_type]
150
+ map
151
+ end
152
+ end
153
+ end
154
+
155
+ def entity_asset_operation(request_method, asset_type, asset_id, entity, entity_id)
156
+ xml_query = entity_association_xml(asset_type, asset_id, entity, entity_id)
157
+ result = request(request_method.to_sym, xml_query)
158
+ if (result[:success])
159
+ true
160
+ elsif (result[:errors])
161
+ handle_exception(result)
162
+ else
163
+ false
164
+ end
165
+ end
166
+
167
+ def add_group_member(asset_type, asset_id, entity_type, entity_id)
168
+ entity_asset_operation(:add_group_member, asset_type, asset_id, entity_type, entity_id)
169
+ end
170
+
171
+ def remove_group_member(asset_type, asset_id, entity_type, entity_id)
172
+ entity_asset_operation(:remove_group_member, asset_type, asset_id, entity_type, entity_id)
173
+ end
174
+
175
+ # Delegate Group
176
+ def list_types(group)
177
+ types = "#{group}_types".to_sym
178
+ result = request("list_#{types}".to_sym)
179
+ if (result && result[types])
180
+ result[types][:string]
181
+ end
182
+ end
183
+
184
+ # Delegate Group, Type
185
+ def describe(group, type)
186
+ xml_query = builder do |xml|
187
+ xml.object_type_lower!(group) do
188
+ xml.template!(:object_type, type)
189
+ end
190
+ end
191
+ remote_method = "describe_#{group}".to_sym
192
+ result = request(remote_method, xml_query)
193
+ if (result)
194
+ field_describe_key = "dynamic_#{group}_field_definition".to_sym
195
+ fields = result[:fields]
196
+ if (fields.is_a?(Hash) && fields.has_key?(field_describe_key))
197
+ result[:fields] = fields[field_describe_key]
198
+ end
199
+ end
200
+ result
201
+ end
202
+
203
+ # Delegate Group, Type
204
+ def describe_type(group, type_name)
205
+ key_type = "#{group}_type".to_sym
206
+ key_types = "#{key_type}s".to_sym
207
+
208
+ if(group == :entity)
209
+ type_name_key = :global_entity_type
210
+ else
211
+ type_name_key = key_type
212
+ end
213
+ result = request("describe_#{group}_type".to_sym, type_name_key => type_name)
214
+ Eloqua.format_results_for_array(result, key_types, key_type)
215
+ end
216
+
217
+ def handle_exception(response)
218
+ exception = response[:errors][:error]
219
+
220
+ error_code = exception[:error_code]
221
+ message = exception[:message]
222
+
223
+ error_message = sprintf("Eloqua Error: Code (%s) | Message: %s", error_code, message)
224
+
225
+ if (error_code =~ /Duplicate/)
226
+ raise(Eloqua::DuplicateRecordError, error_message)
227
+ else
228
+ raise(Eloqua::RemoteError, error_message)
229
+ end
230
+ false
231
+
232
+ end
233
+
234
+ end
235
+
236
+ end
237
+
238
+ end
239
+
240
+ end