provisioning-api 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +20 -0
- data/.rvmrc +47 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +25 -0
- data/README.md +80 -0
- data/Rakefile +14 -0
- data/fixtures/vcr_cassettes/create_user.yml +96 -0
- data/lib/provisioning-api.rb +882 -0
- data/lib/provisioning-api/connection.rb +47 -0
- data/lib/provisioning-api/exceptions.rb +19 -0
- data/provisioning-api.gemspec +13 -0
- data/test/test_provisioning_api.rb +32 -0
- metadata +57 -0
data/.gitignore
ADDED
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
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,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
|