landslider 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
File without changes
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2011, Jay Prall
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,39 @@
1
+ = Landslider
2
+
3
+ Ruby interface to Landslide's SOAP based API
4
+
5
+ == Pre-requisites
6
+
7
+ An account with Landslide that has the API enabled. (www.landslide.com)
8
+
9
+ == Resources
10
+
11
+ === Dependencies
12
+
13
+ This gem requires the following gems:
14
+ handsoap (1.1.8)
15
+
16
+ == Install
17
+
18
+ landslider requires the handsoap gem
19
+
20
+ gem install handsoap landslider
21
+
22
+ == Usage
23
+
24
+ Configuration:
25
+
26
+ # constants to be set by rails environment config files
27
+ LS_INSTANCE_NAME = 'jaytest'
28
+ LS_API_USERNAME = 'XXXXXXXX@landslide.com'
29
+ LS_API_PASSWORD = 'XXXXXXXX'
30
+ LS_API_KEY = Digest::MD5.hexdigest(LS_API_PASSWORD + LS_INSTANCE_NAME)
31
+ LS_API_NAMESPACE = "http://www.landslide.com/webservices/SoapService"
32
+ LS_API_ENDPOINT = {
33
+ :uri => "https://#{LS_INSTANCE_NAME}.api.landslide.com/webservices/SoapService",
34
+ :version => 2
35
+ }
36
+
37
+
38
+
39
+ more here later..
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gemspec|
7
+ gemspec.name = "landslider"
8
+ gemspec.homepage = "https://github.com/j4y/landslider"
9
+ gemspec.summary = "Ruby interface to Landslide SOAP API"
10
+ gemspec.description = "Ruby interface to Landslide SOAP API. "
11
+ gemspec.email = "jayprall@gmail.com"
12
+ gemspec.authors = ['Jay Prall']
13
+ end
14
+ Jeweler::GemcutterTasks.new
15
+ rescue LoadError
16
+ puts "Jeweler not available. Please install the jeweler gem"
17
+ end
18
+
19
+ # Load any rake files that exist
20
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |f| load f }
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 0
3
+ :major: 0
4
+ :minor: 1
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ # can be used as a rails plugin
2
+ require 'landslider'
@@ -0,0 +1,32 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{landslider}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Jay Prall"]
12
+ s.date = %q{2011-04-22}
13
+ s.description = %q{Ruby interface to Landslide SOAP API. }
14
+ s.email = %q{jayprall@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.require_paths = ["lib"]
20
+ s.rubygems_version = %q{1.6.2}
21
+ s.summary = %q{Ruby interface to Landslide SOAP API}
22
+
23
+ if s.respond_to? :specification_version then
24
+ s.specification_version = 3
25
+
26
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
27
+ else
28
+ end
29
+ else
30
+ end
31
+ end
32
+
data/lib/landslider.rb ADDED
@@ -0,0 +1,303 @@
1
+
2
+ require 'handsoap'
3
+ require 'curb'
4
+
5
+ class Landslider < Handsoap::Service
6
+
7
+ endpoint ::LS_API_ENDPOINT
8
+
9
+ def session_id
10
+ @session_id
11
+ end
12
+
13
+ def session_id=(session_id)
14
+ @session_id = session_id
15
+ end
16
+
17
+ def on_create_document(doc)
18
+ doc.alias 'urn', ::LS_API_NAMESPACE
19
+ header = doc.find('Header')
20
+ header.add('urn:SessionHeader') { |sh|
21
+ sh.add('urn:sessionId', self.session_id)
22
+ }
23
+ end
24
+
25
+ def on_http_error(response)
26
+ puts response.inspect
27
+ end
28
+
29
+ def login(session_id)
30
+ self.session_id = session_id
31
+
32
+ response = invoke("login", :soap_action => :none) do |message|
33
+ message.add('wsUser') { |u|
34
+ u.add 'username', ::LS_API_USERNAME
35
+ u.add 'password', ::LS_API_KEY
36
+ }
37
+ end
38
+
39
+ node = response.document.xpath('//ns:loginResponse/loginResponse', ns)
40
+ parse_login_result(node)
41
+ end
42
+
43
+ def get_api_version(session_id)
44
+ self.session_id = session_id
45
+
46
+ response = invoke("urn:getApiVersion", :soap_action => :none)
47
+
48
+ node = response.document.xpath('//ns:getApiVersionResponse', ns)
49
+ parse_api_version_result(node)
50
+ end
51
+
52
+ def get_accounts(session_id)
53
+ self.session_id = session_id
54
+ response = invoke("getAccounts", :soap_action => :none) do |message|
55
+ message.add('accountsRequest') { |ar|
56
+ ar.add 'firstResultPosition', 1
57
+ ar.add 'totalResultsRequested', 10
58
+ ar.add('searchCriteria') { |sc|
59
+ # just find accounts with an empty main city
60
+
61
+ sc.add 'fieldId', 'MainAddressCity'
62
+ sc.add 'operator', 'Empty'
63
+ }
64
+ }
65
+ end
66
+
67
+ node = response.document.xpath('//ns:getAccountsResponse', ns)
68
+ parse_get_accounts_result(node)
69
+ end
70
+
71
+ def get_account_opportunities(session_id, account_id)
72
+ self.session_id = session_id
73
+ response = invoke("getAccountOpportunities", :soap_action => :none) do |message|
74
+ message.add 'accountId', account_id
75
+ end
76
+ puts response.document.inspect
77
+
78
+ node = response.document.xpath('//ns:getAccountOpportunitiesResponse', ns)
79
+ parse_get_account_opportunities_result(node)
80
+ end
81
+
82
+
83
+
84
+ def get_account_contacts(session_id, account_id)
85
+ self.session_id = session_id
86
+ response = invoke("getAccountContacts", :soap_action => :none) do |message|
87
+ message.add 'accountId', account_id
88
+ end
89
+ puts response.document.inspect
90
+
91
+ node = response.document.xpath('//ns:getAccountContactsResponse', ns)
92
+ parse_get_account_contacts_result(node)
93
+ end
94
+
95
+ def get_account_notes(session_id, account_id)
96
+ self.session_id = session_id
97
+
98
+ response = invoke("getAccountNotes", :soap_action => :none) do |message|
99
+ message.add('accountNoteSearch') { |ans|
100
+
101
+ ans.add 'accountId', account_id
102
+ ans.add 'firstResultPosition', 1
103
+ ans.add 'totalResultsRequested', 10
104
+
105
+ # search criteria doesn't seem to work
106
+ # ans.add('searchCriteria') { |sc|
107
+ # sc.add 'fieldId', 'note'
108
+ # sc.add 'operator', 'Contains'
109
+ # sc.add 'queryValue', 'BLAH'
110
+ # }
111
+ }
112
+ end
113
+ puts response.document.inspect
114
+
115
+ end
116
+
117
+
118
+ def get_contact_notes(session_id, contact_id)
119
+ self.session_id = session_id
120
+
121
+ response = invoke("getContactNotes", :soap_action => :none) do |message|
122
+ message.add('contactNote') { |ans|
123
+ ans.add 'contactId', contact_id
124
+ ans.add 'firstResultPosition', 1
125
+ ans.add 'totalResultsRequested', 10
126
+ }
127
+ end
128
+ puts response.document.inspect
129
+
130
+ end
131
+
132
+
133
+ def get_opportunity_notes(session_id, opportunity_id)
134
+ self.session_id = session_id
135
+
136
+ response = invoke("getOpportunityNotes", :soap_action => :none) do |message|
137
+ message.add('opportunityNote') { |ans|
138
+
139
+ ans.add 'opportunityId', opportunity_id
140
+ ans.add 'firstResultPosition', 1
141
+ ans.add 'totalResultsRequested', 10
142
+ }
143
+ end
144
+ puts response.document.inspect
145
+
146
+ end
147
+
148
+ def get_lead_notes(session_id, lead_id)
149
+ self.session_id = session_id
150
+
151
+ response = invoke("getLeadNotes", :soap_action => :none) do |message|
152
+ message.add('leadNote') { |ans|
153
+
154
+ ans.add 'leadId', lead_id
155
+ ans.add 'firstResultPosition', 1
156
+ ans.add 'totalResultsRequested', 10
157
+ }
158
+ end
159
+ puts response.document.inspect
160
+
161
+ end
162
+
163
+
164
+ private
165
+
166
+ def ns
167
+ { 'ns' => LS_API_NAMESPACE }
168
+ end
169
+
170
+ def parse_login_result(node)
171
+ {
172
+ :error => xml_to_bool(node, './error/text()'),
173
+ :error_code => xml_to_int(node, './errorCode/text()'),
174
+ :result_msg => xml_to_str(node, './resultMsg/text()'),
175
+ :status_code => xml_to_int(node, './statusCode/text()'),
176
+ :password_expired => xml_to_bool(node, './passwordExpired/text()'),
177
+ :session_id => xml_to_str(node, './sessionId/text()')
178
+ }
179
+ end
180
+
181
+ def parse_api_version_result(node)
182
+ {
183
+ :internal_name => xml_to_str(node, '//ApiVersion/internalName/text()'),
184
+ :label => xml_to_str(node, '//ApiVersion/label/text()'),
185
+ :major_version => xml_to_int(node, '//ApiVersion/majorVersion/text()'),
186
+ :minor_version => xml_to_int(node, '//ApiVersion/minorVersion/text()'),
187
+ :revision_version => xml_to_int(node, '//ApiVersion/revisionVersion/text()')
188
+ }
189
+ end
190
+
191
+ def parse_get_accounts_result(node)
192
+ {
193
+ :accounts => node.xpath('//Accounts/accountList', ns).map { |child| parse_account(child) },
194
+ :error => xml_to_bool(node, '//Accounts/error/text()'),
195
+ :error_code => xml_to_int(node, '//Accounts/errorCode/text()'),
196
+ :result_msg => xml_to_str(node, '//Accounts/resultMsg/text()'),
197
+ :results_returned => xml_to_int(node, '//Accounts/resultsReturned/text()'),
198
+ :total_results_available => xml_to_int(node, '//Accounts/totalResultsAvailable/text()')
199
+ }
200
+ end
201
+
202
+ def parse_get_account_opportunities_result(node)
203
+ {
204
+ :opportunities => node.xpath('./*/opportunityList', ns).map { |child| parse_opportunity(child) },
205
+ :error => xml_to_bool(node, './*/error/text()'),
206
+ :results_returned => xml_to_int(node, './*/resultsReturned/text()'),
207
+ :total_results_available => xml_to_int(node, './*/totalResultsAvailable/text()')
208
+ }
209
+ end
210
+
211
+ def parse_get_account_contacts_result(node)
212
+ {
213
+ :contacts => node.xpath('./*/contactList', ns).map { |child| parse_contact(child) },
214
+ :error => xml_to_bool(node, './*/error/text()'),
215
+ :results_returned => xml_to_int(node, './*/resultsReturned/text()'),
216
+ :total_results_available => xml_to_int(node, './*/totalResultsAvailable/text()')
217
+ }
218
+ end
219
+
220
+ # WsAccount
221
+ def parse_account(node)
222
+ {
223
+ :entity_id => xml_to_str(node, './entityId/text()'),
224
+ :entity_type => xml_to_str(node, './entityType/text()'),
225
+ :parent_account_id => xml_to_str(node, './parentAccountId/text()'),
226
+ :account_id => xml_to_str(node, './accountId/text()'),
227
+ :account_name => xml_to_str(node, './accountName/text()'),
228
+ :account_owner => xml_to_str(node, './accountOwner/text()'),
229
+ :url => xml_to_str(node, './url/text()'),
230
+ :phone => xml_to_str(node, './phone/text()'),
231
+ :main_address => parse_address(node.xpath('./mainAddress')),
232
+ :shipping_address => parse_address(node.xpath('./shippingAddress')),
233
+ :billing_address => parse_address(node.xpath('./billingAddress')),
234
+ :updated_by => xml_to_int(node, './updatedBy/text()'),
235
+ :updated_on => xml_to_str(node, './updatedOn/text()'),
236
+ :created_by => xml_to_int(node, './createdBy/text()'),
237
+ :created_on => xml_to_str(node, './createdOn/text()'),
238
+ :archived_by => xml_to_str(node, './archivedBy/text()'),
239
+ :sync_with_quickbooks => xml_to_str(node, './isSyncWithQuickbooks/text()')
240
+ }
241
+
242
+ end
243
+
244
+ # WsAccountType
245
+ def parse_account_type(node)
246
+ {
247
+ #:entity_id => xml_to_str(node, './entityId/text()'),
248
+ #:entity_type => xml_to_str(node, './entityType/text()')
249
+ #:account_type_id => xml_to_str(node, './accountTypeId/text()'),
250
+ :account_type => xml_to_str(node, './accountType/text()')
251
+ }
252
+ end
253
+
254
+ # WsAddress
255
+ def parse_address(node)
256
+ {
257
+ #:entity_id => xml_to_str(node, './entityId/text()'),
258
+ #:entity_type => xml_to_str(node, './entityType/text()'),
259
+ #:address_id => xml_to_str(node, './addressId/text()'),
260
+ :address => xml_to_str(node, './address1/text()'),
261
+ :city => xml_to_str(node, './city/text()'),
262
+ :state => xml_to_str(node, './state/text()'),
263
+ :zip => xml_to_str(node, './zipPostal/text()'),
264
+ :country => xml_to_str(node, './country/text()')
265
+ }
266
+ end
267
+
268
+ # WsContact
269
+ def parse_contact(node)
270
+ {
271
+ :first_name => xml_to_str(node, './firstName/text()'),
272
+ :middle_initials => xml_to_str(node, './middleInitials/text()'),
273
+ :last_name => xml_to_str(node, './lastName/text()'),
274
+ :cell_phone => xml_to_str(node, './cellPhone/text()'),
275
+ :work_phone => xml_to_str(node, './workPhone/text()'),
276
+ :home_phone => xml_to_str(node, './homePhone/text()'),
277
+ :email => xml_to_str(node, './email/text()'),
278
+ :owner_id => xml_to_str(node, './ownerId/text()')
279
+ }
280
+ end
281
+
282
+ # WsOpportunity
283
+ def parse_opportunity(node)
284
+ {
285
+ #:entity_id => xml_to_str(node, './entityId/text()'),
286
+ #:entity_type => xml_to_str(node, './entityType/text()'),
287
+ :account_id => xml_to_int(node, './accountId/text()'),
288
+ :account_name => xml_to_str(node, './accountName/text()'),
289
+ :opportunity_id => xml_to_int(node, './opportunityId/text()'),
290
+ :name => xml_to_str(node, './name/text()'),
291
+ :deal_value => xml_to_str(node, './dealValue/text()'),
292
+ :confidence => xml_to_str(node, './confidence/text()'),
293
+ :opportunity_status => xml_to_str(node, './opportunityStatus/status/text()'),
294
+ :selling_process => xml_to_str(node, './sellingProcess/sellingProcess/text()'),
295
+ :selling_process_id => xml_to_int(node, './sellingProcess/sellingProcessId/text()'),
296
+ :primary_owner_id => xml_to_int(node, './primaryOwnerId/text()'),
297
+ :current_phase_name => xml_to_str(node, './currentPhaseName/text()')
298
+ }
299
+ end
300
+
301
+ end
302
+
303
+
@@ -0,0 +1,44 @@
1
+
2
+ require 'test_helper'
3
+
4
+ class LandsliderTest < Test::Unit::TestCase
5
+
6
+ def test_landslider_login
7
+ result = Landslider.login('LOGINTOKEN=' + LS_INSTANCE_NAME)
8
+
9
+ assert_not_nil result
10
+ assert_equal false, result[:error]
11
+ assert_not_nil result[:session_id]
12
+ end
13
+
14
+ def test_landslider_get_api_version
15
+ result = Landslider.login('LOGINTOKEN=' + LS_INSTANCE_NAME)
16
+ result = Landslider.get_api_version(result[:session_id])
17
+
18
+ assert_not_nil result
19
+ assert_operator result[:major_version], :>=, 2
20
+ assert_operator result[:minor_version], :>=, 0
21
+ assert_operator result[:revision_version], :>=, 0
22
+ end
23
+
24
+ def test_get_accounts
25
+ result = Landslider.login('LOGINTOKEN=' + LS_INSTANCE_NAME)
26
+ result = Landslider.get_accounts(result[:session_id])
27
+ assert_equal false, result[:error]
28
+ assert_not_nil result[:accounts]
29
+ assert result[:accounts].all? { |a| !a[:account_name].nil? }, "account name required"
30
+ assert_operator result[:results_returned], :>=, 0
31
+ assert_operator result[:total_results_available], :>=, 0
32
+ assert_not_nil result[:result_msg]
33
+ end
34
+
35
+
36
+ private
37
+
38
+ def login(session_id)
39
+ Landslider.login(session_id)
40
+ end
41
+
42
+
43
+ end
44
+
@@ -0,0 +1,16 @@
1
+ require 'digest/md5'
2
+
3
+ # constants to be set by rails environment config files
4
+ LS_INSTANCE_NAME = 'jaytest'
5
+ LS_API_USERNAME = 'XXXXXXXX@landslide.com'
6
+ LS_API_PASSWORD = 'XXXXXXXX'
7
+ LS_API_KEY = Digest::MD5.hexdigest(LS_API_PASSWORD + LS_INSTANCE_NAME)
8
+ LS_API_NAMESPACE = "http://www.landslide.com/webservices/SoapService"
9
+ LS_API_ENDPOINT = {
10
+ :uri => "https://#{LS_INSTANCE_NAME}.api.landslide.com/webservices/SoapService",
11
+ :version => 2
12
+ }
13
+
14
+ require 'test/unit'
15
+ require 'landslider'
16
+
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: landslider
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.0
6
+ platform: ruby
7
+ authors:
8
+ - Jay Prall
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-04-22 00:00:00 -04:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: "Ruby interface to Landslide SOAP API. "
18
+ email: jayprall@gmail.com
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files:
24
+ - LICENSE
25
+ - README.rdoc
26
+ files:
27
+ - CHANGELOG
28
+ - LICENSE
29
+ - README.rdoc
30
+ - Rakefile
31
+ - VERSION.yml
32
+ - init.rb
33
+ - landslider.gemspec
34
+ - lib/landslider.rb
35
+ - test/landslider_test.rb
36
+ - test/test_helper.rb
37
+ has_rdoc: true
38
+ homepage: https://github.com/j4y/landslider
39
+ licenses: []
40
+
41
+ post_install_message:
42
+ rdoc_options: []
43
+
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ requirements: []
59
+
60
+ rubyforge_project:
61
+ rubygems_version: 1.6.2
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: Ruby interface to Landslide SOAP API
65
+ test_files:
66
+ - test/landslider_test.rb
67
+ - test/test_helper.rb