gprov 0.0.3

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.
@@ -0,0 +1,132 @@
1
+ # = gprov/provision/user.rb: implementation of the gprov provisioning userentry
2
+ #
3
+ # == Overview
4
+ #
5
+ # implementation of the gprov provisioning userentry
6
+ #
7
+ # == Authors
8
+ #
9
+ # Adrien Thebo
10
+ #
11
+ # == Copyright
12
+ #
13
+ # 2011 Puppet Labs
14
+ #
15
+ require 'gprov'
16
+ require 'gprov/provision/feed'
17
+ require 'gprov/provision/entrybase'
18
+ module GProv
19
+ module Provision
20
+ class User < GProv::Provision::EntryBase
21
+
22
+ # The :title attribute is only used after the account has been created
23
+ # TODO implement :none access for attributes. This should be hidden.
24
+ xmlattr :title, :type => :string, :xpath => "xmlns:title/text()"
25
+
26
+ xmlattr :user_name, :xpath => "apps:login/@userName"
27
+ xmlattr :suspended, :xpath => "apps:login/@suspended"
28
+ xmlattr :ip_whitelisted, :xpath => "apps:login/@ipWhitelisted"
29
+ xmlattr :admin, :xpath => "apps:login/@admin"
30
+ xmlattr :agreed_to_terms, :xpath => "apps:login/@agreedToTerms"
31
+ xmlattr :limit, :xpath => "apps:quota/@limit"
32
+ xmlattr :family_name, :xpath => "apps:name/@familyName"
33
+ xmlattr :given_name, :xpath => "apps:name/@givenName"
34
+ xmlattr :change_password_at_next_login, :xpath => "apps:login/@changePasswordAtNextLogin"
35
+
36
+ # Adds explicit ordering to attributes for cleaner output
37
+ def self.attribute_names
38
+ [
39
+ :user_name,
40
+ :given_name,
41
+ :family_name,
42
+ :admin,
43
+ :agreed_to_terms,
44
+ :change_password_at_next_login,
45
+ :suspended,
46
+ :ip_whitelisted,
47
+ :limit
48
+ ]
49
+ end
50
+
51
+ # These attributes appear to never be sent from google but can be
52
+ # posted back
53
+ attr_accessor :password, :hash_function_name
54
+
55
+ # Retrieves all users within a domain
56
+ def self.all(connection)
57
+ feed = GProv::Provision::Feed.new(connection, "/:domain/user/2.0", "/xmlns:feed/xmlns:entry")
58
+ entries = feed.fetch
59
+ entries.map { |xml| new(:status => :clean, :connection => connection, :source => xml) }
60
+ end
61
+
62
+ def self.get(connection, title, options={})
63
+ response = connection.get("/:domain/user/2.0/#{title}")
64
+
65
+ document = Nokogiri::XML(response.body)
66
+ xml = document.root
67
+
68
+ new(:status => :clean, :connection => connection, :source => xml)
69
+ end
70
+
71
+ # Generate a nokogiri representation of this user
72
+ def to_nokogiri
73
+ base_document = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
74
+ xml.entry('xmlns:atom' => 'http://www.w3.org/2005/Atom',
75
+ 'xmlns:apps' => 'http://schemas.google.com/apps/2006' ) {
76
+
77
+ # Namespaces cannot be used until they are declared, so we need to
78
+ # retroactively declare the namespace of the parent
79
+ xml.parent.namespace = xml.parent.namespace_definitions.select {|ns| ns.prefix == "atom"}.first
80
+ xml.category("scheme" => "http://schemas.google.com/g/2005#kind",
81
+ "term" =>"http://schemas.google.com/apps/2006#user")
82
+ xml['apps'].login(login_attributes)
83
+ xml['apps'].quota("limit" => @limit) if @limit
84
+ xml['apps'].name("familyName" => @family_name, "givenName" => @given_name)
85
+ }
86
+ end
87
+
88
+ base_document
89
+ end
90
+
91
+ def create!
92
+ response = connection.post("/:domain/user/2.0", {:body => to_nokogiri.to_xml})
93
+ status = :clean
94
+ end
95
+
96
+ def update!
97
+ response = connection.put("/:domain/user/2.0/#{title}", {:body => to_nokogiri.to_xml})
98
+ status = :clean
99
+ end
100
+
101
+ def delete!
102
+ response = connection.delete("/:domain/user/2.0/#{title}")
103
+ status = :deleted
104
+ end
105
+
106
+ private
107
+
108
+ # Map object properties to xml tag attributes
109
+ def login_attributes
110
+ attrs = {}
111
+
112
+ attr_pairs = [
113
+ {"userName" => @user_name},
114
+ {"suspended" => @suspended},
115
+ {"ipWhitelisted" => @ip_whitelisted},
116
+ {"admin" => @admin},
117
+ {"changePasswordAtNextLogin" => @change_password_at_next_login},
118
+ {"agreedToTerms" => @agreed_to_terms},
119
+ {'password' => @password},
120
+ {'hashFunctionName' => @hash_function_name},
121
+ ]
122
+
123
+ attr_pairs.each do |pair|
124
+ key = pair.keys.first
125
+ attrs.merge!(pair) unless pair[key].nil?
126
+ end
127
+
128
+ attrs
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,3 @@
1
+ module GProv
2
+ VERSION = "0.0.3"
3
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe GProv::Auth::ClientLogin do
4
+
5
+ before :each do
6
+ @klass = GProv::Auth::ClientLogin
7
+ @instance = @klass.new('test', 'password', 'service')
8
+ @dummy_form = {:body => {
9
+ "accountType" => "HOSTED",
10
+ "Email" => "test",
11
+ "Passwd" => "password",
12
+ "service" => "service",
13
+ }}
14
+ end
15
+
16
+ it "should use the google ClientLogin uri" do
17
+ GProv::Auth::ClientLogin.base_uri.should == "https://www.google.com/accounts/ClientLogin"
18
+ end
19
+
20
+ it "should have a token method" do
21
+ @instance.respond_to?(:token).should == true
22
+ end
23
+
24
+ it "should post valid form data to the uri specified base_uri" do
25
+ stub_response = stub :response
26
+ stub_response.stubs(:code).returns 200
27
+ stub_response.stubs(:body).returns "Auth=dummy\n"
28
+ @klass.expects(:post).with('', @dummy_form).returns stub_response
29
+ @instance.token
30
+ end
31
+
32
+ it "should return nil if authorization failed" do
33
+ stub_response = stub :response
34
+ stub_response.stubs(:code).returns 403
35
+ @klass.expects(:post).with('', @dummy_form).returns stub_response
36
+ @instance.token.should be_nil
37
+ end
38
+
39
+ it "should return the token if authorization succeeded" do
40
+ stub_response = stub :response
41
+ stub_response.stubs(:code).returns 200
42
+ stub_response.stubs(:body).returns "Auth=dummy\n"
43
+ @klass.expects(:post).with('', @dummy_form).returns stub_response
44
+ @instance.token.should == "dummy"
45
+ end
46
+
47
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ describe GProv::Connection do
4
+
5
+ before :each do
6
+ @klass = GProv::Connection
7
+ @instance = @klass.new("domain", "token")
8
+
9
+ @expected_options = {:headers => {
10
+ 'Authorization' => "GoogleLogin auth=token",
11
+ 'Content-Type' => 'application/atom+xml',
12
+ }}
13
+ end
14
+
15
+ it "should use to google apps API url as the base uri" do
16
+ @klass.base_uri.should == "https://apps-apis.google.com/a/feeds"
17
+ end
18
+
19
+ it "should have a domain accessor" do
20
+ @instance.respond_to?(:domain).should == true
21
+ end
22
+
23
+ it "should expose the default headers" do
24
+ @instance.default_headers.should == @expected_options
25
+ end
26
+
27
+
28
+ describe "http instance method" do
29
+ [:put, :get, :post, :delete].each do |verb|
30
+ describe %Q{"#{verb}"} do
31
+ before do
32
+ xml = %Q{<?xml version="1.0" encoding="UTF-8"?>\n<test xml="pointy"/>}
33
+ @stub_request = mock
34
+ @stub_request.stubs(:code).returns 200
35
+ @stub_request.stubs(:success?).returns true
36
+ @stub_request.stubs(:class).returns HTTParty::Response
37
+ end
38
+
39
+ it "should be an instance method" do
40
+ @instance.respond_to?(verb).should == true
41
+ end
42
+
43
+ it "should be forwarded to the class" do
44
+ @klass.expects(verb).returns @stub_request
45
+ @instance.send(verb, '')
46
+ end
47
+
48
+ it "should return the http response" do
49
+ @klass.expects(verb).returns @stub_request
50
+ output = @instance.send(verb, "/url")
51
+ output.class.should == HTTParty::Response
52
+ end
53
+
54
+ it "should interpolate the :domain substring" do
55
+ @klass.expects(verb).with("/domain", @expected_options).returns @stub_request
56
+ @instance.send(verb, "/:domain")
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ class FakeEntry < GProv::Provision::EntryBase
4
+
5
+ xml_attr_accessor :test, :xpath => "/foo/bar/text()"
6
+ xml_attr_accessor :test_transform, :xpath => "/foo/bar/text()", :transform => lambda {|x| x.upcase}
7
+ end
8
+
9
+ describe GProv::Provision::EntryBase do
10
+
11
+ before do
12
+ @klass = GProv::Provision::EntryBase
13
+ @test_klass = FakeEntry
14
+ @instance = @test_klass.new
15
+ end
16
+
17
+ describe GProv::Provision::EntryBase::ClassMethods do
18
+
19
+ [:xml_attr_accessor, :xml_to_hash, :attributes].each do |method|
20
+ it "method #{method} should be a class method" do
21
+ FakeEntry.respond_to?(method).should be_true
22
+ end
23
+ end
24
+
25
+ it "xml_attr_accessor should receive a symbol and hash of attributes" do
26
+ @test_klass.attributes[:test].should == {:xpath => "/foo/bar/text()"}
27
+ end
28
+
29
+ describe "xml_to_hash" do
30
+ end
31
+ end
32
+
33
+
34
+ [:status, :connection].each do |method|
35
+ it "method #{method} should be an instance method" do
36
+ @instance.respond_to?(method).should be_true
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby -S rspec
2
+
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
4
+
5
+ require 'mocha'
6
+ require 'gprov'
7
+
8
+ RSpec.configure do |config|
9
+ config.mock_with :mocha
10
+ end
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gprov
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 3
10
+ version: 0.0.3
11
+ platform: ruby
12
+ authors:
13
+ - Adrien Thebo
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-02-02 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: httparty
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 27
29
+ segments:
30
+ - 0
31
+ - 8
32
+ version: "0.8"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: nokogiri
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 5
44
+ segments:
45
+ - 1
46
+ - 5
47
+ version: "1.5"
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ description: Ruby bindings to the Google Provisioning API
51
+ email: adrien@puppetlabs.com
52
+ executables: []
53
+
54
+ extensions: []
55
+
56
+ extra_rdoc_files: []
57
+
58
+ files:
59
+ - lib/gprov/auth/clientlogin.rb
60
+ - lib/gprov/auth.rb
61
+ - lib/gprov/connection.rb
62
+ - lib/gprov/error.rb
63
+ - lib/gprov/provision/customerid.rb
64
+ - lib/gprov/provision/entrybase/classmethods.rb
65
+ - lib/gprov/provision/entrybase/xmlattr.rb
66
+ - lib/gprov/provision/entrybase.rb
67
+ - lib/gprov/provision/feed.rb
68
+ - lib/gprov/provision/group.rb
69
+ - lib/gprov/provision/member.rb
70
+ - lib/gprov/provision/orgmember.rb
71
+ - lib/gprov/provision/orgunit.rb
72
+ - lib/gprov/provision/owner.rb
73
+ - lib/gprov/provision/user.rb
74
+ - lib/gprov/provision.rb
75
+ - lib/gprov/version.rb
76
+ - lib/gprov.rb
77
+ - spec/gdata/auth/clientlogin_spec.rb
78
+ - spec/gdata/connection_spec.rb
79
+ - spec/gdata/provision/entrybase_spec.rb
80
+ - spec/spec_helper.rb
81
+ - LICENSE
82
+ - Rakefile
83
+ - README.markdown
84
+ homepage: http://github.com/adrienthebo/ruby-gprov
85
+ licenses: []
86
+
87
+ post_install_message:
88
+ rdoc_options: []
89
+
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ hash: 3
98
+ segments:
99
+ - 0
100
+ version: "0"
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ hash: 3
107
+ segments:
108
+ - 0
109
+ version: "0"
110
+ requirements: []
111
+
112
+ rubyforge_project:
113
+ rubygems_version: 1.8.10
114
+ signing_key:
115
+ specification_version: 3
116
+ summary: Ruby bindings to the Google Provisioning API
117
+ test_files: []
118
+