postini 0.0.3 → 0.0.6

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.
@@ -1,3 +1,7 @@
1
+ == 0.0.4 2008-10-02
2
+
3
+ * Minor internal reworkings
4
+
1
5
  == 0.0.3 2008-08-21
2
6
 
3
7
  * Added options to allow for the capturing of soap4r wiredumps
@@ -4,10 +4,10 @@ Manifest.txt
4
4
  PostInstall.txt
5
5
  README.txt
6
6
  Rakefile
7
+ TODO
7
8
  config/hoe.rb
8
9
  config/requirements.rb
9
10
  lib/postini.rb
10
- lib/postini/version.rb
11
11
  lib/postini/api.rb
12
12
  lib/postini/api/automatedbatch/AutomatedBatch.rb
13
13
  lib/postini/api/automatedbatch/AutomatedBatchDriver.rb
@@ -18,25 +18,31 @@ lib/postini/api/endpointresolver/EndpointResolverDriver.rb
18
18
  lib/postini/api/endpointresolver/EndpointResolverMappingRegistry.rb
19
19
  lib/postini/api/endpointresolver/EndpointResolverServiceClient.rb
20
20
  lib/postini/domain.rb
21
+ lib/postini/helpers.rb
22
+ lib/postini/helpers/attributes.rb
21
23
  lib/postini/user.rb
24
+ lib/postini/users/aliases.rb
25
+ lib/postini/version.rb
22
26
  script/console
23
27
  script/destroy
24
28
  script/generate
25
29
  script/txt2html
26
30
  setup.rb
31
+ spec/attribute_helper_spec.rb
32
+ spec/domain_spec.rb
27
33
  spec/postini_spec.rb
28
34
  spec/spec.opts
29
35
  spec/spec_helper.rb
30
- spec/domain_spec.rb
31
36
  spec/user_spec.rb
32
37
  tasks/deployment.rake
33
38
  tasks/environment.rake
34
39
  tasks/rspec.rake
35
40
  tasks/website.rake
41
+ vendor/automatedbatch.wsdl
42
+ vendor/endpointresolver.wsdl
36
43
  website/index.html
37
44
  website/index.txt
38
45
  website/javascripts/rounded_corners_lite.inc.js
46
+ website/spam_box.png
39
47
  website/stylesheets/screen.css
40
48
  website/template.html.erb
41
- vendor/automatedbatch.wsdl
42
- vendor/endpointresolver.wsdl
data/Rakefile CHANGED
@@ -1,4 +1,6 @@
1
- require 'config/requirements'
2
- require 'config/hoe' # setup Hoe + all gem configuration
3
-
4
- Dir['tasks/**/*.rake'].each { |rake| load rake }
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
5
+
6
+ task :default => :spec
data/TODO ADDED
@@ -0,0 +1,37 @@
1
+ TODO LIST
2
+ =========
3
+
4
+ Handle exceptions properly, make our own exception classes
5
+ Duplicate domain exception looks like this:
6
+ SOAP::FaultError: Batch: code:general, message: A domain record already exists for 'inx.co.za'. () (Request ID 5328153A-6BBD-11DD-A41F-AE53A6E672CE)
7
+ from #<SOAP::Mapping::Object:0xb7614344>
8
+ Unknown user exception:
9
+ SOAP::FaultError: Batch: code:general, message: No user 'sarie@inx.co.za'. () (Request ID F81C4176-6C88-11DD-8917-A059A6E672CE)
10
+ from #<SOAP::Mapping::Object:0xb75e736c>
11
+
12
+ Prevent unneeded operations:
13
+ * Don't disable an already disabled user
14
+
15
+ Add support for org management
16
+
17
+ Support for lazy-loading:
18
+ * Orgs users => user details
19
+ * Convert search results into fully useable objects
20
+
21
+ Work out a nice set of class+instance method combinations. The API's aren't
22
+ really geared for instance-level stuff. So User.destroy( address ) and
23
+ @user.destroy should essentially be the same thing.
24
+
25
+ PROPER ATTRIBUTE HANDLING, NOT INSTANCE VARIABLES:
26
+
27
+ ActiveRecord-like validations (possible external library)
28
+
29
+ Map remote types to native Ruby types:
30
+ * User#created_on from Unix timestamp to Time instance
31
+ * User#approved_senders 'empty' to []
32
+
33
+ Support for changed attribute tracking, so we can implement a #save method and
34
+ call only the needed API calls or only send the changed paramters.
35
+
36
+ Would it not be cleaner to wrap the records from soap4r (eg UserRecord,
37
+ DomainRecord) inside our own classes instead of having duplicates lying around?
@@ -8,7 +8,7 @@ RUBYFORGE_PROJECT = 'postini4r' # The unix name for your project
8
8
  HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
9
  DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
10
  EXTRA_DEPENDENCIES = [
11
- # ['activesupport', '>= 1.3.1']
11
+ ['activesupport', '>=2.0.2'],
12
12
  ['soap4r', '=1.5.8']
13
13
  ] # An array of rubygem dependencies [name, version]
14
14
 
@@ -73,4 +73,4 @@ CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
73
73
  PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
74
74
  $hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
75
75
  $hoe.rsync_args = '-av --delete --ignore-errors'
76
- $hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue ""
76
+ $hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue ""
@@ -2,7 +2,12 @@ $:.unshift(File.dirname(__FILE__)) unless
2
2
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
3
 
4
4
  # requirements
5
- gem 'soap4r'
5
+ require 'rubygems'
6
+ gem 'soap4r', '=1.5.8'
7
+ unless defined?( ActiveSupport )
8
+ gem 'activesupport', '>=2.0.2'
9
+ end
10
+ require 'postini/helpers'
6
11
  require 'postini/user'
7
12
  require 'postini/domain'
8
13
 
@@ -65,7 +70,7 @@ module Postini
65
70
  # On the fly class variable, getter and setter generation...
66
71
  %w{
67
72
  api_key system_number username password xauth
68
- logger debug soap4r_debug soap4r_debug_dev soap4r_wiredump soap4r_wiredump_dev
73
+ logger debug soap4r_wiredump soap4r_wiredump_dev
69
74
  }.each do |config|
70
75
  class_eval <<-EOF
71
76
  @@#{config} = nil
@@ -134,9 +139,9 @@ module Postini
134
139
  end
135
140
 
136
141
  def soap4r_wiredump_dev
137
- @@soap4r_wiredump_dev ||= soap4r_debug_dev
142
+ @@soap4r_wiredump_dev ||= logger
138
143
  end
139
144
 
140
145
  end
141
146
 
142
- end
147
+ end
@@ -59,7 +59,7 @@ module Postini
59
59
  # TODO: Add improved validations here
60
60
  return false if @name.nil? || @org.nil?
61
61
 
62
- remote = automated_batch_port
62
+ remote = self.class.automated_batch_port
63
63
  args = Postini::API::AutomatedBatch::Adddomainargs.new( @name )
64
64
  request = Postini::API::AutomatedBatch::Adddomain.new(
65
65
  Postini.auth, @org, args
@@ -0,0 +1,13 @@
1
+ require 'activesupport'
2
+ require 'postini/helpers/attributes'
3
+
4
+ module Postini
5
+
6
+ # A collection of helpers to implement various needed convenience methods
7
+ # to our other classes and to keep things DRY. The behaviour is very much
8
+ # based on, and inspired by, ActiveRecord and makes excessive use of
9
+ # ActiveSupport to reach its goals.
10
+ module Helpers
11
+
12
+ end
13
+ end
@@ -0,0 +1,94 @@
1
+ module Postini
2
+ module Helpers
3
+ # Provide our classes with ActiveRecord like attribute handling, mapping
4
+ # plain text to native Ruby objects (and vice versa).
5
+ module Attributes
6
+
7
+ def self.included( base ) #:nodoc:
8
+ base.extend( ClassMethods )
9
+ base.send( :include, InstanceMethods )
10
+ end
11
+
12
+ module ClassMethods
13
+
14
+ def self.extended( base )
15
+ base.send( :class_inheritable_hash, :attributes )
16
+ base.attributes = {}
17
+ end
18
+
19
+ # Specifies the list of attributes for the class, together with an
20
+ # optional type to map them to.
21
+ #
22
+ # has_attributes :address
23
+ # has_attributes :active, :welcome, :type => :boolean
24
+ #
25
+ def has_attributes( *args )
26
+ opts = args.extract_options!
27
+ opts[:type] ||= :string
28
+
29
+ args.each do |attr|
30
+ register_attribute( attr => opts[:type] )
31
+ end
32
+ end
33
+
34
+ # Specify a single attribute together with its type
35
+ def has_attribute( attr )
36
+ raise "Invalid parameter, hash expected" unless attr.is_a?( Hash ) &&
37
+ attr.keys.size == 1
38
+
39
+ register_attribute( attr )
40
+ end
41
+
42
+ private
43
+
44
+ # Register an attribute in our internal list
45
+ def register_attribute( attr )
46
+ self.attributes.merge!( attr.stringify_keys! )
47
+
48
+ # :id needs to be handled specialy
49
+ if attr.keys.first == "id"
50
+ class_eval <<-EOF
51
+ def id
52
+ @attributes[ "id" ]
53
+ end
54
+ def id=( value )
55
+ @attributes[ "id" ] = value
56
+ end
57
+ EOF
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+ module InstanceMethods
64
+
65
+ # Setup a new instance with all the attributes configured
66
+ def initialize( attributes = {} )
67
+ validate_attributes!( attributes )
68
+
69
+ @attributes = attributes.stringify_keys
70
+ end
71
+
72
+ def method_missing( method_name, *args )
73
+ method_name.to_s =~ /^([^=]+)(\=)?$/
74
+ key = $1.to_s
75
+ if self.class.attributes.has_key?( key )
76
+ if $2
77
+ @attributes[ key ] = *args
78
+ else
79
+ @attributes[ key ]
80
+ end
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ def validate_attributes!( attrs = {} )
87
+ attrs.assert_valid_keys( self.class.attributes.symbolize_keys.keys )
88
+ end
89
+
90
+ end
91
+
92
+ end
93
+ end
94
+ end
@@ -1,4 +1,5 @@
1
1
  require 'postini/api/automatedbatch/AutomatedBatchDriver'
2
+ require 'postini/users/aliases'
2
3
 
3
4
  module Postini
4
5
 
@@ -7,13 +8,22 @@ module Postini
7
8
  # TODO: Expand documentation
8
9
  class User
9
10
 
10
- attr_accessor :id, :active, :address, :approved_recipients,
11
- :approved_senders, :blocked_senders, :create_method, :created_date,
12
- :filter_adult, :filter_bulk, :filter_getrich, :filter_offers,
13
- :filter_racial, :initial_password, :junkmail_filter, :lang_locale,
14
- :lastmod_date, :message_encryption, :message_limit, :message_limited,
15
- :message_count, :notice_address, :orgid, :password, :timezone,
16
- :virus_notify, :virus_state, :weblocked, :welcome_count, :wireless_state
11
+ include Helpers::Attributes
12
+
13
+ has_attributes :id, :message_count, :message_limit, :orgid, :create_method,
14
+ :virus_notify, :type => :int
15
+ has_attributes :active, :junkmail_filter, :message_encryption,
16
+ :message_limited, :virus_state, :weblocked, :welcome_count,
17
+ :wireless_state, :type => :bool
18
+ has_attributes :address, :notice_address, :initial_password, :password,
19
+ :lang_locale, :timezone, :orgtag, :ext_encrypt
20
+ has_attributes :approved_recipients, :approved_senders, :blocked_senders,
21
+ :type => :array
22
+ has_attributes :created_date, :lastmod_date, :type => :timestamp
23
+ has_attributes :filter_adult, :filter_bulk, :filter_getrich,
24
+ :filter_offers, :filter_racial, :type => :filter
25
+
26
+ include Users::Aliases
17
27
 
18
28
  class << self
19
29
 
@@ -52,15 +62,8 @@ module Postini
52
62
 
53
63
  end
54
64
 
55
- # Setup a new instance with the combination of attributes set
56
- def initialize( attributes = {} )
57
- attributes.each_pair do |k,v|
58
- instance_variable_set "@#{k.to_s}", v
59
- end
60
- end
61
-
62
65
  def new?
63
- @id.nil?
66
+ self.id.nil?
64
67
  end
65
68
 
66
69
  # Create the new user. Pass +welcome+ as '1' to have a welcome mail sent
@@ -69,11 +72,11 @@ module Postini
69
72
  return false unless new?
70
73
 
71
74
  # TODO: Add missing validations here
72
- return false if @address.nil? || @org.nil?
75
+ return false if self.address.nil? || self.orgid.nil?
73
76
 
74
- remote = automated_batch_port
75
- args = Postini::API::AutomatedBatch::Adduserargs.new( @org, welcome )
76
- request = Postini::API::AutomatedBatch::Adduser.new( Postini.auth, @address, args )
77
+ remote = self.class.automated_batch_port
78
+ args = Postini::API::AutomatedBatch::Adduserargs.new( self.orgid, welcome )
79
+ request = Postini::API::AutomatedBatch::Adduser.new( Postini.auth, self.address, args )
77
80
  remote.adduser( request )
78
81
  end
79
82
 
@@ -81,54 +84,8 @@ module Postini
81
84
  def destroy
82
85
  return false if new?
83
86
 
84
- self.class.destroy( @address )
87
+ self.class.destroy( self.address )
85
88
  end
86
89
 
87
- # Return the list of aliases for the mailbox
88
- def aliases
89
- if @aliases.nil?
90
- remote = self.class.automated_batch_port( @address )
91
- query = Postini::API::AutomatedBatch::ListusersqueryParams.new
92
- query.aliases = 1
93
- query.childorgs = 1
94
- query.primaryqs = @address
95
- query.targetOrg = @orgid
96
- request = Postini::API::AutomatedBatch::Listusers.new(
97
- Postini.auth,
98
- "ALL",
99
- query
100
- )
101
-
102
- response = remote.listusers( request )
103
-
104
- @aliases = []
105
- response.each { |user_record| @aliases << user_record.address }
106
- end
107
-
108
- @aliases
109
- end
110
-
111
- # Add an alias to this user
112
- def add_alias( address )
113
- @aliases = nil # clear our cache
114
- remote = self.class.automated_batch_port( @address )
115
- request = Postini::API::AutomatedBatch::Addalias.new( Postini.auth, @address, address )
116
- remote.addalias( request )
117
- end
118
-
119
- # Removes the specified alias
120
- def remove_alias( address )
121
- @aliases = nil # clear our cache
122
- remote = self.class.automated_batch_port( @address )
123
- request = Postini::API::AutomatedBatch::Deletealias.new( Postini.auth, address )
124
- remote.deletealias( request )
125
- end
126
-
127
- # Removes all aliases from the user
128
- def clear_aliases
129
- aliases.each do |address|
130
- remove_alias( address )
131
- end
132
- end
133
90
  end
134
91
  end
@@ -0,0 +1,55 @@
1
+ module Postini
2
+ module Users
3
+
4
+ # Managing aliases of the users
5
+ module Aliases
6
+ # Return the list of aliases for the mailbox
7
+ def aliases
8
+ if @aliases.nil?
9
+ remote = self.class.automated_batch_port( self.address )
10
+ query = Postini::API::AutomatedBatch::ListusersqueryParams.new
11
+ query.aliases = 1
12
+ query.childorgs = 1
13
+ query.primaryqs = self.address
14
+ query.targetOrg = self.orgid
15
+ request = Postini::API::AutomatedBatch::Listusers.new(
16
+ Postini.auth,
17
+ "ALL",
18
+ query
19
+ )
20
+
21
+ response = remote.listusers( request )
22
+
23
+ @aliases = []
24
+ response.each { |user_record| @aliases << user_record.address }
25
+ end
26
+
27
+ @aliases
28
+ end
29
+
30
+ # Add an alias to this user
31
+ def add_alias( address )
32
+ @aliases = nil # clear our cache
33
+ remote = self.class.automated_batch_port( self.address )
34
+ request = Postini::API::AutomatedBatch::Addalias.new( Postini.auth, self.address, address )
35
+ remote.addalias( request )
36
+ end
37
+
38
+ # Removes the specified alias
39
+ def remove_alias( address )
40
+ @aliases = nil # clear our cache
41
+ remote = self.class.automated_batch_port( self.address )
42
+ request = Postini::API::AutomatedBatch::Deletealias.new( Postini.auth, address )
43
+ remote.deletealias( request )
44
+ end
45
+
46
+ # Removes all aliases from the user
47
+ def clear_aliases
48
+ aliases.each do |address|
49
+ remove_alias( address )
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -2,7 +2,7 @@ module Postini
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 0
5
- TINY = 3
5
+ TINY = 6
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -0,0 +1,47 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ class AttributeTester
4
+ include Postini::Helpers::Attributes
5
+
6
+ has_attribute :id => :int
7
+ has_attribute :now => :timestamp
8
+ has_attribute :active => :boolean
9
+ has_attributes :address, :name, :type => :string
10
+
11
+ end
12
+
13
+ describe Postini::Helpers::Attributes do
14
+
15
+ describe "and initialization" do
16
+
17
+ it "should handle no attributes" do
18
+ lambda {
19
+ at = AttributeTester.new
20
+ }.should_not raise_error
21
+ end
22
+
23
+ it "should set valid attributes" do
24
+ at = AttributeTester.new( :id => 1, :active => true )
25
+ at.id.should be(1)
26
+ at.active.should be_true
27
+ end
28
+
29
+ it "should raise exceptions on invalid values" do
30
+ lambda {
31
+ AttributeTester.new( :wtf => "is this?" )
32
+ }.should raise_error
33
+ end
34
+ end
35
+
36
+ describe "and getters/setters" do
37
+
38
+ before(:each) do
39
+ @at = AttributeTester.new
40
+ end
41
+
42
+ it "that should act like attr_accessors" do
43
+ @at.active = true
44
+ @at.active.should be_true
45
+ end
46
+ end
47
+ end
@@ -27,4 +27,32 @@ describe "Postini master module" do
27
27
  Postini.xauth.should eql('format_unknown_to_author')
28
28
  end
29
29
 
30
+ it "should return a pre-built URI if no user is provided" do
31
+ Postini.system_number = 0
32
+ Postini.endpoint_uri.should eql('https://api-s0.postini.com/api2/automatedbatch')
33
+ end
34
+
35
+ it "should use the Endpoint Resolver service if a user is provided" do
36
+ mock_remote = Postini::API::EndpointResolver::EndpointResolverPort.new
37
+ mock_remote.expects( :getServiceEndpoint ).with(anything).returns(
38
+ OpenStruct.new( :endpointURI => 'https://api-s0.postini.com/api2/automatedbatch' )
39
+ )
40
+ Postini::API::EndpointResolver::EndpointResolverPort.expects(:new).returns(mock_remote)
41
+
42
+ Postini.endpoint_uri( 'support@jumboinc.com' ).should eql('https://api-s0.postini.com/api2/automatedbatch')
43
+
44
+ pending "IMPROVE"
45
+ end
46
+
47
+ it "should generate auth elements without user details" do
48
+ pending
49
+ end
50
+
51
+ it "should generate auth elements with username and passwords" do
52
+ pending
53
+ end
54
+
55
+ it "should generate auth elements with usernames and xauth strings" do
56
+ pending
57
+ end
30
58
  end
@@ -8,3 +8,8 @@ end
8
8
 
9
9
  $:.unshift(File.dirname(__FILE__) + '/../lib')
10
10
  require 'postini'
11
+ require 'ostruct'
12
+
13
+ Spec::Runner.configure do |config|
14
+ config.mock_with :mocha
15
+ end
@@ -1,12 +1,142 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper.rb'
2
2
 
3
3
  describe Postini::User do
4
+
4
5
  before(:each) do
5
- @user = Postini::User.new
6
+ Postini.stubs(:endpoint_uri).with(anything).returns('http://example.com/api2/automatedbatch')
7
+ Postini.stubs(:auth).with(anything).returns(
8
+ Postini::API::AutomatedBatch::AuthElem.new(
9
+ '0000000000000000', 'postini4r@jumboinc.com', 'secret', nil
10
+ )
11
+ )
6
12
  end
13
+
14
+ describe "provides convenience methods" do
15
+ it "load a user" do
16
+ address = 'support@jumboinc.com'
7
17
 
8
- it "should be tested" do
9
- violated "Test me"
18
+ mock_request = Postini::API::AutomatedBatch::Displayuser.new( Postini.auth, address )
19
+ Postini::API::AutomatedBatch::Displayuser.expects(:new).with( Postini.auth, address ).returns( mock_request )
20
+
21
+ mock_remote = Postini::API::AutomatedBatch::AutomatedBatchPort.new( Postini.endpoint_uri(address) )
22
+ Postini::User.expects(:automated_batch_port).with(address).returns(mock_remote)
23
+
24
+ mock_user = Postini::API::AutomatedBatch::UserRecord.new
25
+ mock_user.address = address
26
+ mock_user.user_id = 0
27
+
28
+ mock_response = Postini::API::AutomatedBatch::DisplayuserResponse.new( mock_user )
29
+
30
+ mock_remote.expects(:displayuser).with(mock_request).returns(mock_response)
31
+
32
+ ####
33
+
34
+ user = Postini::User.find( address )
35
+
36
+ user.address.should eql(address)
37
+ user.id.should be(0)
38
+ end
39
+
40
+ it "destroy a user" do
41
+ address = 'support@jumboinc.com'
42
+
43
+ mock_remote = Postini::API::AutomatedBatch::AutomatedBatchPort.new( Postini.endpoint_uri(address) )
44
+ mock_remote.expects(:deleteuser).with(anything)
45
+ Postini::User.expects(:automated_batch_port).with(address).returns(mock_remote)
46
+
47
+ Postini::User.destroy(address)
48
+
49
+ pending "IMPROVE"
50
+ end
10
51
  end
11
- end
12
52
 
53
+ describe "when new" do
54
+ before(:each) do
55
+ @user = Postini::User.new( :active => "no" )
56
+ end
57
+
58
+ it "should convert the options hash into instance variables" do
59
+ @user.active.should eql("no")
60
+ end
61
+
62
+ it "should indicate so" do
63
+ @user.should be_new
64
+ end
65
+
66
+ it "should only be created if all validations pass" do
67
+ Postini::User.expects(:automated_batch_port).never
68
+
69
+ @user.create.should be_false
70
+ end
71
+
72
+ it "should be created if valid" do
73
+ @user.address = 'support@jumboinc.com'
74
+ @user.orgid = 'support'
75
+
76
+ mock_args = Postini::API::AutomatedBatch::Adduserargs.new( @user.orgid, 0 )
77
+ Postini::API::AutomatedBatch::Adduserargs.expects(:new).with( @user.orgid, 0 ).returns(mock_args)
78
+
79
+ mock_request = Postini::API::AutomatedBatch::Adduser.new( Postini.auth, @user.address, mock_args )
80
+ Postini::API::AutomatedBatch::Adduser.expects(:new).with( Postini.auth, @user.address, mock_args ).returns(mock_request)
81
+
82
+ mock_remote = Postini::API::AutomatedBatch::AutomatedBatchPort.new( Postini.endpoint_uri )
83
+ Postini::User.expects(:automated_batch_port).returns(mock_remote)
84
+ mock_remote.expects(:adduser).with(mock_request)
85
+
86
+ ####
87
+
88
+ @user.create
89
+ end
90
+ end
91
+
92
+ describe "when loaded" do
93
+ before(:each) do
94
+ @user = Postini::User.new(
95
+ :id => 0,
96
+ :address => 'support@jumboinc.com',
97
+ :orgid => 'support'
98
+ )
99
+ end
100
+
101
+ it "cannot be created again" do
102
+ Postini::User.expects(:automated_batch_port).never
103
+
104
+ @user.create.should be_false
105
+ end
106
+
107
+ it "can be deleted" do
108
+ Postini::User.expects(:destroy).with(@user.address)
109
+
110
+ @user.destroy
111
+ end
112
+ end
113
+
114
+ describe "and aliases" do
115
+ before(:each) do
116
+ @user = Postini::User.new( :address => 'support@jumboinc.com' )
117
+
118
+ end
119
+
120
+ it "can be loaded" do
121
+ mock_remote = Postini::API::AutomatedBatch::AutomatedBatchPort.new( Postini.endpoint_uri(@user.address) )
122
+ Postini::User.expects(:automated_batch_port).with(@user.address).returns(mock_remote)
123
+ mock_remote.expects(:listusers).with(anything).returns([])
124
+
125
+ @user.aliases.should be_empty
126
+
127
+ pending "IMPROVE"
128
+ end
129
+
130
+ it "can be added to" do
131
+ pending
132
+ end
133
+
134
+ it "can be removed" do
135
+ pending
136
+ end
137
+
138
+ it "can be cleared" do
139
+ pending
140
+ end
141
+ end
142
+ end
@@ -19,3 +19,21 @@ Spec::Rake::SpecTask.new do |t|
19
19
  t.spec_opts = ['--options', "spec/spec.opts"]
20
20
  t.spec_files = FileList['spec/**/*_spec.rb']
21
21
  end
22
+
23
+ namespace :spec do
24
+ desc "Print Specdoc for all specs (excluding plugin specs)"
25
+ Spec::Rake::SpecTask.new(:doc) do |t|
26
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
27
+ t.spec_files = FileList['spec/**/*_spec.rb']
28
+ end
29
+
30
+ desc "Run all specs in spec directory with RCov (excluding plugin specs)"
31
+ Spec::Rake::SpecTask.new(:rcov) do |t|
32
+ t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/../spec/spec.opts\""]
33
+ t.spec_files = FileList['spec/**/*_spec.rb']
34
+ t.rcov = true
35
+ t.rcov_opts = lambda do
36
+ IO.readlines("#{File.dirname(__FILE__)}/../spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
37
+ end
38
+ end
39
+ end
@@ -33,7 +33,8 @@
33
33
  <h1>postini Gem</h1>
34
34
  <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/postini4r"; return false'>
35
35
  <p>Get Version</p>
36
- <a href="http://rubyforge.org/projects/postini4r" class="numbers">0.0.3</a>
36
+ <a href="http://rubyforge.org/projects/postini4r" class="numbers">0.0.6</a>
37
+ <a href="http://www.spaminabox.co.za"><img src="spam_box.png" alt="SPAM in a Box" /></a>
37
38
  </div>
38
39
  <h2>Part of the postini4r project</h2>
39
40
  <p>The postini4r project is a collection of sub-projects that aim to implement a broad range of Postini-related tools.</p>
@@ -71,7 +72,7 @@ rake install_gem</pre>
71
72
  <p>postini4r is developed by <a href="http://www.opensourcery.co.za/">Kenneth Kalmer</a> for <a href="http://www.spaminabox.co.za"><span class="caps">SPAM</span> in a Box</a> who has allowed the library to be released under the <span class="caps">MIT</span> License through their sponsorship.</p>
72
73
  <p class="coda">
73
74
  <a href="http://www.opensourcery.co.za">Kenneth Kalmer</a> &amp;
74
- <a href="http://www.spaminabox.co.za">SPAM in a Box</a>, 16th August 2008<br>
75
+ <a href="http://www.spaminabox.co.za">SPAM in a Box</a>, 11th March 2009<br>
75
76
  Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
76
77
  </p>
77
78
  </div>
Binary file
@@ -1,138 +1,143 @@
1
- body {
2
- background-color: #E1D1F1;
3
- font-family: "Georgia", sans-serif;
4
- font-size: 16px;
5
- line-height: 1.6em;
6
- padding: 1.6em 0 0 0;
7
- color: #333;
8
- }
9
- h1, h2, h3, h4, h5, h6 {
10
- color: #444;
11
- }
12
- h1 {
13
- font-family: sans-serif;
14
- font-weight: normal;
15
- font-size: 4em;
16
- line-height: 0.8em;
17
- letter-spacing: -0.1ex;
18
- margin: 5px;
19
- }
20
- li {
21
- padding: 0;
22
- margin: 0;
23
- list-style-type: square;
24
- }
25
- a {
26
- color: #5E5AFF;
27
- background-color: #DAC;
28
- font-weight: normal;
29
- text-decoration: underline;
30
- }
31
- blockquote {
32
- font-size: 90%;
33
- font-style: italic;
34
- border-left: 1px solid #111;
35
- padding-left: 1em;
36
- }
37
- .caps {
38
- font-size: 80%;
39
- }
40
-
41
- #main {
42
- width: 45em;
43
- padding: 0;
44
- margin: 0 auto;
45
- }
46
- .coda {
47
- text-align: right;
48
- color: #77f;
49
- font-size: smaller;
50
- }
51
-
52
- table {
53
- font-size: 90%;
54
- line-height: 1.4em;
55
- color: #ff8;
56
- background-color: #111;
57
- padding: 2px 10px 2px 10px;
58
- border-style: dashed;
59
- }
60
-
61
- th {
62
- color: #fff;
63
- }
64
-
65
- td {
66
- padding: 2px 10px 2px 10px;
67
- }
68
-
69
- .success {
70
- color: #0CC52B;
71
- }
72
-
73
- .failed {
74
- color: #E90A1B;
75
- }
76
-
77
- .unknown {
78
- color: #995000;
79
- }
80
- pre, code {
81
- font-family: monospace;
82
- font-size: 90%;
83
- line-height: 1.4em;
84
- color: #ff8;
85
- background-color: #111;
86
- padding: 2px 10px 2px 10px;
87
- }
88
- .comment { color: #aaa; font-style: italic; }
89
- .keyword { color: #eff; font-weight: bold; }
90
- .punct { color: #eee; font-weight: bold; }
91
- .symbol { color: #0bb; }
92
- .string { color: #6b4; }
93
- .ident { color: #ff8; }
94
- .constant { color: #66f; }
95
- .regex { color: #ec6; }
96
- .number { color: #F99; }
97
- .expr { color: #227; }
98
-
99
- #version {
100
- float: right;
101
- text-align: right;
102
- font-family: sans-serif;
103
- font-weight: normal;
104
- background-color: #B3ABFF;
105
- color: #141331;
106
- padding: 15px 20px 10px 20px;
107
- margin: 0 auto;
108
- margin-top: 15px;
109
- border: 3px solid #141331;
110
- }
111
-
112
- #version .numbers {
113
- display: block;
114
- font-size: 4em;
115
- line-height: 0.8em;
116
- letter-spacing: -0.1ex;
117
- margin-bottom: 15px;
118
- }
119
-
120
- #version p {
121
- text-decoration: none;
122
- color: #141331;
123
- background-color: #B3ABFF;
124
- margin: 0;
125
- padding: 0;
126
- }
127
-
128
- #version a {
129
- text-decoration: none;
130
- color: #141331;
131
- background-color: #B3ABFF;
132
- }
133
-
134
- .clickable {
135
- cursor: pointer;
136
- cursor: hand;
137
- }
138
-
1
+ body {
2
+ background-color: #E1D1F1;
3
+ font-family: "Georgia", sans-serif;
4
+ font-size: 16px;
5
+ line-height: 1.6em;
6
+ padding: 1.6em 0 0 0;
7
+ color: #333;
8
+ }
9
+ h1, h2, h3, h4, h5, h6 {
10
+ color: #444;
11
+ }
12
+ h1 {
13
+ font-family: sans-serif;
14
+ font-weight: normal;
15
+ font-size: 4em;
16
+ line-height: 0.8em;
17
+ letter-spacing: -0.1ex;
18
+ margin: 5px;
19
+ }
20
+ li {
21
+ padding: 0;
22
+ margin: 0;
23
+ list-style-type: square;
24
+ }
25
+ a {
26
+ color: #5E5AFF;
27
+ background-color: #DAC;
28
+ font-weight: normal;
29
+ text-decoration: underline;
30
+ }
31
+ blockquote {
32
+ font-size: 90%;
33
+ font-style: italic;
34
+ border-left: 1px solid #111;
35
+ padding-left: 1em;
36
+ }
37
+ .caps {
38
+ font-size: 80%;
39
+ }
40
+
41
+ #main {
42
+ width: 45em;
43
+ padding: 0;
44
+ margin: 0 auto;
45
+ }
46
+ .coda {
47
+ text-align: right;
48
+ color: #77f;
49
+ font-size: smaller;
50
+ }
51
+
52
+ table {
53
+ font-size: 90%;
54
+ line-height: 1.4em;
55
+ color: #ff8;
56
+ background-color: #111;
57
+ padding: 2px 10px 2px 10px;
58
+ border-style: dashed;
59
+ }
60
+
61
+ th {
62
+ color: #fff;
63
+ }
64
+
65
+ td {
66
+ padding: 2px 10px 2px 10px;
67
+ }
68
+
69
+ .success {
70
+ color: #0CC52B;
71
+ }
72
+
73
+ .failed {
74
+ color: #E90A1B;
75
+ }
76
+
77
+ .unknown {
78
+ color: #995000;
79
+ }
80
+ pre, code {
81
+ font-family: monospace;
82
+ font-size: 90%;
83
+ line-height: 1.4em;
84
+ color: #ff8;
85
+ background-color: #111;
86
+ padding: 2px 10px 2px 10px;
87
+ }
88
+ .comment { color: #aaa; font-style: italic; }
89
+ .keyword { color: #eff; font-weight: bold; }
90
+ .punct { color: #eee; font-weight: bold; }
91
+ .symbol { color: #0bb; }
92
+ .string { color: #6b4; }
93
+ .ident { color: #ff8; }
94
+ .constant { color: #66f; }
95
+ .regex { color: #ec6; }
96
+ .number { color: #F99; }
97
+ .expr { color: #227; }
98
+
99
+ #version {
100
+ float: right;
101
+ text-align: right;
102
+ font-family: sans-serif;
103
+ font-weight: normal;
104
+ background-color: #B3ABFF;
105
+ color: #141331;
106
+ padding: 15px 20px 10px 20px;
107
+ margin: 0 auto;
108
+ margin-top: 15px;
109
+ border: 3px solid #141331;
110
+ }
111
+
112
+ #version .numbers {
113
+ display: block;
114
+ font-size: 4em;
115
+ line-height: 0.8em;
116
+ letter-spacing: -0.1ex;
117
+ margin-bottom: 15px;
118
+ }
119
+
120
+ #version p {
121
+ text-decoration: none;
122
+ color: #141331;
123
+ background-color: #B3ABFF;
124
+ margin: 0;
125
+ padding: 0;
126
+ }
127
+
128
+ #version a {
129
+ text-decoration: none;
130
+ color: #141331;
131
+ background-color: #B3ABFF;
132
+ }
133
+
134
+ #version img {
135
+ margin-right: 15px;
136
+ border: 0;
137
+ }
138
+
139
+ .clickable {
140
+ cursor: pointer;
141
+ cursor: hand;
142
+ }
143
+
@@ -34,6 +34,7 @@
34
34
  <div id="version" class="clickable" onclick='document.location = "<%= download %>"; return false'>
35
35
  <p>Get Version</p>
36
36
  <a href="<%= download %>" class="numbers"><%= version %></a>
37
+ <a href="http://www.spaminabox.co.za"><img src="spam_box.png" alt="SPAM in a Box" /></a>
37
38
  </div>
38
39
  <%= body %>
39
40
  <p class="coda">
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: postini
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenneth Kalmer
@@ -9,9 +9,19 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-08-21 00:00:00 +02:00
12
+ date: 2009-03-24 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.0.2
24
+ version:
15
25
  - !ruby/object:Gem::Dependency
16
26
  name: soap4r
17
27
  type: :runtime
@@ -30,7 +40,7 @@ dependencies:
30
40
  requirements:
31
41
  - - ">="
32
42
  - !ruby/object:Gem::Version
33
- version: 1.7.0
43
+ version: 1.8.0
34
44
  version:
35
45
  description: Ruby wrapper around the Postini SOAP API (Early Access Program)
36
46
  email:
@@ -53,10 +63,10 @@ files:
53
63
  - PostInstall.txt
54
64
  - README.txt
55
65
  - Rakefile
66
+ - TODO
56
67
  - config/hoe.rb
57
68
  - config/requirements.rb
58
69
  - lib/postini.rb
59
- - lib/postini/version.rb
60
70
  - lib/postini/api.rb
61
71
  - lib/postini/api/automatedbatch/AutomatedBatch.rb
62
72
  - lib/postini/api/automatedbatch/AutomatedBatchDriver.rb
@@ -67,28 +77,34 @@ files:
67
77
  - lib/postini/api/endpointresolver/EndpointResolverMappingRegistry.rb
68
78
  - lib/postini/api/endpointresolver/EndpointResolverServiceClient.rb
69
79
  - lib/postini/domain.rb
80
+ - lib/postini/helpers.rb
81
+ - lib/postini/helpers/attributes.rb
70
82
  - lib/postini/user.rb
83
+ - lib/postini/users/aliases.rb
84
+ - lib/postini/version.rb
71
85
  - script/console
72
86
  - script/destroy
73
87
  - script/generate
74
88
  - script/txt2html
75
89
  - setup.rb
90
+ - spec/attribute_helper_spec.rb
91
+ - spec/domain_spec.rb
76
92
  - spec/postini_spec.rb
77
93
  - spec/spec.opts
78
94
  - spec/spec_helper.rb
79
- - spec/domain_spec.rb
80
95
  - spec/user_spec.rb
81
96
  - tasks/deployment.rake
82
97
  - tasks/environment.rake
83
98
  - tasks/rspec.rake
84
99
  - tasks/website.rake
100
+ - vendor/automatedbatch.wsdl
101
+ - vendor/endpointresolver.wsdl
85
102
  - website/index.html
86
103
  - website/index.txt
87
104
  - website/javascripts/rounded_corners_lite.inc.js
105
+ - website/spam_box.png
88
106
  - website/stylesheets/screen.css
89
107
  - website/template.html.erb
90
- - vendor/automatedbatch.wsdl
91
- - vendor/endpointresolver.wsdl
92
108
  has_rdoc: true
93
109
  homepage: http://postini4r.rubyforge.org
94
110
  post_install_message: |+
@@ -120,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
136
  requirements: []
121
137
 
122
138
  rubyforge_project: postini4r
123
- rubygems_version: 1.2.0
139
+ rubygems_version: 1.3.1
124
140
  signing_key:
125
141
  specification_version: 2
126
142
  summary: Ruby wrapper around the Postini SOAP API (Early Access Program)