provisioning-api 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ .DS_Store
2
+ *.gem
3
+ *.rbc
4
+ .bundle
5
+ .config
6
+ coverage
7
+ InstalledFiles
8
+ lib/bundler/man
9
+ pkg
10
+ rdoc
11
+ spec/reports
12
+ test/tmp
13
+ test/version_tmp
14
+ tmp
15
+
16
+ # YARD artifacts
17
+ .yardoc
18
+ _yardoc
19
+ doc/
20
+
data/.rvmrc ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # This is an RVM Project .rvmrc file, used to automatically load the ruby
4
+ # development environment upon cd'ing into the directory
5
+
6
+ # First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
7
+ environment_id="ruby-1.9.2-p290@provisioning-api"
8
+
9
+ #
10
+ # Uncomment following line if you want options to be set only for given project.
11
+ #
12
+ # PROJECT_JRUBY_OPTS=( --1.9 )
13
+
14
+ #
15
+ # First we attempt to load the desired environment directly from the environment
16
+ # file. This is very fast and efficient compared to running through the entire
17
+ # CLI and selector. If you want feedback on which environment was used then
18
+ # insert the word 'use' after --create as this triggers verbose mode.
19
+ #
20
+ if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
21
+ && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
22
+ then
23
+ \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
24
+
25
+ if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]]
26
+ then
27
+ . "${rvm_path:-$HOME/.rvm}/hooks/after_use"
28
+ fi
29
+ else
30
+ # If the environment file has not yet been created, use the RVM CLI to select.
31
+ if ! rvm --create "$environment_id"
32
+ then
33
+ echo "Failed to create RVM environment '${environment_id}'."
34
+ exit 1
35
+ fi
36
+ fi
37
+
38
+ #
39
+ # If you use an RVM gemset file to install a list of gems (*.gems), you can have
40
+ # it be automatically loaded. Uncomment the following and adjust the filename if
41
+ # necessary.
42
+ #
43
+ # filename=".gems"
44
+ # if [[ -s "$filename" ]] ; then
45
+ # rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d'
46
+ # fi
47
+
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source :rubygems
2
+
3
+ group :development, :test do
4
+ gem 'vcr'
5
+ gem 'pry'
6
+ gem 'fakeweb'
7
+ end
8
+
data/Gemfile.lock ADDED
@@ -0,0 +1,25 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ coderay (0.9.8)
5
+ fakeweb (1.3.0)
6
+ method_source (0.6.7)
7
+ ruby_parser (>= 2.3.1)
8
+ pry (0.9.7.4)
9
+ coderay (~> 0.9.8)
10
+ method_source (~> 0.6.7)
11
+ ruby_parser (>= 2.3.1)
12
+ slop (~> 2.1.0)
13
+ ruby_parser (2.3.1)
14
+ sexp_processor (~> 3.0)
15
+ sexp_processor (3.0.8)
16
+ slop (2.1.0)
17
+ vcr (1.11.3)
18
+
19
+ PLATFORMS
20
+ ruby
21
+
22
+ DEPENDENCIES
23
+ fakeweb
24
+ pry
25
+ vcr
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ Google apps provisioning API ruby library
2
+ ========================================
3
+
4
+ This is a copy of the Google Apps provisioning API taken from http://code.google.com/p/gdatav2rubyclientlib/ v 1.2 (latest)
5
+
6
+ BEFORE USE Enable the API on Google Admin Panel
7
+ =================================================
8
+
9
+ Domain Settings -> User Settings -> Enable Provisionin API
10
+
11
+ https://www.google.com/a/cpanel/[YOUR_DOMAIN.com]/DomainSettingsUserSettings
12
+
13
+ Example
14
+ =========
15
+
16
+ #!/usr/bin/ruby
17
+ require 'gappsprovisioning/provisioningapi'
18
+ include GAppsProvisioning
19
+ adminuser = "root@mydomain.com"
20
+ password = "PaSsWo4d!"
21
+ myapps = ProvisioningApi.new(adminuser,password)
22
+
23
+ new_user = myapps.create_user("jsmith", "john", "smith", "12345678", nil, "2048")
24
+ puts new_user.family_name
25
+ puts new_user.given_name
26
+
27
+ Want to update a user ?
28
+
29
+ user = myapps.retrieve_user('jsmith')
30
+ user_updated = myapps.update_user(user.username, user.given_name, user.family_name, nil, nil, "true")
31
+
32
+ Want to add an alias or nickname ?
33
+
34
+ new_nickname = myapps.create_nickname("jsmith", "john.smith")
35
+
36
+ Want to add an email forwarding (thanks to Scott Jungling) ?
37
+
38
+ new_forwarding = myapps.create_email_forwarding("jsmith", "brenda@yourdomain.com", "KEEP")
39
+
40
+ Want to manage groups ? (i.e. mailing lists)
41
+
42
+ new_group = myapps.create_group("sales-dep", ['Sales Departement'])
43
+ new_member = myapps.add_member_to_group("jsmith", "sales-dep")
44
+ new_owner = myapps.add_owner_to_group("jsmith", "sales-dep")
45
+ # (ATTENTION: a owner is added only if it's already member of the group!)
46
+
47
+ Want to handle errors ?
48
+
49
+ begin
50
+ user = myapps.retrieve_user('noone')
51
+ puts "givenName : "+user.given_name, "familyName : "+user.family_name, "username : "+user.username
52
+ puts "admin ? : "+user.admin
53
+ rescue GDataError => e
54
+ puts "errorcode = "+e.code, "input : "+e.input, "reason : "+e.reason
55
+ end
56
+
57
+
58
+ Character Usage
59
+ ===============
60
+
61
+ - Usernames may contain letters (a-z), numbers (0-9), dashes (-), underscores (_), and periods (.), and may not contain an equal sign (=) or brackets (<,>).
62
+ They can't contain more than one period in a row.
63
+
64
+ - Passwords may contain any combination of characters, but a minimum of 8 characters is required.
65
+
66
+ - First and last names support unicode/UTF-8 characters, and may contain spaces, letters (a-z), numbers (0-9), dashes (-), forward slashes (/), and periods (.), with a maximum of 40 characters.
67
+
68
+ -Characters that cannot be part of a name include: !, #, $, %, &, (, ), *, +, /, ?, \, ^, |, ~
69
+
70
+ Testing
71
+ =========
72
+
73
+ Google API testing is hard. There are multiple server side rules that
74
+ make testing hard, such as deleting a user and creating it back requires
75
+ you to wait for 5 days.
76
+
77
+ Instead we simply use VCR to verify that code interprets correctly and
78
+ that the codes are being made. If you want to "really" test the API you
79
+ need a username and password for a domain to run your tests.
80
+
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ t.pattern = "test/test_*.rb"
6
+ end
7
+
8
+ desc "Run tests"
9
+ task :default => :test
10
+
11
+ task :build do
12
+ system "gem build provisioning-api.gemspec"
13
+ end
14
+
@@ -0,0 +1,96 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :post
5
+ uri: https://apps-apis.google.com:443/accounts/ClientLogin
6
+ body: !!null
7
+ headers:
8
+ content-type:
9
+ - application/x-www-form-urlencoded
10
+ content-length:
11
+ - '75'
12
+ response: !ruby/struct:VCR::Response
13
+ status: !ruby/struct:VCR::ResponseStatus
14
+ code: 200
15
+ message: OK
16
+ headers:
17
+ content-type:
18
+ - text/plain
19
+ cache-control:
20
+ - no-cache, no-store
21
+ pragma:
22
+ - no-cache
23
+ expires:
24
+ - Mon, 01-Jan-1990 00:00:00 GMT
25
+ date:
26
+ - Sat, 26 Nov 2011 20:35:13 GMT
27
+ x-content-type-options:
28
+ - nosniff
29
+ x-xss-protection:
30
+ - 1; mode=block
31
+ content-length:
32
+ - '1010'
33
+ server:
34
+ - GSE
35
+ body: ! 'SID=DQAAAOcAAABGChSuJCFvcdA-phg8w37dgl7m125nCpbJSMsqlGTD8nr-T5fqvL4VJJUPQfgOLwArzuJ_v5r3r0irFYlp75W7CuwVVIZcGVh3NinwQuK1C2b1LoDRXPYQAksj0FHf_-M4La-t3sx9Psz9KVZS0_sBRnaLACaX613iyTQQhih75XdF_pPJEAk2i-FODvFlywaVITn6aft6Q15ba2Ns3pXBxHC2xmNtXTD_A-6ItDo5h6ged6uE_tMUOI37hpmT56mqHGM2MKeKS1FWltKG04Q7a4IqAFtbOqIfm7NQng2OGTH8n35QamnvpNClsHXj-LU
36
+
37
+ LSID=DQAAAOgAAACmOK2Tz82DjgQCZsSyl3BBXyBrE_FRnJ1kX_b2--FxR41rFaDLrF7vZCVQRbYj6umr8m2k16XSHyRGC0OHAEN4ordG7pi3gVFePuPLGStA_0TXdR6kAD0E8XeuEiEo4jU2QOZUhNdUEsYJ2rmvyfCaieKPq28xy2jhxlni3HKe4ys6kCV9nslCcvpmgXGPtTe1MJJ_GhRgIwfh3Xp9JsP87tijHw7FK8n5rhZCuxtYWlMXZGXuTtWD_NsqcJ8rRLedk6KAsIxTFH_X9IC-3CRvRacRk29Wc6Ccv2YEMQWm5qq9WgrXkTcoQzdt-aY1JM0
38
+
39
+ Auth=DQAAAOkAAACmOK2Tz82DjgQCZsSyl3BBXyBrE_FRnJ1kX_b2--FxR41rFaDLrF7vZCVQRbYj6uluQDfTwKQVZT7NBybM4B5pq3iIBq-B7igOAeC3hfBQGPfE8Q5Lyu9qoAXLYOOkRjNBfydACgdsJxGbCZoggW3Amkh1Js4awD-DXSOVepBGOYiF8hCYiLu3LlwMt1e6EzTbVyOlCyB8aa1HPZDvHTh0VDNBSGSQZtl6dUjp4z1rOfutoNhpl0niywLX974lp0nXm4oqWH0a2ASv1vlZ2t_wbDMe3EVWI42N_DBMCP7t6jscweCZZhbREpjUEcEvgQQ
40
+
41
+ '
42
+ http_version: '1.1'
43
+ - !ruby/struct:VCR::HTTPInteraction
44
+ request: !ruby/struct:VCR::Request
45
+ method: :post
46
+ uri: https://apps-apis.google.com:443/a/feeds/authysec.com/user/2.0
47
+ body: !!null
48
+ headers:
49
+ content-type:
50
+ - application/atom+xml
51
+ authorization:
52
+ - GoogleLogin auth=DQAAAOkAAACmOK2Tz82DjgQCZsSyl3BBXyBrE_FRnJ1kX_b2--FxR41rFaDLrF7vZCVQRbYj6uluQDfTwKQVZT7NBybM4B5pq3iIBq-B7igOAeC3hfBQGPfE8Q5Lyu9qoAXLYOOkRjNBfydACgdsJxGbCZoggW3Amkh1Js4awD-DXSOVepBGOYiF8hCYiLu3LlwMt1e6EzTbVyOlCyB8aa1HPZDvHTh0VDNBSGSQZtl6dUjp4z1rOfutoNhpl0niywLX974lp0nXm4oqWH0a2ASv1vlZ2t_wbDMe3EVWI42N_DBMCP7t6jscweCZZhbREpjUEcEvgQQ
53
+ content-length:
54
+ - '473'
55
+ response: !ruby/struct:VCR::Response
56
+ status: !ruby/struct:VCR::ResponseStatus
57
+ code: 201
58
+ message: Created
59
+ headers:
60
+ content-type:
61
+ - application/atom+xml; charset=UTF-8
62
+ expires:
63
+ - Sat, 26 Nov 2011 20:35:17 GMT
64
+ date:
65
+ - Sat, 26 Nov 2011 20:35:17 GMT
66
+ cache-control:
67
+ - private, max-age=0, must-revalidate, no-transform
68
+ vary:
69
+ - Accept, X-GData-Authorization, GData-Version
70
+ gdata-version:
71
+ - '1.0'
72
+ location:
73
+ - https://apps-apis.google.com/a/feeds/authysec.com/user/2.0/josmith
74
+ content-location:
75
+ - https://apps-apis.google.com/a/feeds/authysec.com/user/2.0/josmith
76
+ x-content-type-options:
77
+ - nosniff
78
+ x-frame-options:
79
+ - SAMEORIGIN
80
+ x-xss-protection:
81
+ - 1; mode=block
82
+ server:
83
+ - GSE
84
+ transfer-encoding:
85
+ - chunked
86
+ body: <?xml version='1.0' encoding='UTF-8'?><entry xmlns='http://www.w3.org/2005/Atom'
87
+ xmlns:apps='http://schemas.google.com/apps/2006' xmlns:gd='http://schemas.google.com/g/2005'><id>https://apps-apis.google.com/a/feeds/authysec.com/user/2.0/josmith</id><updated>1970-01-01T00:00:00.000Z</updated><category
88
+ scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/apps/2006#user'/><title
89
+ type='text'>josmith</title><link rel='self' type='application/atom+xml' href='https://apps-apis.google.com/a/feeds/authysec.com/user/2.0/josmith'/><link
90
+ rel='edit' type='application/atom+xml' href='https://apps-apis.google.com/a/feeds/authysec.com/user/2.0/josmith'/><apps:login
91
+ userName='josmith' suspended='false' ipWhitelisted='false' admin='false' changePasswordAtNextLogin='true'
92
+ agreedToTerms='false'/><apps:quota limit='7168'/><apps:name familyName='smith'
93
+ givenName='john'/><gd:feedLink rel='http://schemas.google.com/apps/2006#user.nicknames'
94
+ href='https://apps-apis.google.com/a/feeds/authysec.com/nickname/2.0?username=josmith'/><gd:feedLink
95
+ rel='http://schemas.google.com/apps/2006#user.emailLists' href='https://apps-apis.google.com/a/feeds/authysec.com/emailList/2.0?recipient=josmith%40authysec.com'/></entry>
96
+ http_version: '1.1'
@@ -0,0 +1,882 @@
1
+ #!/usr/bin/ruby
2
+ # == Google Apps Provisioning API client library
3
+ #
4
+ # This library allows you to manage your domain (accounts, email lists, aliases) within your Ruby code.
5
+ # It's based on the GDATA provisioning API v2.0.
6
+ # Reference : http://code.google.com/apis/apps/gdata_provisioning_api_v2.0_reference.html.
7
+ #
8
+ # All the public methods with _ruby_style_ names are aliased with _javaStyle_ names. Ex : create_user and createUser.
9
+ #
10
+ # Notice : because it uses REXML, your script using this library MUST be encoded in unicode (UTF-8).
11
+ #
12
+ # == Examples
13
+ #
14
+ # #!/usr/bin/ruby
15
+ # require 'provisioning-api/provisioningapi'
16
+ # include provisioning-api
17
+ # adminuser = "root@mydomain.com"
18
+ # password = "PaSsWo4d!"
19
+ # myapps = ProvisioningApi.new(adminuser,password)
20
+ # (see examples in ProvisioningApi.new documentation for handling proxies)
21
+ #
22
+ # new_user = myapps.create_user("jsmith", "john", "smith", "secret", nil, "2048")
23
+ # puts new_user.family_name
24
+ # puts new_user.given_name
25
+ #
26
+ # Want to update a user ?
27
+ #
28
+ # user = myapps.retrieve_user('jsmith')
29
+ # user_updated = myapps.update_user(user.username, user.given_name, user.family_name, nil, nil, "true")
30
+ #
31
+ # Want to add an alias or nickname ?
32
+ #
33
+ # new_nickname = myapps.create_nickname("jsmith", "john.smith")
34
+ #
35
+ # Want to manage groups ? (i.e. mailing lists)
36
+ #
37
+ # new_group = myapps.create_group("sales-dep", ['Sales Departement'])
38
+ # new_member = myapps.add_member_to_group("jsmith", "sales-dep")
39
+ # new_owner = myapps.add_owner_to_group("jsmith", "sales-dep")
40
+ # (ATTENTION: an owner is added only if it's already member of the group!)
41
+ #
42
+ # Want to handle errors ?
43
+ #
44
+ # begin
45
+ # user = myapps.retrieve_user('noone')
46
+ # puts "givenName : "+user.given_name, "familyName : "+user.family_name, "username : "+user.username"
47
+ # puts "admin ? : "+user.admin
48
+ # rescue GDataError => e
49
+ # puts "errorcode = " +e.code, "input : "+e.input, "reason : "+e.reason
50
+ # end
51
+ #
52
+ # Email lists (deprecated) ?
53
+ #
54
+ # new_list = myapps.create_email_list("sales-dep")
55
+ # new_address = myapps.add_address_to_email_list("sales-dep", "bibi@ruby-forge.org")
56
+ #
57
+ # All methods described in the provisioning-api::ProvisioningApi class documentation.
58
+ #
59
+ # Authors :: Jérôme Bousquié, Roberto Cerigato
60
+ # Ruby version :: from 1.8.6
61
+ # Licence :: Apache Licence, version 2
62
+ #
63
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may not
64
+ # use this file except in compliance with the License. You may obtain a copy of
65
+ # the License at
66
+ #
67
+ # http://www.apache.org/licenses/LICENSE-2.0
68
+ #
69
+ # Unless required by applicable law or agreed to in writing, software
70
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
71
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
72
+ # License for the specific language governing permissions and limitations under
73
+ # the License.
74
+ #
75
+
76
+ require 'cgi'
77
+ require 'rexml/document'
78
+
79
+ require 'provisioning-api/connection'
80
+ require 'provisioning-api/exceptions'
81
+
82
+ include REXML
83
+
84
+
85
+
86
+ module GAppsProvisioning #:nodoc:
87
+
88
+ # =Administrative object for accessing your domain
89
+ # Examples
90
+ #
91
+ # adminuser = "root@mydomain.com"
92
+ # password = "PaSsWo4d!"
93
+ # myapps = ProvisioningApi.new(adminuser,password)
94
+ # (see examples in ProvisioningApi.new documentation for handling proxies)
95
+ #
96
+ # new_user = myapps.create_user("jsmith", "john", "smith", "secret", nil, "2048")
97
+ # puts new_user.family_name
98
+ # puts new_user.given_name
99
+ #
100
+ # Want to update a user ?
101
+ #
102
+ # user = myapps.retrieve_user('jsmith')
103
+ # user_updated = myapps.update_user(user.username, user.given_name, user.family_name, nil, nil, "true")
104
+ #
105
+ # Want to add an alias or nickname ?
106
+ #
107
+ # new_nickname = myapps.create_nickname("jsmith", "john.smith")
108
+ #
109
+ # Want to manage groups ? (i.e. mailing lists)
110
+ #
111
+ # new_group = myapps.create_group("sales-dep", ['Sales Departement'])
112
+ # new_member1 = myapps.add_member_to_group("john.doe@somedomain.com", "sales-dep")
113
+ # new_member2 = myapps.add_member_to_group("jsmith", "sales-dep")
114
+ # new_owner = myapps.add_owner_to_group("jsmith", "sales-dep")
115
+ # (ATTENTION: an owner is added only if it's already member of the group!)
116
+ #
117
+ #
118
+ # Want to handle errors ?
119
+ #
120
+ # begin
121
+ # user = myapps.retrieve_user('noone')
122
+ # puts "givenName : "+user.given_name, "familyName : "+user.family_name, "username : "+user.username"
123
+ # puts "admin ? : "+user.admin
124
+ # rescue GDataError => e
125
+ # puts "errorcode = " +e.code, "input : "+e.input, "reason : "+e.reason
126
+ # end
127
+ #
128
+ #
129
+
130
+
131
+
132
+ class ProvisioningApi
133
+ @@google_host = 'apps-apis.google.com'
134
+ @@google_port = 443
135
+ # authentication token, valid up to 24 hours after the last connection
136
+ attr_reader :token
137
+
138
+
139
+ # Creates a new ProvisioningApi object
140
+ #
141
+ # mail : Google Apps domain administrator e-mail (string)
142
+ # passwd : Google Apps domain administrator password (string)
143
+ # proxy : (optional) host name, or IP, of the proxy (string)
144
+ # proxy_port : (optional) proxy port number (numeric)
145
+ # proxy_user : (optional) login for authenticated proxy only (string)
146
+ # proxy_passwd : (optional) password for authenticated proxy only (string)
147
+ #
148
+ # The domain name is extracted from the mail param value.
149
+ #
150
+ # Examples :
151
+ # standard : no proxy
152
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
153
+ # proxy :
154
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd','domain.proxy.com',8080)
155
+ # authenticated proxy :
156
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd','domain.proxy.com',8080,'foo','bAr')
157
+ def initialize(mail, passwd, proxy=nil, proxy_port=nil, proxy_user=nil, proxy_passwd=nil)
158
+ domain = mail.split('@')[1]
159
+ @action = setup_actions(domain)
160
+ conn = Connection.new(@@google_host, @@google_port, proxy, proxy_port, proxy_user, proxy_passwd)
161
+ @connection = conn
162
+ @token = login(mail, passwd)
163
+ @headers = {'Content-Type'=>'application/atom+xml', 'Authorization'=> 'GoogleLogin auth='+token}
164
+ return @connection
165
+ end
166
+
167
+
168
+
169
+ # Returns a UserEntry instance from a username
170
+ # ex :
171
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
172
+ # user = myapps.retrieve_user('jsmith')
173
+ # puts "givenName : "+user.given_name
174
+ # puts "familyName : "+user.family_name
175
+ def retrieve_user(username)
176
+ xml_response = request(:user_retrieve, username, @headers)
177
+ user_entry = UserEntry.new(xml_response.elements["entry"])
178
+ end
179
+
180
+ # Returns a UserEntry array populated with all the users in the domain. May take a while depending on the number of users in your domain.
181
+ # ex :
182
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
183
+ # list= myapps.retrieve_all_users
184
+ # list.each{ |user| puts user.username}
185
+ # puts 'nb users : ',list.size
186
+ def retrieve_all_users
187
+ response = request(:user_retrieve_all,nil,@headers)
188
+ user_feed = Feed.new(response.elements["feed"], UserEntry)
189
+ user_feed = add_next_feeds(user_feed, response, UserEntry)
190
+ end
191
+
192
+ # Returns a UserEntry array populated with 100 users, starting from a username
193
+ # ex :
194
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
195
+ # list= myapps.retrieve_page_of_users("jsmtih")
196
+ # list.each{ |user| puts user.username}
197
+ def retrieve_page_of_users(start_username)
198
+ param='?startUsername='+start_username
199
+ response = request(:user_retrieve_all,param,@headers)
200
+ user_feed = Feed.new(response.elements["feed"], UserEntry)
201
+ end
202
+
203
+ # Creates an account in your domain, returns a UserEntry instance
204
+ # params :
205
+ # username, given_name, family_name and password are required
206
+ # passwd_hash_function (optional) : nil (default) or "SHA-1"
207
+ # quota (optional) : nil (default) or integer for limit in MB
208
+ # ex :
209
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
210
+ # user = myapps.create('jsmith', 'John', 'Smith', 'p455wD')
211
+ #
212
+ # By default, a new user must change his password at first login. Please use update_user if you want to change this just after the creation.
213
+ def create_user(username, given_name, family_name, password, passwd_hash_function=nil, quota=nil)
214
+ msg = RequestMessage.new
215
+ msg.about_login(username,password,passwd_hash_function,"false","false", "true")
216
+ msg.about_name(family_name, given_name)
217
+ msg.about_quota(quota.to_s) if quota
218
+ response = request(:user_create,nil,@headers, msg.to_s)
219
+ user_entry = UserEntry.new(response.elements["entry"])
220
+ end
221
+
222
+ # Updates an account in your domain, returns a UserEntry instance
223
+ # params :
224
+ # username is required and can't be updated.
225
+ # given_name and family_name are required, may be updated.
226
+ # if set to nil, every other parameter won't update the attribute.
227
+ # passwd_hash_function : string "SHA-1", "MD5" or nil (default)
228
+ # admin : string "true" or string "false" or nil (no boolean : true or false).
229
+ # suspended : string "true" or string "false" or nil (no boolean : true or false)
230
+ # change_passwd : string "true" or string "false" or nil (no boolean : true or false)
231
+ # quota : limit en MB, ex : string "2048"
232
+ # ex :
233
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
234
+ # user = myapps.update('jsmith', 'John', 'Smith', nil, nil, "true", nil, "true", nil)
235
+ # puts user.admin => "true"
236
+ def update_user(username, given_name, family_name, password=nil, passwd_hash_function=nil, admin=nil, suspended=nil, changepasswd=nil, quota=nil)
237
+ msg = RequestMessage.new
238
+ msg.about_login(username,password,passwd_hash_function,admin,suspended, changepasswd)
239
+ msg.about_name(family_name, given_name)
240
+ msg.about_quota(quota) if quota
241
+ msg.add_path('https://'+@@google_host+@action[:user_update][:path]+username)
242
+ response = request(:user_update,username,@headers, msg.to_s)
243
+ user_entry = UserEntry.new(response.elements["entry"])
244
+ end
245
+
246
+ # Renames a user, returns a UserEntry instance
247
+ # ex :
248
+ #
249
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
250
+ # user = myapps.rename_user('jsmith','jdoe')
251
+ #
252
+ # It is recommended to log out rhe user from all browser sessions and service before renaming.
253
+ # Once renamed, the old username becomes a nickname of the new username.
254
+ # Note from Google: Google Talk will lose all remembered chat invitations after renaming.
255
+ # The user must request permission to chat with friends again.
256
+ # Also, when a user is renamed, the old username is retained as a nickname to ensure continuous mail delivery in the case of email forwarding settings.
257
+ # To remove the nickname, you should issue an HTTP DELETE to the nicknames feed after renaming.
258
+ def rename_user(username, new_username)
259
+ msg = RequestMessage.new
260
+ msg.about_login(new_username)
261
+ msg.add_path('https://'+@@google_host+@action[:user_rename][:path]+username)
262
+ response = request(:user_update,username,@headers, msg.to_s)
263
+ end
264
+
265
+ # Suspends an account in your domain, returns a UserEntry instance
266
+ # ex :
267
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
268
+ # user = myapps.suspend('jsmith')
269
+ # puts user.suspended => "true"
270
+ def suspend_user(username)
271
+ msg = RequestMessage.new
272
+ msg.about_login(username,nil,nil,nil,"true")
273
+ msg.add_path('https://'+@@google_host+@action[:user_update][:path]+username)
274
+ response = request(:user_update,username,@headers, msg.to_s)
275
+ user_entry = UserEntry.new(response.elements["entry"])
276
+ end
277
+
278
+ # Restores a suspended account in your domain, returns a UserEntry instance
279
+ # ex :
280
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
281
+ # user = myapps.restore('jsmith')
282
+ # puts user.suspended => "false"
283
+ def restore_user(username)
284
+ msg = RequestMessage.new
285
+ msg.about_login(username,nil,nil,nil,"false")
286
+ msg.add_path('https://'+@@google_host+@action[:user_update][:path]+username)
287
+ response = request(:user_update,username,@headers, msg.to_s)
288
+ user_entry = UserEntry.new(response.elements["entry"])
289
+ end
290
+
291
+ # Deletes an account in your domain
292
+ # ex :
293
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
294
+ # myapps.delete('jsmith')
295
+ def delete_user(username)
296
+ response = request(:user_delete,username,@headers)
297
+ end
298
+
299
+ # Returns a NicknameEntry instance from a nickname
300
+ # ex :
301
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
302
+ # nickname = myapps.retrieve_nickname('jsmith')
303
+ # puts "login : "+nickname.login
304
+ def retrieve_nickname(nickname)
305
+ xml_response = request(:nickname_retrieve, nickname, @headers)
306
+ nickname_entry = NicknameEntry.new(xml_response.elements["entry"])
307
+ end
308
+
309
+ # Returns a NicknameEntry array from a username
310
+ # ex : lists jsmith's nicknames
311
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
312
+ # mynicks = myapps.retrieve('jsmith')
313
+ # mynicks.each {|nick| puts nick.nickname }
314
+ def retrieve_nicknames(username)
315
+ xml_response = request(:nickname_retrieve_all_for_user, username, @headers)
316
+ nicknames_feed = Feed.new(xml_response.elements["feed"], NicknameEntry)
317
+ nicknames_feed = add_next_feeds(nicknames_feed, xml_response, NicknameEntry)
318
+ end
319
+
320
+ # Returns a NicknameEntry array for the whole domain. May take a while depending on the number of users in your domain.
321
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
322
+ # allnicks = myapps.retrieve_all_nicknames
323
+ # allnicks.each {|nick| puts nick.nickname }
324
+ def retrieve_all_nicknames
325
+ xml_response = request(:nickname_retrieve_all_in_domain, nil, @headers)
326
+ nicknames_feed = Feed.new(xml_response.elements["feed"], NicknameEntry)
327
+ nicknames_feed = add_next_feeds(nicknames_feed, xml_response, NicknameEntry)
328
+ end
329
+
330
+ # Creates a nickname for the username in your domain and returns a NicknameEntry instance
331
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
332
+ # mynewnick = myapps.create_nickname('jsmith', 'john.smith')
333
+ def create_nickname(username,nickname)
334
+ msg = RequestMessage.new
335
+ msg.about_login(username)
336
+ msg.about_nickname(nickname)
337
+ response = request(:nickname_create,nil,@headers, msg.to_s)
338
+ nickname_entry = NicknameEntry.new(response.elements["entry"])
339
+ end
340
+
341
+ # Deletes the nickname in your domain
342
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
343
+ # myapps.delete_nickname('john.smith')
344
+ def delete_nickname(nickname)
345
+ response = request(:nickname_delete,nickname,@headers)
346
+ end
347
+
348
+ # Returns a NicknameEntry array populated with 100 nicknames, starting from a nickname
349
+ # ex :
350
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
351
+ # list= myapps.retrieve_page_of_nicknames("joe")
352
+ # list.each{ |nick| puts nick.login}
353
+ def retrieve_page_of_nicknames(start_nickname)
354
+ param='?startNickname='+start_nickname
355
+ xml_response = request(:nickname_retrieve_all_in_domain, param, @headers)
356
+ nicknames_feed = Feed.new(xml_response.elements["feed"], NicknameEntry)
357
+ end
358
+
359
+ # Deprecated. Please use Group management instead.
360
+ def retrieve_email_lists(email_adress)
361
+ puts("retrieve_email_lists : deprecated. Please use Group management instead.")
362
+ end
363
+
364
+ # Deprecated. Please use Group management instead.
365
+ def retrieve_all_email_lists
366
+ puts("retrieve_all_email_lists : deprecated. Please use Group management instead.")
367
+ end
368
+
369
+ # Deprecated. Please use Group management instead.
370
+ def retrieve_page_of_email_lists(start_listname)
371
+ puts("retrieve_page_of_email_lists : deprecated. Please use Group management instead.")
372
+ end
373
+
374
+ # Deprecated. Please use Group management instead.
375
+ def create_email_list(name)
376
+ puts("create_email_list : deprecated. Please use Group management instead.")
377
+ end
378
+
379
+ # Deprecated. Please use Group management instead.
380
+ def delete_email_list(name)
381
+ puts("delete_email_list : deprecated. Please use Group management instead.")
382
+ end
383
+
384
+ # Deprecated. Please use Group management instead.
385
+ def retrieve_all_recipients(email_list)
386
+ puts("retrieve_all_recipients : deprecated. Please use Group management instead.")
387
+ end
388
+
389
+ # Deprecated. Please use Group management instead.
390
+ def retrieve_page_of_recipients(email_list, start_recipient)
391
+ puts("Deprecated. Please use Group management instead.")
392
+ end
393
+
394
+ # Deprecated. Please use Group management instead.
395
+ def add_address_to_email_list(email_list,address)
396
+ puts("add_address_to_email_list : deprecated. Please use Group management instead.")
397
+ end
398
+
399
+ # Deprecated. Please use Group management instead.
400
+ def remove_address_from_email_list(address,email_list)
401
+ puts("remove_address_from_email_list : deprecated. Please use Group management instead.")
402
+ end
403
+
404
+ # Creates a group in your domain and returns a GroupEntry (ATTENTION: the group name is necessary!).
405
+ # ex :
406
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
407
+ # group= myapps.create_group("mygroup", ["My Group name", "My Group description", "<emailPermission>"])
408
+ def create_group(group_id, properties)
409
+ msg = RequestMessage.new
410
+ msg.about_group(group_id, properties)
411
+ response = request(:group_create, nil, @headers, msg.to_s)
412
+ group_entry = GroupEntry.new(response.elements["entry"])
413
+ end
414
+
415
+ # Updates a group in your domain and returns a GroupEntry (ATTENTION: the group name is necessary!).
416
+ # ex :
417
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
418
+ # group= myapps.update_group("mygroup", ["My Group name", "My Group description", "<emailPermission>"])
419
+ def update_group(group_id, properties)
420
+ msg = RequestMessage.new
421
+ msg.about_group(group_id, properties)
422
+ response = request(:group_update, group_id, @headers, msg.to_s)
423
+ group_entry = GroupEntry.new(response.elements["entry"])
424
+ end
425
+
426
+ # Deletes a group in your domain.
427
+ # ex :
428
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
429
+ # myapps.delete_group("mygroup")
430
+ def delete_group(group_id)
431
+ response = request(:group_delete,group_id,@headers)
432
+ end
433
+
434
+ # Returns a GroupEntry array for a particular member of the domain (ATTENTION: it doesn't work for members of other domains!).
435
+ # The user parameter can be a complete email address or can be written without "@mydomain.com".
436
+ # ex :
437
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
438
+ # mylists = myapps.retrieve_groups('jsmith') # you can search for 'jsmith@mydomain.com' too
439
+ # mylists.each {|list| puts list.group_id }
440
+ def retrieve_groups(user)
441
+ xml_response = request(:groups_retrieve, user, @headers)
442
+ list_feed = Feed.new(xml_response.elements["feed"], GroupEntry)
443
+ list_feed = add_next_feeds(list_feed, xml_response, GroupEntry)
444
+ end
445
+
446
+ # Returns a GroupEntry array for the whole domain.
447
+ # ex :
448
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
449
+ # all_lists = myapps.retrieve_all_groups
450
+ # all_lists.each {|list| puts list.group_id }
451
+ def retrieve_all_groups
452
+ xml_response = request(:all_groups_retrieve, nil, @headers)
453
+ list_feed = Feed.new(xml_response.elements["feed"], GroupEntry)
454
+ list_feed = add_next_feeds(list_feed, xml_response, GroupEntry)
455
+ end
456
+
457
+ # Adds an email address (user or group) to a mailing list in your domain and returns a MemberEntry instance.
458
+ # You can add addresses from other domains to your mailing list. Omit "@mydomain.com" in the group name.
459
+ # ex :
460
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
461
+ # new_member = myapps.add_member_to_group('example@otherdomain.com', 'mygroup')
462
+ def add_member_to_group(email_address, group_id)
463
+ msg = RequestMessage.new
464
+ msg.about_member(email_address)
465
+ response = request(:membership_add, group_id+'/member', @headers, msg.to_s)
466
+ member_entry = MemberEntry.new(response.elements["entry"])
467
+ end
468
+
469
+ # Removes an email address (user or group) from a mailing list. Omit "@mydomain.com" in the group name.
470
+ # ex :
471
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
472
+ # myapps.remove_member_from_group('example@otherdomain.com', 'mygroup')
473
+ def remove_member_from_group(email_address, group_id)
474
+ response = request(:membership_remove, group_id+'/member/'+email_address,@headers)
475
+ end
476
+
477
+ # Returns true if the email address (user or group) is member of the group, false otherwise.
478
+ # ex :
479
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
480
+ # boolean = myapps.is_member('example@otherdomain.com', 'mylist')
481
+ def is_member(email_address, group_id)
482
+ xml_response = request(:membership_confirm, group_id+'/member/'+email_address, @headers)
483
+ # if the email_address is not member of the group, an error is raised, otherwise true is returned
484
+ return true
485
+
486
+ rescue GDataError => e
487
+ return false if e.reason.eql?("EntityDoesNotExist")
488
+ end
489
+
490
+ # Returns a MemberEntry array with the members of a group.
491
+ # ex :
492
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
493
+ # list = myapps.retrieve_all_members('mygroup')
494
+ # lists.each {|list| puts list.member_id }
495
+ def retrieve_all_members(group_id)
496
+ xml_response = request(:all_members_retrieve, group_id+'/member', @headers)
497
+ list_feed = Feed.new(xml_response.elements["feed"], MemberEntry)
498
+ list_feed = add_next_feeds(list_feed, xml_response, MemberEntry)
499
+ end
500
+
501
+ # Adds a owner (user or group) to a mailing list in your domain and returns a OwnerEntry instance.
502
+ # You can add addresses from other domains to your mailing list. Omit "@mydomain.com" in the group name.
503
+ # ATTENTION: a owner is added only if it's already member of the group, otherwise no action is done!
504
+ # ex :
505
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
506
+ # new_member = myapps.add_owner_to_group('example@otherdomain.com', 'mygroup')
507
+ def add_owner_to_group(email_address, group_id)
508
+ msg = RequestMessage.new
509
+ msg.about_owner(email_address)
510
+ response = request(:ownership_add, group_id+'/owner', @headers, msg.to_s)
511
+ owner_entry = OwnerEntry.new(response.elements["entry"])
512
+ end
513
+
514
+ # Removes an owner from a mailing list. Omit "@mydomain.com" in the group name.
515
+ # ATTENTION: when a owner is removed, it loses the privileges but still remains member of the group!
516
+ # ex :
517
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
518
+ # myapps.remove_owner_from_group('example@otherdomain.com', 'mygroup')
519
+ def remove_owner_from_group(email_address, group_id)
520
+ response = request(:ownership_remove, group_id+'/owner/'+email_address,@headers)
521
+ end
522
+
523
+ # Returns true if the email address (user or group) is owner of the group, false otherwise.
524
+ # ex :
525
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
526
+ # boolean = myapps.is_owner('example@otherdomain.com', 'mylist')
527
+ def is_owner(email_address, group_id)
528
+ xml_response = request(:ownership_confirm, group_id+'/owner/'+email_address, @headers)
529
+ # if the email_address is not member of the group, an error is raised, otherwise true is returned
530
+ return true
531
+
532
+ rescue GDataError => e
533
+ return false if e.reason.eql?("EntityDoesNotExist")
534
+ end
535
+
536
+ # Returns a OwnerEntry array with the owners of a group.
537
+ # ex :
538
+ # myapps = ProvisioningApi.new('root@mydomain.com','PaSsWoRd')
539
+ # list = myapps.retrieve_all_owners('mygroup')
540
+ # lists.each {|list| puts list.owner_id }
541
+ def retrieve_all_owners(group_id)
542
+ xml_response = request(:all_owners_retrieve, group_id+'/owner', @headers)
543
+ list_feed = Feed.new(xml_response.elements["feed"], OwnerEntry)
544
+ list_feed = add_next_feeds(list_feed, xml_response, OwnerEntry)
545
+ end
546
+
547
+ # Aliases
548
+ alias createUser create_user
549
+ alias retrieveUser retrieve_user
550
+ alias retrieveAllUsers retrieve_all_users
551
+ alias retrievePageOfUsers retrieve_page_of_users
552
+ alias updateUser update_user
553
+ alias renameUser rename_user
554
+ alias suspendUser suspend_user
555
+ alias restoreUser restore_user
556
+ alias deleteUser delete_user
557
+ alias createNickname create_nickname
558
+ alias retrieveNickname retrieve_nickname
559
+ alias retrieveNicknames retrieve_nicknames
560
+ alias retrieveAllNicknames retrieve_all_nicknames
561
+ alias retrievePageOfNicknames retrieve_page_of_nicknames
562
+ alias deleteNickname delete_nickname
563
+ alias retrieveAllRecipients retrieve_all_recipients
564
+ alias retrievePageOfRecipients retrieve_page_of_recipients
565
+ alias removeRecipientFromEmailList remove_address_from_email_list
566
+ alias createGroup create_group
567
+ alias updateGroup update_group
568
+ alias deleteGroup delete_group
569
+ alias retrieveGroups retrieve_groups
570
+ alias retrieveAllGroups retrieve_all_groups
571
+ alias addMemberToGroup add_member_to_group
572
+ alias removeMemberFromGroup remove_member_from_group
573
+ alias isMember is_member
574
+ alias retrieveAllMembers retrieve_all_members
575
+ alias addOwnerToGroup add_owner_to_group
576
+ alias removeOwnerFromGroup remove_owner_from_group
577
+ alias isOwner is_owner
578
+ alias retrieveAllOwners retrieve_all_owners
579
+
580
+
581
+ # private methods
582
+ private #:nodoc:
583
+
584
+ # Associates methods, http verbs and URL for REST access
585
+ def setup_actions(domain)
586
+ path_user = '/a/feeds/'+domain+'/user/2.0'
587
+ path_nickname = '/a/feeds/'+domain+'/nickname/2.0'
588
+ path_group = '/a/feeds/group/2.0/'+domain # path for Google groups
589
+
590
+ action = Hash.new
591
+ action[:domain_login] = {:method => 'POST', :path => '/accounts/ClientLogin' }
592
+ action[:user_create] = { :method => 'POST', :path => path_user }
593
+ action[:user_retrieve] = { :method => 'GET', :path => path_user+'/' }
594
+ action[:user_retrieve_all] = { :method => 'GET', :path => path_user }
595
+ action[:user_update] = { :method => 'PUT', :path => path_user +'/' }
596
+ action[:user_rename] = { :method => 'PUT', :path => path_user +'/' }
597
+ action[:user_delete] = { :method => 'DELETE', :path => path_user +'/' }
598
+ action[:nickname_create] = { :method => 'POST', :path =>path_nickname }
599
+ action[:nickname_retrieve] = { :method => 'GET', :path =>path_nickname+'/' }
600
+ action[:nickname_retrieve_all_for_user] = { :method => 'GET', :path =>path_nickname+'?username=' }
601
+ action[:nickname_retrieve_all_in_domain] = { :method => 'GET', :path =>path_nickname }
602
+ action[:nickname_delete] = { :method => 'DELETE', :path =>path_nickname+'/' }
603
+ action[:group_create] = { :method => 'POST', :path =>path_group }
604
+ action[:group_update] = { :method => 'PUT', :path =>path_group+'/' }
605
+ action[:group_delete] = { :method => 'DELETE', :path =>path_group+'/' }
606
+ action[:groups_retrieve] = { :method => 'GET', :path =>path_group+'?member=' }
607
+ action[:all_groups_retrieve] = { :method => 'GET', :path =>path_group }
608
+ action[:membership_add] = { :method => 'POST', :path =>path_group+'/' }
609
+ action[:membership_remove] = { :method => 'DELETE', :path =>path_group+'/' }
610
+ action[:membership_confirm] = { :method => 'GET', :path =>path_group+'/' }
611
+ action[:all_members_retrieve] = { :method => 'GET', :path =>path_group+'/' }
612
+ action[:ownership_add] = { :method => 'POST', :path =>path_group+'/' }
613
+ action[:ownership_remove] = { :method => 'DELETE', :path =>path_group+'/' }
614
+ action[:ownership_confirm] = { :method => 'GET', :path =>path_group+'/' }
615
+ action[:all_owners_retrieve] = { :method => 'GET', :path =>path_group+'/' }
616
+
617
+ # special action "next" for linked feed results. :path will be affected with URL received in a link tag.
618
+ action[:next] = {:method => 'GET', :path =>nil }
619
+ return action
620
+ end
621
+
622
+ # Sends credentials and returns an authentication token
623
+ def login(mail, passwd)
624
+ request_body = '&Email='+CGI.escape(mail)+'&Passwd='+CGI.escape(passwd)+'&accountType=HOSTED&service=apps'
625
+ res = request(:domain_login, nil, {'Content-Type'=>'application/x-www-form-urlencoded'}, request_body)
626
+ return /^Auth=(.+)$/.match(res.to_s)[1]
627
+ # res.to_s needed, because res.class is REXML::Document
628
+ end
629
+
630
+
631
+ # Completes the feed by following et requesting the URL links
632
+ def add_next_feeds(current_feed, xml_content, element_class)
633
+ xml_content.elements.each("feed/link") {|link|
634
+ if link.attributes["rel"] == "next"
635
+ @action[:next] = {:method => 'GET', :path=> link.attributes["href"]}
636
+ next_response = request(:next,nil,@headers)
637
+ current_feed.concat(Feed.new(next_response.elements["feed"], element_class))
638
+ current_feed = add_next_feeds(current_feed, next_response, element_class)
639
+ end
640
+ }
641
+ return current_feed
642
+ end
643
+
644
+ # Perfoms a REST request based on the action hash (cf setup_actions)
645
+ # ex : request (:user_retrieve, 'jsmith') sends a http GET www.google.com/a/feeds/domain/user/2.0/jsmith
646
+ # returns REXML Document
647
+ def request(action, value=nil, header=nil, message=nil)
648
+ #param value : value to be concatenated to action path ex: GET host/path/value
649
+ method = @action[action][:method]
650
+ value = '' if !value
651
+ path = @action[action][:path]+value
652
+ response = @connection.perform(method, path, message, header)
653
+ response_xml = Document.new(response.body)
654
+ test_errors(response_xml)
655
+ return response_xml
656
+ end
657
+
658
+ # parses xml response for an API error tag. If an error, constructs and raises a GDataError.
659
+ def test_errors(xml)
660
+ error = xml.elements["AppsForYourDomainErrors/error"]
661
+ if error
662
+ gdata_error = GDataError.new
663
+ gdata_error.code = error.attributes["errorCode"]
664
+ gdata_error.input = error.attributes["invalidInput"]
665
+ gdata_error.reason = error.attributes["reason"]
666
+ msg = "error code : "+gdata_error.code+", invalid input : "+gdata_error.input+", reason : "+gdata_error.reason
667
+ raise gdata_error, msg
668
+ end
669
+ #in case the domain is not configured to use google apps
670
+ error = xml.elements['HTML']
671
+ if(error)
672
+ gdata_error = GDataError.new
673
+ msg = /.*<TITLE>(.*)<\/TITLE>.*/.match(error.to_s)
674
+ raise gdata_error, msg[1]
675
+ end
676
+
677
+ end
678
+ end
679
+
680
+
681
+ # UserEntry object.
682
+ #
683
+ # Handles API responses relative to a user
684
+ #
685
+ # Attributes :
686
+ # username : string
687
+ # given_name : string
688
+ # family_name : string
689
+ # suspended : string "true" or string "false"
690
+ # ip_whitelisted : string "true" or string "false"
691
+ # admin : string "true" or string "false"
692
+ # change_password_at_next_login : string "true" or string "false"
693
+ # agreed_to_terms : string "true" or string "false"
694
+ # quota_limit : string (value in MB)
695
+ class UserEntry
696
+ attr_reader :given_name, :family_name, :username, :suspended, :ip_whitelisted, :admin, :change_password_at_next_login, :agreed_to_terms, :quota_limit
697
+
698
+ # UserEntry constructor. Needs a REXML::Element <entry> as parameter
699
+ def initialize(entry) #:nodoc:
700
+ @family_name = entry.elements["apps:name"].attributes["familyName"]
701
+ @given_name = entry.elements["apps:name"].attributes["givenName"]
702
+ @username = entry.elements["apps:login"].attributes["userName"]
703
+ @suspended = entry.elements["apps:login"].attributes["suspended"]
704
+ @ip_whitelisted = entry.elements["apps:login"].attributes["ipWhitelisted"]
705
+ @admin = entry.elements["apps:login"].attributes["admin"]
706
+ @change_password_at_next_login = entry.elements["apps:login"].attributes["changePasswordAtNextLogin"]
707
+ @agreed_to_terms = entry.elements["apps:login"].attributes["agreedToTerms"]
708
+ @quota_limit = entry.elements["apps:quota"].attributes["limit"]
709
+ end
710
+ end
711
+
712
+
713
+ # NicknameEntry object.
714
+ #
715
+ # Handles API responses relative to a nickname
716
+ #
717
+ # Attributes :
718
+ # login : string
719
+ # nickname : string
720
+ class NicknameEntry
721
+ attr_reader :login, :nickname
722
+
723
+ # NicknameEntry constructor. Needs a REXML::Element <entry> as parameter
724
+ def initialize(entry) #:nodoc:
725
+ @login = entry.elements["apps:login"].attributes["userName"]
726
+ @nickname = entry.elements["apps:nickname"].attributes["name"]
727
+ end
728
+ end
729
+
730
+
731
+ # UserFeed object : Array populated with Element_class objects (UserEntry, NicknameEntry, EmailListEntry or EmailListRecipientEntry)
732
+ class Feed < Array #:nodoc:
733
+
734
+ # UserFeed constructor. Populates an array with Element_class objects. Each object is an xml <entry> parsed from the REXML::Element <feed>.
735
+ # Ex : user_feed = Feed.new(xml_feed, UserEntry)
736
+ # nickname_feed = Feed.new(xml_feed, NicknameEntry)
737
+ def initialize(xml_feed, element_class)
738
+ xml_feed.elements.each("entry"){ |entry| self << element_class.new(entry) }
739
+ end
740
+ end
741
+
742
+
743
+
744
+ # GroupEntry object.
745
+ #
746
+ # Handles API responses relative to a group.
747
+ #
748
+ # Attributes :
749
+ # group_id : string . The group_id is written without "@" and everything following.
750
+ class GroupEntry
751
+ attr_reader :group_id
752
+
753
+ # GroupEntry constructor. Needs a REXML::Element <entry> as parameter
754
+ def initialize(entry) #:nodoc:
755
+ entry.elements.each("apps:property"){ |e| @group_id = e.attributes["value"] if e.attributes["name"].eql?("groupId") }
756
+ end
757
+ end
758
+
759
+
760
+ # MemberEntry object.
761
+ #
762
+ # Handles API responses relative to a meber of a group.
763
+ #
764
+ # Attributes :
765
+ # member_id : string . The member_id is a complete email address.
766
+ class MemberEntry
767
+ attr_reader :member_id
768
+
769
+ # MemberEntry constructor. Needs a REXML::Element <entry> as parameter
770
+ def initialize(entry) #:nodoc:
771
+ entry.elements.each("apps:property"){ |e| @member_id = e.attributes["value"] if e.attributes["name"].eql?("memberId") }
772
+ end
773
+ end
774
+
775
+
776
+ # OwnerEntry object.
777
+ #
778
+ # Handles API responses relative to a owner of a group.
779
+ #
780
+ # Attributes :
781
+ # owner_id : string . The owner_id is a complete email address.
782
+ class OwnerEntry
783
+ attr_reader :owner_id
784
+
785
+ # OwnerEntry constructor. Needs a REXML::Element <entry> as parameter
786
+ def initialize(entry) #:nodoc:
787
+ entry.elements.each("apps:property"){ |e| @owner_id = e.attributes["value"] if e.attributes["name"].eql?("email") }
788
+ end
789
+ end
790
+
791
+
792
+ class RequestMessage < Document #:nodoc:
793
+ # Request message constructor.
794
+ # parameter type : "user", "nickname" or "emailList"
795
+
796
+ # creates the object and initiates the construction
797
+ def initialize
798
+ super '<?xml version="1.0" encoding="UTF-8"?>'
799
+ self.add_element "atom:entry", {"xmlns:apps" => "http://schemas.google.com/apps/2006",
800
+ "xmlns:gd" => "http://schemas.google.com/g/2005",
801
+ "xmlns:atom" => "http://www.w3.org/2005/Atom"}
802
+ self.elements["atom:entry"].add_element "atom:category", {"scheme" => "http://schemas.google.com/g/2005#kind"}
803
+ end
804
+
805
+ # adds <atom:id> element in the message body. Url is inserted as a text.
806
+ def add_path(url)
807
+ self.elements["atom:entry"].add_element "atom:id"
808
+ self.elements["atom:entry/atom:id"].text = url
809
+ end
810
+
811
+ # adds <apps:emailList> element in the message body.
812
+ def about_email_list(email_list)
813
+ self.elements["atom:entry/atom:category"].add_attribute("term", "http://schemas.google.com/apps/2006#emailList")
814
+ self.elements["atom:entry"].add_element "apps:emailList", {"name" => email_list }
815
+ end
816
+
817
+ # adds <apps:property> element in the message body for a group.
818
+ def about_group(group_id, properties)
819
+ self.elements["atom:entry/atom:category"].add_attribute("term", "http://schemas.google.com/apps/2006#emailList")
820
+ self.elements["atom:entry"].add_element "apps:property", {"name" => "groupId", "value" => group_id }
821
+ self.elements["atom:entry"].add_element "apps:property", {"name" => "groupName", "value" => properties[0] }
822
+ self.elements["atom:entry"].add_element "apps:property", {"name" => "description", "value" => properties[1] }
823
+ self.elements["atom:entry"].add_element "apps:property", {"name" => "emailPermission", "value" => properties[2] }
824
+ end
825
+
826
+ # adds <apps:property> element in the message body for a member.
827
+ def about_member(email_address)
828
+ self.elements["atom:entry/atom:category"].add_attribute("term", "http://schemas.google.com/apps/2006#user")
829
+ self.elements["atom:entry"].add_element "apps:property", {"name" => "memberId", "value" => email_address }
830
+ end
831
+
832
+ # adds <apps:property> element in the message body for an owner.
833
+ def about_owner(email_address)
834
+ self.elements["atom:entry/atom:category"].add_attribute("term", "http://schemas.google.com/apps/2006#user")
835
+ self.elements["atom:entry"].add_element "apps:property", {"name" => "email", "value" => email_address }
836
+ end
837
+
838
+
839
+ # adds <apps:login> element in the message body.
840
+ # warning : if valued admin, suspended, or change_passwd_at_next_login must be the STRINGS "true" or "false", not the boolean true or false
841
+ # when needed to construct the message, should always been used before other "about_" methods so that the category tag can be overwritten
842
+ # only values permitted for hash_function_function_name : "SHA-1", "MD5" or nil
843
+ def about_login(user_name, passwd=nil, hash_function_name=nil, admin=nil, suspended=nil, change_passwd_at_next_login=nil)
844
+ self.elements["atom:entry/atom:category"].add_attribute("term", "http://schemas.google.com/apps/2006#user")
845
+ self.elements["atom:entry"].add_element "apps:login", {"userName" => user_name }
846
+ self.elements["atom:entry/apps:login"].add_attribute("password", passwd) if not passwd.nil?
847
+ self.elements["atom:entry/apps:login"].add_attribute("hashFunctionName", hash_function_name) if not hash_function_name.nil?
848
+ self.elements["atom:entry/apps:login"].add_attribute("admin", admin) if not admin.nil?
849
+ self.elements["atom:entry/apps:login"].add_attribute("suspended", suspended) if not suspended.nil?
850
+ self.elements["atom:entry/apps:login"].add_attribute("changePasswordAtNextLogin", change_passwd_at_next_login) if not change_passwd_at_next_login.nil?
851
+ return self
852
+ end
853
+
854
+ # adds <apps:quota> in the message body.
855
+ # limit in MB: integer
856
+ def about_quota(limit)
857
+ self.elements["atom:entry"].add_element "apps:quota", {"limit" => limit }
858
+ return self
859
+ end
860
+
861
+ # adds <apps:name> in the message body.
862
+ def about_name(family_name, given_name)
863
+ self.elements["atom:entry"].add_element "apps:name", {"familyName" => family_name, "givenName" => given_name }
864
+ return self
865
+ end
866
+
867
+ # adds <apps:nickname> in the message body.
868
+ def about_nickname(name)
869
+ self.elements["atom:entry/atom:category"].add_attribute("term", "http://schemas.google.com/apps/2006#nickname")
870
+ self.elements["atom:entry"].add_element "apps:nickname", {"name" => name}
871
+ return self
872
+ end
873
+
874
+ # adds <gd:who> in the message body.
875
+ def about_who(email)
876
+ self.elements["atom:entry"].add_element "gd:who", {"email" => email }
877
+ return self
878
+ end
879
+
880
+ end
881
+
882
+ end