/gdata/apps/service.py

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