postini 0.0.6 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/History.txt +4 -0
  2. data/Manifest.txt +12 -26
  3. data/README.txt +11 -4
  4. data/Rakefile +27 -4
  5. data/features/development.feature +13 -0
  6. data/features/step_definitions/common_steps.rb +172 -0
  7. data/features/support/common.rb +29 -0
  8. data/features/support/env.rb +6 -0
  9. data/features/support/matchers.rb +11 -0
  10. data/lib/postini/automated_batch_service.rb +464 -0
  11. data/lib/postini/configuration_check.rb +25 -0
  12. data/lib/postini/endpoint_resolver_service.rb +41 -0
  13. data/lib/postini/endpoints.rb +26 -0
  14. data/lib/postini/exceptions.rb +85 -0
  15. data/lib/postini.rb +74 -102
  16. data/script/console +1 -1
  17. data/script/txt2html +5 -16
  18. data/spec/exceptions_spec.rb +19 -0
  19. data/spec/postini_spec.rb +5 -38
  20. data/spec/rcov.opts +1 -0
  21. data/spec/spec_helper.rb +1 -1
  22. data/tasks/rspec.rake +1 -19
  23. data/vendor/automatedbatch.wsdl +1 -1
  24. metadata +21 -54
  25. data/config/hoe.rb +0 -76
  26. data/config/requirements.rb +0 -15
  27. data/lib/postini/api/automatedbatch/AutomatedBatch.rb +0 -1244
  28. data/lib/postini/api/automatedbatch/AutomatedBatchDriver.rb +0 -216
  29. data/lib/postini/api/automatedbatch/AutomatedBatchMappingRegistry.rb +0 -1883
  30. data/lib/postini/api/automatedbatch/AutomatedBatchServiceClient.rb +0 -523
  31. data/lib/postini/api/endpointresolver/EndpointResolver.rb +0 -121
  32. data/lib/postini/api/endpointresolver/EndpointResolverDriver.rb +0 -51
  33. data/lib/postini/api/endpointresolver/EndpointResolverMappingRegistry.rb +0 -268
  34. data/lib/postini/api/endpointresolver/EndpointResolverServiceClient.rb +0 -38
  35. data/lib/postini/api.rb +0 -8
  36. data/lib/postini/domain.rb +0 -72
  37. data/lib/postini/helpers/attributes.rb +0 -94
  38. data/lib/postini/helpers.rb +0 -13
  39. data/lib/postini/user.rb +0 -91
  40. data/lib/postini/users/aliases.rb +0 -55
  41. data/lib/postini/version.rb +0 -9
  42. data/spec/attribute_helper_spec.rb +0 -47
  43. data/spec/domain_spec.rb +0 -36
  44. data/spec/user_spec.rb +0 -142
  45. data/website/index.html +0 -89
  46. data/website/index.txt +0 -60
  47. data/website/javascripts/rounded_corners_lite.inc.js +0 -285
  48. data/website/spam_box.png +0 -0
  49. data/website/stylesheets/screen.css +0 -143
  50. data/website/template.html.erb +0 -56
@@ -0,0 +1,464 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Postini
3
+ class AutomatedBatchService < Handsoap::Service
4
+
5
+ include ConfigurationCheck
6
+
7
+ endpoint Postini::Endpoints.automated_batch
8
+
9
+ on_create_document do |doc|
10
+ doc.alias 'aut', 'http://postini.com/PSTN/SOAPAPI/v2/automatedbatch'
11
+ end
12
+
13
+ def on_fault( fault )
14
+ exception = RemoteException.delegate( fault.reason )
15
+
16
+ # Handle specifics, translate to higher level exception
17
+
18
+ # or raise
19
+ raise exception
20
+ end
21
+
22
+ # public methods
23
+
24
+ # Associates an additional address with a user's primary email
25
+ # address. The alias receives the same filtering and shares the
26
+ # same User Ouarantine as the user’s primary email address.
27
+ #
28
+ # * confirm - If an existing user address is being overwritten to
29
+ # become an alias address, use confirm
30
+ #
31
+ # Raises a Postini::BatchError if something goes wrong
32
+ def add_alias( user_address, alias_address, confirm = true )
33
+ response = invoke("aut:addalias") do |message|
34
+ build_auth!( message )
35
+ message.add('userAddressOrId', user_address)
36
+ message.add('aliasAddress', alias_address)
37
+ message.add('confirm', 'confirm') if confirm
38
+ end
39
+
40
+ true
41
+ end
42
+ requires_configured :add_alias
43
+
44
+ # Adds the domain record +name+ to the organization
45
+ # +orgid+. Enclose +orgid+ in double quotes or preceded with a
46
+ # '\' symbol if it contains a quote ('), double quote ("),
47
+ # backslash (\), apostrophe, commas, #, = symbols.
48
+ #
49
+ # Raises a Postini::BatchException if something goes wrong
50
+ def add_domain( orgid, name )
51
+ response = invoke( "aut:adddomain" ) do |message|
52
+ build_auth!( message )
53
+ message.add('orgNameOrId', orgid )
54
+ message.add('args') do |args|
55
+ args.add('domain', name)
56
+ end
57
+ end
58
+
59
+ true
60
+ end
61
+ requires_configured :add_domain
62
+
63
+ # Adds a user (+address+) to an organization (+org+). Enclose
64
+ # +orgid+ in double quotes or preceded with a
65
+ # '\' symbol if it contains a quote ('), double quote ("),
66
+ # backslash (\), apostrophe, commas, #, = symbols.
67
+ #
68
+ # Raises a Postini::BatchException if something foes wrong
69
+ def add_user( orgid, address, welcome = false )
70
+ response = invoke("aut:adduser") do |message|
71
+ build_auth!( message )
72
+ message.add('userAddress', address)
73
+ message.add('args') do |args|
74
+ args.add('org', orgid)
75
+ args.add('welcome', welcome)
76
+ end
77
+ end
78
+
79
+ true
80
+ end
81
+ requires_configured :add_user
82
+
83
+ # This operation is an Service Management API’s AutomatedBatch
84
+ # utility. It checks the user’s email, API license key, and
85
+ # password authentication tokens used for connection and
86
+ # authorization validation between the web service and the client.
87
+ #
88
+ # * email - The email address entered by the user.
89
+ # * apiKey - A unique customer and product ID.
90
+ # * password -- The PMP password entered by the user.
91
+ #
92
+ # If the organization is configured for POP authorization, always
93
+ # use the administrator's email login and password which will be
94
+ # in the PMP format. An end user's POP password will fail.
95
+ def check_auth( email = nil, password = nil, api_key = nil )
96
+ response = invoke("aut:checkauth") do |message|
97
+ build_auth!( message, email, password, api_key )
98
+ end
99
+
100
+ return true
101
+ end
102
+ requires_configured :check_auth
103
+
104
+ # Removes the specified alias completely from the email security
105
+ # service.
106
+ def delete_alias( alias_address )
107
+ response = invoke("aut:deletealias") do |message|
108
+ build_auth!( message )
109
+ message.add('aliasAddress', alias_address)
110
+ end
111
+
112
+ return true
113
+ end
114
+ requires_configured :delete_alias
115
+
116
+ # Removes the domain from the organizational hierarchy. All the
117
+ # users for the domain needs to be removed first by #delete_user.
118
+ #
119
+ # Raises a Postini::BatchException if something goes wrong
120
+ def delete_domain( name )
121
+ response = invoke("aut:deletedomain") do |message|
122
+ build_auth!( message )
123
+ message.add('domainNameOrId', name)
124
+ end
125
+
126
+ true
127
+ end
128
+ requires_configured :delete_domain
129
+
130
+ # Delete a user record from the email security service.
131
+ #
132
+ # Raises a Postini::BatchExceptio if something goes wrong
133
+ def delete_user( address )
134
+ response = invoke("aut:deleteuser") do |message|
135
+ build_auth!( message )
136
+ message.add('userAddressOrId', address)
137
+ end
138
+
139
+ true
140
+ end
141
+ requires_configured :delete_user
142
+
143
+ # Retrieve the details of the domain from the email security
144
+ # service as a hash with the following keys:
145
+ #
146
+ # :org => string - Name of the parent org
147
+ # :substrip => true/false - Whether sub domain stripping in enabled
148
+ # :aliased_to => nil/string - Alias of another domain
149
+ # :aliased_as => array - List of domain aliases
150
+ # :id => integer - Domain id
151
+ # :name => string - Domain name
152
+ def display_domain( name )
153
+ response = invoke("aut:displaydomain") do |message|
154
+ build_auth!( message )
155
+ message.add('domainNameOrId', name )
156
+ end
157
+
158
+ parse_display_domain_results( response.document.xpath('//tns:displaydomainResponse', tns).first )
159
+ end
160
+ requires_configured :display_domain
161
+
162
+ # Retrieve the details of the user from the email securty service
163
+ # as a hash with following keys:
164
+ #
165
+ # :active => bool
166
+ # :address => string
167
+ # :approved_recipients => array
168
+ # :approved_senders => array
169
+ # :blocked_senders => array
170
+ # :create_method => integer
171
+ # :created_date => Time
172
+ # :filter_adult => string
173
+ # :filter_bulk => string
174
+ # :filter_getrich => string
175
+ # :filter_offers => string
176
+ # :filter_racial => string
177
+ # :initial_password => string
178
+ # :junkmail_filter => bool
179
+ # :lang_locale => string
180
+ # :lastmod_date => Time
181
+ # :message_encryption => string
182
+ # :message_limit => string
183
+ # :message_limited => bool
184
+ # :message_count => integer
185
+ # :notice_address => string
186
+ # :org => string
187
+ # :password => string
188
+ # :timezone => string
189
+ # :id => integer
190
+ # :virus_notify => string
191
+ # :virus_state => bool
192
+ # :weblocked => bool
193
+ # :welcome_count => integer
194
+ # :wireless_state => string
195
+ def display_user( address )
196
+ response = invoke("aut:displayuser") do |message|
197
+ build_auth!( message )
198
+ message.add('userAddressOrId', address)
199
+ end
200
+
201
+ parse_display_user_results( response.document.xpath('//tns:displayuserResponse', tns).first )
202
+ end
203
+ requires_configured :display_user
204
+
205
+ # Modify a domain by moving it to a new organization, setting or
206
+ # removing aliases, or enabling/disabling subdomain
207
+ # stripping. Changes are passed as a hash with the following keys:
208
+ #
209
+ # :org => string - New organization to move domain to
210
+ # :substrip => bool - New new value for substrip
211
+ # :aliases => array - Add new domain aliases to the array, to
212
+ # remove an existing domain alias prepend the name
213
+ # with a hyphen (-)
214
+ def modify_domain( name, changes = {} )
215
+ valid_changes = {}
216
+ valid_changes['neworg'] = changes[:org] if changes.has_key?(:org)
217
+ if changes.has_key?(:substrip)
218
+ valid_changes['substrip'] = ( changes[:substrip] == true ? 'yes' : 'no' )
219
+ end
220
+ valid_changes['alias'] = changes[:aliases].to_a.join(', ') if changes.has_key?(:aliases)
221
+
222
+ response = invoke("aut:modifydomain") do |message|
223
+ build_auth!( message )
224
+ message.add('domainNameOrId', name)
225
+ message.add('domainModifications') do |mods|
226
+ valid_changes.each do |k,v|
227
+ mods.add( k, v )
228
+ end
229
+ end
230
+ end
231
+
232
+ display_domain( name )
233
+ end
234
+ requires_configured :modify_domain
235
+
236
+ # Modify a user extensively by providing any of the following keys
237
+ # in the changes hash
238
+ #
239
+ # :active => bool
240
+ # :address => string (change the email address)
241
+ # :approved_recipients => array (full or changes)
242
+ # :approved_senders => array (full or changes)
243
+ # :blocked_senders => array (full or changes)
244
+ # :filter_adult => string
245
+ # :filter_bulk => string
246
+ # :filter_getrich => string
247
+ # :filter_offers => string
248
+ # :filter_racial => string
249
+ # :initial_password => string
250
+ # :junkemail_filter => bool
251
+ # :lang_locale => string
252
+ # :message_limit => integer
253
+ # :message_limited => bool
254
+ # :notice_address => string
255
+ # :org => string
256
+ # :password => string
257
+ # :virus_notify => bool
258
+ # :virus_state => bool
259
+ # :weblocked => bool
260
+ # :wireless_state => string
261
+ #
262
+ # Notes on array parameters: Provide the full set of values, or an
263
+ # array of diffs (new entries prepended with a plus (+) and
264
+ # entries to be removed prepended with a hyphen (-).
265
+ #
266
+ # Notes on *all* parameters: I don't use all of these, nor will I
267
+ # ever, so please test them well and report any bugs to me.
268
+ def modify_user( address, changes = {} )
269
+ valid_changes = {}
270
+ valid_changes[:orgid] = changes[:org] if changes.has_key?(:org)
271
+
272
+ # Vanilla string copies
273
+ [ :active, :address, :filter_adult, :filter_bulk, :filter_getrich,
274
+ :filter_offers, :filter_racial, :initial_password, :lang_locale,
275
+ :notice_address, :password, :wireless_state, :message_limit
276
+ ].each do |k|
277
+
278
+ valid_changes[k] = changes[k] if changes.has_key?(k)
279
+ end
280
+
281
+ # Booleans need some special handling
282
+ [ :active, :junkemail_filter, :message_limited, :virus_notify,
283
+ :virus_state, :weblocked
284
+ ].each do |k|
285
+
286
+ if changes.has_key?(k)
287
+ valid_changes[k] = ( changes[k] == true ? 'yes' : 'no' )
288
+ end
289
+ end
290
+
291
+ # Join the arrays
292
+ [ :approved_senders, :approved_recipients, :blocked_senders ].each do |k|
293
+
294
+ if changes.has_key?( k )
295
+ valid_changes[k] = changes[k].join(', ')
296
+ end
297
+ end
298
+
299
+ # pray
300
+ response = invoke("aut:modifyuser") do |message|
301
+ build_auth!( message )
302
+ message.add('userAddressOrId', address)
303
+ message.add('userModifications') do |mods|
304
+ valid_changes.each do |k,v|
305
+ mods.add( k.to_s, v )
306
+ end
307
+ end
308
+ end
309
+
310
+ address = valid_changes[:address] || address
311
+
312
+ display_user( address )
313
+ end
314
+ requires_configured :modify_user
315
+
316
+ # Determines if connections to the web service and the web service
317
+ # client are not blocked. It is a simple round trip test.
318
+ #
319
+ # * true - The connection is successful. If it fails, the
320
+ # development tool will throw either an error, or warning
321
+ # depending upon the type of failure.
322
+ # * false - To test the exception handling between the web service
323
+ # and the application, use test<false> which will
324
+ # complete the roundtrip between the servers and return
325
+ # a StatusException.
326
+ #
327
+ # The Endpoint Resolver web service is not used with the test command.
328
+ def test( pass = true )
329
+ response = invoke("aut:test") do |message|
330
+ message.add('should_work', pass)
331
+ end
332
+
333
+ parse_test_results( response.document.xpath('//tns:testResponse', tns).first )
334
+ end
335
+ requires_configured :test
336
+
337
+ private
338
+
339
+ def tns
340
+ { 'tns' => 'http://postini.com/PSTN/SOAPAPI/v2/automatedbatch' }
341
+ end
342
+
343
+ def build_auth!( message, email = nil, password = nil, api_key = nil )
344
+ message.add('authElem') do |auth|
345
+ auth.add('apiKey', api_key || Postini.api_key)
346
+ auth.add('email', email || Postini.username )
347
+ auth.add('pword', password || Postini.password )
348
+ end
349
+ end
350
+
351
+ def to_array( string )
352
+ array = string.split(/[,\s+]/)
353
+ array.delete_if { |e| e == 'empty' }
354
+ array
355
+ end
356
+
357
+ # helpers
358
+
359
+ def parse_test_results( node )
360
+ node.xpath('./confirmation_message/text()').to_s
361
+ end
362
+
363
+ def parse_display_domain_results( node )
364
+ # <tns:displaydomainResponse>
365
+ # <domainRecord>
366
+ # <aliasedto>postini4r1.co.za</aliasedto>
367
+ # <aliasedfrom>postini4rone.co.za</aliasedfrom>
368
+ # <domainid>10000</domainid>
369
+ # <domainname>postini4r1.co.za</domainname>
370
+ # <org>postini-0.stage.example.org</org>
371
+ # <substrip>0</substrip>
372
+ # </domainRecord>
373
+ # </tns:displaydomainResponse>
374
+
375
+ data = {
376
+ :id => node.xpath('./domainRecord/domainid/text()').to_s.to_i,
377
+ :name => node.xpath('./domainRecord/domainname/text()').to_s,
378
+ :org => node.xpath('./domainRecord/org/text()').to_s,
379
+ :substrip => node.xpath('./domainRecord/substrip/text()').to_s == '1'
380
+ }
381
+
382
+ unless node.xpath('./domainRecord/aliasedto/text()').empty?
383
+ data[:aliased_to] = node.xpath('./domainRecord/aliasedto/text()').to_s
384
+ end
385
+
386
+ unless node.xpath('./domainRecord/aliasedfrom/text()').empty?
387
+ data[:aliased_from] = to_array( node.xpath('./domainRecord/aliasedfrom/text()').to_s )
388
+ end
389
+
390
+ data
391
+ end
392
+
393
+ def parse_display_user_results( node )
394
+ # <tns:displayuserResponse>
395
+ # <userRecord>
396
+ # <active>yes</active>
397
+ # <address>info@example.com</address>
398
+ # <approved_recipients>empty</approved_recipients>
399
+ # <approved_senders>empty</approved_senders>
400
+ # <blocked_senders>empty</blocked_senders>
401
+ # <create_method>3</create_method>
402
+ # <created_date>123456789</created_date>
403
+ # <filter_adult>moderately aggressive</filter_adult>
404
+ # <filter_bulk>leniently aggressive</filter_bulk>
405
+ # <filter_getrich>moderately aggressive</filter_getrich>
406
+ # <filter_offers>moderately aggressive</filter_offers>
407
+ # <filter_racial>moderately aggressive</filter_racial>
408
+ # <initial_password/>
409
+ # <junkmail_filter>on</junkmail_filter>
410
+ # <lang_locale/>
411
+ # <lastmod_date>123456789</lastmod_date>
412
+ # <message_count>0</message_count>
413
+ # <message_limit/>
414
+ # <message_limited>no</message_limited>
415
+ # <notice_address/>
416
+ # <orgid>Example Org Users</orgid>
417
+ # <password>randomhashrepresentation</password>
418
+ # <timezone>Europe/Lisbon</timezone>
419
+ # <user_id>1</user_id>
420
+ # <virus_notify>Organization default</virus_notify>
421
+ # <virus_state>on</virus_state>
422
+ # <weblocked>no</weblocked>
423
+ # <welcome_count>1</welcome_count>
424
+ # <wireless_state>unavailable</wireless_state>
425
+ # </userRecord>
426
+ # </tns:displayuserResponse>
427
+
428
+ data = {
429
+ :active => node.xpath('./userRecord/active/text()').to_s == 'yes',
430
+ :address => node.xpath('./userRecord/address/text()').to_s,
431
+ :approved_recipients => to_array( node.xpath('./userRecord/approved_recipients/text()').to_s ),
432
+ :approved_senders => to_array( node.xpath('./userRecord/approved_senders/text()').to_s ),
433
+ :blocked_senders => to_array( node.xpath('./userRecord/blocked_senders/text()').to_s ),
434
+ :create_method => node.xpath('./userRecord/create_method/text()').to_s.to_i,
435
+ :created_date => Time.at( node.xpath('./userRecord/created_date/text()').to_s.to_i ),
436
+ :filter_adult => node.xpath('./userRecord/filter_adult/text()').to_s,
437
+ :filter_bulk => node.xpath('./userRecord/filter_bulk/text()').to_s,
438
+ :filter_getrich => node.xpath('./userRecord/filter_getrich/text()').to_s,
439
+ :filter_offers => node.xpath('./userRecord/filter_offers/text()').to_s,
440
+ :filter_racial => node.xpath('./userRecord/filter_racial/text()').to_s,
441
+ :initial_password => node.xpath('./userRecord/initial_password/text()').to_s,
442
+ :junkmail_filter => node.xpath('./userRecord/junkmail_filter/text()').to_s == 'on',
443
+ :lang_locale => node.xpath('./userRecord/lang_local/text()').to_s,
444
+ :lastmod_date => Time.at( node.xpath('./userRecord/lastmod_date/text()').to_s.to_i ),
445
+ :message_encryption => node.xpath('./userRecord/message_encryption/text()').to_s,
446
+ :message_limit => node.xpath('./userRecord/message_limit/text()').to_s,
447
+ :message_limited => node.xpath('./userRecord/message_limited/text()').to_s == 'yes',
448
+ :message_count => node.xpath('./userRecord/message_count/text()').to_s.to_i,
449
+ :notice_address => node.xpath('./userRecord/notice_address/text()').to_s,
450
+ :org => node.xpath('./userRecord/orgid/text()').to_s,
451
+ :password => node.xpath('./userRecord/password/text()').to_s,
452
+ :timezone => node.xpath('./userRecord/timezone/text()').to_s,
453
+ :id => node.xpath('./userRecord/user_id/text()').to_s,
454
+ :virus_notify => node.xpath('./userRecord/virus_notify/text()').to_s,
455
+ :virus_state => node.xpath('./userRecord/virus_state/text()').to_s,
456
+ :weblocked => node.xpath('./userRecord/weblocked/text()').to_s == 'yes',
457
+ :welcome_count => node.xpath('./userRecord/welcome_count/text()').to_s.to_i,
458
+ :wireless_state => node.xpath('./userRecord/wireless_state/text()').to_s
459
+ }
460
+
461
+ data
462
+ end
463
+ end
464
+ end
@@ -0,0 +1,25 @@
1
+ module Postini
2
+
3
+ # Mixin with a method decorator that prevents calls from being made
4
+ # if the library is not properly configured.
5
+ module ConfigurationCheck
6
+
7
+ def self.included( base )
8
+ base.extend( ClassMethods )
9
+ end
10
+
11
+ module ClassMethods
12
+
13
+ def requires_configured( method_name )
14
+ class_eval <<-EOF, __FILE__, __LINE__
15
+ alias #{method_name}_original #{method_name}
16
+ def #{method_name}( *args )
17
+ raise Postini::NotConfigured, "Cannot call #{method_name} if not configured" unless Postini.configured?
18
+
19
+ #{method_name}_original( *args )
20
+ end
21
+ EOF
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,41 @@
1
+ module Postini
2
+ class EndpointResolverService < Handsoap::Service
3
+
4
+ include ConfigurationCheck
5
+
6
+ endpoint Postini::Endpoints.resolver
7
+
8
+ on_create_document do |doc|
9
+ doc.alias 'end', 'https://api-meta.postini.com/api2/endpointresolver'
10
+ end
11
+
12
+ # public methods
13
+
14
+ def get_service_endpoint( email, service = "v2AutomatedBatch" )
15
+ response = invoke("end:GetServiceEndpoint") do |message|
16
+ message.add( "apiKey", Postini.api_key )
17
+ message.add( "email", email )
18
+ message.add( "service", service )
19
+ end
20
+
21
+ parse_get_service_endpoint_result( response.document.xpath('//tns:GetServiceEndpointResponse', tns).first )
22
+ end
23
+ requires_configured :get_service_endpoint
24
+
25
+ private
26
+
27
+ def tns
28
+ { 'tns' => 'http://postini.com/PSTN/SOAPAPI/v2/endpointresolver' }
29
+ end
30
+
31
+ # helpers
32
+
33
+ def parse_get_service_endpoint_result( node )
34
+ #<tns:GetServiceEndpointResponse>
35
+ # <EndpointURI>https://api-s200.postini.com/api2/automatedbatch</EndpointURI>
36
+ #</tns:GetServiceEndpointResponse>
37
+
38
+ node.xpath('./EndpointURI/text()').to_s
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,26 @@
1
+ module Postini
2
+
3
+ # Our endpoints for use by handsoap
4
+ class Endpoints
5
+
6
+ class << self
7
+
8
+ def resolver
9
+ {
10
+ :uri => "https://api-meta.postini.com/api2/endpointresolver",
11
+ :version => 1
12
+ }
13
+ end
14
+
15
+ def automated_batch
16
+ raise NotConfigured, "automatedbatch service endpoint requires system number" if Postini.system_number.nil?
17
+
18
+ {
19
+ :uri => "https://api-s#{Postini.system_number}.postini.com/api2/automatedbatch",
20
+ :version => 1
21
+ }
22
+ end
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,85 @@
1
+ module Postini
2
+
3
+ # Parent class of our exception hierarchy
4
+ class Error < ::StandardError; end
5
+
6
+ class DuplicateAddress < Error; end
7
+
8
+ class UnknownDomain < Error; end
9
+
10
+ # Raised if the #Postini library is not sufficiently configured.
11
+ class NotConfigured < Error; end
12
+
13
+ # Handle exceptions thrown by Postini
14
+ class RemoteException < Error
15
+
16
+ attr_reader :type, :message, :request_id
17
+
18
+ class << self
19
+
20
+ # Find the correct sub-class and pass the exception on
21
+ def delegate( reason )
22
+ if reason =~ /^(\w+):/
23
+ type = $1
24
+ type << 'Exception' unless type =~ /Exception$/
25
+
26
+ if Postini.const_defined?( type )
27
+ return Postini.const_get( type ).new( reason )
28
+ end
29
+ end
30
+
31
+ return new( reason )
32
+ end
33
+ end
34
+
35
+ def initialize( reason )
36
+
37
+ if reason =~ /^(\w+):(.*)\(Request ID ([0-9A-F\-]{36})\)$/
38
+ @type = $1
39
+ @message = $2.strip
40
+ @request_id = $3
41
+ else
42
+ @message = reason
43
+ end
44
+ end
45
+
46
+ def inspect
47
+ "#{self.class} Type: #{@type}, Message: #{@message}, Request ID: #{@request_id}"
48
+ end
49
+
50
+ def to_s
51
+ inspect
52
+ end
53
+ end
54
+
55
+ # Intentionally thrown exception, used to test connection level
56
+ # operation and the ability to send exceptions.
57
+ class StatusException < RemoteException; end
58
+
59
+ # Specified API license key blocked for administrative reasons
60
+ class AdminBlockException < RemoteException; end
61
+
62
+ # Invalid authentication tokens and other auth errors
63
+ class AuthenticationException < RemoteException; end
64
+
65
+ # Exceptions based on those given by the batch commandline interface
66
+ class BatchException < RemoteException; end
67
+
68
+ # Internal exceptions caused by server-wide problems
69
+ class InternalException < RemoteException; end
70
+
71
+ # One or more element values does not validate
72
+ class InvalidValueException < RemoteException; end
73
+
74
+ # Malformed API license key
75
+ class MalformedKeyException < RemoteException; end
76
+
77
+ # One or more required elements is missing from the input
78
+ class MissingElementException < RemoteException; end
79
+
80
+ # Specified API license key does not exist
81
+ class NoSuchKeyException < RemoteException; end
82
+
83
+ # Exceptions caused by unhandled server-side problems
84
+ class UnknownInternalException < RemoteException; end
85
+ end