PageRenderTime 224ms CodeModel.GetById 130ms app.highlight 9ms RepoModel.GetById 82ms app.codeStats 0ms

/src/googlecl/client.py

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