gprov 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+