PageRenderTime 42ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/googlecl/client.py

http://googlecl.googlecode.com/
Python | 139 lines | 76 code | 14 blank | 49 comment | 12 complexity | 4c0caf4cccf452a828f69243dce7a8ea MD5 | raw file
  1. # Copyright (C) 2010 Google Inc.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """Basic service extensions for the gdata python client library for use on
  15. the command line."""
  16. import gdata.client
  17. import googlecl
  18. import googlecl.base
  19. import logging
  20. LOG = logging.getLogger(__name__)
  21. # This class CANNOT be used unless an instance also inherits from
  22. # gdata.client.GDClient somehow.
  23. # TODO: pylint bugs out over the missing functions/attributes here,
  24. # but there are no run-time errors. Make pylint happy!
  25. class BaseClientCL(googlecl.base.BaseCL):
  26. """Extension of gdata.GDataService specific to GoogleCL."""
  27. def __init__(self, section, config,
  28. request_error_class=gdata.client.RequestError,
  29. *args, **kwargs):
  30. super(BaseClientCL, self).__init__(section, config, request_error_class,
  31. *args, **kwargs)
  32. # Used for automatic retries of requests that fail due to 302 errors.
  33. # See BaseCL.retry_operation.
  34. self.original_request = self.request
  35. self.request = self.retry_request
  36. LOG.debug('Initialized googlecl.client.BaseClientCL')
  37. def is_token_valid(self, test_uri):
  38. try:
  39. return super(BaseClientCL, self).is_token_valid(test_uri)
  40. # If access has been revoked through account settings, get weird
  41. # Unauthorized error complaining about AuthSub.
  42. except gdata.client.Unauthorized:
  43. return False
  44. IsTokenValid = is_token_valid
  45. def retry_request(self, *args, **kwargs):
  46. """Retries a request."""
  47. self.original_operation = self.original_request
  48. return self.retry_operation(*args, **kwargs)
  49. def request_access(self, domain, display_name, scopes=None, browser=None):
  50. """Do all the steps involved with getting an OAuth access token.
  51. Keyword arguments:
  52. domain: Domain to request access for.
  53. (Sets the hd query parameter for the authorization step).
  54. display_name: Descriptor for the machine doing the requesting.
  55. scopes: String or list of strings describing scopes to request
  56. access to. If None, tries to access self.auth_scopes
  57. browser: Browser object for opening a URL, or None to just print the url.
  58. Returns:
  59. True if access token was succesfully retrieved and set, otherwise False.
  60. """
  61. import urllib
  62. import time
  63. # XXX: Not sure if get_oauth_token() will accept a list of mixed strings and
  64. # atom.http_core.Uri objects...
  65. if not scopes:
  66. scopes = self.auth_scopes
  67. if not isinstance(scopes, list):
  68. scopes = [scopes,]
  69. # Some scopes are packaged as tuples, which is a no-no for
  70. # gauth.generate_request_for_request_token() (called by get_oauth_token)
  71. for i, scope in enumerate(scopes):
  72. if isinstance(scope, tuple):
  73. scopes[i:i+1] = list(scope)
  74. scopes.extend(['https://www.googleapis.com/auth/userinfo#email'])
  75. LOG.debug('Scopes being requested: ' + str(scopes))
  76. url = gdata.gauth.REQUEST_TOKEN_URL + '?xoauth_displayname=' +\
  77. urllib.quote(display_name)
  78. try:
  79. # Installed applications do not have a pre-registration and so follow
  80. # directions for unregistered applications
  81. request_token = self.get_oauth_token(scopes, next='oob',
  82. consumer_key='anonymous',
  83. consumer_secret='anonymous',
  84. url=url)
  85. except self.request_error, err:
  86. LOG.error(err)
  87. if str(err).find('Timestamp') != -1:
  88. LOG.info('Is your system clock up to date? See the FAQ on our wiki: '
  89. 'http://code.google.com/p/googlecl/wiki/FAQ'
  90. '#Timestamp_too_far_from_current_time')
  91. return False
  92. auth_url = request_token.generate_authorization_url(
  93. google_apps_domain=domain)
  94. if browser is not None:
  95. try:
  96. browser.open(str(auth_url))
  97. except Exception, err:
  98. # Blanket catch of Exception is a bad idea, but don't want to pass in
  99. # error to look for.
  100. LOG.error('Failed to launch web browser: ' + unicode(err))
  101. print 'Please log in and/or grant access at %s' % auth_url
  102. # Try to keep that damn "Created new window in existing browser session."
  103. # message away from raw_input call.
  104. time.sleep(2)
  105. print ''
  106. request_token.verifier = raw_input('Please enter the verification code on'
  107. ' the success page: ').strip()
  108. # This upgrades the token, and if successful, sets the access token
  109. try:
  110. access_token = self.get_access_token(request_token)
  111. except gdata.client.RequestError, err:
  112. LOG.error(err)
  113. LOG.error('Token upgrade failed! Could not get OAuth access token.')
  114. return False
  115. else:
  116. self.auth_token = access_token
  117. return True
  118. RequestAccess = request_access
  119. def SetOAuthToken(self, token):
  120. self.auth_token = token