postini 0.0.6 → 0.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 (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