From 04ff83fc2d97f8ebc4319c12fbb002d9f896ec10 Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Mon, 5 Oct 2015 07:49:10 -0700 Subject: [PATCH 1/6] Correct gam update org add cros /all cros --- src/gam.py | 223 +++++++++++++++++------------------------------------ 1 file changed, 71 insertions(+), 152 deletions(-) diff --git a/src/gam.py b/src/gam.py index 4bef2dc6..d2a1ab7e 100644 --- a/src/gam.py +++ b/src/gam.py @@ -154,27 +154,15 @@ gam.exe update group announcements add member jsmith def setGamDirs(): global gamPath, gamSiteConfigDir, gamUserConfigDir, gamDriveDir, gamCacheDir - - gamPath = os.path.dirname(os.path.realpath(sys.argv[0])) - try: - gamSiteConfigDir = os.environ[u'GAMSITECONFIGDIR'] - except KeyError: - gamSiteConfigDir = gamPath - try: - gamUserConfigDir = os.environ[u'GAMUSERCONFIGDIR'] - except KeyError: - gamUserConfigDir = gamPath - try: - gamCacheDir = os.environ[u'GAMCACHEDIR'] - except KeyError: - gamCacheDir = os.path.join(gamPath, u'gamcache') - try: - gamDriveDir = os.environ[u'GAMDRIVEDIR'] - except KeyError: - gamDriveDir = gamPath - + gamPath = os.path.dirname(os.path.realpath(__file__)) + gamSiteConfigDir = os.environ.get(u'GAMSITECONFIGDIR', gamPath) + gamUserConfigDir = os.environ.get(u'GAMUSERCONFIGDIR', gamPath) if os.path.isfile(os.path.join(gamUserConfigDir, u'nocache.txt')): gamCacheDir = None + else: + gamCacheDir = os.environ.get(u'GAMCACHEDIR', os.path.join(gamPath, u'gamcache')) + gamDriveDir = os.environ.get(u'GAMDRIVEDIR', gamPath) + def doGAMVersion(): import struct @@ -241,111 +229,63 @@ def commonAppsObjInit(appsObj): return appsObj def checkErrorCode(e, service): - try: - if e[0]['reason'] in [u'Token invalid - Invalid token: Stateless token expired', u'Token invalid - Invalid token: Token not found']: - keep_domain = service.domain - tryOAuth(service) - service.domain = keep_domain - return False - except KeyError: - pass + + # First check for errors that need special handling + if e[0].get('reason', '') in [u'Token invalid - Invalid token: Stateless token expired', u'Token invalid - Invalid token: Token not found']: + keep_domain = service.domain + tryOAuth(service) + service.domain = keep_domain + return False if e[0]['body'][:34] in [u'Required field must not be blank: ', u'These characters are not allowed: ']: return e[0]['body'] if e.error_code == 600 and e[0][u'body'] == u'Quota exceeded for the current request' or e[0][u'reason'] == u'Bad Gateway': return False if e.error_code == 600 and e[0][u'reason'] == u'Token invalid - Invalid token: Token disabled, revoked, or expired.': return u'403 - Token disabled, revoked, or expired. Please delete and re-create oauth.txt' - if e.error_code == 1000: # UnknownError - return False - elif e.error_code == 1001: # ServerBusy - return False - elif e.error_code == 1002: - return u'1002 - Unauthorized and forbidden' - elif e.error_code == 1100: - return u'1100 - User deleted recently' - elif e.error_code == 1200: - return u'1200 - Domain user limit exceeded' - elif e.error_code == 1201: - return u'1201 - Domain alias limit exceeded' - elif e.error_code == 1202: - return u'1202 - Domain suspended' - elif e.error_code == 1203: - return u'1203 - Domain feature unavailable' - elif e.error_code == 1300: - if e.invalidInput != '': - return u'1300 - Entity %s exists' % e.invalidInput - else: - return u'1300 - Entity exists' - elif e.error_code == 1301: - if e.invalidInput != '': - return u'1301 - Entity %s Does Not Exist' % e.invalidInput - else: - return u'1301 - Entity Does Not Exist' - elif e.error_code == 1302: - return u'1302 - Entity Name Is Reserved' - elif e.error_code == 1303: - if e.invalidInput != '': - return u'1303 - Entity %s name not valid' % e.invalidInput - else: - return u'1303 - Entity name not valid' - elif e.error_code == 1306: - if e.invalidInput != '': - return u'1306 - %s has members. Cannot delete.' % e.invalidInput - else: - return u'1306 - Entity has members. Cannot delete.' - elif e.error_code == 1400: - return u'1400 - Invalid Given Name' - elif e.error_code == 1401: - return u'1401 - Invalid Family Name' - elif e.error_code == 1402: - return u'1402 - Invalid Password' - elif e.error_code == 1403: - return u'1403 - Invalid Username' - elif e.error_code == 1404: - return u'1404 - Invalid Hash Function Name' - elif e.error_code == 1405: - return u'1405 - Invalid Hash Digest Length' - elif e.error_code == 1406: - return u'1406 - Invalid Email Address' - elif e.error_code == 1407: - return u'1407 - Invalid Query Parameter Value' - elif e.error_code == 1408: - return u'1408 - Invalid SSO Signing Key' - elif e.error_code == 1409: - return u'1409 - Invalid Encryption Public Key' - elif e.error_code == 1410: - return u'1410 - Feature Unavailable For User' - elif e.error_code == 1500: - return u'1500 - Too Many Recipients On Email List' - elif e.error_code == 1501: - return u'1501 - Too Many Aliases For User' - elif e.error_code == 1502: - return u'1502 - Too Many Delegates For User' - elif e.error_code == 1601: - return u'1601 - Duplicate Destinations' - elif e.error_code == 1602: - return u'1602 - Too Many Destinations' - elif e.error_code == 1603: - return u'1603 - Invalid Route Address' - elif e.error_code == 1700: - return u'1700 - Group Cannot Contain Cycle' - elif e.error_code == 1800: - return u'1800 - Invalid Domain Edition' - elif e.error_code == 1801: - if e.invalidInput != '': - return u'1801 - Invalid value %s' % e.invalidInput - else: - return u'1801 - Invalid Value' - else: - return u'%s: Unknown Error: %s' % (e.error_code, str(e)) + + # We got a "normal" error, define the mapping below + error_code_map = { + 1000: False, + 1001: False, + 1002: u'Unauthorized and forbidden', + 1100: u'User deleted recently', + 1200: u'Domain user limit exceeded', + 1201: u'Domain alias limit exceeded', + 1202: u'Domain suspended', + 1203: u'Domain feature unavailable', + 1300: u'Entity %s exists' % e.invalidInput or '', + 1301: u'Entity %s Does Not Exist' % e.invalidInput or '', + 1302: u'Entity Name Is Reserved', + 1303: u'Entity %s name not valid' % e.invalidInput or '', + 1306: u'%s has members. Cannot delete.' % e.invalidInput or '', + 1400: u'Invalid Given Name', + 1401: u'Invalid Family Name', + 1402: u'Invalid Password', + 1403: u'Invalid Username', + 1404: u'Invalid Hash Function Name', + 1405: u'Invalid Hash Digest Length', + 1406: u'Invalid Email Address', + 1407: u'Invalid Query Parameter Value', + 1408: u'Invalid SSO Signing Key', + 1409: u'Invalid Encryption Public Key', + 1410: u'Feature Unavailable For User', + 1500: u'Too Many Recipients On Email List', + 1501: u'Too Many Aliases For User', + 1502: u'Too Many Delegates For User', + 1601: u'Duplicate Destinations', + 1602: u'Too Many Destinations', + 1603: u'Invalid Route Address', + 1700: u'Group Cannot Contain Cycle', + 1800: u'Group Cannot Contain Cycle', + 1801: u'Invalid value %s' % e.invalidInput or '' + } + + return u'%s - %s' % (e.error_code, error_code_map.get(e.error_code, u'Unknown Error: %s' % (e.error_code, str(e)))) def tryOAuth(gdataObject): global domain global customerId - try: - oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) - except KeyError: - oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') + oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', 'oauth2.txt')) storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() if credentials is None or credentials.invalid: @@ -357,14 +297,8 @@ def tryOAuth(gdataObject): disable_ssl_certificate_validation = True credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=disable_ssl_certificate_validation)) gdataObject.additional_headers = {u'Authorization': u'Bearer %s' % credentials.access_token} - try: - domain = os.environ[u'GA_DOMAIN'].lower() - except KeyError: - domain = credentials.id_token[u'hd'].lower() - try: - customerId = os.environ[u'CUSTOMER_ID'] - except KeyError: - customerId = u'my_customer' + domain = os.environ.get(u'GA_DOMAIN', credentials.id_token[u'hd']).lower() + customerId = os.environ.get(u'CUSTOMER_ID', 'my_customer') gdataObject.domain = domain return True @@ -556,10 +490,7 @@ def getAPIScope(api): def buildGAPIObject(api): global domain, customerId - try: - oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) - except KeyError: - oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') + oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', 'oauth2.txt')) storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() if credentials is None or credentials.invalid: @@ -622,10 +553,7 @@ def buildGAPIObject(api): return service def buildGAPIServiceObject(api, act_as=None, soft_errors=False): - try: - oauth2servicefile = os.path.join(gamUserConfigDir, os.environ[u'OAUTHSERVICEFILE']) - except KeyError: - oauth2servicefile = os.path.join(gamUserConfigDir, u'oauth2service') + oauth2servicefile = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHSERVICEFILE', 'oauth2service')) oauth2servicefilejson = u'%s.json' % oauth2servicefile oauth2servicefilep12 = u'%s.p12' % oauth2servicefile try: @@ -5877,7 +5805,7 @@ def doUpdateOrg(): users = getUsersToModify(entity_type=sys.argv[5], entity=sys.argv[6]) else: users = getUsersToModify(entity_type=u'user', entity=sys.argv[5]) - if sys.argv[5].lower() == u'cros': + if (sys.argv[5].lower() == u'cros') or ((sys.argv[5].lower() == u'all') and (sys.argv[6].lower == u'cros')): cros_count = len(users) current_cros = 1 for cros in users: @@ -5960,10 +5888,7 @@ def doGetUserInfo(user_email=None): try: user_email = sys.argv[3] except IndexError: - try: - oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) - except KeyError: - oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') + oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE'), 'oauth2.txt') storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() if credentials is None or credentials.invalid: @@ -8370,6 +8295,12 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa users.append(member[u'deviceId']) if not silent: sys.stderr.write(u"done getting %s CrOS devices.\r\n" % len(users)) + else: + print 'ERROR: %s is not a valid argument for "gam all"' % entity + sys.exit(3) + elif entity_type == u'cros': + users = entity.replace(u',', u' ').split() + entity = u'cros' else: print 'ERROR: %s is not a valid argument for "gam"' % entity_type sys.exit(2) @@ -8396,10 +8327,7 @@ def OAuthInfo(): try: access_token = sys.argv[3] except IndexError: - try: - oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) - except KeyError: - oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') + oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', 'oauth2.txt')) storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() if credentials is None or credentials.invalid: @@ -8434,10 +8362,7 @@ def OAuthInfo(): print u'Google Apps Admin: Unknown' def doDeleteOAuth(): - try: - oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) - except KeyError: - oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') + oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', 'oauth2.txt')) storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() try: @@ -8499,10 +8424,7 @@ possible_scopes = [u'https://www.googleapis.com/auth/admin.directory.group', u'https://www.googleapis.com/auth/admin.directory.domain'] # Domain API def doRequestOAuth(incremental_auth=False): - try: - CLIENT_SECRETS = os.path.join(gamUserConfigDir, os.environ[u'CLIENTSECRETSFILE']) - except KeyError: - CLIENT_SECRETS = os.path.join(gamUserConfigDir, u'client_secrets.json') + CLIENT_SECRETS = os.path.join(gamUserConfigDir, os.environ.get(u'CLIENTSECRETSFILE', 'client_secrets.json')) MISSING_CLIENT_SECRETS_MESSAGE = u""" WARNING: Please configure OAuth 2.0 @@ -8625,10 +8547,7 @@ access or an 'a' to grant action-only access. FLOW = oauth2client.client.flow_from_clientsecrets(CLIENT_SECRETS, scope=scopes, message=MISSING_CLIENT_SECRETS_MESSAGE) - try: - oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) - except KeyError: - oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') + oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', 'oauth2.txt')) storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() flags = cmd_flags() @@ -8661,7 +8580,7 @@ def run_batch(items): if not getattr(sys, 'frozen', False): # we're not frozen python_cmd.append(os.path.realpath(sys.argv[0])) try: - num_worker_threads = int(os.environ[u'GAM_THREADS']) + num_worker_threads = int(os.environ.get(u'GAM_THREADS', 5)) except (TypeError, KeyError): num_worker_threads = 5 import Queue, threading From c82672d77b23a84e63077ba937429a53131fac7e Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Tue, 27 Oct 2015 18:30:07 -0700 Subject: [PATCH 2/6] 3.62 Fixes --- src/gam.py | 85 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 29 deletions(-) diff --git a/src/gam.py b/src/gam.py index d2a1ab7e..75cad89e 100644 --- a/src/gam.py +++ b/src/gam.py @@ -24,7 +24,7 @@ For more information, see http://git.io/gam """ __author__ = u'Jay Lee ' -__version__ = u'3.61' +__version__ = u'3.62' __license__ = u'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)' import sys, os, time, datetime, random, socket, csv, platform, re, calendar, base64, string @@ -65,14 +65,15 @@ def convertUTF8(data): import collections if isinstance(data, str): return data - elif isinstance(data, unicode): - return data.encode('utf-8') - elif isinstance(data, collections.Mapping): - return dict(map(convertUTF8, data.iteritems())) - elif isinstance(data, collections.Iterable): - return type(data)(map(convertUTF8, data)) - else: + if isinstance(data, unicode): + if os.name != u'nt': + return data.encode('utf-8') return data + if isinstance(data, collections.Mapping): + return dict(map(convertUTF8, data.iteritems())) + if isinstance(data, collections.Iterable): + return type(data)(map(convertUTF8, data)) + return data def win32_unicode_argv(): from ctypes import POINTER, byref, cdll, c_int, windll @@ -163,7 +164,6 @@ def setGamDirs(): gamCacheDir = os.environ.get(u'GAMCACHEDIR', os.path.join(gamPath, u'gamcache')) gamDriveDir = os.environ.get(u'GAMDRIVEDIR', gamPath) - def doGAMVersion(): import struct print u'GAM %s - http://git.io/gam\n%s\nPython %s.%s.%s %s-bit %s\ngoogle-api-python-client %s\n%s %s\nPath: %s' % (__version__, __author__, @@ -253,11 +253,11 @@ def checkErrorCode(e, service): 1201: u'Domain alias limit exceeded', 1202: u'Domain suspended', 1203: u'Domain feature unavailable', - 1300: u'Entity %s exists' % e.invalidInput or '', - 1301: u'Entity %s Does Not Exist' % e.invalidInput or '', + 1300: u'Entity %s exists' % getattr(e, u'invalidInput', u''), + 1301: u'Entity %s Does Not Exist' % getattr(e, u'invalidInput', u''), 1302: u'Entity Name Is Reserved', - 1303: u'Entity %s name not valid' % e.invalidInput or '', - 1306: u'%s has members. Cannot delete.' % e.invalidInput or '', + 1303: u'Entity %s name not valid' % getattr(e, u'invalidInput', u''), + 1306: u'%s has members. Cannot delete.' % getattr(e, u'invalidInput', u''), 1400: u'Invalid Given Name', 1401: u'Invalid Family Name', 1402: u'Invalid Password', @@ -276,16 +276,19 @@ def checkErrorCode(e, service): 1602: u'Too Many Destinations', 1603: u'Invalid Route Address', 1700: u'Group Cannot Contain Cycle', - 1800: u'Group Cannot Contain Cycle', - 1801: u'Invalid value %s' % e.invalidInput or '' + 1800: u'Group Cannot Contain Cycle', + 1801: u'Invalid value %s' % getattr(e, u'invalidInput', u''), } - return u'%s - %s' % (e.error_code, error_code_map.get(e.error_code, u'Unknown Error: %s' % (e.error_code, str(e)))) + return u'%s - %s' % (e.error_code, error_code_map.get(e.error_code, u'Unknown Error: %s' % (str(e)))) def tryOAuth(gdataObject): global domain global customerId - oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', 'oauth2.txt')) + try: + oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) + except KeyError: + oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() if credentials is None or credentials.invalid: @@ -297,8 +300,14 @@ def tryOAuth(gdataObject): disable_ssl_certificate_validation = True credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=disable_ssl_certificate_validation)) gdataObject.additional_headers = {u'Authorization': u'Bearer %s' % credentials.access_token} - domain = os.environ.get(u'GA_DOMAIN', credentials.id_token[u'hd']).lower() - customerId = os.environ.get(u'CUSTOMER_ID', 'my_customer') + try: + domain = os.environ[u'GA_DOMAIN'].lower() + except KeyError: + domain = credentials.id_token[u'hd'].lower() + try: + customerId = os.environ[u'CUSTOMER_ID'] + except KeyError: + customerId = u'my_customer' gdataObject.domain = domain return True @@ -490,7 +499,10 @@ def getAPIScope(api): def buildGAPIObject(api): global domain, customerId - oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', 'oauth2.txt')) + try: + oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) + except KeyError: + oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() if credentials is None or credentials.invalid: @@ -553,7 +565,10 @@ def buildGAPIObject(api): return service def buildGAPIServiceObject(api, act_as=None, soft_errors=False): - oauth2servicefile = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHSERVICEFILE', 'oauth2service')) + try: + oauth2servicefile = os.path.join(gamUserConfigDir, os.environ[u'OAUTHSERVICEFILE']) + except KeyError: + oauth2servicefile = os.path.join(gamUserConfigDir, u'oauth2service') oauth2servicefilejson = u'%s.json' % oauth2servicefile oauth2servicefilep12 = u'%s.p12' % oauth2servicefile try: @@ -3029,7 +3044,7 @@ def showDriveFiles(users): for f_file in feed: a_file = {u'Owner': user} for attrib in f_file: - if attrib in [u'kind', u'etags', u'etag', u'owners', 'parents']: + if attrib in [u'kind', u'etags', u'etag', u'owners', u'parents', u'permissions']: continue attrib_type = type(f_file[attrib]) if attrib not in titles and not attrib_type is dict: @@ -5888,7 +5903,10 @@ def doGetUserInfo(user_email=None): try: user_email = sys.argv[3] except IndexError: - oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE'), 'oauth2.txt') + try: + oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) + except KeyError: + oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() if credentials is None or credentials.invalid: @@ -6751,13 +6769,13 @@ def doGetInstanceInfo(): if customerId != u'my_customer': customer_id = customerId else: - result = callGAPI(service=cd.users(), function=u'list', fields=u'users(customerId)', customer=customerId, sortOrder=u'DESCENDING') + result = callGAPI(service=cd.users(), function=u'list', fields=u'users(customerId)', customer=customerId, maxResults=1) customer_id = result[u'users'][0][u'customerId'] print u'Customer ID: %s' % customer_id default_language = callGAPI(service=adm.defaultLanguage(), function=u'get', domainName=domain) print u'Default Language: %s' % default_language[u'entry'][u'apps$property'][0][u'value'] org_name = callGAPI(service=adm.organizationName(), function='get', domainName=domain) - print u'Organization Name: %s' % org_name[u'entry'][u'apps$property'][0][u'value'] + print convertUTF8(u'Organization Name: %s' % org_name[u'entry'][u'apps$property'][0][u'value']) admin_email = callGAPI(service=adm.adminSecondaryEmail(), function='get', domainName=domain) print u'Admin Secondary Email: %s' % admin_email[u'entry'][u'apps$property'][0][u'value'] max_users = callGAPI(service=adm.maximumNumberOfUsers(), function=u'get', domainName=domain) @@ -8327,7 +8345,10 @@ def OAuthInfo(): try: access_token = sys.argv[3] except IndexError: - oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', 'oauth2.txt')) + try: + oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) + except KeyError: + oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() if credentials is None or credentials.invalid: @@ -8362,7 +8383,10 @@ def OAuthInfo(): print u'Google Apps Admin: Unknown' def doDeleteOAuth(): - oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', 'oauth2.txt')) + try: + oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) + except KeyError: + oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() try: @@ -8547,7 +8571,10 @@ access or an 'a' to grant action-only access. FLOW = oauth2client.client.flow_from_clientsecrets(CLIENT_SECRETS, scope=scopes, message=MISSING_CLIENT_SECRETS_MESSAGE) - oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', 'oauth2.txt')) + try: + oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) + except KeyError: + oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() flags = cmd_flags() @@ -8580,7 +8607,7 @@ def run_batch(items): if not getattr(sys, 'frozen', False): # we're not frozen python_cmd.append(os.path.realpath(sys.argv[0])) try: - num_worker_threads = int(os.environ.get(u'GAM_THREADS', 5)) + num_worker_threads = int(os.environ[u'GAM_THREADS']) except (TypeError, KeyError): num_worker_threads = 5 import Queue, threading From f40af555c3c27205d26c9883a71692ea5ae092e3 Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Wed, 28 Oct 2015 11:45:40 -0700 Subject: [PATCH 3/6] Use os.environ.get, remove try/except --- src/gam.py | 55 ++++++++++++++---------------------------------------- 1 file changed, 14 insertions(+), 41 deletions(-) diff --git a/src/gam.py b/src/gam.py index 75cad89e..a353fac6 100644 --- a/src/gam.py +++ b/src/gam.py @@ -285,10 +285,7 @@ def checkErrorCode(e, service): def tryOAuth(gdataObject): global domain global customerId - try: - oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) - except KeyError: - oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') + oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', 'oauth2.txt')) storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() if credentials is None or credentials.invalid: @@ -300,14 +297,8 @@ def tryOAuth(gdataObject): disable_ssl_certificate_validation = True credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=disable_ssl_certificate_validation)) gdataObject.additional_headers = {u'Authorization': u'Bearer %s' % credentials.access_token} - try: - domain = os.environ[u'GA_DOMAIN'].lower() - except KeyError: - domain = credentials.id_token[u'hd'].lower() - try: - customerId = os.environ[u'CUSTOMER_ID'] - except KeyError: - customerId = u'my_customer' + domain = os.environ.get(u'GA_DOMAIN', credentials.id_token[u'hd']).lower() + customerId = os.environ.get(u'CUSTOMER_ID', 'my_customer') gdataObject.domain = domain return True @@ -499,10 +490,7 @@ def getAPIScope(api): def buildGAPIObject(api): global domain, customerId - try: - oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) - except KeyError: - oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') + oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', 'oauth2.txt')) storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() if credentials is None or credentials.invalid: @@ -565,10 +553,7 @@ def buildGAPIObject(api): return service def buildGAPIServiceObject(api, act_as=None, soft_errors=False): - try: - oauth2servicefile = os.path.join(gamUserConfigDir, os.environ[u'OAUTHSERVICEFILE']) - except KeyError: - oauth2servicefile = os.path.join(gamUserConfigDir, u'oauth2service') + oauth2servicefile = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHSERVICEFILE', 'oauth2service')) oauth2servicefilejson = u'%s.json' % oauth2servicefile oauth2servicefilep12 = u'%s.p12' % oauth2servicefile try: @@ -5903,10 +5888,7 @@ def doGetUserInfo(user_email=None): try: user_email = sys.argv[3] except IndexError: - try: - oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) - except KeyError: - oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') + oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE'), 'oauth2.txt') storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() if credentials is None or credentials.invalid: @@ -8345,10 +8327,7 @@ def OAuthInfo(): try: access_token = sys.argv[3] except IndexError: - try: - oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) - except KeyError: - oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') + oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', 'oauth2.txt')) storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() if credentials is None or credentials.invalid: @@ -8383,10 +8362,7 @@ def OAuthInfo(): print u'Google Apps Admin: Unknown' def doDeleteOAuth(): - try: - oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) - except KeyError: - oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') + oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', 'oauth2.txt')) storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() try: @@ -8571,10 +8547,7 @@ access or an 'a' to grant action-only access. FLOW = oauth2client.client.flow_from_clientsecrets(CLIENT_SECRETS, scope=scopes, message=MISSING_CLIENT_SECRETS_MESSAGE) - try: - oauth2file = os.path.join(gamUserConfigDir, os.environ[u'OAUTHFILE']) - except KeyError: - oauth2file = os.path.join(gamUserConfigDir, u'oauth2.txt') + oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', 'oauth2.txt')) storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() flags = cmd_flags() @@ -8607,8 +8580,8 @@ def run_batch(items): if not getattr(sys, 'frozen', False): # we're not frozen python_cmd.append(os.path.realpath(sys.argv[0])) try: - num_worker_threads = int(os.environ[u'GAM_THREADS']) - except (TypeError, KeyError): + num_worker_threads = int(os.environ.get(u'GAM_THREADS', '5')) + except TypeError: num_worker_threads = 5 import Queue, threading global q @@ -8987,14 +8960,14 @@ try: print user sys.exit(0) try: - autoBatch = int(os.environ[u'GAM_AUTOBATCH']) - if len(users) > autoBatch: + autoBatch = int(os.environ[u'GAM_AUTOBATCH', '0']) + if (autoBatch > 0) and (len(users) > autoBatch): items = [] for user in users: items.append([u'user', user] + sys.argv[3:]) run_batch(items) sys.exit(0) - except (TypeError, KeyError): + except TypeError: pass if command == u'transfer': transferWhat = sys.argv[4].lower() From b16d75ec4338c003a1d0aa4b8301dbb4e7024b5f Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Wed, 28 Oct 2015 11:54:36 -0700 Subject: [PATCH 4/6] Fix .lower where () was missing --- src/gam.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gam.py b/src/gam.py index a353fac6..f0dafe00 100644 --- a/src/gam.py +++ b/src/gam.py @@ -3074,7 +3074,7 @@ def deleteDriveFile(users): if fileIds[:6].lower() == u'query:': file_ids = doDriveSearch(drive, query=fileIds[6:]) else: - if fileIds[:8].lower() == u'https://' or fileIds[:7].lower == u'http://': + if fileIds[:8].lower() == u'https://' or fileIds[:7].lower() == u'http://': fileIds = fileIds[fileIds.find(u'/d/')+3:] if fileIds.find(u'/') != -1: fileIds = fileIds[:fileIds.find(u'/')] @@ -3447,7 +3447,7 @@ def downloadDriveFile(users): if query: fileIds = doDriveSearch(drive, query=query) else: - if fileIds[0][:8].lower() == 'https://' or fileIds[0][:7].lower == 'http://': + if fileIds[0][:8].lower() == 'https://' or fileIds[0][:7].lower() == 'http://': fileIds[0] = fileIds[0][fileIds[0].find('/d/')+3:] if fileIds[0].find('/') != -1: fileIds[0] = fileIds[0][:fileIds[0].find('/')] @@ -5802,10 +5802,10 @@ def doUpdateOrg(): cd = buildGAPIObject(u'directory') if sys.argv[4].lower() in [u'move', u'add']: if sys.argv[5].lower() in usergroup_types: - users = getUsersToModify(entity_type=sys.argv[5], entity=sys.argv[6]) + users = getUsersToModify(entity_type=sys.argv[5].lower(), entity=sys.argv[6]) else: users = getUsersToModify(entity_type=u'user', entity=sys.argv[5]) - if (sys.argv[5].lower() == u'cros') or ((sys.argv[5].lower() == u'all') and (sys.argv[6].lower == u'cros')): + if (sys.argv[5].lower() == u'cros') or ((sys.argv[5].lower() == u'all') and (sys.argv[6].lower() == u'cros')): cros_count = len(users) current_cros = 1 for cros in users: @@ -8274,7 +8274,7 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa elif entity_type == u'all': got_uids = True users = [] - if entity == u'users': + if entity.lower() == u'users': if not silent: sys.stderr.write(u"Getting all users in Google Apps account (may take some time on a large account)...\n") page_message = u'Got %%total_items%% users...' @@ -8287,7 +8287,7 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa users.append(member[u'primaryEmail']) if not silent: sys.stderr.write(u"done getting %s users.\r\n" % len(users)) - elif entity == u'cros': + elif entity.lower() == u'cros': if not silent: sys.stderr.write(u"Getting all CrOS devices in Google Apps account (may take some time on a large account)...\n") all_cros = callGAPIpages(service=cd.chromeosdevices(), function=u'list', items=u'chromeosdevices', customerId=customerId, fields=u'nextPageToken,chromeosdevices(deviceId)') From 2d643a551c5aac0d4f080f3f60a39327f8da96b7 Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Wed, 28 Oct 2015 12:26:32 -0700 Subject: [PATCH 5/6] Use update instead of patch in doUpdateOrg as patch doesn't work --- src/gam.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gam.py b/src/gam.py index f0dafe00..0b3e552a 100644 --- a/src/gam.py +++ b/src/gam.py @@ -5850,7 +5850,7 @@ def doUpdateOrg(): sys.exit(2) if orgUnitPath[0] == u'/': # we don't want a / at the beginning for OU updates orgUnitPath = orgUnitPath[1:] - callGAPI(service=cd.orgunits(), function=u'patch', customerId=customerId, orgUnitPath=orgUnitPath, body=body) + callGAPI(service=cd.orgunits(), function=u'update', customerId=customerId, orgUnitPath=orgUnitPath, body=body) def doWhatIs(): email = sys.argv[2] From a958bf8be7fa0b7bd7075639ca647bdcf88ea7c6 Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Thu, 29 Oct 2015 16:02:24 -0700 Subject: [PATCH 6/6] Small cleanups --- src/gam.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gam.py b/src/gam.py index 0b3e552a..7b636c73 100644 --- a/src/gam.py +++ b/src/gam.py @@ -2416,7 +2416,7 @@ def doCalendarAddACL(calendarId=None, act_as=None, role=None, scope=None, entity else: body[u'role'] = sys.argv[4].lower() if body[u'role'] not in [u'freebusy', u'read', u'editor', u'owner', u'none']: - print u'ERROR: Role must be freebusy, read, editor or owner. Not %s' % body['role'] + print u'ERROR: Role must be freebusy, read, editor, owner or none. Not %s' % body['role'] sys.exit(2) if body[u'role'] == u'freebusy': body[u'role'] = u'freeBusyReader' @@ -5446,7 +5446,7 @@ def doUpdateUser(users): sys.exit(2) field_value = sys.argv[i+1] is_multivalue = False - if field_value.lower() == u'multivalue': + if field_value.lower() in [u'multivalue', u'multivalued', u'value']: is_multivalue = True field_value = sys.argv[i+2] if schemaName not in body[u'customSchemas']: @@ -6728,7 +6728,7 @@ def doUpdateInstance(): elif account_handling == u'unknown_accounts': account_handling = u'unknownAccounts' else: - print u'ERROR: value for account_handling must be all_accounts, provisioned_account or unknown_accounts. Got %s' % sys.argv[i+1] + print u'ERROR: value for account_handling must be all_accounts, provisioned_accounts or unknown_accounts. Got %s' % sys.argv[i+1] sys.exit(2) i += 2 else: