/gdata/apps/service.py
Python | 550 lines | 515 code | 14 blank | 21 comment | 0 complexity | 44c79070a2e7cecbf9a377824f72b161 MD5 | raw file
1#!/usr/bin/python 2# 3# Copyright (C) 2007 SIOS Technology, Inc. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17__author__ = 'tmatsuo@sios.com (Takashi MATSUO)' 18 19try: 20 from xml.etree import cElementTree as ElementTree 21except ImportError: 22 try: 23 import cElementTree as ElementTree 24 except ImportError: 25 try: 26 from xml.etree import ElementTree 27 except ImportError: 28 from elementtree import ElementTree 29import urllib 30import gdata 31import atom.service 32import gdata.service 33import gdata.apps 34import atom 35 36API_VER="2.0" 37HTTP_OK=200 38 39UNKOWN_ERROR=1000 40USER_DELETED_RECENTLY=1100 41USER_SUSPENDED=1101 42DOMAIN_USER_LIMIT_EXCEEDED=1200 43DOMAIN_ALIAS_LIMIT_EXCEEDED=1201 44DOMAIN_SUSPENDED=1202 45DOMAIN_FEATURE_UNAVAILABLE=1203 46ENTITY_EXISTS=1300 47ENTITY_DOES_NOT_EXIST=1301 48ENTITY_NAME_IS_RESERVED=1302 49ENTITY_NAME_NOT_VALID=1303 50INVALID_GIVEN_NAME=1400 51INVALID_FAMILY_NAME=1401 52INVALID_PASSWORD=1402 53INVALID_USERNAME=1403 54INVALID_HASH_FUNCTION_NAME=1404 55INVALID_HASH_DIGGEST_LENGTH=1405 56INVALID_EMAIL_ADDRESS=1406 57INVALID_QUERY_PARAMETER_VALUE=1407 58TOO_MANY_RECIPIENTS_ON_EMAIL_LIST=1500 59 60DEFAULT_QUOTA_LIMIT='2048' 61 62 63class Error(Exception): 64 pass 65 66 67class AppsForYourDomainException(Error): 68 69 def __init__(self, response): 70 71 Error.__init__(self, response) 72 try: 73 self.element_tree = ElementTree.fromstring(response['body']) 74 self.error_code = int(self.element_tree[0].attrib['errorCode']) 75 self.reason = self.element_tree[0].attrib['reason'] 76 self.invalidInput = self.element_tree[0].attrib['invalidInput'] 77 except: 78 self.error_code = UNKOWN_ERROR 79 80 81class AppsService(gdata.service.GDataService): 82 """Client for the Google Apps Provisioning service.""" 83 84 def __init__(self, email=None, password=None, domain=None, source=None, 85 server='apps-apis.google.com', additional_headers=None, 86 **kwargs): 87 """Creates a client for the Google Apps Provisioning service. 88 89 Args: 90 email: string (optional) The user's email address, used for 91 authentication. 92 password: string (optional) The user's password. 93 domain: string (optional) The Google Apps domain name. 94 source: string (optional) The name of the user's application. 95 server: string (optional) The name of the server to which a connection 96 will be opened. Default value: 'apps-apis.google.com'. 97 **kwargs: The other parameters to pass to gdata.service.GDataService 98 constructor. 99 """ 100 gdata.service.GDataService.__init__( 101 self, email=email, password=password, service='apps', source=source, 102 server=server, additional_headers=additional_headers, **kwargs) 103 self.ssl = True 104 self.port = 443 105 self.domain = domain 106 107 def _baseURL(self): 108 return "/a/feeds/%s" % self.domain 109 110 def AddAllElementsFromAllPages(self, link_finder, func): 111 """retrieve all pages and add all elements""" 112 next = link_finder.GetNextLink() 113 while next is not None: 114 next_feed = self.Get(next.href, converter=func) 115 for a_entry in next_feed.entry: 116 link_finder.entry.append(a_entry) 117 next = next_feed.GetNextLink() 118 return link_finder 119 120 def RetrievePageOfEmailLists(self, start_email_list_name=None, 121 num_retries=gdata.service.DEFAULT_NUM_RETRIES, 122 delay=gdata.service.DEFAULT_DELAY, 123 backoff=gdata.service.DEFAULT_BACKOFF): 124 """Retrieve one page of email list""" 125 uri = "%s/emailList/%s" % (self._baseURL(), API_VER) 126 if start_email_list_name is not None: 127 uri += "?startEmailListName=%s" % start_email_list_name 128 try: 129 return gdata.apps.EmailListFeedFromString(str(self.GetWithRetries( 130 uri, num_retries=num_retries, delay=delay, backoff=backoff))) 131 except gdata.service.RequestError, e: 132 raise AppsForYourDomainException(e.args[0]) 133 134 def GetGeneratorForAllEmailLists( 135 self, num_retries=gdata.service.DEFAULT_NUM_RETRIES, 136 delay=gdata.service.DEFAULT_DELAY, backoff=gdata.service.DEFAULT_BACKOFF): 137 """Retrieve a generator for all emaillists in this domain.""" 138 first_page = self.RetrievePageOfEmailLists(num_retries=num_retries, 139 delay=delay, 140 backoff=backoff) 141 return self.GetGeneratorFromLinkFinder( 142 first_page, gdata.apps.EmailListRecipientFeedFromString, 143 num_retries=num_retries, delay=delay, backoff=backoff) 144 145 def RetrieveAllEmailLists(self): 146 """Retrieve all email list of a domain.""" 147 148 ret = self.RetrievePageOfEmailLists() 149 # pagination 150 return self.AddAllElementsFromAllPages( 151 ret, gdata.apps.EmailListFeedFromString) 152 153 def RetrieveEmailList(self, list_name): 154 """Retreive a single email list by the list's name.""" 155 156 uri = "%s/emailList/%s/%s" % ( 157 self._baseURL(), API_VER, list_name) 158 try: 159 return self.Get(uri, converter=gdata.apps.EmailListEntryFromString) 160 except gdata.service.RequestError, e: 161 raise AppsForYourDomainException(e.args[0]) 162 163 def RetrieveEmailLists(self, recipient): 164 """Retrieve All Email List Subscriptions for an Email Address.""" 165 166 uri = "%s/emailList/%s?recipient=%s" % ( 167 self._baseURL(), API_VER, recipient) 168 try: 169 ret = gdata.apps.EmailListFeedFromString(str(self.Get(uri))) 170 except gdata.service.RequestError, e: 171 raise AppsForYourDomainException(e.args[0]) 172 173 # pagination 174 return self.AddAllElementsFromAllPages( 175 ret, gdata.apps.EmailListFeedFromString) 176 177 def RemoveRecipientFromEmailList(self, recipient, list_name): 178 """Remove recipient from email list.""" 179 180 uri = "%s/emailList/%s/%s/recipient/%s" % ( 181 self._baseURL(), API_VER, list_name, recipient) 182 try: 183 self.Delete(uri) 184 except gdata.service.RequestError, e: 185 raise AppsForYourDomainException(e.args[0]) 186 187 def RetrievePageOfRecipients(self, list_name, start_recipient=None, 188 num_retries=gdata.service.DEFAULT_NUM_RETRIES, 189 delay=gdata.service.DEFAULT_DELAY, 190 backoff=gdata.service.DEFAULT_BACKOFF): 191 """Retrieve one page of recipient of an email list. """ 192 193 uri = "%s/emailList/%s/%s/recipient" % ( 194 self._baseURL(), API_VER, list_name) 195 196 if start_recipient is not None: 197 uri += "?startRecipient=%s" % start_recipient 198 try: 199 return gdata.apps.EmailListRecipientFeedFromString(str( 200 self.GetWithRetries( 201 uri, num_retries=num_retries, delay=delay, backoff=backoff))) 202 except gdata.service.RequestError, e: 203 raise AppsForYourDomainException(e.args[0]) 204 205 def GetGeneratorForAllRecipients( 206 self, list_name, num_retries=gdata.service.DEFAULT_NUM_RETRIES, 207 delay=gdata.service.DEFAULT_DELAY, backoff=gdata.service.DEFAULT_BACKOFF): 208 """Retrieve a generator for all recipients of a particular emaillist.""" 209 first_page = self.RetrievePageOfRecipients(list_name, 210 num_retries=num_retries, 211 delay=delay, 212 backoff=backoff) 213 return self.GetGeneratorFromLinkFinder( 214 first_page, gdata.apps.EmailListRecipientFeedFromString, 215 num_retries=num_retries, delay=delay, backoff=backoff) 216 217 def RetrieveAllRecipients(self, list_name): 218 """Retrieve all recipient of an email list.""" 219 220 ret = self.RetrievePageOfRecipients(list_name) 221 # pagination 222 return self.AddAllElementsFromAllPages( 223 ret, gdata.apps.EmailListRecipientFeedFromString) 224 225 def AddRecipientToEmailList(self, recipient, list_name): 226 """Add a recipient to a email list.""" 227 228 uri = "%s/emailList/%s/%s/recipient" % ( 229 self._baseURL(), API_VER, list_name) 230 recipient_entry = gdata.apps.EmailListRecipientEntry() 231 recipient_entry.who = gdata.apps.Who(email=recipient) 232 233 try: 234 return gdata.apps.EmailListRecipientEntryFromString( 235 str(self.Post(recipient_entry, uri))) 236 except gdata.service.RequestError, e: 237 raise AppsForYourDomainException(e.args[0]) 238 239 def DeleteEmailList(self, list_name): 240 """Delete a email list""" 241 242 uri = "%s/emailList/%s/%s" % (self._baseURL(), API_VER, list_name) 243 try: 244 self.Delete(uri) 245 except gdata.service.RequestError, e: 246 raise AppsForYourDomainException(e.args[0]) 247 248 def CreateEmailList(self, list_name): 249 """Create a email list. """ 250 251 uri = "%s/emailList/%s" % (self._baseURL(), API_VER) 252 email_list_entry = gdata.apps.EmailListEntry() 253 email_list_entry.email_list = gdata.apps.EmailList(name=list_name) 254 try: 255 return gdata.apps.EmailListEntryFromString( 256 str(self.Post(email_list_entry, uri))) 257 except gdata.service.RequestError, e: 258 raise AppsForYourDomainException(e.args[0]) 259 260 def DeleteNickname(self, nickname): 261 """Delete a nickname""" 262 263 uri = "%s/nickname/%s/%s" % (self._baseURL(), API_VER, nickname) 264 try: 265 self.Delete(uri) 266 except gdata.service.RequestError, e: 267 raise AppsForYourDomainException(e.args[0]) 268 269 def RetrievePageOfNicknames(self, start_nickname=None, 270 num_retries=gdata.service.DEFAULT_NUM_RETRIES, 271 delay=gdata.service.DEFAULT_DELAY, 272 backoff=gdata.service.DEFAULT_BACKOFF): 273 """Retrieve one page of nicknames in the domain""" 274 275 uri = "%s/nickname/%s" % (self._baseURL(), API_VER) 276 if start_nickname is not None: 277 uri += "?startNickname=%s" % start_nickname 278 try: 279 return gdata.apps.NicknameFeedFromString(str(self.GetWithRetries( 280 uri, num_retries=num_retries, delay=delay, backoff=backoff))) 281 except gdata.service.RequestError, e: 282 raise AppsForYourDomainException(e.args[0]) 283 284 def GetGeneratorForAllNicknames( 285 self, num_retries=gdata.service.DEFAULT_NUM_RETRIES, 286 delay=gdata.service.DEFAULT_DELAY, backoff=gdata.service.DEFAULT_BACKOFF): 287 """Retrieve a generator for all nicknames in this domain.""" 288 first_page = self.RetrievePageOfNicknames(num_retries=num_retries, 289 delay=delay, 290 backoff=backoff) 291 return self.GetGeneratorFromLinkFinder( 292 first_page, gdata.apps.NicknameFeedFromString, num_retries=num_retries, 293 delay=delay, backoff=backoff) 294 295 def RetrieveAllNicknames(self): 296 """Retrieve all nicknames in the domain""" 297 298 ret = self.RetrievePageOfNicknames() 299 # pagination 300 return self.AddAllElementsFromAllPages( 301 ret, gdata.apps.NicknameFeedFromString) 302 303 def GetGeneratorForAllNicknamesOfAUser( 304 self, user_name, num_retries=gdata.service.DEFAULT_NUM_RETRIES, 305 delay=gdata.service.DEFAULT_DELAY, backoff=gdata.service.DEFAULT_BACKOFF): 306 """Retrieve a generator for all nicknames of a particular user.""" 307 uri = "%s/nickname/%s?username=%s" % (self._baseURL(), API_VER, user_name) 308 try: 309 first_page = gdata.apps.NicknameFeedFromString(str(self.GetWithRetries( 310 uri, num_retries=num_retries, delay=delay, backoff=backoff))) 311 except gdata.service.RequestError, e: 312 raise AppsForYourDomainException(e.args[0]) 313 return self.GetGeneratorFromLinkFinder( 314 first_page, gdata.apps.NicknameFeedFromString, num_retries=num_retries, 315 delay=delay, backoff=backoff) 316 317 def RetrieveNicknames(self, user_name): 318 """Retrieve nicknames of the user""" 319 320 uri = "%s/nickname/%s?username=%s" % (self._baseURL(), API_VER, user_name) 321 try: 322 ret = gdata.apps.NicknameFeedFromString(str(self.Get(uri))) 323 except gdata.service.RequestError, e: 324 raise AppsForYourDomainException(e.args[0]) 325 326 # pagination 327 return self.AddAllElementsFromAllPages( 328 ret, gdata.apps.NicknameFeedFromString) 329 330 def RetrieveNickname(self, nickname): 331 """Retrieve a nickname. 332 333 Args: 334 nickname: string The nickname to retrieve 335 336 Returns: 337 gdata.apps.NicknameEntry 338 """ 339 340 uri = "%s/nickname/%s/%s" % (self._baseURL(), API_VER, nickname) 341 try: 342 return gdata.apps.NicknameEntryFromString(str(self.Get(uri))) 343 except gdata.service.RequestError, e: 344 raise AppsForYourDomainException(e.args[0]) 345 346 def CreateNickname(self, user_name, nickname): 347 """Create a nickname""" 348 349 uri = "%s/nickname/%s" % (self._baseURL(), API_VER) 350 nickname_entry = gdata.apps.NicknameEntry() 351 nickname_entry.login = gdata.apps.Login(user_name=user_name) 352 nickname_entry.nickname = gdata.apps.Nickname(name=nickname) 353 354 try: 355 return gdata.apps.NicknameEntryFromString( 356 str(self.Post(nickname_entry, uri))) 357 except gdata.service.RequestError, e: 358 raise AppsForYourDomainException(e.args[0]) 359 360 def DeleteUser(self, user_name): 361 """Delete a user account""" 362 363 uri = "%s/user/%s/%s" % (self._baseURL(), API_VER, user_name) 364 try: 365 return self.Delete(uri) 366 except gdata.service.RequestError, e: 367 raise AppsForYourDomainException(e.args[0]) 368 369 def UpdateUser(self, user_name, user_entry): 370 """Update a user account.""" 371 372 uri = "%s/user/%s/%s" % (self._baseURL(), API_VER, user_name) 373 try: 374 return gdata.apps.UserEntryFromString(str(self.Put(user_entry, uri))) 375 except gdata.service.RequestError, e: 376 raise AppsForYourDomainException(e.args[0]) 377 378 def CreateUser(self, user_name, family_name, given_name, password, 379 suspended='false', quota_limit=None, 380 password_hash_function=None): 381 """Create a user account. """ 382 383 uri = "%s/user/%s" % (self._baseURL(), API_VER) 384 user_entry = gdata.apps.UserEntry() 385 user_entry.login = gdata.apps.Login( 386 user_name=user_name, password=password, suspended=suspended, 387 hash_function_name=password_hash_function) 388 user_entry.name = gdata.apps.Name(family_name=family_name, 389 given_name=given_name) 390 if quota_limit is not None: 391 user_entry.quota = gdata.apps.Quota(limit=str(quota_limit)) 392 393 try: 394 return gdata.apps.UserEntryFromString(str(self.Post(user_entry, uri))) 395 except gdata.service.RequestError, e: 396 raise AppsForYourDomainException(e.args[0]) 397 398 def SuspendUser(self, user_name): 399 user_entry = self.RetrieveUser(user_name) 400 if user_entry.login.suspended != 'true': 401 user_entry.login.suspended = 'true' 402 user_entry = self.UpdateUser(user_name, user_entry) 403 return user_entry 404 405 def RestoreUser(self, user_name): 406 user_entry = self.RetrieveUser(user_name) 407 if user_entry.login.suspended != 'false': 408 user_entry.login.suspended = 'false' 409 user_entry = self.UpdateUser(user_name, user_entry) 410 return user_entry 411 412 def RetrieveUser(self, user_name): 413 """Retrieve an user account. 414 415 Args: 416 user_name: string The user name to retrieve 417 418 Returns: 419 gdata.apps.UserEntry 420 """ 421 422 uri = "%s/user/%s/%s" % (self._baseURL(), API_VER, user_name) 423 try: 424 return gdata.apps.UserEntryFromString(str(self.Get(uri))) 425 except gdata.service.RequestError, e: 426 raise AppsForYourDomainException(e.args[0]) 427 428 def RetrievePageOfUsers(self, start_username=None, 429 num_retries=gdata.service.DEFAULT_NUM_RETRIES, 430 delay=gdata.service.DEFAULT_DELAY, 431 backoff=gdata.service.DEFAULT_BACKOFF): 432 """Retrieve one page of users in this domain.""" 433 434 uri = "%s/user/%s" % (self._baseURL(), API_VER) 435 if start_username is not None: 436 uri += "?startUsername=%s" % start_username 437 try: 438 return gdata.apps.UserFeedFromString(str(self.GetWithRetries( 439 uri, num_retries=num_retries, delay=delay, backoff=backoff))) 440 except gdata.service.RequestError, e: 441 raise AppsForYourDomainException(e.args[0]) 442 443 def GetGeneratorForAllUsers(self, 444 num_retries=gdata.service.DEFAULT_NUM_RETRIES, 445 delay=gdata.service.DEFAULT_DELAY, 446 backoff=gdata.service.DEFAULT_BACKOFF): 447 """Retrieve a generator for all users in this domain.""" 448 first_page = self.RetrievePageOfUsers(num_retries=num_retries, delay=delay, 449 backoff=backoff) 450 return self.GetGeneratorFromLinkFinder( 451 first_page, gdata.apps.UserFeedFromString, num_retries=num_retries, 452 delay=delay, backoff=backoff) 453 454 def RetrieveAllUsers(self): 455 """Retrieve all users in this domain. OBSOLETE""" 456 457 ret = self.RetrievePageOfUsers() 458 # pagination 459 return self.AddAllElementsFromAllPages( 460 ret, gdata.apps.UserFeedFromString) 461 462 463class PropertyService(gdata.service.GDataService): 464 """Client for the Google Apps Property service.""" 465 466 def __init__(self, email=None, password=None, domain=None, source=None, 467 server='apps-apis.google.com', additional_headers=None): 468 gdata.service.GDataService.__init__(self, email=email, password=password, 469 service='apps', source=source, 470 server=server, 471 additional_headers=additional_headers) 472 self.ssl = True 473 self.port = 443 474 self.domain = domain 475 476 def AddAllElementsFromAllPages(self, link_finder, func): 477 """retrieve all pages and add all elements""" 478 next = link_finder.GetNextLink() 479 while next is not None: 480 next_feed = self.Get(next.href, converter=func) 481 for a_entry in next_feed.entry: 482 link_finder.entry.append(a_entry) 483 next = next_feed.GetNextLink() 484 return link_finder 485 486 def _GetPropertyEntry(self, properties): 487 property_entry = gdata.apps.PropertyEntry() 488 property = [] 489 for name, value in properties.iteritems(): 490 if name is not None and value is not None: 491 property.append(gdata.apps.Property(name=name, value=value)) 492 property_entry.property = property 493 return property_entry 494 495 def _PropertyEntry2Dict(self, property_entry): 496 properties = {} 497 for i, property in enumerate(property_entry.property): 498 properties[property.name] = property.value 499 return properties 500 501 def _GetPropertyFeed(self, uri): 502 try: 503 return gdata.apps.PropertyFeedFromString(str(self.Get(uri))) 504 except gdata.service.RequestError, e: 505 raise gdata.apps.service.AppsForYourDomainException(e.args[0]) 506 507 def _GetPropertiesList(self, uri): 508 property_feed = self._GetPropertyFeed(uri) 509 # pagination 510 property_feed = self.AddAllElementsFromAllPages( 511 property_feed, gdata.apps.PropertyFeedFromString) 512 properties_list = [] 513 for property_entry in property_feed.entry: 514 properties_list.append(self._PropertyEntry2Dict(property_entry)) 515 return properties_list 516 517 def _GetProperties(self, uri): 518 try: 519 return self._PropertyEntry2Dict(gdata.apps.PropertyEntryFromString( 520 str(self.Get(uri)))) 521 except gdata.service.RequestError, e: 522 raise gdata.apps.service.AppsForYourDomainException(e.args[0]) 523 524 def _PostProperties(self, uri, properties): 525 property_entry = self._GetPropertyEntry(properties) 526 try: 527 return self._PropertyEntry2Dict(gdata.apps.PropertyEntryFromString( 528 str(self.Post(property_entry, uri)))) 529 except gdata.service.RequestError, e: 530 raise gdata.apps.service.AppsForYourDomainException(e.args[0]) 531 532 def _PutProperties(self, uri, properties): 533 property_entry = self._GetPropertyEntry(properties) 534 try: 535 return self._PropertyEntry2Dict(gdata.apps.PropertyEntryFromString( 536 str(self.Put(property_entry, uri)))) 537 except gdata.service.RequestError, e: 538 raise gdata.apps.service.AppsForYourDomainException(e.args[0]) 539 540 def _DeleteProperties(self, uri): 541 try: 542 self.Delete(uri) 543 except gdata.service.RequestError, e: 544 raise gdata.apps.service.AppsForYourDomainException(e.args[0]) 545 546 547def _bool2str(b): 548 if b is None: 549 return None 550 return str(b is True).lower()