From 5f2c2103a5c5a74058a11b9b3946e2b79de00932 Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Tue, 22 Dec 2015 16:10:30 -0800 Subject: [PATCH 01/11] Revamp environment variables/signal files processing Global variables not from environment variables/signal files in GM_Globals Global variables from environment variables/signal files in GC_Values SetGlobalVariables processes all environment variables/signal files buildGAPIObject reworked buildGAPIServiceObject reworked Switch resource calendar processing from GData to GAPI Implement role assignments --- src/gam.py | 1237 ++++++++++++++++++---------- src/gdata/apps/res_cal/__init__.py | 1 - src/gdata/apps/res_cal/service.py | 71 -- 3 files changed, 797 insertions(+), 512 deletions(-) delete mode 100644 src/gdata/apps/res_cal/__init__.py delete mode 100644 src/gdata/apps/res_cal/service.py diff --git a/src/gam.py b/src/gam.py index fc078f75..449c64fc 100755 --- a/src/gam.py +++ b/src/gam.py @@ -57,7 +57,6 @@ GAM_APPSPOT_LATEST_VERSION_ANNOUNCEMENT = GAM_APPSPOT+u'/latest-version-announce TRUE = u'true' FALSE = u'false' -extra_args = {u'prettyPrint': False} true_values = [u'on', u'yes', u'enabled', u'true', u'1'] false_values = [u'off', u'no', u'disabled', u'false', u'0'] usergroup_types = [u'user', u'users', u'group', u'ou', u'org', @@ -74,17 +73,180 @@ FN_LAST_UPDATE_CHECK_TXT = u'lastupdatecheck.txt' FN_OAUTH2SERVICE_JSON = u'oauth2service.json' FN_OAUTH2_TXT = u'oauth2.txt' MY_CUSTOMER = u'my_customer' -UNKNOWN_DOMAIN = u'Unknown' +UNKNOWN = u'Unknown' +# +# Global variables +# +# The following GM_XXX constants are arbitrary but must be unique +# Most errors print a message and bail out with a return code +# Some commands want to set a non-zero return code but not bail +GM_SYSEXITRC = u'sxrc' +# Path to gam +GM_GAM_PATH = u'gpth' +# Are we on Windows? +GM_WINDOWS = u'wndo' +# Encodings +GM_SYS_ENCODING = u'syen' +# Shared by batch_worker and run_batch +GM_BATCH_QUEUE = u'batq' +# Extra arguments to pass to GAPI functions +GM_EXTRA_ARGS_DICT = u'exad' +# Values retrieved from oauth2service.json +GM_OAUTH2SERVICE_KEY = u'oauk' +GM_OAUTH2SERVICE_ACCOUNT_EMAIL = u'oaae' +GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID = u'oaci' +# File containing time of last GAM update check +GM_LAST_UPDATE_CHECK_TXT = u'lupc' +# Dictionary mapping OrgUnit ID to Name +GM_MAP_ORGUNIT_ID_TO_NAME = u'oi2n' +# Dictionary mapping Role ID to Name +GM_MAP_ROLE_ID_TO_NAME = u'ri2n' +# Dictionary mapping Role Name to ID +GM_MAP_ROLE_NAME_TO_ID = u'rn2i' +# Dictionary mapping User ID to Name +GM_MAP_USER_ID_TO_NAME = u'ui2n' +# +GM_Globals = { + GM_SYSEXITRC: 0, + GM_GAM_PATH: os.path.dirname(os.path.realpath(__file__)), + GM_WINDOWS: os.name == u'nt', + GM_SYS_ENCODING: sys.getfilesystemencoding() if os.name == u'nt' else u'utf-8', + GM_BATCH_QUEUE: None, + GM_EXTRA_ARGS_DICT: {u'prettyPrint': False}, + GM_OAUTH2SERVICE_KEY: None, + GM_OAUTH2SERVICE_ACCOUNT_EMAIL: None, + GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID: None, + GM_LAST_UPDATE_CHECK_TXT: u'', + GM_MAP_ORGUNIT_ID_TO_NAME: None, + GM_MAP_ROLE_ID_TO_NAME: None, + GM_MAP_ROLE_NAME_TO_ID: None, + GM_MAP_USER_ID_TO_NAME: None, + } +# +# Global variables defined by environment variables/signal files +# +# When retrieving lists of Google Drive activities from API, how many should be retrieved in each chunk +GC_ACTIVITY_MAX_RESULTS = u'activity_max_results' +# Automatically generate gam batch command if number of users specified in gam users xxx command exceeds this number +# Default: 0, don't automatically generate gam batch commands +GC_AUTO_BATCH_MIN = u'auto_batch_min' +# GAM cache directory. If no_cache is specified, this variable will be set to None +GC_CACHE_DIR = u'cache_dir' +# Character set of batch, csv, data files +GC_CHARSET = u'charset' +# Path to client_secrets.json +GC_CLIENT_SECRETS_JSON = u'client_secrets_json' +# GAM config directory containing client_secrets.json, oauth2.txt, oauth2service.json, extra_args.txt +GC_CONFIG_DIR = u'config_dir' +# custmerId from gam.cfg or retrieved from Google +GC_CUSTOMER_ID = u'customer_id' +# If debug_level > 0: extra_args[u'prettyPrint'] = True, httplib2.debuglevel = gam_debug_level, appsObj.debug = True +GC_DEBUG_LEVEL = u'debug_level' +# When retrieving lists of ChromeOS/Mobile devices from API, how many should be retrieved in each chunk +GC_DEVICE_MAX_RESULTS = u'device_max_results' +# Domain obtained from gam.cfg or oauth2.txt +GC_DOMAIN = u'domain' +# Google Drive download directory +GC_DRIVE_DIR = u'drive_dir' +# When retrieving lists of Drive files/folders from API, how many should be retrieved in each chunk +GC_DRIVE_MAX_RESULTS = u'drive_max_results' +# If no_browser is False, writeCSVfile won't open a browser when todrive is set +# and doRequestOAuth prints a link and waits for the verification code when oauth2.txt is being created +GC_NO_BROWSER = u'no_browser' +# Disable GAM API caching +GC_NO_CACHE = u'no_cache' +# Disable GAM update check +GC_NO_UPDATE_CHECK = u'no_update_check' +# Disable SSL certificate validation +GC_NO_VERIFY_SSL = u'no_verify_ssl' +# Number of threads for gam batch +GC_NUM_THREADS = u'num_threads' +# Path to oauth2.txt +GC_OAUTH2_TXT = u'oauth2_txt' +# Path to oauth2service.json +GC_OAUTH2SERVICE_JSON = u'oauth2service_json' +# Default section to use for processing +GC_SECTION = u'section' +# Add (n/m) to end of messages if number of items to be processed exceeds this number +GC_SHOW_COUNTS_MIN = u'show_counts_min' +# Enable/disable "Getting ... " messages +GC_SHOW_GETTINGS = u'show_gettings' +# GAM config directory containing admin-settings-v1.json, cloudprint-v2.json +GC_SITE_DIR = u'site_dir' +# When adding Users to Groups/Org Units, how many should be processed in each batch +GC_USER_BATCH_SIZE = u'user_batch_size' +# When retrieving lists of Users from API, how many should be retrieved in each chunk +GC_USER_MAX_RESULTS = u'user_max_results' -customerId = None -domain = None -q = None +GC_Defaults = { + GC_ACTIVITY_MAX_RESULTS: 100, + GC_AUTO_BATCH_MIN: 0, + GC_CACHE_DIR: u'', + GC_CHARSET: u'utf-8', + GC_CLIENT_SECRETS_JSON: FN_CLIENT_SECRETS_JSON, + GC_CONFIG_DIR: u'', + GC_CUSTOMER_ID: u'', + GC_DEBUG_LEVEL: 0, + GC_DEVICE_MAX_RESULTS: 500, + GC_DOMAIN: u'', + GC_DRIVE_DIR: u'', + GC_DRIVE_MAX_RESULTS: 1000, + GC_NO_BROWSER: FALSE, + GC_NO_CACHE: FALSE, + GC_NO_UPDATE_CHECK: FALSE, + GC_NO_VERIFY_SSL: FALSE, + GC_NUM_THREADS: 5, + GC_OAUTH2_TXT: FN_OAUTH2_TXT, + GC_OAUTH2SERVICE_JSON: FN_OAUTH2SERVICE_JSON, + GC_SECTION: u'', + GC_SHOW_COUNTS_MIN: 1, + GC_SHOW_GETTINGS: TRUE, + GC_SITE_DIR: u'', + GC_USER_BATCH_SIZE: 50, + GC_USER_MAX_RESULTS: 500, + } -gamPath = None -gamSiteConfigDir = None -gamUserConfigDir = None -gamDriveDir = None -gamCacheDir = None +GC_Values = {} + +GC_TYPE_BOOLEAN = u'bool' +GC_TYPE_CHOICE = u'choi' +GC_TYPE_DIRECTORY = u'dire' +GC_TYPE_EMAIL = u'emai' +GC_TYPE_FILE = u'file' +GC_TYPE_INTEGER = u'inte' +GC_TYPE_LANGUAGE = u'lang' +GC_TYPE_STRING = u'stri' + +GC_VAR_TYPE_KEY = u'type' +GC_VAR_LIMITS_KEY = u'lmit' + +GC_VAR_INFO = { + GC_ACTIVITY_MAX_RESULTS: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, 500)}, + GC_AUTO_BATCH_MIN: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (0, None)}, + GC_CACHE_DIR: {GC_VAR_TYPE_KEY: GC_TYPE_DIRECTORY}, + GC_CHARSET: {GC_VAR_TYPE_KEY: GC_TYPE_STRING}, + GC_CLIENT_SECRETS_JSON: {GC_VAR_TYPE_KEY: GC_TYPE_FILE}, + GC_CONFIG_DIR: {GC_VAR_TYPE_KEY: GC_TYPE_DIRECTORY}, + GC_CUSTOMER_ID: {GC_VAR_TYPE_KEY: GC_TYPE_STRING}, + GC_DEBUG_LEVEL: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (0, None)}, + GC_DEVICE_MAX_RESULTS: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, 1000)}, + GC_DOMAIN: {GC_VAR_TYPE_KEY: GC_TYPE_STRING}, + GC_DRIVE_DIR: {GC_VAR_TYPE_KEY: GC_TYPE_DIRECTORY}, + GC_DRIVE_MAX_RESULTS: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, 1000)}, + GC_NO_BROWSER: {GC_VAR_TYPE_KEY: GC_TYPE_BOOLEAN}, + GC_NO_CACHE: {GC_VAR_TYPE_KEY: GC_TYPE_BOOLEAN}, + GC_NO_UPDATE_CHECK: {GC_VAR_TYPE_KEY: GC_TYPE_BOOLEAN}, + GC_NO_VERIFY_SSL: {GC_VAR_TYPE_KEY: GC_TYPE_BOOLEAN}, + GC_NUM_THREADS: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, None)}, + GC_OAUTH2_TXT: {GC_VAR_TYPE_KEY: GC_TYPE_FILE}, + GC_OAUTH2SERVICE_JSON: {GC_VAR_TYPE_KEY: GC_TYPE_FILE}, + GC_SECTION: {GC_VAR_TYPE_KEY: GC_TYPE_STRING}, + GC_SHOW_COUNTS_MIN: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (0, None)}, + GC_SHOW_GETTINGS: {GC_VAR_TYPE_KEY: GC_TYPE_BOOLEAN}, + GC_SITE_DIR: {GC_VAR_TYPE_KEY: GC_TYPE_DIRECTORY}, + GC_USER_BATCH_SIZE: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, 1000)}, + GC_USER_MAX_RESULTS: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, 500)}, + } MESSAGE_CLIENT_API_ACCESS_DENIED = u'Access Denied. Please make sure the Client Name:\n\n{0}\n\nis authorized for the API Scope(s):\n\n{1}\n\nThis can be configured in your Control Panel under:\n\nSecurity -->\nAdvanced Settings -->\nManage API client access' MESSAGE_GAM_EXITING_FOR_UPDATE = u'GAM is now exiting so that you can overwrite this old version with the latest release' @@ -105,9 +267,9 @@ def convertUTF8(data): if isinstance(data, str): return data if isinstance(data, unicode): - if os.name == u'nt': + if GM_Globals[GM_WINDOWS]: return data - return data.encode('utf-8') + return data.encode(GM_Globals[GM_SYS_ENCODING]) if isinstance(data, collections.Mapping): return dict(map(convertUTF8, data.iteritems())) if isinstance(data, collections.Iterable): @@ -256,28 +418,95 @@ def writeFile(filename, data, mode=u'wb', continueOnError=False, displayError=Tr sys.stderr.write(u'{0}{1}\n'.format(ERROR_PREFIX, e)) return False systemErrorExit(6, e) - +# +# Set global variables +# Check for GAM updates based on status of noupdatecheck.txt +# def SetGlobalVariables(): - global gamPath, gamSiteConfigDir, gamUserConfigDir, gamDriveDir, gamCacheDir - 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) - if not os.path.isfile(os.path.join(gamUserConfigDir, u'noupdatecheck.txt')): + + def _getOldEnvVar(itemName, envVar): + value = os.environ.get(envVar, GC_Defaults[itemName]) + if GC_VAR_INFO[itemName][GC_VAR_TYPE_KEY] == GC_TYPE_INTEGER: + try: + number = int(value) + minVal, maxVal = GC_VAR_INFO[itemName][GC_VAR_LIMITS_KEY] + if number < minVal: + number = minVal + elif maxVal and (number > maxVal): + number = maxVal + except ValueError: + number = GC_Defaults[itemName] + value = number + GC_Defaults[itemName] = value + + def _getOldSignalFile(itemName, fileName, trueValue=True, falseValue=False): + GC_Defaults[itemName] = trueValue if os.path.isfile(os.path.join(GC_Defaults[GC_CONFIG_DIR], fileName)) else falseValue + + def _getCfgDirectory(itemName): + return GC_Defaults[itemName] + + def _getCfgFile(itemName): + value = os.path.expanduser(GC_Defaults[itemName]) + if not os.path.isabs(value): + value = os.path.expanduser(os.path.join(GC_Values[GC_CONFIG_DIR], value)) + return value + + GC_Defaults[GC_CONFIG_DIR] = GM_Globals[GM_GAM_PATH] + GC_Defaults[GC_CACHE_DIR] = os.path.join(GM_Globals[GM_GAM_PATH], u'gamcache') + GC_Defaults[GC_DRIVE_DIR] = GM_Globals[GM_GAM_PATH] + GC_Defaults[GC_SITE_DIR] = GM_Globals[GM_GAM_PATH] + + _getOldEnvVar(GC_CONFIG_DIR, u'GAMUSERCONFIGDIR') + _getOldEnvVar(GC_SITE_DIR, u'GAMSITECONFIGDIR') + _getOldEnvVar(GC_CACHE_DIR, u'GAMCACHEDIR') + _getOldEnvVar(GC_DRIVE_DIR, u'GAMDRIVEDIR') + _getOldEnvVar(GC_OAUTH2_TXT, u'OAUTHFILE') + _getOldEnvVar(GC_OAUTH2SERVICE_JSON, u'OAUTHSERVICEFILE') + if GC_Defaults[GC_OAUTH2SERVICE_JSON].find(u'.') == -1: + GC_Defaults[GC_OAUTH2SERVICE_JSON] += u'.json' + _getOldEnvVar(GC_CLIENT_SECRETS_JSON, u'CLIENTSECRETS') + _getOldEnvVar(GC_DOMAIN, u'GA_DOMAIN') + _getOldEnvVar(GC_CUSTOMER_ID, u'CUSTOMER_ID') + _getOldEnvVar(GC_CHARSET, u'GAM_CHARSET') + _getOldEnvVar(GC_NUM_THREADS, u'GAM_THREADS') + _getOldEnvVar(GC_AUTO_BATCH_MIN, u'GAM_AUTOBATCH') + _getOldEnvVar(GC_ACTIVITY_MAX_RESULTS, u'GAM_ACTIVITY_MAX_RESULTS') + _getOldEnvVar(GC_DEVICE_MAX_RESULTS, u'GAM_DEVICE_MAX_RESULTS') + _getOldEnvVar(GC_DRIVE_MAX_RESULTS, u'GAM_DRIVE_MAX_RESULTS') + _getOldEnvVar(GC_USER_MAX_RESULTS, u'GAM_USER_MAX_RESULTS') + _getOldSignalFile(GC_DEBUG_LEVEL, u'debug.gam', trueValue=4, falseValue=0) + _getOldSignalFile(GC_NO_VERIFY_SSL, u'noverifyssl.txt') + _getOldSignalFile(GC_NO_BROWSER, u'nobrowser.txt') + _getOldSignalFile(GC_NO_CACHE, u'nocache.txt') + _getOldSignalFile(GC_NO_UPDATE_CHECK, u'noupdatecheck.txt') +# Assign directories first + for itemName in GC_VAR_INFO: + if GC_VAR_INFO[itemName][GC_VAR_TYPE_KEY] == GC_TYPE_DIRECTORY: + GC_Values[itemName] = _getCfgDirectory(itemName) + for itemName in GC_VAR_INFO: + varType = GC_VAR_INFO[itemName][GC_VAR_TYPE_KEY] + if varType == GC_TYPE_FILE: + GC_Values[itemName] = _getCfgFile(itemName) + else: + GC_Values[itemName] = GC_Defaults[itemName] + GM_Globals[GM_LAST_UPDATE_CHECK_TXT] = os.path.join(GC_Values[GC_CONFIG_DIR], FN_LAST_UPDATE_CHECK_TXT) + if not GC_Values[GC_NO_UPDATE_CHECK]: doGAMCheckForUpdates() - if os.path.isfile(os.path.join(gamUserConfigDir, u'debug.gam')): - httplib2.debuglevel = 4 - extra_args[u'prettyPrint'] = True - if os.path.isfile(os.path.join(gamUserConfigDir, FN_EXTRA_ARGS_TXT)): +# Globals derived from config file values + GM_Globals[GM_OAUTH2SERVICE_KEY] = None + GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_EMAIL] = None + GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID] = None + GM_Globals[GM_EXTRA_ARGS_DICT] = {u'prettyPrint': GC_Values[GC_DEBUG_LEVEL] > 0} + httplib2.debuglevel = GC_Values[GC_DEBUG_LEVEL] + if os.path.isfile(os.path.join(GC_Values[GC_CONFIG_DIR], FN_EXTRA_ARGS_TXT)): import ConfigParser - config = ConfigParser.ConfigParser() - config.optionxform = str - config.read(os.path.join(gamUserConfigDir, FN_EXTRA_ARGS_TXT)) - extra_args.update(dict(config.items(u'extra-args'))) + ea_config = ConfigParser.ConfigParser() + ea_config.optionxform = str + ea_config.read(os.path.join(GC_Values[GC_CONFIG_DIR], FN_EXTRA_ARGS_TXT)) + GM_Globals[GM_EXTRA_ARGS_DICT].update(dict(ea_config.items(u'extra-args'))) + if GC_Values[GC_NO_CACHE]: + GC_Values[GC_CACHE_DIR] = None + return True def doGAMCheckForUpdates(forceCheck=False): import urllib2 @@ -287,7 +516,7 @@ def doGAMCheckForUpdates(forceCheck=False): return now_time = calendar.timegm(time.gmtime()) if not forceCheck: - last_check_time = readFile(os.path.join(gamUserConfigDir, FN_LAST_UPDATE_CHECK_TXT), continueOnError=True, displayError=forceCheck) + last_check_time = readFile(GM_Globals[GM_LAST_UPDATE_CHECK_TXT], continueOnError=True, displayError=forceCheck) if last_check_time == None: last_check_time = 0 if last_check_time > now_time-604800: @@ -301,7 +530,7 @@ def doGAMCheckForUpdates(forceCheck=False): if forceCheck or (latest_version > current_version): print u'Version: Check, Current: {0:.2f}, Latest: {1:.2f}'.format(current_version, latest_version) if latest_version <= current_version: - writeFile(os.path.join(gamUserConfigDir, FN_LAST_UPDATE_CHECK_TXT), str(now_time), continueOnError=True, displayError=forceCheck) + writeFile(GM_Globals[GM_LAST_UPDATE_CHECK_TXT], str(now_time), continueOnError=True, displayError=forceCheck) return a = urllib2.urlopen(GAM_APPSPOT_LATEST_VERSION_ANNOUNCEMENT) announcement = a.read() @@ -314,7 +543,7 @@ def doGAMCheckForUpdates(forceCheck=False): webbrowser.open(GAM_RELEASES) printLine(MESSAGE_GAM_EXITING_FOR_UPDATE) sys.exit(0) - writeFile(os.path.join(gamUserConfigDir, FN_LAST_UPDATE_CHECK_TXT), str(now_time), continueOnError=True, displayError=forceCheck) + writeFile(GM_Globals[GM_LAST_UPDATE_CHECK_TXT], str(now_time), continueOnError=True, displayError=forceCheck) return except (urllib2.HTTPError, urllib2.URLError): return @@ -327,22 +556,22 @@ def doGAMVersion(): struct.calcsize('P')*8, sys.version_info[3], googleapiclient.__version__, platform.platform(), platform.machine(), - gamPath) + GM_Globals[GM_GAM_PATH]) def tryOAuth(gdataObject): - global domain - global customerId - storage = oauth2client.file.Storage(os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', FN_OAUTH2_TXT))) + storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) credentials = storage.get() if credentials is None or credentials.invalid: doRequestOAuth() credentials = storage.get() if credentials.access_token_expired: - credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt')))) + credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL])) 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') - gdataObject.domain = domain + if not GC_Values[GC_DOMAIN]: + GC_Values[GC_DOMAIN] = credentials.id_token.get(u'hd', UNKNOWN).lower() + if not GC_Values[GC_CUSTOMER_ID]: + GC_Values[GC_CUSTOMER_ID] = MY_CUSTOMER + gdataObject.domain = GC_Values[GC_DOMAIN] return True def checkGDataError(e, service): @@ -427,7 +656,7 @@ def callGData(service, function, soft_errors=False, throw_errors=[], **kwargs): def callGAPI(service, function, silent_errors=False, soft_errors=False, throw_reasons=[], retry_reasons=[], **kwargs): method = getattr(service, function) retries = 10 - parameters = dict(kwargs.items() + extra_args.items()) + parameters = dict(kwargs.items() + GM_Globals[GM_EXTRA_ARGS_DICT].items()) for n in range(1, retries+1): try: return method(**parameters).execute() @@ -436,7 +665,7 @@ def callGAPI(service, function, silent_errors=False, soft_errors=False, throw_re error = json.loads(e.content) except ValueError: if n < 3: - service._http.request.credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt')))) + service._http.request.credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL])) continue if (e.resp[u'status'] == u'503') and (e.content == u'Quota exceeded for the current request'): time.sleep(1) @@ -454,7 +683,7 @@ def callGAPI(service, function, silent_errors=False, soft_errors=False, throw_re reason = http_status if reason in throw_reasons: raise e - if n != retries and (reason in [u'rateLimitExceeded', u'userRateLimitExceeded', u'backendError', u'internalError'] or reason in retry_reasons): + if n != retries and (reason in [u'quotaExceeded', u'rateLimitExceeded', u'userRateLimitExceeded', u'backendError', u'internalError'] or reason in retry_reasons): wait_on_fail = (2 ** n) if (2 ** n) < 60 else 60 randomness = float(random.randint(1, 1000)) / 1000 wait_on_fail = wait_on_fail + randomness @@ -555,7 +784,7 @@ def getAPIScope(api): def getServiceFromDiscoveryDocument(api, version, http): disc_filename = u'%s-%s.json' % (api, version) - disc_file = os.path.join(gamSiteConfigDir, disc_filename) + disc_file = os.path.join(GC_Values[GC_SITE_DIR], disc_filename) if hasattr(sys, '_MEIPASS'): pyinstaller_disc_file = os.path.join(sys._MEIPASS, disc_filename) else: @@ -569,14 +798,13 @@ def getServiceFromDiscoveryDocument(api, version, http): return googleapiclient.discovery.build_from_document(discovery, base=u'https://www.googleapis.com', http=http) def buildGAPIObject(api): - global domain, customerId - storage = oauth2client.file.Storage(os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', FN_OAUTH2_TXT))) + storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) credentials = storage.get() - if credentials is None or credentials.invalid: + if not credentials or credentials.invalid: doRequestOAuth() credentials = storage.get() credentials.user_agent = GAM_INFO - http = credentials.authorize(httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt')), cache=gamCacheDir)) + http = credentials.authorize(httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL], cache=GC_Values[GC_CACHE_DIR])) version = getAPIVer(api) if api in [u'directory', u'reports', u'datatransfer']: api = u'admin' @@ -588,44 +816,58 @@ def buildGAPIObject(api): systemErrorExit(4, e) except httplib2.CertificateValidationUnsupported: noPythonSSLExit() - try: - domain = os.environ[u'GA_DOMAIN'] - _, customerId_result = service._http.request(u'https://www.googleapis.com/admin/directory/v1/users?domain=%s&maxResults=1&fields=users(customerId)' % domain) - customerId_obj = json.loads(customerId_result) - customerId = customerId_obj[u'users'][0][u'customerId'] - except KeyError: - try: - domain = credentials.id_token[u'hd'] - except (TypeError, KeyError): - domain = UNKNOWN_DOMAIN - customerId = MY_CUSTOMER + if GC_Values[GC_DOMAIN]: + if not GC_Values[GC_CUSTOMER_ID]: + resp, result = service._http.request(u'https://www.googleapis.com/admin/directory/v1/users?domain={0}&maxResults=1&fields=users(customerId)'.format(GC_Values[GC_DOMAIN])) + try: + resultObj = json.loads(result) + except ValueError: + systemErrorExit(8, u'Unexpected response: {0}'.format(result)) + if resp[u'status'] in [u'403', u'404']: + try: + message = resultObj[u'error'][u'errors'][0][u'message'] + except KeyError: + message = resultObj[u'error'][u'message'] + systemErrorExit(8, u'{0} - {1}'.format(message, GC_Values[GC_DOMAIN])) + try: + GC_Values[GC_CUSTOMER_ID] = resultObj[u'users'][0][u'customerId'] + except KeyError: + GC_Values[GC_CUSTOMER_ID] = MY_CUSTOMER + else: + GC_Values[GC_DOMAIN] = credentials.id_token.get(u'hd', UNKNOWN).lower() + if not GC_Values[GC_CUSTOMER_ID]: + GC_Values[GC_CUSTOMER_ID] = MY_CUSTOMER return service -def buildGAPIServiceObject(api, act_as=None, soft_errors=False): - oauth2servicefile = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHSERVICEFILE', 'oauth2service')) - oauth2servicefilejson = u'%s.json' % oauth2servicefile - oauth2servicefilep12 = u'%s.p12' % oauth2servicefile - json_string = readFile(oauth2servicefilejson, continueOnError=True, displayError=True) - if not json_string: - printLine(MESSAGE_WIKI_INSTRUCTIONS_OAUTH2SERVICE_JSON) - printLine(GAM_WIKI_CREATE_CLIENT_SECRETS) - sys.exit(6) - json_data = json.loads(json_string) - try: - SERVICE_ACCOUNT_EMAIL = json_data[u'web'][u'client_email'] - SERVICE_ACCOUNT_CLIENT_ID = json_data[u'web'][u'client_id'] - key = readFile(oauth2servicefilep12) - except KeyError: - # new format with config and data in the .json file... - SERVICE_ACCOUNT_EMAIL = json_data[u'client_email'] - SERVICE_ACCOUNT_CLIENT_ID = json_data[u'client_id'] - key = json_data[u'private_key'] +def buildGAPIServiceObject(api, act_as, soft_errors=False): + if not GM_Globals[GM_OAUTH2SERVICE_KEY]: + json_string = readFile(GC_Values[GC_OAUTH2SERVICE_JSON], continueOnError=True, displayError=True) + if not json_string: + printLine(MESSAGE_WIKI_INSTRUCTIONS_OAUTH2SERVICE_JSON) + printLine(GAM_WIKI_CREATE_CLIENT_SECRETS) + systemErrorExit(6, None) + json_data = json.loads(json_string) + try: + # new format with config and key in the .json file... + GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_EMAIL] = json_data[u'client_email'] + GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID] = json_data[u'client_id'] + GM_Globals[GM_OAUTH2SERVICE_KEY] = json_data[u'private_key'] + except KeyError: + try: + # old format with config in the .json file and key in the .p12 file... + GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_EMAIL] = json_data[u'web'][u'client_email'] + GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID] = json_data[u'web'][u'client_id'] + GM_Globals[GM_OAUTH2SERVICE_KEY] = readFile(GC_Values[GC_OAUTH2SERVICE_JSON].replace(u'.json', u'.p12')) + except KeyError: + printLine(MESSAGE_WIKI_INSTRUCTIONS_OAUTH2SERVICE_JSON) + printLine(GAM_WIKI_CREATE_CLIENT_SECRETS) + systemErrorExit(17, MESSAGE_OAUTH2SERVICE_JSON_INVALID.format(GC_Values[GC_OAUTH2SERVICE_JSON])) scope = getAPIScope(api) - if act_as == None: - credentials = oauth2client.client.SignedJwtAssertionCredentials(SERVICE_ACCOUNT_EMAIL, key, scope=scope, user_agent=GAM_INFO) - else: - credentials = oauth2client.client.SignedJwtAssertionCredentials(SERVICE_ACCOUNT_EMAIL, key, scope=scope, user_agent=GAM_INFO, sub=act_as) - http = credentials.authorize(httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt')), cache=gamCacheDir)) + credentials = oauth2client.client.SignedJwtAssertionCredentials(GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_EMAIL], + GM_Globals[GM_OAUTH2SERVICE_KEY], + scope=scope, user_agent=GAM_INFO, sub=act_as) + http = credentials.authorize(httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL], + cache=GC_Values[GC_CACHE_DIR])) version = getAPIVer(api) try: return googleapiclient.discovery.build(api, version, http=http) @@ -635,7 +877,7 @@ def buildGAPIServiceObject(api, act_as=None, soft_errors=False): systemErrorExit(4, e) except oauth2client.client.AccessTokenRefreshError, e: if e.message in [u'access_denied', u'unauthorized_client: Unauthorized client or scope in request.']: - systemErrorExit(5, MESSAGE_CLIENT_API_ACCESS_DENIED.format(SERVICE_ACCOUNT_CLIENT_ID, u','.join(scope))) + systemErrorExit(5, MESSAGE_CLIENT_API_ACCESS_DENIED.format(GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID], u','.join(scope))) sys.stderr.write(u'{0}{1}\n'.format(ERROR_PREFIX, e)) if soft_errors: return False @@ -647,7 +889,7 @@ def buildDiscoveryObject(api): if api in [u'directory', u'reports']: api = u'admin' params = {'api': api, 'apiVersion': version} - http = httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt')), cache=gamCacheDir) + http = httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL], cache=GC_Values[GC_CACHE_DIR]) requested_url = uritemplate.expand(googleapiclient.discovery.DISCOVERY_URI, params) resp, content = http.request(requested_url) if resp.status == 404: @@ -667,7 +909,7 @@ def commonAppsObjInit(appsObj): #Identify GAM to Google's Servers appsObj.source = GAM_INFO #Show debugging output if debug.gam exists - if os.path.isfile(os.path.join(gamUserConfigDir, u'debug.gam')): + if GC_Values[GC_DEBUG_LEVEL] > 0: appsObj.debug = True return appsObj @@ -683,10 +925,6 @@ def getEmailSettingsObject(): import gdata.apps.emailsettings.service return commonAppsObjInit(gdata.apps.emailsettings.service.EmailSettingsService()) -def getResCalObject(): - import gdata.apps.res_cal.service - return commonAppsObjInit(gdata.apps.res_cal.service.ResCalService()) - def geturl(url, dst): import urllib2 u = urllib2.urlopen(url) @@ -713,9 +951,9 @@ def geturl(url, dst): closeFile(f) def showReport(): - report = sys.argv[2].lower() - global customerId rep = buildGAPIObject(u'reports') + report = sys.argv[2].lower() + customerId = GC_Values[GC_CUSTOMER_ID] if customerId == MY_CUSTOMER: customerId = None date = filters = parameters = actorIpAddress = startTime = endTime = eventName = None @@ -880,7 +1118,7 @@ def doDelegates(users): if sys.argv[4].lower() == u'to': delegate = sys.argv[5].lower() if not delegate.find(u'@') > 0: - delegate_domain = domain.lower() + delegate_domain = GC_Values[GC_DOMAIN].lower() delegate_email = u'%s@%s' % (delegate, delegate_domain) else: delegate_domain = delegate[delegate.find(u'@')+1:].lower() @@ -896,7 +1134,7 @@ def doDelegates(users): delegator_email = delegator delegator = delegator[:delegator.find('@')] else: - delegator_domain = domain.lower() + delegator_domain = GC_Values[GC_DOMAIN].lower() delegator_email = u'%s@%s' % (delegator, delegator_domain) emailsettings.domain = delegator_domain print u"Giving %s delegate access to %s (%s of %s)" % (delegate_email, delegator_email, i, count) @@ -998,7 +1236,7 @@ def getDelegates(users): emailsettings.domain = user[user.find('@')+1:] user = user[:user.find('@')] else: - emailsettings.domain = domain + emailsettings.domain = GC_Values[GC_DOMAIN] sys.stderr.write(u"Getting delegates for %s...\n" % (user + '@' + emailsettings.domain)) delegates = callGData(service=emailsettings, function=u'GetDelegates', soft_errors=True, delegator=user) try: @@ -1017,7 +1255,7 @@ def deleteDelegate(users): if users[0].find(u'@') > 0: delegatedomain = users[0][users[0].find(u'@')+1:] else: - delegatedomain = domain + delegatedomain = GC_Values[GC_DOMAIN] delegate = delegate+u'@'+delegatedomain count = len(users) i = 1 @@ -1026,7 +1264,7 @@ def deleteDelegate(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Deleting %s delegate access to %s (%s of %s)" % (delegate, user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'DeleteDelegate', delegate=delegate, delegator=user) @@ -1161,7 +1399,7 @@ def doCreateDomain(): cd = buildGAPIObject(u'directory') domain_name = sys.argv[3] body = {u'domainName': domain_name} - callGAPI(service=cd.domains(), function=u'insert', customer=customerId, body=body) + callGAPI(service=cd.domains(), function=u'insert', customer=GC_Values[GC_CUSTOMER_ID], body=body) print u'Added domain %s' % domain_name def doCreateDomainAlias(): @@ -1169,7 +1407,7 @@ def doCreateDomainAlias(): body = {} body[u'domainAliasName'] = sys.argv[3] body[u'parentDomainName'] = sys.argv[4] - callGAPI(service=cd.domainAliases(), function=u'insert', customer=customerId, body=body) + callGAPI(service=cd.domainAliases(), function=u'insert', customer=GC_Values[GC_CUSTOMER_ID], body=body) def doUpdateDomain(): cd = buildGAPIObject(u'directory') @@ -1183,16 +1421,16 @@ def doUpdateDomain(): else: print u'ERROR: %s is not a valid argument for "gam update domain"' % sys.argv[i] sys.exit(2) - callGAPI(service=cd.customers(), function=u'update', customerKey=customerId, body=body) + callGAPI(service=cd.customers(), function=u'update', customerKey=GC_Values[GC_CUSTOMER_ID], body=body) print u'%s is now the primary domain.' % domain_name def doGetDomainInfo(): if (len(sys.argv) < 4) or (sys.argv[3] == u'logo'): doGetInstanceInfo() return - domainName = sys.argv[3] cd = buildGAPIObject(u'directory') - result = callGAPI(service=cd.domains(), function=u'get', customer=customerId, domainName=domainName) + domainName = sys.argv[3] + result = callGAPI(service=cd.domains(), function=u'get', customer=GC_Values[GC_CUSTOMER_ID], domainName=domainName) if u'creationTime' in result: result[u'creationTime'] = unicode(datetime.datetime.fromtimestamp(int(result[u'creationTime'])/1000)) if u'domainAliases' in result: @@ -1202,16 +1440,16 @@ def doGetDomainInfo(): print_json(None, result) def doGetDomainAliasInfo(): - alias = sys.argv[3] cd = buildGAPIObject(u'directory') - result = callGAPI(service=cd.domainAliases(), function=u'get', customer=customerId, domainAliasName=alias) + alias = sys.argv[3] + result = callGAPI(service=cd.domainAliases(), function=u'get', customer=GC_Values[GC_CUSTOMER_ID], domainAliasName=alias) if u'creationTime' in result: result[u'creationTime'] = unicode(datetime.datetime.fromtimestamp(int(result[u'creationTime'])/1000)) print_json(None, result) def doGetCustomerInfo(): cd = buildGAPIObject(u'directory') - customer_info = callGAPI(service=cd.customers(), function=u'get', customerKey=customerId) + customer_info = callGAPI(service=cd.customers(), function=u'get', customerKey=GC_Values[GC_CUSTOMER_ID]) print_json(None, customer_info) def doUpdateCustomer(): @@ -1251,25 +1489,25 @@ def doUpdateCustomer(): else: print u'ERROR: %s is not a valid argument for "gam update customer"' % myarg sys.exit(2) - callGAPI(service=cd.customers(), function=u'update', customerKey=customerId, body=body) + callGAPI(service=cd.customers(), function=u'update', customerKey=GC_Values[GC_CUSTOMER_ID], body=body) print u'Updated customer' def doDelDomain(): - domainName = sys.argv[3] cd = buildGAPIObject(u'directory') - callGAPI(service=cd.domains(), function=u'delete', customer=customerId, domainName=domainName) + domainName = sys.argv[3] + callGAPI(service=cd.domains(), function=u'delete', customer=GC_Values[GC_CUSTOMER_ID], domainName=domainName) def doDelDomainAlias(): - domainAliasName = sys.argv[3] cd = buildGAPIObject(u'directory') - callGAPI(service=cd.domainAliases(), function=u'delete', customer=customerId, domainAliasName=domainAliasName) + domainAliasName = sys.argv[3] + callGAPI(service=cd.domainAliases(), function=u'delete', customer=GC_Values[GC_CUSTOMER_ID], domainAliasName=domainAliasName) def doPrintDomains(): + cd = buildGAPIObject(u'directory') titles = [] domains_attributes = [{}] todrive = False - cd = buildGAPIObject(u'directory') - domains = callGAPI(service=cd.domains(), function=u'list', customer=customerId) + domains = callGAPI(service=cd.domains(), function=u'list', customer=GC_Values[GC_CUSTOMER_ID]) i = 3 while i < len(sys.argv): if sys.argv[i].lower() == u'todrive': @@ -1312,6 +1550,152 @@ def doPrintDomains(): domains_attributes.append(aliasdomain_attributes) output_csv(domains_attributes, titles, u'Domains', todrive) +def doDelAdmin(): + cd = buildGAPIObject(u'directory') + roleAssignmentId = sys.argv[3] + print u'Deleting Admin Role Assignment %s' % roleAssignmentId + callGAPI(service=cd.roleAssignments(), function=u'delete', + customer=GC_Values[GC_CUSTOMER_ID], roleAssignmentId=roleAssignmentId) + +def doCreateAdmin(): + cd = buildGAPIObject(u'directory') + body = {} + user = sys.argv[3] + if user[:4].lower() == u'uid:': + body[u'assignedTo'] = user[4:] + else: + print user[:3] + body[u'assignedTo'] = callGAPI(service=cd.users(), function=u'get', + userKey=user, projection=u'basic', fields=u'id')[u'id'] + role = sys.argv[4] + if role[:4].lower() == u'uid:': + body[u'roleId'] = role[4:] + else: + body[u'roleId'] = roleid_from_role(role) + if not body[u'roleId']: + print u'ERROR: %s is not a valid role. Please ensure role name is exactly as shown in admin console.' % role + sys.exit(4) + body[u'scopeType'] = sys.argv[5].upper() + if body[u'scopeType'] not in [u'CUSTOMER', u'ORG_UNIT']: + print u'ERROR: scope type must be customer or org_unit, got %s' % body[u'scopeType'] + sys.exit(3) + if body[u'scopeType'] == u'ORG_UNIT': + orgUnit = sys.argv[6] + if orgUnit[:4] == u'uid:': + body[u'orgUnitId'] = orgUnit[4:] + else: + if orgUnit[0] == u'/': + orgUnit = orgUnit[1:] + body[u'orgUnitId'] = callGAPI(service=cd.orgunits(), function=u'get', + customerId=GC_Values[GC_CUSTOMER_ID], orgUnitPath=orgUnit, + fields=u'orgUnitId')[u'orgUnitId'][3:] + if body[u'scopeType'] == u'CUSTOMER': + scope = u'customer' + else: + scope = orgUnit + print u'Giving %s admin role %s for %s' % (user, role, scope) + callGAPI(service=cd.roleAssignments(), function=u'insert', + customer=GC_Values[GC_CUSTOMER_ID], body=body) + +def doPrintAdmins(): + cd = buildGAPIObject(u'directory') + roleId = None + userKey = None + i = 3 + while i < len(sys.argv): + if sys.argv[i].lower() == u'user': + userKey = sys.argv[i+1] + i += 2 + elif sys.argv[i].lower() == u'role': + role = sys.argv[i+1] + if role[:4].lower() == u'uid:': + roleId = role[4:] + else: + roleId = roleid_from_role(role) + if not roleId: + print u'ERROR: %s is not a valid role' % role + sys.exit(5) + i += 2 + admins = callGAPIpages(service=cd.roleAssignments(), function=u'list', + customer=GC_Values[GC_CUSTOMER_ID], userKey=userKey, roleId=roleId, maxResults=200) + admins_attrib = [{}] + for admin in admins: + admin_attrib = {} + for key, value in admin.items(): + if key in [u'kind', u'etag']: + continue + if key not in admins_attrib[0]: + admins_attrib[0][key] = key + admin_attrib[key] = value + if key == u'assignedTo': + assignedToUser = user_from_userid(value) + if u'assignedToUser' not in admins_attrib[0]: + admins_attrib[0][u'assignedToUser'] = u'assignedToUser' + admin_attrib[u'assignedToUser'] = assignedToUser + elif key == u'roleId': + role = role_from_roleid(value) + if u'role' not in admins_attrib[0]: + admins_attrib[0][u'role'] = u'role' + admin_attrib[u'role'] = role + elif key == u'orgUnitId': + orgUnit = orgunit_from_orgunitid(value) + if u'orgUnit' not in admins_attrib[0]: + admins_attrib[0][u'orgUnit'] = u'orgUnit' + admin_attrib[u'orgUnit'] = orgUnit + admins_attrib.append(admin_attrib) + output_csv(admins_attrib, admins_attrib[0], u'Admins', False) + +def buildOrgUnitIdToNameMap(): + cd = buildGAPIObject(u'directory') + result = callGAPI(service=cd.orgunits(), function=u'list', + customerId=GC_Values[GC_CUSTOMER_ID], + fields=u'organizationUnits(orgUnitPath,orgUnitId)') + GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME] = {} + for orgUnit in result[u'organizationUnits']: + GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME][orgUnit[u'orgUnitId']] = orgUnit[u'orgUnitPath'] + +def orgunit_from_orgunitid(orgunitid): + if not GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME]: + buildOrgUnitIdToNameMap() + return GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME][u'id:%s' % orgunitid] + +def buildRoleIdToNameToIdMap(): + cd = buildGAPIObject(u'directory') + result = callGAPIpages(service=cd.roles(), function=u'list', items=u'items', + customer=GC_Values[GC_CUSTOMER_ID], + fields=u'nextPageToken,items(roleId,roleName)', + maxResults=100) + GM_Globals[GM_MAP_ROLE_ID_TO_NAME] = {} + GM_Globals[GM_MAP_ROLE_NAME_TO_ID] = {} + for role in result: + GM_Globals[GM_MAP_ROLE_ID_TO_NAME][role[u'roleId']] = role[u'roleName'] + GM_Globals[GM_MAP_ROLE_NAME_TO_ID][role[u'roleName']] = role[u'roleId'] + +def role_from_roleid(roleid): + if not GM_Globals[GM_MAP_ROLE_ID_TO_NAME]: + buildRoleIdToNameToIdMap() + return GM_Globals[GM_MAP_ROLE_ID_TO_NAME][roleid] + +def roleid_from_role(role): + if not GM_Globals[GM_MAP_ROLE_NAME_TO_ID]: + buildRoleIdToNameToIdMap() + return GM_Globals[GM_MAP_ROLE_NAME_TO_ID][role] + +def buildUserIdToNameMap(): + cd = buildGAPIObject(u'directory') + result = callGAPIpages(service=cd.users(), function=u'list', items=u'users', + customer=GC_Values[GC_CUSTOMER_ID], + fields=u'nextPageToken,users(id,primaryEmail)', + maxResults=GC_Values[GC_USER_MAX_RESULTS]) + GM_Globals[GM_MAP_USER_ID_TO_NAME] = {} + for user in result: + GM_Globals[GM_MAP_USER_ID_TO_NAME][user[u'id']] = user[u'primaryEmail'] + +def user_from_userid(userid): + if not GM_Globals[GM_MAP_USER_ID_TO_NAME]: + buildUserIdToNameMap() + return GM_Globals[GM_MAP_USER_ID_TO_NAME][userid] + SERVICE_NAME_TO_ID_MAP = { u'Drive': u'55656082996', u'Google+': '553547912911', @@ -1321,7 +1705,7 @@ def appID2app(dt, appID): for serviceName, serviceID in SERVICE_NAME_TO_ID_MAP.items(): if appID == serviceID: return serviceName - online_services = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=customerId) + online_services = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=GC_Values[GC_CUSTOMER_ID]) for online_service in online_services: if appID == online_service[u'id']: return online_service[u'name'] @@ -1340,7 +1724,7 @@ def app2appID(dt, app): serviceName = app.lower() if serviceName in SERVICE_NAME_CHOICES_MAP: return (SERVICE_NAME_CHOICES_MAP[serviceName], SERVICE_NAME_TO_ID_MAP[SERVICE_NAME_CHOICES_MAP[serviceName]]) - online_services = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=customerId) + online_services = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=GC_Values[GC_CUSTOMER_ID]) for online_service in online_services: if serviceName == online_service[u'name'].lower(): return online_service[u'id'] @@ -1350,9 +1734,9 @@ def app2appID(dt, app): def convertToUserID(user): if user[:4].lower() == u'uid:': return user[4:] - if user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) cd = buildGAPIObject(u'directory') + if user.find(u'@') == -1: + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) try: return callGAPI(service=cd.users(), function=u'get', throw_reasons=[u'notFound'], userKey=user, fields=u'id')[u'id'] except googleapiclient.errors.HttpError: @@ -1390,7 +1774,7 @@ def doCreateDataTranfer(): def doPrintTransferApps(): dt = buildGAPIObject(u'datatransfer') - apps = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=customerId) + apps = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=GC_Values[GC_CUSTOMER_ID]) for app in apps: print_json(None, app) print @@ -1420,7 +1804,7 @@ def doPrintDataTransfers(): sys.exit(2) transfers_attributes = [{}] transfers = callGAPIpages(service=dt.transfers(), function=u'list', - items=u'dataTransfers', customerId=customerId, status=status, + items=u'dataTransfers', customerId=GC_Values[GC_CUSTOMER_ID], status=status, newOwnerUserId=newOwnerUserId, oldOwnerUserId=oldOwnerUserId) for transfer in transfers: for i in range(0, len(transfer[u'applicationDataTransfers'])): @@ -1502,10 +1886,10 @@ def doCreateCourse(): print u'Created course %s' % result[u'id'] def doGetCourseInfo(): + croom = buildGAPIObject(u'classroom') courseId = sys.argv[3] if not courseId.isdigit(): courseId = u'd:%s' % courseId - croom = buildGAPIObject(u'classroom') info = callGAPI(service=croom.courses(), function=u'get', id=courseId) print_json(None, info) teachers = callGAPIpages(service=croom.courses().teachers(), function=u'list', items=u'teachers', courseId=courseId) @@ -1827,7 +2211,7 @@ def changeCalendarAttendees(users): for user in users: sys.stdout.write(u'Checking user %s\n' % user) if user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) cal = buildGAPIServiceObject(u'calendar', user) page_token = None while True: @@ -1881,10 +2265,10 @@ def deleteCalendar(users): cal = buildGAPIServiceObject(u'calendar', users[0]) calendarId = sys.argv[5] if calendarId.find(u'@') == -1: - calendarId = u'%s@%s' % (calendarId, domain) + calendarId = u'%s@%s' % (calendarId, GC_Values[GC_DOMAIN]) for user in users: if user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) cal = buildGAPIServiceObject(u'calendar', user) callGAPI(service=cal.calendarList(), function=u'delete', calendarId=calendarId) @@ -1894,7 +2278,7 @@ def addCalendar(users): body[u'defaultReminders'] = list() body[u'id'] = sys.argv[5] if body[u'id'].find(u'@') == -1: - body[u'id'] = u'%s@%s' % (body[u'id'], domain) + body[u'id'] = u'%s@%s' % (body[u'id'], GC_Values[GC_DOMAIN]) body[u'selected'] = True body[u'hidden'] = False colorRgbFormat = False @@ -1951,7 +2335,7 @@ def addCalendar(users): count = len(users) for user in users: if user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) print u"Subscribing %s to %s calendar (%s of %s)" % (user, body['id'], i, count) cal = buildGAPIServiceObject(u'calendar', user) callGAPI(service=cal.calendarList(), function=u'insert', body=body, colorRgbFormat=colorRgbFormat) @@ -2022,8 +2406,8 @@ def updateCalendar(users): callGAPI(service=cal.calendarList(), function=u'update', calendarId=calendarId, body=body, colorRgbFormat=colorRgbFormat) def doPrinterShowACL(): - show_printer = sys.argv[2] cp = buildGAPIObject(u'cloudprint') + show_printer = sys.argv[2] printer_info = callGAPI(service=cp.printers(), function=u'get', printerid=show_printer) checkCloudPrintResult(printer_info) for acl in printer_info[u'printers'][0][u'access']: @@ -2033,6 +2417,7 @@ def doPrinterShowACL(): print def doPrinterAddACL(): + cp = buildGAPIObject(u'cloudprint') printer = sys.argv[2] role = sys.argv[4].upper() scope = sys.argv[5] @@ -2045,7 +2430,6 @@ def doPrinterAddACL(): skip_notification = None elif scope.find(u'@') == -1: scope = u'/hd/domain/%s' % scope - cp = buildGAPIObject(u'cloudprint') result = callGAPI(service=cp.printers(), function=u'share', printerid=printer, role=role, scope=scope, public=public, skip_notification=skip_notification) checkCloudPrintResult(result) who = scope @@ -2055,6 +2439,7 @@ def doPrinterAddACL(): print u'Added %s %s' % (role, who) def doPrinterDelACL(): + cp = buildGAPIObject(u'cloudprint') printer = sys.argv[2] scope = sys.argv[4] public = None @@ -2063,7 +2448,6 @@ def doPrinterDelACL(): scope = None elif scope.find(u'@') == -1: scope = u'/hd/domain/%s' % scope - cp = buildGAPIObject(u'cloudprint') result = callGAPI(service=cp.printers(), function=u'unshare', printerid=printer, scope=scope, public=public) checkCloudPrintResult(result) who = scope @@ -2295,9 +2679,9 @@ def doPrinterRegister(): print u'Created printer %s' % result[u'printers'][0][u'id'] def doPrintJobResubmit(): + cp = buildGAPIObject(u'cloudprint') jobid = sys.argv[2] printerid = sys.argv[4] - cp = buildGAPIObject(u'cloudprint') ssd = '''{ "state": {"type": "HELD"} }''' @@ -2309,8 +2693,8 @@ def doPrintJobResubmit(): print u'Success resubmitting %s as job %s to printer %s' % (jobid, result[u'job'][u'id'], printerid) def doPrintJobSubmit(): - printer = sys.argv[2] cp = buildGAPIObject(u'cloudprint') + printer = sys.argv[2] content = sys.argv[4] form_fields = {u'printerid': printer, u'title': content, @@ -2350,15 +2734,15 @@ def doPrintJobSubmit(): print u'Submitted print job %s' % result[u'job'][u'id'] def doDeletePrintJob(): - job = sys.argv[2] cp = buildGAPIObject(u'cloudprint') + job = sys.argv[2] result = callGAPI(service=cp.jobs(), function=u'delete', jobid=job) checkCloudPrintResult(result) print u'Print Job %s deleted' % job def doCancelPrintJob(): - job = sys.argv[2] cp = buildGAPIObject(u'cloudprint') + job = sys.argv[2] ssd = '{"state": {"type": "ABORTED", "user_action_cause": {"action_code": "CANCELLED"}}}' result = callGAPI(service=cp.jobs(), function=u'update', jobid=job, semantic_state_diff=ssd) checkCloudPrintResult(result) @@ -2376,10 +2760,10 @@ def checkCloudPrintResult(result): sys.exit(result[u'errorCode']) def doCalendarShowACL(): - show_cal = sys.argv[2] cal = buildGAPIObject(u'calendar') + show_cal = sys.argv[2] if show_cal.find(u'@') == -1: - show_cal = u'%s@%s' % (show_cal, domain) + show_cal = u'%s@%s' % (show_cal, GC_Values[GC_DOMAIN]) acls = callGAPI(service=cal.acl(), function=u'list', calendarId=show_cal) try: for rule in acls[u'items']: @@ -2399,7 +2783,7 @@ def doCalendarAddACL(calendarId=None, act_as=None, role=None, scope=None, entity if calendarId == None: calendarId = sys.argv[2] if calendarId.find(u'@') == -1: - calendarId = u'%s@%s' % (calendarId, domain) + calendarId = u'%s@%s' % (calendarId, GC_Values[GC_DOMAIN]) if role != None: body[u'role'] = role else: @@ -2427,14 +2811,14 @@ def doCalendarAddACL(calendarId=None, act_as=None, role=None, scope=None, entity else: body[u'scope'][u'value'] = sys.argv[i].lower() if (body[u'scope'][u'type'] in [u'user', u'group']) and body[u'scope'][u'value'].find(u'@') == -1: - body[u'scope'][u'value'] = u'%s@%s' % (body[u'scope'][u'value'], domain) + body[u'scope'][u'value'] = u'%s@%s' % (body[u'scope'][u'value'], GC_Values[GC_DOMAIN]) except IndexError: pass if body[u'scope'][u'type'] == u'domain': try: body[u'scope'][u'value'] = sys.argv[6].lower() except IndexError: - body[u'scope'][u'value'] = domain + body[u'scope'][u'value'] = GC_Values[GC_DOMAIN] callGAPI(service=cal.acl(), function=u'insert', calendarId=calendarId, body=body) def doCalendarUpdateACL(): @@ -2462,7 +2846,7 @@ def doCalendarWipeData(): calendarId = sys.argv[2] cal = buildGAPIServiceObject(u'calendar', calendarId) if calendarId.find(u'@') == -1: - calendarId = u'%s@%s' % (calendarId, domain) + calendarId = u'%s@%s' % (calendarId, GC_Values[GC_DOMAIN]) callGAPI(service=cal.calendars(), function=u'clear', calendarId=calendarId) def doCalendarAddEvent(): @@ -2586,6 +2970,7 @@ def doCalendarAddEvent(): def doProfile(users): + cd = buildGAPIObject(u'directory') if sys.argv[4].lower() == u'share' or sys.argv[4].lower() == u'shared': body = {u'includeInGlobalAddressList': True} elif sys.argv[4].lower() == u'unshare' or sys.argv[4].lower() == u'unshared': @@ -2593,27 +2978,26 @@ def doProfile(users): else: print u'ERROR: value for "gam profile" must be true or false, got %s' % sys.argv[4] sys.exit(2) - cd = buildGAPIObject(u'directory') count = len(users) i = 1 for user in users: if user[:4].lower() == u'uid:': user = user[4:] elif user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) print u'Setting Profile Sharing to %s for %s (%s of %s)' % (body[u'includeInGlobalAddressList'], user, i, count) callGAPI(service=cd.users(), function=u'patch', soft_errors=True, userKey=user, body=body) i += 1 def showProfile(users): + cd = buildGAPIObject(u'directory') i = 1 count = len(users) - cd = buildGAPIObject(u'directory') for user in users: if user[:4].lower() == u'uid:': user = user[4:] elif user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) result = callGAPI(service=cd.users(), function=u'get', userKey=user, fields=u'includeInGlobalAddressList') try: print u'User: %s Profile Shared: %s (%s/%s)' % (user, result[u'includeInGlobalAddressList'], i, count) @@ -2629,7 +3013,7 @@ def doPhoto(users): if user[:4].lower() == u'uid:': user = user[4:] elif user.find('@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) filename = sys.argv[5].replace(u'#user#', user) filename = filename.replace(u'#email#', user) filename = filename.replace(u'#username#', user[:user.find(u'@')]) @@ -2662,7 +3046,7 @@ def getPhoto(users): if user[:4].lower() == u'uid:': user = user[4:] elif user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) filename = u'%s.jpg' % user print u"Saving photo to %s (%s/%s)" % (filename, i, count) i += 1 @@ -2688,7 +3072,7 @@ def deletePhoto(users): if user[:4].lower() == u'uid:': user = user[4:] elif user.find('@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) print u"Deleting photo for %s (%s of %s)" % (user, i, count) callGAPI(service=cd.users().photos(), function='delete', userKey=user) i += 1 @@ -2801,7 +3185,7 @@ def doDriveActivity(users): feed = callGAPIpages(service=activity.activities(), function=u'list', items=u'activities', page_message=page_message, source=u'drive.google.com', userId=u'me', drive_ancestorId=drive_ancestorId, groupingStrategy=u'none', - drive_fileId=drive_fileId, pageSize=100) + drive_fileId=drive_fileId, pageSize=GC_Values[GC_ACTIVITY_MAX_RESULTS]) for item in feed: activity_attributes.append(flatten_json(item[u'combinedEvent'])) for an_item in activity_attributes[-1]: @@ -3013,7 +3397,7 @@ def showDriveFiles(users): page_message = u' got %%%%total_items%%%% files for %s...\n' % user feed = callGAPIpages(service=drive.files(), function=u'list', page_message=page_message, soft_errors=True, - q=query, fields=fields, maxResults=1000) + q=query, fields=fields, maxResults=GC_Values[GC_DRIVE_MAX_RESULTS]) for f_file in feed: a_file = {u'Owner': user} for attrib in f_file: @@ -3053,7 +3437,7 @@ def doDriveSearch(drive, query=None): page_message = u' got %%total_items%% files...\n' files = callGAPIpages(service=drive.files(), function=u'list', page_message=page_message, - q=query, fields=u'nextPageToken,items(id)', maxResults=1000) + q=query, fields=u'nextPageToken,items(id)', maxResults=GC_Values[GC_DRIVE_MAX_RESULTS]) ids = list() for f_file in files: ids.append(f_file[u'id']) @@ -3106,7 +3490,7 @@ def showDriveFileTree(users): sys.stderr.write(u'Getting all files for %s...\n' % user) page_message = u' got %%%%total_items%%%% files for %s...\n' % user feed = callGAPIpages(service=drive.files(), function=u'list', page_message=page_message, - fields=u'items(id,title,parents(id),mimeType),nextPageToken', maxResults=1000) + fields=u'items(id,title,parents(id),mimeType),nextPageToken', maxResults=GC_Values[GC_DRIVE_MAX_RESULTS]) printDriveFolderContents(feed, root_folder, 0) def deleteEmptyDriveFolders(users): @@ -3121,7 +3505,7 @@ def deleteEmptyDriveFolders(users): sys.stderr.write(u'Getting folders for %s...\n' % user) page_message = u' got %%%%total_items%%%% folders for %s...\n' % user feed = callGAPIpages(service=drive.files(), function=u'list', page_message=page_message, - q=query, fields=u'items(title,id),nextPageToken', maxResults=1000) + q=query, fields=u'items(title,id),nextPageToken', maxResults=GC_Values[GC_DRIVE_MAX_RESULTS]) deleted_empty = False for folder in feed: children = callGAPI(service=drive.children(), function=u'list', @@ -3399,7 +3783,7 @@ def downloadDriveFile(users): i = 5 query = fileIds = None gdownload_format = u'openoffice' - target_folder = gamDriveDir + target_folder = GC_Values[GC_DRIVE_DIR] safe_filename_chars = "-_.() %s%s" % (string.ascii_letters, string.digits) while i < len(sys.argv): if sys.argv[i].lower() == u'id': @@ -3655,7 +4039,7 @@ def doImap(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting IMAP Access to %s for %s (%s of %s)" % (str(enable), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateImap', soft_errors=True, username=user, enable=enable) @@ -3669,7 +4053,7 @@ def getImap(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain + emailsettings.domain = GC_Values[GC_DOMAIN] imapsettings = callGData(service=emailsettings, function=u'GetImap', soft_errors=True, username=user) try: print u'User %s IMAP Enabled:%s (%s of %s)' % (user+u'@'+emailsettings.domain, imapsettings[u'enable'], i, count) @@ -3723,7 +4107,7 @@ def doLicense(users, operation): productId, skuId = getProductAndSKU(sku) for user in users: if user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) if operation == u'delete': callGAPI(service=lic.licenseAssignments(), function=operation, soft_errors=True, productId=productId, skuId=skuId, userId=user) elif operation == u'insert': @@ -3787,7 +4171,7 @@ def doPop(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting POP Access to %s for %s (%s of %s)" % (str(enable), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdatePop', soft_errors=True, username=user, enable=enable, enable_for=enable_for, action=action) @@ -3799,7 +4183,7 @@ def getPop(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain + emailsettings.domain = GC_Values[GC_DOMAIN] popsettings = callGData(service=emailsettings, function=u'GetPop', soft_errors=True, username=user) try: print u'User %s POP Enabled:%s Action:%s' % (user+u'@'+emailsettings.domain, popsettings[u'enable'], popsettings[u'action']) @@ -3823,7 +4207,7 @@ def doSendAs(users): sys.exit(2) emailsettings = getEmailSettingsObject() if sendas.find(u'@') < 0: - sendas = sendas+u'@'+domain + sendas = sendas+u'@'+GC_Values[GC_DOMAIN] count = len(users) i = 1 for user in users: @@ -3831,7 +4215,7 @@ def doSendAs(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Allowing %s to send as %s (%s of %s)" % (user+u'@'+emailsettings.domain, sendas, i, count) i += 1 callGData(service=emailsettings, function=u'CreateSendAsAlias', soft_errors=True, username=user, name=sendasName, address=sendas, make_default=make_default, reply_to=reply_to) @@ -3843,7 +4227,7 @@ def showSendAs(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain + emailsettings.domain = GC_Values[GC_DOMAIN] print u'%s has the following send as aliases:' % (user+u'@'+emailsettings.domain) sendases = callGData(service=emailsettings, function=u'GetSendAsAlias', soft_errors=True, username=user) try: @@ -3875,7 +4259,7 @@ def doLanguage(users): emailsettings.domain = user[user.find('@')+1:] user = user[:user.find('@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting the language for %s to %s (%s of %s)" % (user+u'@'+emailsettings.domain, language, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateLanguage', soft_errors=True, username=user, language=language) @@ -3896,7 +4280,7 @@ def doUTF(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting UTF-8 to %s for %s (%s of %s)" % (str(SetUTF), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateGeneral', soft_errors=True, username=user, unicode=SetUTF) @@ -3915,7 +4299,7 @@ def doPageSize(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting Page Size to %s for %s (%s of %s)" % (PageSize, user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateGeneral', soft_errors=True, username=user, page_size=PageSize) @@ -3936,7 +4320,7 @@ def doShortCuts(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting Keyboard Short Cuts to %s for %s (%s of %s)" % (str(SetShortCuts), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateGeneral', soft_errors=True, username=user, shortcuts=SetShortCuts) @@ -3957,7 +4341,7 @@ def doArrows(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting Personal Indicator Arrows to %s for %s (%s of %s)" % (str(SetArrows), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateGeneral', soft_errors=True, username=user, arrows=SetArrows) @@ -3978,7 +4362,7 @@ def doSnippets(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting Preview Snippets to %s for %s (%s of %s)" % (str(SetSnippets), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateGeneral', soft_errors=True, username=user, snippets=SetSnippets) @@ -4017,7 +4401,7 @@ def doLabel(users): print u'ERROR: %s is not a valid argument for this command.' % sys.argv[n] sys.exit(2) for user in users: - gmail = buildGAPIServiceObject(u'gmail', act_as=user) + gmail = buildGAPIServiceObject(u'gmail', user) print u"Creating label %s for %s (%s of %s)" % (label, user, i, count) i += 1 callGAPI(service=gmail.users().labels(), function=u'create', soft_errors=True, userId=user, body=body) @@ -4044,7 +4428,7 @@ def doDeleteMessages(trashOrDelete, users): print u'ERROR: No query specified. You must specify some query!' sys.exit(2) for user in users: - gmail = buildGAPIServiceObject(u'gmail', act_as=user) + gmail = buildGAPIServiceObject(u'gmail', user) page_message = u'Got %%%%total_items%%%% messages for user %s' % user listResult = callGAPIpages(service=gmail.users().messages(), function=u'list', items=u'messages', page_message=page_message, @@ -4056,34 +4440,17 @@ def doDeleteMessages(trashOrDelete, users): elif del_count > maxToDelete: print u'WARNING: refusing to delete ANY messages for %s since max_to_delete is %s and messages to be deleted is %s\n' % (user, maxToDelete, del_count) continue - i = 1 - # Batch seemed like a good idea but it kills - # Gmail UI for users :-( - '''dbatch = googleapiclient.http.BatchHttpRequest() + i = 0 for del_me in listResult: - print u' deleting message %s for user %s (%s/%s)' % (del_me[u'id'], user, i, del_count) i += 1 - if trashOrDelete == u'trash': - dbatch.add(gmail.users().messages().trash(userId=u'me', - id=del_me[u'id']), callback=gmail_del_result) - elif trashOrDelete == u'delete': - dbatch.add(gmail.users().messages().delete(userId=u'me', - id=del_me[u'id']), callback=gmail_del_result) - if len(dbatch._order) == 5: - dbatch.execute() - dbatch = googleapiclient.http.BatchHttpRequest() - if len(dbatch._order) > 0: - dbatch.execute()''' - for del_me in listResult: print u' %s message %s for user %s (%s/%s)' % (trashOrDelete, del_me[u'id'], user, i, del_count) - i += 1 callGAPI(service=gmail.users().messages(), function=trashOrDelete, id=del_me[u'id'], userId=u'me') def doDeleteLabel(users): label = sys.argv[5] for user in users: - gmail = buildGAPIServiceObject(u'gmail', act_as=user) + gmail = buildGAPIServiceObject(u'gmail', user) print u'Getting all labels for %s...' % user labels = callGAPI(service=gmail.users().labels(), function=u'list', userId=user, fields=u'labels(name,id,type)') del_labels = [] @@ -4138,7 +4505,7 @@ def showLabels(users): print u'ERROR: %s is not a valid argument for "gam show labels"' % sys.argv[i] sys.exit(2) for user in users: - gmail = buildGAPIServiceObject(u'gmail', act_as=user) + gmail = buildGAPIServiceObject(u'gmail', user) labels = callGAPI(service=gmail.users().labels(), function=u'list', userId=user) for label in labels[u'labels']: if label[u'type'] == u'system' and not show_system: @@ -4163,7 +4530,7 @@ def showGmailProfile(users): profiles = [{}] for user in users: print 'Getting Gmail profile for %s' % user - gmail = buildGAPIServiceObject(u'gmail', act_as=user, soft_errors=True) + gmail = buildGAPIServiceObject(u'gmail', user, soft_errors=True) if not gmail: continue results = callGAPI(service=gmail.users(), function=u'getProfile', userId=u'me', soft_errors=True) @@ -4202,7 +4569,7 @@ def updateLabels(users): print u'ERROR: %s is not a valid argument for "gam update labels"' % sys.argv[i] sys.exit(2) for user in users: - gmail = buildGAPIServiceObject(u'gmail', act_as=user) + gmail = buildGAPIServiceObject(u'gmail', user) labels = callGAPI(service=gmail.users().labels(), function=u'list', userId=user, fields=u'labels(id,name)') label_id = None for label in labels[u'labels']: @@ -4233,7 +4600,7 @@ def renameLabels(users): sys.exit(2) pattern = re.compile(search, re.IGNORECASE) for user in users: - gmail = buildGAPIServiceObject(u'gmail', act_as=user) + gmail = buildGAPIServiceObject(u'gmail', user) labels = callGAPI(service=gmail.users().labels(), function=u'list', userId=user) for label in labels[u'labels']: if label[u'type'] == u'system': @@ -4343,7 +4710,7 @@ def doFilter(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Creating filter for %s (%s of %s)" % (user+'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'CreateFilter', soft_errors=True, @@ -4387,7 +4754,7 @@ def doForward(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Turning forward %s for %s, emails will be %s (%s of %s)" % (sys.argv[4], user+'@'+emailsettings.domain, action, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateForwarding', soft_errors=True, username=user, enable=enable, action=action, forward_to=forward_to) @@ -4399,7 +4766,7 @@ def getForward(users): emailsettings.domain = user[user.find('@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain + emailsettings.domain = GC_Values[GC_DOMAIN] forward = callGData(service=emailsettings, function=u'GetForward', soft_errors=True, username=user) try: print u"User %s: Forward To:%s Enabled:%s Action:%s" % (user+u'@'+emailsettings.domain, forward[u'forwardTo'], forward[u'enable'], forward[u'action']) @@ -4424,7 +4791,7 @@ def doSignature(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting Signature for %s (%s of %s)" % (user+u'@'+emailsettings.domain, i, count) uri = u'https://apps-apis.google.com/a/feeds/emailsettings/2.0/%s/%s/signature' % (emailsettings.domain, user) i += 1 @@ -4437,7 +4804,7 @@ def getSignature(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain + emailsettings.domain = GC_Values[GC_DOMAIN] signature = callGData(service=emailsettings, function=u'GetSignature', soft_errors=True, username=user) try: sys.stderr.write(u"User %s signature:\n " % (user+u'@'+emailsettings.domain)) @@ -4461,7 +4828,7 @@ def doWebClips(users): emailsettings.domain = user[user.find('@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Turning Web Clips %s for %s (%s of %s)" % (sys.argv[4], user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateWebClipSettings', soft_errors=True, username=user, enable=enable) @@ -4512,7 +4879,7 @@ def doVacation(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting Vacation for %s (%s of %s)" % (user+'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateVacation', @@ -4527,7 +4894,7 @@ def getVacation(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain + emailsettings.domain = GC_Values[GC_DOMAIN] vacationsettings = callGData(service=emailsettings, function=u'GetVacation', soft_errors=True, username=user) try: print convertUTF8(u'''User %s @@ -4546,7 +4913,7 @@ def getVacation(users): def doDelSchema(): cd = buildGAPIObject(u'directory') schemaKey = sys.argv[3] - callGAPI(service=cd.schemas(), function=u'delete', customerId=customerId, schemaKey=schemaKey) + callGAPI(service=cd.schemas(), function=u'delete', customerId=GC_Values[GC_CUSTOMER_ID], schemaKey=schemaKey) print u'Deleted schema %s' % schemaKey def doCreateOrUpdateUserSchema(): @@ -4588,15 +4955,15 @@ def doCreateOrUpdateUserSchema(): print 'ERROR: %s is not a valid argument for "gam create schema"' % sys.argv[i] sys.exit(2) if sys.argv[1].lower() == u'create': - result = callGAPI(service=cd.schemas(), function=u'insert', customerId=customerId, body=body) + result = callGAPI(service=cd.schemas(), function=u'insert', customerId=GC_Values[GC_CUSTOMER_ID], body=body) print 'Created user schema %s' % result[u'schemaName'] elif sys.argv[1].lower() == u'update': - result = callGAPI(service=cd.schemas(), function=u'update', customerId=customerId, body=body, schemaKey=schemaName) + result = callGAPI(service=cd.schemas(), function=u'update', customerId=GC_Values[GC_CUSTOMER_ID], body=body, schemaKey=schemaName) print 'Updated user schema %s' % result[u'schemaName'] def doPrintUserSchemas(): cd = buildGAPIObject(u'directory') - schemas = callGAPI(service=cd.schemas(), function=u'list', customerId=customerId) + schemas = callGAPI(service=cd.schemas(), function=u'list', customerId=GC_Values[GC_CUSTOMER_ID]) if not schemas or u'schemas' not in schemas: return for schema in schemas[u'schemas']: @@ -4616,7 +4983,7 @@ def doPrintUserSchemas(): def doGetUserSchema(): cd = buildGAPIObject(u'directory') schemaKey = sys.argv[3] - schema = callGAPI(service=cd.schemas(), function=u'get', customerId=customerId, schemaKey=schemaKey) + schema = callGAPI(service=cd.schemas(), function=u'get', customerId=GC_Values[GC_CUSTOMER_ID], schemaKey=schemaKey) print u'Schema: %s' % schema[u'schemaName'] for a_key in schema: if a_key not in [u'schemaName', u'fields', u'etag', u'kind']: @@ -4635,7 +5002,7 @@ def doCreateUser(): body[u'name'] = dict() body[u'primaryEmail'] = sys.argv[3] if body[u'primaryEmail'].find(u'@') == -1: - body[u'primaryEmail'] = u'%s@%s' % (body[u'primaryEmail'], domain) + body[u'primaryEmail'] = u'%s@%s' % (body[u'primaryEmail'], GC_Values[GC_DOMAIN]) gotFirstName = gotLastName = do_admin = False need_to_hash_password = need_password = True i = 4 @@ -4975,12 +5342,12 @@ def doCreateUser(): callGAPI(service=cd.users(), function=u'makeAdmin', userKey=body[u'primaryEmail'], body=admin_body) def doCreateGroup(): - use_gs_api = False cd = buildGAPIObject(u'directory') + use_gs_api = False body = dict() body[u'email'] = sys.argv[3] if body[u'email'].find(u'@') == -1: - body[u'email'] = u'%s@%s' % (body[u'email'], domain) + body[u'email'] = u'%s@%s' % (body[u'email'], GC_Values[GC_DOMAIN]) got_name = False i = 4 gs_body = dict() @@ -5041,14 +5408,14 @@ def doCreateAlias(): body = dict() body[u'alias'] = sys.argv[3] if body[u'alias'].find(u'@') == -1: - body[u'alias'] = u'%s@%s' % (body[u'alias'], domain) + body[u'alias'] = u'%s@%s' % (body[u'alias'], GC_Values[GC_DOMAIN]) target_type = sys.argv[4].lower() if target_type not in [u'user', u'group', u'target']: print u'ERROR: type of target should be user or group. Got %s' % target_type sys.exit(2) targetKey = sys.argv[5] if targetKey.find(u'@') == -1: - targetKey = u'%s@%s' % (targetKey, domain) + targetKey = u'%s@%s' % (targetKey, GC_Values[GC_DOMAIN]) print u'Creating alias %s for %s %s' % (body[u'alias'], target_type, targetKey) if target_type == u'user': callGAPI(service=cd.users().aliases(), function=u'insert', userKey=targetKey, body=body) @@ -5081,26 +5448,26 @@ def doCreateOrg(): else: print u'ERROR: %s is not a valid argument for "gam create org"' % sys.argv[i] sys.exit(2) - callGAPI(service=cd.orgunits(), function=u'insert', customerId=customerId, body=body) + callGAPI(service=cd.orgunits(), function=u'insert', customerId=GC_Values[GC_CUSTOMER_ID], body=body) -def doCreateResource(): - resId = sys.argv[3] - common_name = sys.argv[4] - description = None - resType = None +def doCreateResourceCalendar(): + cd = buildGAPIObject(u'directory') + body = {u'resourceId': sys.argv[3], + u'resourceName': sys.argv[4]} i = 5 while i < len(sys.argv): if sys.argv[i].lower() == u'description': - description = sys.argv[i+1] + body[u'resourceDescription'] = sys.argv[i+1] i += 2 elif sys.argv[i].lower() == u'type': - resType = sys.argv[i+1] + body[u'resourceType'] = sys.argv[i+1] i += 2 else: print u'ERROR: %s is not a valid argument for "gam create resource"' % sys.argv[i] sys.exit(2) - rescal = getResCalObject() - callGData(service=rescal, function=u'CreateResourceCalendar', id=resId, common_name=common_name, description=description, type=resType) + print u'Creating resource %s...' % body[u'resourceId'] + callGAPI(service=cd.resources().calendars(), function=u'insert', + customer=GC_Values[GC_CUSTOMER_ID], body=body) def doUpdateUser(users): cd = buildGAPIObject(u'directory') @@ -5130,7 +5497,7 @@ def doUpdateUser(users): do_update_user = True body[u'primaryEmail'] = sys.argv[i+1] if body[u'primaryEmail'].find(u'@') == -1: - body[u'primaryEmail'] = u'%s@%s' % (body[u'primaryEmail'], domain) + body[u'primaryEmail'] = u'%s@%s' % (body[u'primaryEmail'], GC_Values[GC_DOMAIN]) i += 2 elif sys.argv[i].lower() == u'password': do_update_user = True @@ -5476,7 +5843,7 @@ def doUpdateUser(users): if user[:4].lower() == u'uid:': user = user[4:] elif user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) if u'primaryEmail' in body and body[u'primaryEmail'][:4].lower() == u'vfe@': user_primary = callGAPI(service=cd.users(), function=u'get', userKey=user, fields=u'primaryEmail,id') user = user_primary[u'id'] @@ -5519,13 +5886,13 @@ def doRemoveUsersGroups(users): print u'' def doUpdateGroup(): + cd = buildGAPIObject(u'directory') group = sys.argv[3] if sys.argv[4].lower() in [u'add', u'update', u'sync', u'remove']: - cd = buildGAPIObject(u'directory') if group[0:3].lower() == u'uid:': group = group[4:] elif group.find(u'@') == -1: - group = u'%s@%s' % (group, domain) + group = u'%s@%s' % (group, GC_Values[GC_DOMAIN]) if sys.argv[4].lower() in [u'add', u'update']: role = sys.argv[5].upper() i = 6 @@ -5538,7 +5905,7 @@ def doUpdateGroup(): users_email = [sys.argv[i],] for user_email in users_email: if user_email != u'*' and user_email.find(u'@') == -1: - user_email = u'%s@%s' % (user_email, domain) + user_email = u'%s@%s' % (user_email, GC_Values[GC_DOMAIN]) sys.stderr.write(u' %sing %s %s...' % (sys.argv[4].lower(), role.lower(), user_email)) try: if sys.argv[4].lower() == u'add': @@ -5587,7 +5954,7 @@ def doUpdateGroup(): user_emails = [sys.argv[i],] for user_email in user_emails: if user_email != u'*' and user_email.find(u'@') == -1: - user_email = u'%s@%s' % (user_email, domain) + user_email = u'%s@%s' % (user_email, GC_Values[GC_DOMAIN]) sys.stderr.write(u' removing %s\n' % user_email) result = callGAPI(service=cd.members(), function=u'delete', soft_errors=True, groupKey=group, memberKey=user_email) else: @@ -5648,13 +6015,11 @@ def doUpdateGroup(): use_cd_api = True group = group[4:] elif group.find(u'@') == -1: - cd = buildGAPIObject(u'directory') - group = u'%s@%s' % (group, domain) + group = u'%s@%s' % (group, GC_Values[GC_DOMAIN]) if use_cd_api: - cd = buildGAPIObject(u'directory') try: if cd_body[u'email'].find('@') == -1: - cd_body[u'email'] = u'%s@%s' % (cd_body[u'email'], domain) + cd_body[u'email'] = u'%s@%s' % (cd_body[u'email'], GC_Values[GC_DOMAIN]) except KeyError: pass cd_result = callGAPI(service=cd.groups(), function=u'patch', groupKey=group, body=cd_body) @@ -5666,17 +6031,17 @@ def doUpdateGroup(): print u'updated group %s' % group def doUpdateAlias(): + cd = buildGAPIObject(u'directory') alias = sys.argv[3] target_type = sys.argv[4].lower() if target_type not in [u'user', u'group', u'target']: print u'ERROR: target type should be "user", "group" or "target", got %s' % target_type sys.exit(2) target_email = sys.argv[5] - cd = buildGAPIObject(u'directory') if alias.find(u'@') == -1: - alias = u'%s@%s' % (alias, domain) + alias = u'%s@%s' % (alias, GC_Values[GC_DOMAIN]) if target_email.find(u'@') == -1: - target_email = u'%s@%s' % (target_email, domain) + target_email = u'%s@%s' % (target_email, GC_Values[GC_DOMAIN]) try: callGAPI(service=cd.users().aliases(), function=u'delete', throw_reasons=[u'invalid'], userKey=alias, alias=alias) except googleapiclient.errors.HttpError: @@ -5693,35 +6058,37 @@ def doUpdateAlias(): print u'updated alias %s' % alias def doUpdateResourceCalendar(): + cd = buildGAPIObject(u'directory') resId = sys.argv[3] - common_name = None - description = None - resType = None + body = {} i = 4 while i < len(sys.argv): if sys.argv[i].lower() == u'name': - common_name = sys.argv[i+1] + body[u'resourceName'] = sys.argv[i+1] i += 2 elif sys.argv[i].lower() == u'description': - description = sys.argv[i+1] + body[u'resourceDescription'] = sys.argv[i+1] i += 2 elif sys.argv[i].lower() == u'type': - resType = sys.argv[i+1] + body[u'resourceType'] = sys.argv[i+1] i += 2 else: print u'ERROR: %s is not a valid argument for "gam update resource"' % sys.argv[i] sys.exit(2) - rescal = getResCalObject() - callGData(service=rescal, function=u'UpdateResourceCalendar', id=resId, common_name=common_name, description=description, type=resType) + # Use patch since it seems to work better. + # update requires name to be set. + callGAPI(service=cd.resources().calendars(), function=u'patch', + customer=GC_Values[GC_CUSTOMER_ID], calendarResourceId=resId, body=body, + fields=u'') print u'updated resource %s' % resId def doUpdateCros(): - deviceId = sys.argv[3] cd = buildGAPIObject(u'directory') + deviceId = sys.argv[3] if deviceId[:6].lower() == u'query:': query = deviceId[6:] devices_result = callGAPIpages(service=cd.chromeosdevices(), function=u'list', items=u'chromeosdevices', - query=query, customerId=customerId, fields=u'chromeosdevices/deviceId,nextPageToken') + query=query, customerId=GC_Values[GC_CUSTOMER_ID], fields=u'chromeosdevices/deviceId,nextPageToken') devices = list() for a_device in devices_result: devices.append(a_device[u'deviceId']) @@ -5761,12 +6128,12 @@ def doUpdateCros(): i = 1 for this_device in devices: print u' updating %s (%s of %s)' % (this_device, i, device_count) - callGAPI(service=cd.chromeosdevices(), function=u'patch', deviceId=this_device, body=body, customerId=customerId) + callGAPI(service=cd.chromeosdevices(), function=u'patch', deviceId=this_device, body=body, customerId=GC_Values[GC_CUSTOMER_ID]) i += 1 def doUpdateMobile(): - resourceId = sys.argv[3] cd = buildGAPIObject(u'directory') + resourceId = sys.argv[3] i = 4 action_body = patch_body = dict() doPatch = doAction = False @@ -5798,18 +6165,18 @@ def doUpdateMobile(): print u'ERROR: %s is not a valid argument for "gam update mobile"' % sys.argv[i] sys.exit(2) if doPatch: - callGAPI(service=cd.mobiledevices(), function=u'patch', resourceId=resourceId, body=patch_body, customerId=customerId) + callGAPI(service=cd.mobiledevices(), function=u'patch', resourceId=resourceId, body=patch_body, customerId=GC_Values[GC_CUSTOMER_ID]) if doAction: - callGAPI(service=cd.mobiledevices(), function=u'action', resourceId=resourceId, body=action_body, customerId=customerId) + callGAPI(service=cd.mobiledevices(), function=u'action', resourceId=resourceId, body=action_body, customerId=GC_Values[GC_CUSTOMER_ID]) def doDeleteMobile(): cd = buildGAPIObject(u'directory') resourceId = sys.argv[3] - callGAPI(service=cd.mobiledevices(), function='delete', resourceId=resourceId, customerId=customerId) + callGAPI(service=cd.mobiledevices(), function='delete', resourceId=resourceId, customerId=GC_Values[GC_CUSTOMER_ID]) def doUpdateOrg(): - orgUnitPath = sys.argv[3] cd = buildGAPIObject(u'directory') + orgUnitPath = sys.argv[3] 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].lower(), entity=sys.argv[6]) @@ -5821,7 +6188,7 @@ def doUpdateOrg(): for cros in users: sys.stderr.write(u' moving %s to %s (%s/%s)\n' % (cros, orgUnitPath, current_cros, cros_count)) callGAPI(service=cd.chromeosdevices(), function=u'patch', soft_errors=True, - customerId=customerId, deviceId=cros, body={u'orgUnitPath': '//%s' % orgUnitPath}) + customerId=GC_Values[GC_CUSTOMER_ID], deviceId=cros, body={u'orgUnitPath': '//%s' % orgUnitPath}) current_cros += 1 else: user_count = len(users) @@ -5861,13 +6228,13 @@ 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'update', customerId=customerId, orgUnitPath=orgUnitPath, body=body) + callGAPI(service=cd.orgunits(), function=u'update', customerId=GC_Values[GC_CUSTOMER_ID], orgUnitPath=orgUnitPath, body=body) def doWhatIs(): - email = sys.argv[2] cd = buildGAPIObject(u'directory') + email = sys.argv[2] if email.find(u'@') == -1: - email = u'%s@%s' % (email, domain) + email = u'%s@%s' % (email, GC_Values[GC_DOMAIN]) try: user_or_alias = callGAPI(service=cd.users(), function=u'get', throw_reasons=[u'notFound', u'badRequest', u'invalid'], userKey=email, fields=u'primaryEmail') if user_or_alias[u'primaryEmail'].lower() == email.lower(): @@ -5899,7 +6266,7 @@ def doGetUserInfo(user_email=None): try: user_email = sys.argv[3] except IndexError: - storage = oauth2client.file.Storage(os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE'), FN_OAUTH2_TXT)) + storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) credentials = storage.get() if credentials is None or credentials.invalid: doRequestOAuth() @@ -5908,7 +6275,7 @@ def doGetUserInfo(user_email=None): if user_email[:4].lower() == u'uid:': user_email = user_email[4:] elif user_email.find(u'@') == -1: - user_email = u'%s@%s' % (user_email, domain) + user_email = u'%s@%s' % (user_email, GC_Values[GC_DOMAIN]) getSchemas = getAliases = getGroups = getLicenses = True projection = u'full' customFieldMask = viewType = None @@ -6084,6 +6451,8 @@ def doGetUserInfo(user_email=None): print u' %s' % result[u'skuId'] def doGetGroupInfo(group_name=None): + cd = buildGAPIObject(u'directory') + gs = buildGAPIObject(u'groupssettings') if group_name == None: group_name = sys.argv[3] get_users = True @@ -6092,12 +6461,10 @@ def doGetGroupInfo(group_name=None): get_users = False except IndexError: pass - cd = buildGAPIObject(u'directory') - gs = buildGAPIObject(u'groupssettings') if group_name[:4].lower() == u'uid:': group_name = group_name[4:] elif group_name.find(u'@') == -1: - group_name = group_name+u'@'+domain + group_name = group_name+u'@'+GC_Values[GC_DOMAIN] basic_info = callGAPI(service=cd.groups(), function=u'get', groupKey=group_name) try: settings = callGAPI(service=gs.groups(), function=u'get', retry_reasons=[u'serviceLimit'], throw_reasons=u'authError', @@ -6141,11 +6508,11 @@ def doGetGroupInfo(group_name=None): print u'Total %s users in group' % len(members) def doGetAliasInfo(alias_email=None): + cd = buildGAPIObject(u'directory') if alias_email == None: alias_email = sys.argv[3] - cd = buildGAPIObject(u'directory') if alias_email.find(u'@') == -1: - alias_email = u'%s@%s' % (alias_email, domain) + alias_email = u'%s@%s' % (alias_email, GC_Values[GC_DOMAIN]) try: result = callGAPI(service=cd.users(), function=u'get', throw_reasons=[u'invalid', u'badRequest'], userKey=alias_email) except googleapiclient.errors.HttpError: @@ -6161,31 +6528,25 @@ def doGetAliasInfo(alias_email=None): print u' Unique ID: %s' % result[u'id'] def doGetResourceCalendarInfo(): + cd = buildGAPIObject(u'directory') resId = sys.argv[3] - rescal = getResCalObject() - result = callGData(service=rescal, function=u'RetrieveResourceCalendar', id=resId) - print u' Resource ID: '+result[u'resourceId'] - print u' Name: '+result[u'resourceCommonName'] - print u' Email: '+result[u'resourceEmail'] - try: - print u' Type: '+result[u'resourceType'] - except KeyError: - print u' Type: ' - try: - print u' Description: '+result[u'resourceDescription'] - except KeyError: - print u' Description: ' + resource = callGAPI(service=cd.resources().calendars(), function=u'get', + customer=GC_Values[GC_CUSTOMER_ID], calendarResourceId=resId) + for key, value in resource.items(): + if key in [u'kind', u'etag', u'etags']: + continue + print u'%s: %s' % (key, value) def doGetCrosInfo(): - deviceId = sys.argv[3] cd = buildGAPIObject(u'directory') - info = callGAPI(service=cd.chromeosdevices(), function=u'get', customerId=customerId, deviceId=deviceId) + deviceId = sys.argv[3] + info = callGAPI(service=cd.chromeosdevices(), function=u'get', customerId=GC_Values[GC_CUSTOMER_ID], deviceId=deviceId) print_json(None, info) def doGetMobileInfo(): - deviceId = sys.argv[3] cd = buildGAPIObject(u'directory') - info = callGAPI(service=cd.mobiledevices(), function=u'get', customerId=customerId, resourceId=deviceId) + deviceId = sys.argv[3] + info = callGAPI(service=cd.mobiledevices(), function=u'get', customerId=GC_Values[GC_CUSTOMER_ID], resourceId=deviceId) print_json(None, info) def print_json(object_name, object_value, spacing=u''): @@ -6237,13 +6598,13 @@ def doUpdateNotification(): print u'ERROR: notifications need to be marked as read or unread.' sys.exit(2) if get_all: - notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=customerId, fields=u'items(notificationId,isUnread),nextPageToken') + notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=GC_Values[GC_CUSTOMER_ID], fields=u'items(notificationId,isUnread),nextPageToken') for noti in notifications: if noti[u'isUnread'] != isUnread: ids.append(noti[u'notificationId']) print u'Marking %s notification(s) as %s...' % (len(ids), mark_as) for notificationId in ids: - result = callGAPI(service=cd.notifications(), function=u'patch', customer=customerId, notificationId=notificationId, body={u'isUnread': isUnread}, fields=u'notificationId,isUnread') + result = callGAPI(service=cd.notifications(), function=u'patch', customer=GC_Values[GC_CUSTOMER_ID], notificationId=notificationId, body={u'isUnread': isUnread}, fields=u'notificationId,isUnread') if result[u'isUnread']: read_result = u'unread' else: @@ -6266,12 +6627,12 @@ def doDeleteNotification(): print 'ERROR: %s is not a valid argument for "gam delete notification", expected id' % sys.argv[i] sys.exit(2) if get_all: - notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=customerId, fields=u'items(notificationId),nextPageToken') + notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=GC_Values[GC_CUSTOMER_ID], fields=u'items(notificationId),nextPageToken') for noti in notifications: ids.append(noti[u'notificationId']) print u'Deleting %s notification(s)...' % len(ids) for notificationId in ids: - callGAPI(service=cd.notifications(), function=u'delete', customer=customerId, notificationId=notificationId) + callGAPI(service=cd.notifications(), function=u'delete', customer=GC_Values[GC_CUSTOMER_ID], notificationId=notificationId) print u'deleted %s' % id def doSiteVerifyShow(): @@ -6379,7 +6740,7 @@ def doSiteVerifyAttempt(): except KeyError: pass print - print u'You can now add %s or it\'s subdomains as secondary or domain aliases of the %s Google Apps Account.' % (a_domain, domain) + print u'You can now add %s or it\'s subdomains as secondary or domain aliases of the %s Google Apps Account.' % (a_domain, GC_Values[GC_DOMAIN]) def doGetNotifications(): cd = buildGAPIObject(u'directory') @@ -6392,7 +6753,7 @@ def doGetNotifications(): print 'ERROR: %s is not a valid argument for "gam info notification", expected unreadonly' % sys.argv[i] sys.exit(2) i += 1 - notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=customerId) + notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=GC_Values[GC_CUSTOMER_ID]) for notification in notifications: if unread_only and not notification[u'isUnread']: continue @@ -6424,20 +6785,20 @@ def doGetOrgInfo(): pass if name == u'/': orgs = callGAPI(service=cd.orgunits(), function=u'list', - customerId=customerId, type=u'children', + customerId=GC_Values[GC_CUSTOMER_ID], type=u'children', fields=u'organizationUnits/parentOrgUnitId') name = orgs[u'organizationUnits'][0][u'parentOrgUnitId'] if len(name) > 1 and name[0] == u'/': name = name[1:] - result = callGAPI(service=cd.orgunits(), function=u'get', customerId=customerId, orgUnitPath=name) + result = callGAPI(service=cd.orgunits(), function=u'get', customerId=GC_Values[GC_CUSTOMER_ID], orgUnitPath=name) print_json(None, result) if get_users: name = result[u'orgUnitPath'] print u'Users: ' page_message = u'Got %%total_items%% users: %%first_item%% - %%last_item%%\n' users = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - message_attribute=u'primaryEmail', customer=customerId, query=u"orgUnitPath='%s'" % name, - fields=u'users(primaryEmail,orgUnitPath),nextPageToken', maxResults=500) + message_attribute=u'primaryEmail', customer=GC_Values[GC_CUSTOMER_ID], query=u"orgUnitPath='%s'" % name, + fields=u'users(primaryEmail,orgUnitPath),nextPageToken', maxResults=GC_Values[GC_USER_MAX_RESULTS]) for user in users: if show_children or (name.lower() == user[u'orgUnitPath'].lower()): sys.stdout.write(u' %s' % user[u'primaryEmail']) @@ -6466,8 +6827,8 @@ def doGetASPs(users): print u' no ASPs for %s\n' % user def doDelASP(users): - codeId = sys.argv[5] cd = buildGAPIObject(u'directory') + codeId = sys.argv[5] for user in users: callGAPI(service=cd.asps(), function=u'delete', userKey=user, codeId=codeId) print u'deleted ASP %s for %s' % (codeId, user) @@ -6746,48 +7107,52 @@ def doGetInstanceInfo(): adm = buildGAPIObject(u'admin-settings') if len(sys.argv) > 4 and sys.argv[3].lower() == u'logo': target_file = sys.argv[4] - url = 'http://www.google.com/a/cpanel/%s/images/logo.gif' % (domain) + url = 'http://www.google.com/a/cpanel/%s/images/logo.gif' % (GC_Values[GC_DOMAIN]) geturl(url, target_file) - return - print u'Google Apps Domain: %s' % domain + sys.exit(0) + print u'Google Apps Domain: %s' % (GC_Values[GC_DOMAIN]) cd = buildGAPIObject(u'directory') - if customerId != MY_CUSTOMER: - customer_id = customerId + if GC_Values[GC_CUSTOMER_ID] != MY_CUSTOMER: + customerId = GC_Values[GC_CUSTOMER_ID] else: - 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) + result = callGAPI(service=cd.users(), function=u'list', + fields=u'users(customerId)', customer=GC_Values[GC_CUSTOMER_ID], maxResults=1) + try: + customerId = result[u'users'][0][u'customerId'] + except KeyError: + customerId = UNKNOWN + print u'Customer ID: %s' % customerId + default_language = callGAPI(service=adm.defaultLanguage(), function=u'get', domainName=GC_Values[GC_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) + org_name = callGAPI(service=adm.organizationName(), function='get', domainName=GC_Values[GC_DOMAIN]) 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) + admin_email = callGAPI(service=adm.adminSecondaryEmail(), function='get', domainName=GC_Values[GC_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) + max_users = callGAPI(service=adm.maximumNumberOfUsers(), function=u'get', domainName=GC_Values[GC_DOMAIN]) print u'Maximum Users: %s' % max_users[u'entry'][u'apps$property'][0][u'value'] - current_users = callGAPI(service=adm.currentNumberOfUsers(), function=u'get', domainName=domain) + current_users = callGAPI(service=adm.currentNumberOfUsers(), function=u'get', domainName=GC_Values[GC_DOMAIN]) print u'Current Users: %s' % current_users[u'entry'][u'apps$property'][0][u'value'] - is_dom_verified = callGAPI(service=adm.isVerified(), function=u'get', domainName=domain) + is_dom_verified = callGAPI(service=adm.isVerified(), function=u'get', domainName=GC_Values[GC_DOMAIN]) print u'Domain is Verified: %s' % is_dom_verified[u'entry'][u'apps$property'][0][u'value'] - domain_edition = callGAPI(service=adm.edition(), function=u'get', domainName=domain) + domain_edition = callGAPI(service=adm.edition(), function=u'get', domainName=GC_Values[GC_DOMAIN]) print u'Domain Edition: %s' % domain_edition[u'entry'][u'apps$property'][0][u'value'] - customer_pin = callGAPI(service=adm.customerPIN(), function=u'get', domainName=domain) + customer_pin = callGAPI(service=adm.customerPIN(), function=u'get', domainName=GC_Values[GC_DOMAIN]) print u'Customer PIN: %s' % customer_pin[u'entry'][u'apps$property'][0][u'value'] - creation_time = callGAPI(service=adm.creationTime(), function=u'get', domainName=domain) + creation_time = callGAPI(service=adm.creationTime(), function=u'get', domainName=GC_Values[GC_DOMAIN]) my_date = creation_time[u'entry'][u'apps$property'][0][u'value'] my_date = my_date[:15] my_offset = creation_time[u'entry'][u'apps$property'][0][u'value'][19:] nice_time = datetime.datetime.strptime(my_date, u"%Y%m%dT%H%M%S") print u'Domain Creation Time: %s %s' % (nice_time, my_offset) - country_code = callGAPI(service=adm.countryCode(), function=u'get', domainName=domain) + country_code = callGAPI(service=adm.countryCode(), function=u'get', domainName=GC_Values[GC_DOMAIN]) print u'Domain Country Code: %s' % country_code[u'entry'][u'apps$property'][0][u'value'] - mxverificationstatus = callGAPI(service=adm.mxVerification(), function=u'get', domainName=domain) + mxverificationstatus = callGAPI(service=adm.mxVerification(), function=u'get', domainName=GC_Values[GC_DOMAIN]) for entry in mxverificationstatus[u'entry'][u'apps$property']: if entry[u'name'] == u'verified': print u'MX Verification Verified: %s' % entry[u'value'] elif entry[u'name'] == u'verificationMethod': print u'MX Verification Method: %s' % entry[u'value'] - ssosettings = callGAPI(service=adm.ssoGeneral(), function=u'get', domainName=domain) + ssosettings = callGAPI(service=adm.ssoGeneral(), function=u'get', domainName=GC_Values[GC_DOMAIN]) for entry in ssosettings[u'entry'][u'apps$property']: if entry[u'name'] == u'enableSSO': print u'SSO Enabled: %s' % entry[u'value'] @@ -6801,7 +7166,7 @@ def doGetInstanceInfo(): print u'SSO Whitelist IPs: %s' % entry[u'value'] elif entry[u'name'] == u'useDomainSpecificIssuer': print u'SSO Use Domain Specific Issuer: %s' % entry[u'value'] - ssokey = callGAPI(service=adm.ssoSigningKey(), function=u'get', silent_errors=True, soft_errors=True, domainName=domain) + ssokey = callGAPI(service=adm.ssoSigningKey(), function=u'get', silent_errors=True, soft_errors=True, domainName=GC_Values[GC_DOMAIN]) try: for entry in ssokey[u'entry'][u'apps$property']: if entry[u'name'] == u'algorithm': @@ -6818,10 +7183,10 @@ def doGetInstanceInfo(): print u'Full SSO Key: %s' % entry[u'value'] except TypeError: pass - migration_status = callGAPI(service=adm.userEmailMigrationEnabled(), function=u'get', domainName=domain) + migration_status = callGAPI(service=adm.userEmailMigrationEnabled(), function=u'get', domainName=GC_Values[GC_DOMAIN]) print u'User Migration Enabled: %s' % migration_status[u'entry'][u'apps$property'][0][u'value'] outbound_gateway_settings = {u'smartHost': u'', u'smtpMode': u''} # Initialize blank in case we get an 1801 Error - outbound_gateway_settings = callGAPI(service=adm.outboundGateway(), function=u'get', domainName=domain) + outbound_gateway_settings = callGAPI(service=adm.outboundGateway(), function=u'get', domainName=GC_Values[GC_DOMAIN]) try: for entry in outbound_gateway_settings[u'entry'][u'apps$property']: if entry[u'name'] == u'smartHost': @@ -6833,16 +7198,17 @@ def doGetInstanceInfo(): print u'Outbound Gateway SMTP Mode: None' def doDeleteUser(): - user_email = sys.argv[3] cd = buildGAPIObject(u'directory') + user_email = sys.argv[3] if user_email[:4].lower() == u'uid:': user_email = user_email[4:] elif user_email.find(u'@') == -1: - user_email = u'%s@%s' % (user_email, domain) + user_email = u'%s@%s' % (user_email, GC_Values[GC_DOMAIN]) print u"Deleting account for %s" % (user_email) callGAPI(service=cd.users(), function=u'delete', userKey=user_email) def doUndeleteUser(): + cd = buildGAPIObject(u'directory') user = sys.argv[3].lower() user_uid = False orgUnit = u'/' @@ -6851,15 +7217,14 @@ def doUndeleteUser(): orgUnit = sys.argv[5] except IndexError: pass - cd = buildGAPIObject(u'directory') if user[:4].lower() == u'uid:': user_uid = user[4:] elif user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) if not user_uid: print u'Looking up UID for %s...' % user deleted_users = callGAPIpages(service=cd.users(), function=u'list', - items=u'users', customer=customerId, showDeleted=True, maxResults=500) + items=u'users', customer=GC_Values[GC_CUSTOMER_ID], showDeleted=True, maxResults=GC_Values[GC_USER_MAX_RESULTS]) matching_users = list() for deleted_user in deleted_users: if str(deleted_user[u'primaryEmail']).lower() == user: @@ -6887,16 +7252,17 @@ def doUndeleteUser(): callGAPI(service=cd.users(), function=u'undelete', userKey=user_uid, body={u'orgUnitPath': orgUnit}) def doDeleteGroup(): - group = sys.argv[3] cd = buildGAPIObject(u'directory') + group = sys.argv[3] if group[:4].lower() == u'uid:': group = group[4:] elif group.find(u'@') == -1: - group = u'%s@%s' % (group, domain) + group = u'%s@%s' % (group, GC_Values[GC_DOMAIN]) print u"Deleting group %s" % group callGAPI(service=cd.groups(), function=u'delete', groupKey=group) def doDeleteAlias(alias_email=None): + cd = buildGAPIObject(u'directory') is_user = is_group = False if alias_email == None: alias_email = sys.argv[3] @@ -6906,9 +7272,8 @@ def doDeleteAlias(alias_email=None): elif alias_email.lower() == u'group': is_group = True alias_email = sys.argv[4] - cd = buildGAPIObject(u'directory') if alias_email.find(u'@') == -1: - alias_email = u'%s@%s' % (alias_email, domain) + alias_email = u'%s@%s' % (alias_email, GC_Values[GC_DOMAIN]) print u"Deleting alias %s" % alias_email if is_user or (not is_user and not is_group): try: @@ -6924,18 +7289,19 @@ def doDeleteAlias(alias_email=None): callGAPI(service=cd.groups().aliases(), function=u'delete', groupKey=alias_email, alias=alias_email) def doDeleteResourceCalendar(): - res_id = sys.argv[3] - rescal = getResCalObject() - print u"Deleting resource calendar %s" % res_id - callGData(service=rescal, function=u'DeleteResourceCalendar', id=res_id) + resId = sys.argv[3] + cd = buildGAPIObject(u'directory') + print u"Deleting resource calendar %s" % resId + callGAPI(service=cd.resources().calendars(), function=u'delete', + customer=GC_Values[GC_CUSTOMER_ID], calendarResourceId=resId) def doDeleteOrg(): - name = sys.argv[3] cd = buildGAPIObject(u'directory') + name = sys.argv[3] if name[0] == u'/': name = name[1:] print u"Deleting organization %s" % name - callGAPI(service=cd.orgunits(), function=u'delete', customerId=customerId, orgUnitPath=name) + callGAPI(service=cd.orgunits(), function=u'delete', customerId=GC_Values[GC_CUSTOMER_ID], orgUnitPath=name) def output_csv(csv_list, titles, list_type, todrive): csv.register_dialect(u'nixstdout', lineterminator=u'\n') @@ -6955,12 +7321,12 @@ def output_csv(csv_list, titles, list_type, todrive): convert = False drive = buildGAPIObject(u'drive') result = callGAPI(service=drive.files(), function=u'insert', convert=convert, - body={u'description': u' '.join(sys.argv), u'title': u'%s - %s' % (domain, list_type), u'mimeType': u'text/csv'}, + body={u'description': u' '.join(sys.argv), u'title': u'%s - %s' % (GC_Values[GC_DOMAIN], list_type), u'mimeType': u'text/csv'}, media_body=googleapiclient.http.MediaInMemoryUpload(string_file.getvalue(), mimetype=u'text/csv')) file_url = result[u'alternateLink'] - if os.path.isfile(os.path.join(gamUserConfigDir, u'nobrowser.txt')): + if GC_Values[GC_NO_BROWSER]: msg_txt = u'Drive file uploaded to:\n %s' % file_url - msg_subj = u'%s - %s' % (domain, list_type) + msg_subj = u'%s - %s' % (GC_Values[GC_DOMAIN], list_type) send_email(msg_subj, msg_txt) print msg_txt else: @@ -6988,7 +7354,7 @@ def doPrintUsers(): cd = buildGAPIObject(u'directory') user_fields = [u'primaryEmail',] fields = u'' - customer = customerId + customer = GC_Values[GC_CUSTOMER_ID] domain = None query = None projection = u'basic' @@ -7121,7 +7487,7 @@ def doPrintUsers(): all_users = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, message_attribute=u'primaryEmail', customer=customer, domain=domain, fields=fields, showDeleted=deleted_only, orderBy=orderBy, sortOrder=sortOrder, viewType=viewType, - query=query, projection=projection, customFieldMask=customFieldMask, maxResults=500) + query=query, projection=projection, customFieldMask=customFieldMask, maxResults=GC_Values[GC_USER_MAX_RESULTS]) titles = [u'primaryEmail',] attributes = [] for user in all_users: @@ -7174,8 +7540,10 @@ def doPrintUsers(): output_csv(attributes, titles, u'Users', todrive) def doPrintGroups(): + cd = buildGAPIObject(u'directory') i = 3 printname = printdesc = printid = members = owners = managers = settings = admin_created = aliases = todrive = False + customer = GC_Values[GC_CUSTOMER_ID] usedomain = usemember = None listDelimiter = u'\n' group_attributes = [{u'Email': u'Email'}] @@ -7184,6 +7552,7 @@ def doPrintGroups(): while i < len(sys.argv): if sys.argv[i].lower() == u'domain': usedomain = sys.argv[i+1].lower() + customer = None i += 2 elif sys.argv[i].lower() == u'todrive': todrive = True @@ -7193,6 +7562,7 @@ def doPrintGroups(): i += 2 elif sys.argv[i].lower() == u'member': usemember = sys.argv[i+1].lower() + customer = None i += 2 elif sys.argv[i].lower() == u'name': fields += u',groups(name)' @@ -7247,14 +7617,10 @@ def doPrintGroups(): else: print 'ERROR: %s is not a valid argument for "gam print groups"' % sys.argv[i] sys.exit(2) - cd = buildGAPIObject(u'directory') - global customerId - if usedomain or usemember: - customerId = None sys.stderr.write(u"Retrieving All Groups for Google Apps account (may take some time on a large account)...\n") page_message = u'Got %%num_items%% groups: %%first_item%% - %%last_item%%\n' all_groups = callGAPIpages(service=cd.groups(), function=u'list', items=u'groups', page_message=page_message, - message_attribute=u'email', customer=customerId, domain=usedomain, userKey=usemember, fields=fields) + message_attribute=u'email', customer=customer, domain=usedomain, userKey=usemember, fields=fields) total_groups = len(all_groups) count = 0 for group_vals in all_groups: @@ -7348,6 +7714,7 @@ def doPrintGroups(): output_csv(group_attributes, titles, u'Groups', todrive) def doPrintOrgs(): + cd = buildGAPIObject(u'directory') i = 3 printname = printdesc = printparent = printinherit = todrive = False listType = u'all' @@ -7398,9 +7765,8 @@ def doPrintOrgs(): if fields: org_attributes[0][u'Path'] = u'Path' titles.append(u'Path') - cd = buildGAPIObject(u'directory') sys.stderr.write(u"Retrieving All Organizational Units for your account (may take some time on large domain)...") - orgs = callGAPI(service=cd.orgunits(), function=u'list', customerId=customerId, fields=fields, type=listType, orgUnitPath=orgUnitPath) + orgs = callGAPI(service=cd.orgunits(), function=u'list', customerId=GC_Values[GC_CUSTOMER_ID], fields=fields, type=listType, orgUnitPath=orgUnitPath) sys.stderr.write(u"done\n") if not u'organizationUnits' in orgs: print u'0 org units in this Google Apps instance...' @@ -7442,6 +7808,7 @@ def doPrintOrgs(): output_csv(org_attributes, titles, u'Orgs', todrive) def doPrintAliases(): + cd = buildGAPIObject(u'directory') todrive = False i = 3 while i < len(sys.argv): @@ -7451,27 +7818,26 @@ def doPrintAliases(): else: print u'ERROR: %s is not a valid argument for "gam print aliases"' % sys.argv[i] sys.exit(2) - cd = buildGAPIObject(u'directory') alias_attributes = [] alias_attributes.append({u'Alias': u'Alias'}) alias_attributes[0].update(Target=u'Target') alias_attributes[0].update(TargetType=u'TargetType') titles = [u'Alias', u'Target', u'TargetType'] - sys.stderr.write(u"Retrieving All User Aliases for %s organization (may take some time on large domain)...\n" % domain) + sys.stderr.write(u"Retrieving All User Aliases for %s organization (may take some time on large domain)...\n" % GC_Values[GC_DOMAIN]) page_message = u'Got %%num_items%% users %%first_item%% - %%last_item%%\n' all_users = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - message_attribute=u'primaryEmail', customer=customerId, - fields=u'users(primaryEmail,aliases),nextPageToken', maxResults=500) + message_attribute=u'primaryEmail', customer=GC_Values[GC_CUSTOMER_ID], + fields=u'users(primaryEmail,aliases),nextPageToken', maxResults=GC_Values[GC_USER_MAX_RESULTS]) for user in all_users: try: for alias in user[u'aliases']: alias_attributes.append({u'Alias': alias, u'Target': user[u'primaryEmail'], u'TargetType': u'User'}) except KeyError: continue - sys.stderr.write(u"Retrieving All User Aliases for %s organization (may take some time on large domain)...\n" % domain) + sys.stderr.write(u"Retrieving All User Aliases for %s organization (may take some time on large domain)...\n" % GC_Values[GC_DOMAIN]) page_message = u'Got %%num_items%% groups %%first_item%% - %%last_item%%\n' all_groups = callGAPIpages(service=cd.groups(), function=u'list', items=u'groups', page_message=page_message, - message_attribute=u'email', customer=customerId, + message_attribute=u'email', customer=GC_Values[GC_CUSTOMER_ID], fields=u'groups(email,aliases),nextPageToken') for group in all_groups: try: @@ -7482,6 +7848,7 @@ def doPrintAliases(): output_csv(alias_attributes, titles, u'Aliases', todrive) def doPrintGroupMembers(): + cd = buildGAPIObject(u'directory') todrive = all_groups = False i = 3 while i < len(sys.argv): @@ -7494,11 +7861,10 @@ def doPrintGroupMembers(): else: print 'ERROR: %s is not a valid argument for "gam print group-members"' % sys.argv[i] sys.exit(2) - cd = buildGAPIObject(u'directory') member_attributes = [{u'group': u'group'},] if not all_groups: all_groups = callGAPIpages(service=cd.groups(), function=u'list', items=u'groups', message_attribute=u'email', - customer=customerId, fields=u'nextPageToken,groups(email)') + customer=GC_Values[GC_CUSTOMER_ID], fields=u'nextPageToken,groups(email)') total_groups = len(all_groups) i = 1 for group in all_groups: @@ -7554,8 +7920,8 @@ def doPrintMobileDevices(): sys.stderr.write(u'Retrieving All Mobile Devices for organization (may take some time for large accounts)...\n') page_message = u'Got %%num_items%% mobile devices...\n' all_mobile = callGAPIpages(service=cd.mobiledevices(), function=u'list', items=u'mobiledevices', page_message=page_message, - customerId=customerId, query=query, - orderBy=orderBy, sortOrder=sortOrder, maxResults=500) + customerId=GC_Values[GC_CUSTOMER_ID], query=query, + orderBy=orderBy, sortOrder=sortOrder, maxResults=GC_Values[GC_DEVICE_MAX_RESULTS]) for mobile in all_mobile: mobiledevice = dict() for title in mobile: @@ -7636,8 +8002,8 @@ def doPrintCrosDevices(): sys.stderr.write(u'Retrieving All Chrome OS Devices for organization (may take some time for large accounts)...\n') page_message = u'Got %%num_items%% Chrome devices...\n' all_cros = callGAPIpages(service=cd.chromeosdevices(), function=u'list', items=u'chromeosdevices', page_message=page_message, - query=query, customerId=customerId, projection=projection, - orderBy=orderBy, sortOrder=sortOrder, maxResults=500) + query=query, customerId=GC_Values[GC_CUSTOMER_ID], projection=projection, + orderBy=orderBy, sortOrder=sortOrder, maxResults=GC_Values[GC_DEVICE_MAX_RESULTS]) if all_cros: if (not noLists) and (not selectAttrib): for cros in all_cros: @@ -7703,7 +8069,7 @@ def doPrintLicenses(return_list=False, skus=None): page_message = u'Got %%%%total_items%%%% Licenses for %s...\n' % sku try: licenses += callGAPIpages(service=lic.licenseAssignments(), function=u'listForProductAndSku', throw_reasons=[u'invalid', u'forbidden'], page_message=page_message, - customerId=domain, productId=product, skuId=sku, fields=u'items(productId,skuId,userId),nextPageToken') + customerId=GC_Values[GC_DOMAIN], productId=product, skuId=sku, fields=u'items(productId,skuId,userId),nextPageToken') except googleapiclient.errors.HttpError: licenses += [] else: @@ -7711,7 +8077,7 @@ def doPrintLicenses(return_list=False, skus=None): page_message = u'Got %%%%total_items%%%% Licenses for %s...\n' % productId try: licenses += callGAPIpages(service=lic.licenseAssignments(), function=u'listForProduct', throw_reasons=[u'invalid', u'forbidden'], page_message=page_message, - customerId=domain, productId=productId, fields=u'items(productId,skuId,userId),nextPageToken') + customerId=GC_Values[GC_DOMAIN], productId=productId, fields=u'items(productId,skuId,userId),nextPageToken') except googleapiclient.errors.HttpError: licenses = +[] for u_license in licenses: @@ -7728,6 +8094,7 @@ def doPrintLicenses(return_list=False, skus=None): output_csv(lic_attributes, lic_attributes[0], u'Licenses', todrive) def doPrintTokens(): + cd = buildGAPIObject(u'directory') todrive = False i = 3 entity_type = u'all' @@ -7743,7 +8110,6 @@ def doPrintTokens(): else: print u'ERROR: %s is not a valid argument for "gam print tokens"' % sys.argv[i] sys.exit(2) - cd = buildGAPIObject(u'directory') all_users = getUsersToModify(entity_type=entity_type, entity=entity, silent=False) titles = [u'user', u'displayText', u'clientId', u'nativeApp', u'anonymous', u'scopes'] token_attributes = [{}] @@ -7769,67 +8135,51 @@ def doPrintTokens(): pass output_csv(token_attributes, titles, u'OAuth Tokens', todrive) -def doPrintResources(): +def doPrintResourceCalendars(): + cd = buildGAPIObject(u'directory') + todrive = False + fields = [u'resourceId', u'resourceName', u'resourceEmail'] i = 3 - res_attributes = [] - res_attributes.append({u'Name': u'Name'}) - titles = ['Name'] - printid = printdesc = printemail = printtype = todrive = False while i < len(sys.argv): if sys.argv[i].lower() == u'allfields': - printid = printdesc = printemail = True - res_attributes[0].update(ID=u'ID', Description=u'Description', Email=u'Email', Type=u'Type') - titles.append(u'ID') - titles.append(u'Description') - titles.append(u'Email') - titles.append(u'Type') + fields = None i += 1 elif sys.argv[i].lower() == u'todrive': todrive = True i += 1 elif sys.argv[i].lower() == u'id': - printid = True - res_attributes[0].update(ID=u'ID') - titles.append(u'ID') i += 1 elif sys.argv[i].lower() == u'description': - printdesc = True - res_attributes[0].update(Description=u'Description') - titles.append(u'Description') + fields.append(u'resourceDescription') i += 1 elif sys.argv[i].lower() == u'email': - printemail = True - res_attributes[0].update(Email=u'Email') - titles.append(u'Email') i += 1 elif sys.argv[i].lower() == u'type': - printtype = True - res_attributes[0].update(Type=u'Type') - titles.append(u'Type') + fields.append(u'resourceType') i += 1 else: print 'ERROR: %s is not a valid argument for "gam print resources"' % sys.argv[i] sys.exit(2) - resObj = getResCalObject() + if fields: + fields = u'nextPageToken,items(%s)' % u','.join(fields) sys.stderr.write(u"Retrieving All Resource Calendars for your account (may take some time on a large domain)\n") - resources = callGData(service=resObj, function=u'RetrieveAllResourceCalendars') + page_message = u'Got %%total_items%% resources: %%first_item%% - %%last_item%%\n' + resources = callGAPIpages(service=cd.resources().calendars(), function=u'list', items=u'items', + page_message=page_message, message_attribute=u'resourceId', + customer=GC_Values[GC_CUSTOMER_ID], fields=fields, maxResults=500) + resources_attrib = [{u'resourceId':u'resourceId', + u'resourceEmail': u'resourceEmail', + u'resourceName': u'resourceName'}] for resource in resources: - resUnit = {} - resUnit.update({u'Name': resource[u'resourceCommonName']}) - if printid: - resUnit.update({u'ID': resource[u'resourceId']}) - if printdesc: - try: - desc = resource[u'resourceDescription'] - except KeyError: - desc = '' - resUnit.update({u'Description': desc}) - if printemail: - resUnit.update({u'Email': resource[u'resourceEmail']}) - if printtype: - resUnit.update({u'Type': resource[u'resourceType']}) - res_attributes.append(resUnit) - output_csv(res_attributes, titles, u'Resources', todrive) + resource_attrib = {} + for key, value in resource.items(): + if key in [u'kind', u'etags']: + continue + if key not in resources_attrib[0]: + resources_attrib[0][key] = key + resource_attrib[key] = value + resources_attrib.append(resource_attrib) + output_csv(resources_attrib, resources_attrib[0], u'Resources', todrive) def doCreateMonitor(): source_user = sys.argv[4].lower() @@ -8189,7 +8539,7 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa else: member_type_message = u'%ss' % member_type.lower() if group.find(u'@') == -1: - group = u'%s@%s' % (group, domain) + group = u'%s@%s' % (group, GC_Values[GC_DOMAIN]) page_message = None if not silent: sys.stderr.write(u"Getting %s of %s (may take some time for large groups)..." % (member_type_message, group)) @@ -8213,8 +8563,8 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa sys.stderr.write(u"Getting all users in the Google Apps organization (may take some time on a large domain)...\n") page_message = u'Got %%total_items%% users...' members = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - customer=customerId, fields=u'nextPageToken,users(primaryEmail,id,orgUnitPath)', - query=u"orgUnitPath='%s'" % ou, maxResults=500) + customer=GC_Values[GC_CUSTOMER_ID], fields=u'nextPageToken,users(primaryEmail,id,orgUnitPath)', + query=u"orgUnitPath='%s'" % ou, maxResults=GC_Values[GC_USER_MAX_RESULTS]) for member in members: if ou.lower() != member[u'orgUnitPath'].lower(): continue @@ -8235,8 +8585,8 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa sys.stderr.write(u"Getting all users in the Google Apps organization (may take some time on a large domain)...\n") page_message = u'Got %%total_items%% users..' members = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - customer=customerId, fields=u'nextPageToken,users(primaryEmail,id)', - query=u"orgUnitPath='%s'" % ou, maxResults=500) + customer=GC_Values[GC_CUSTOMER_ID], fields=u'nextPageToken,users(primaryEmail,id)', + query=u"orgUnitPath='%s'" % ou, maxResults=GC_Values[GC_USER_MAX_RESULTS]) for member in members: if return_uids: users.append(member[u'id']) @@ -8251,8 +8601,8 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa sys.stderr.write(u"Getting all users that match query %s (may take some time on a large domain)...\n" % entity) page_message = u'Got %%total_items%% users...' members = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - customer=customerId, fields=u'nextPageToken,users(primaryEmail,id)', - query=entity, maxResults=500) + customer=GC_Values[GC_CUSTOMER_ID], fields=u'nextPageToken,users(primaryEmail,id)', + query=entity, maxResults=GC_Values[GC_USER_MAX_RESULTS]) for member in members: if return_uids: users.append(member[u'id']) @@ -8304,8 +8654,8 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa 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...' all_users = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - customer=customerId, - fields=u'nextPageToken,users(primaryEmail,suspended,id)', maxResults=500) + customer=GC_Values[GC_CUSTOMER_ID], + fields=u'nextPageToken,users(primaryEmail,suspended,id)', maxResults=GC_Values[GC_USER_MAX_RESULTS]) for member in all_users: if member[u'suspended'] == False: if return_uids: @@ -8318,8 +8668,8 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa 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)', - maxResults=500) + customerId=GC_Values[GC_CUSTOMER_ID], fields=u'nextPageToken,chromeosdevices(deviceId)', + maxResults=GC_Values[GC_DEVICE_MAX_RESULTS]) for member in all_cros: users.append(member[u'deviceId']) if not silent: @@ -8339,7 +8689,7 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa if user[:4] == u'uid:': full_users.append(user[4:]) elif user.find(u'@') == -1: - full_users.append(u'%s@%s' % (user, domain)) + full_users.append(u'%s@%s' % (user, GC_Values[GC_DOMAIN])) else: full_users.append(user) else: @@ -8356,18 +8706,17 @@ def OAuthInfo(): try: access_token = sys.argv[3] except IndexError: - oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', FN_OAUTH2_TXT)) - storage = oauth2client.file.Storage(oauth2file) + storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) credentials = storage.get() if credentials is None or credentials.invalid: doRequestOAuth() credentials = storage.get() credentials.user_agent = GAM_INFO - http = httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt'))) + http = httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL]) if credentials.access_token_expired: credentials.refresh(http) access_token = credentials.access_token - print u"\nOAuth File: %s" % oauth2file + print u"\nOAuth File: %s" % GC_Values[GC_OAUTH2_TXT] oa2 = buildGAPIObject(u'oauth2') token_info = callGAPI(service=oa2, function=u'tokeninfo', access_token=access_token) print u"Client ID: %s" % token_info[u'issued_to'] @@ -8384,14 +8733,13 @@ def OAuthInfo(): print u'Google Apps Admin: Unknown' def doDeleteOAuth(): - oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', FN_OAUTH2_TXT)) - storage = oauth2client.file.Storage(oauth2file) + storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) credentials = storage.get() try: credentials.revoke_uri = oauth2client.GOOGLE_REVOKE_URI except AttributeError: systemErrorExit(1, u'Authorization doesn\'t exist') - http = httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt'))) + http = httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL]) sys.stderr.write(u'This OAuth token will self-destruct in 3...') time.sleep(1) sys.stderr.write(u'2...') @@ -8403,7 +8751,7 @@ def doDeleteOAuth(): credentials.revoke(http) except oauth2client.client.TokenRevokeError, e: sys.stderr.write(u'{0}{1}\n'.format(ERROR_PREFIX, e.message)) - os.remove(oauth2file) + os.remove(GC_Values[GC_OAUTH2_TXT]) class cmd_flags(object): def __init__(self, noLocalWebserver): @@ -8419,7 +8767,7 @@ possible_scopes = [u'https://www.googleapis.com/auth/admin.directory.group', u'https://www.googleapis.com/auth/admin.directory.device.chromeos', # Chrome OS Devices Directory Scope u'https://www.googleapis.com/auth/admin.directory.device.mobile', # Mobile Device Directory Scope u'https://apps-apis.google.com/a/feeds/emailsettings/2.0/', # Email Settings API - u'https://apps-apis.google.com/a/feeds/calendar/resource/', # Calendar Resource API + u'https://www.googleapis.com/auth/admin.directory.resource.calendar',# Resource Calendar API u'https://apps-apis.google.com/a/feeds/compliance/audit/', # Email Audit API u'https://apps-apis.google.com/a/feeds/domain/', # Admin Settings API u'https://www.googleapis.com/auth/apps.groups.settings', # Group Settings API @@ -8437,10 +8785,11 @@ possible_scopes = [u'https://www.googleapis.com/auth/admin.directory.group', u'https://www.googleapis.com/auth/cloudprint', # CloudPrint API u'https://www.googleapis.com/auth/admin.datatransfer', # Data Transfer API u'https://www.googleapis.com/auth/admin.directory.customer', # Customer API - u'https://www.googleapis.com/auth/admin.directory.domain'] # Domain API + u'https://www.googleapis.com/auth/admin.directory.domain', # Domain API + u'https://www.googleapis.com/auth/admin.directory.rolemanagement', # Roles API + ] def doRequestOAuth(incremental_auth=False): - CLIENT_SECRETS = os.path.join(gamUserConfigDir, os.environ.get(u'CLIENTSECRETSFILE', FN_CLIENT_SECRETS_JSON)) MISSING_CLIENT_SECRETS_MESSAGE = u""" WARNING: Please configure OAuth 2.0 @@ -8457,7 +8806,7 @@ https://github.com/jay0lee/GAM/wiki/CreatingClientSecretsFile for instructions. -""" % CLIENT_SECRETS +""" % GC_Values[GC_CLIENT_SECRETS_JSON] num_scopes = len(possible_scopes) menu = u'''Select the authorized scopes for this token. Include a 'r' to grant read-only access or an 'a' to grant action-only access. @@ -8468,7 +8817,7 @@ access or an 'a' to grant action-only access. [%%s] %s) Chrome OS Device Directory API (supports read-only) [%%s] %s) Mobile Device Directory API (supports read-only and action) [%%s] %s) User Email Settings API -[%%s] %s) Calendar Resources API +[%%s] %s) Resource Calendar API (supports read-only) [%%s] %s) Audit Monitors, Activity and Mailbox Exports API [%%s] %s) Admin Settings API [%%s] %s) Groups Settings API @@ -8487,12 +8836,14 @@ access or an 'a' to grant action-only access. [%%s] %s) Data Transfer API (supports read-only) [%%s] %s) Customer Directory API (supports read-only) [%%s] %s) Domains Directory API (supports read-only) +[%%s] %s) Roles API (supports read-only) %%s) Select all scopes %%s) Unselect all scopes %%s) Continue ''' % tuple(range(0, num_scopes)) selected_scopes = [u'*'] * num_scopes + selected_scopes[16] = u' ' select_all_scopes = unicode(str(num_scopes)) unselect_all_scopes = unicode(str(num_scopes+1)) authorize_scopes = unicode(str(num_scopes+2)) @@ -8505,7 +8856,7 @@ access or an 'a' to grant action-only access. try: if selection.lower().find(u'r') != -1: selection = int(selection.lower().replace(u'r', u'')) - if selection not in [0, 1, 2, 3, 4, 10, 19, 22, 23, 24]: + if selection not in [0, 1, 2, 3, 4, 6, 10, 19, 22, 23, 24, 25]: os.system([u'clear', u'cls'][os.name == u'nt']) print u'THAT SCOPE DOES NOT SUPPORT READ-ONLY MODE!\n' continue @@ -8561,14 +8912,14 @@ access or an 'a' to grant action-only access. elif selected_scopes[i] == u'A': scopes.append(u'%s.action' % possible_scopes[i]) try: - FLOW = oauth2client.client.flow_from_clientsecrets(CLIENT_SECRETS, scope=scopes) + FLOW = oauth2client.client.flow_from_clientsecrets(GC_Values[GC_CLIENT_SECRETS_JSON], scope=scopes) except oauth2client.client.clientsecrets.InvalidClientSecretsError: systemErrorExit(14, MISSING_CLIENT_SECRETS_MESSAGE) - storage = oauth2client.file.Storage(os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', FN_OAUTH2_TXT))) + storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) credentials = storage.get() - flags = cmd_flags(noLocalWebserver=os.path.isfile(os.path.join(gamUserConfigDir, u'nobrowser.txt'))) + flags = cmd_flags(noLocalWebserver=GC_Values[GC_NO_BROWSER]) if credentials is None or credentials.invalid or incremental_auth: - http = httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt'))) + http = httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL]) try: credentials = oauth2client.tools.run_flow(flow=FLOW, storage=storage, flags=flags, http=http) except httplib2.CertificateValidationUnsupported: @@ -8576,24 +8927,19 @@ access or an 'a' to grant action-only access. def batch_worker(): while True: - item = q.get() + item = GM_Globals[GM_BATCH_QUEUE].get() subprocess.call(item, stderr=subprocess.STDOUT) - q.task_done() + GM_Globals[GM_BATCH_QUEUE].task_done() def run_batch(items): import Queue, threading - global q total_items = len(items) current_item = 0 python_cmd = [sys.executable.lower(),] 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')) - except TypeError: - num_worker_threads = 5 - num_worker_threads = min(total_items, num_worker_threads) - q = Queue.Queue(maxsize=num_worker_threads) # q.put() gets blocked when trying to create more items than there are workers + num_worker_threads = min(total_items, GC_Values[GC_NUM_THREADS]) + GM_Globals[GM_BATCH_QUEUE] = Queue.Queue(maxsize=num_worker_threads) # GM_Globals[GM_BATCH_QUEUE].put() gets blocked when trying to create more items than there are workers print u'starting %s worker threads...' % num_worker_threads for i in range(num_worker_threads): t = threading.Thread(target=batch_worker) @@ -8605,17 +8951,17 @@ def run_batch(items): print u'starting job %s / %s' % (current_item, total_items) if item[0] == u'commit-batch': sys.stderr.write(u'commit-batch - waiting for running processes to finish before proceeding...') - q.join() + GM_Globals[GM_BATCH_QUEUE].join() sys.stderr.write(u'done with commit-batch\n') continue - q.put(python_cmd+item) - q.join() + GM_Globals[GM_BATCH_QUEUE].put(python_cmd+item) + GM_Globals[GM_BATCH_QUEUE].join() # Main reload(sys) sys.setdefaultencoding(u'UTF-8') try: - if os.name == u'nt': + if GM_Globals[GM_WINDOWS]: sys.argv = win32_unicode_argv() # cleanup sys.argv on Windows SetGlobalVariables() if sys.argv[1].lower() == u'batch': @@ -8643,10 +8989,16 @@ try: print 'ERROR: "gam csv " should be followed by a full GAM command...' sys.exit(3) argv_template = sys.argv[4:] + substring_replacements = re.findall(r'~~(.*?)~~', u' '.join(argv_template)) items = list() for row in input_file: argv = list() for arg in argv_template: + for substring_replacement in substring_replacements: + try: + arg = arg.replace(u'~~%s~~' % substring_replacement, row[substring_replacement]) + except KeyError: + systemErrorExit(3, u'%s is not in %s' % (substring_replacement, row)) if arg[0] != '~': argv.append(arg) elif arg[1:] in row: @@ -8670,7 +9022,7 @@ try: elif sys.argv[2].lower() in [u'org', 'ou']: doCreateOrg() elif sys.argv[2].lower() == u'resource': - doCreateResource() + doCreateResourceCalendar() elif sys.argv[2].lower() in [u'verify', u'verification']: doSiteVerifyShow() elif sys.argv[2].lower() in [u'schema']: @@ -8683,6 +9035,8 @@ try: doCreateDomain() elif sys.argv[2].lower() in [u'domainalias', u'aliasdomain']: doCreateDomainAlias() + elif sys.argv[2].lower() in [u'admin']: + doCreateAdmin() else: print u'ERROR: %s is not a valid argument for "gam create"' % sys.argv[2] sys.exit(2) @@ -8786,6 +9140,8 @@ try: doDelDomain() elif sys.argv[2].lower() in [u'domainalias',]: doDelDomainAlias() + elif sys.argv[2].lower() in [u'admin',]: + doDelAdmin() else: print u'ERROR: %s is not a valid argument for "gam delete"' % sys.argv[2] sys.exit(2) @@ -8852,7 +9208,7 @@ try: elif sys.argv[2].lower() in [u'orgs', u'ous']: doPrintOrgs() elif sys.argv[2].lower() == u'resources': - doPrintResources() + doPrintResourceCalendars() elif sys.argv[2].lower() == u'cros': doPrintCrosDevices() elif sys.argv[2].lower() == u'mobile': @@ -8877,6 +9233,8 @@ try: doPrintTransferApps() elif sys.argv[2].lower() in [u'domains']: doPrintDomains() + elif sys.argv[2].lower() in [u'admins']: + doPrintAdmins() else: print u'ERROR: %s is not a valid argument for "gam print"' % sys.argv[2] sys.exit(2) @@ -8963,8 +9321,7 @@ try: print user sys.exit(0) try: - autoBatch = int(os.environ.get(u'GAM_AUTOBATCH', '0')) - if (autoBatch > 0) and (len(users) > autoBatch): + if (GC_Values[GC_AUTO_BATCH_MIN] > 0) and (len(users) > GC_Values[GC_AUTO_BATCH_MIN]): items = [] for user in users: items.append([u'user', user] + sys.argv[3:]) diff --git a/src/gdata/apps/res_cal/__init__.py b/src/gdata/apps/res_cal/__init__.py deleted file mode 100644 index 8b137891..00000000 --- a/src/gdata/apps/res_cal/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/gdata/apps/res_cal/service.py b/src/gdata/apps/res_cal/service.py deleted file mode 100644 index bb173bbc..00000000 --- a/src/gdata/apps/res_cal/service.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright (C) 2008 Google, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Allow Google Apps domain administrators to create/modify/delete resource calendars. - - ResCalService: Interact with Resource Calendars.""" - -__author__ = 'jlee@pbu.edu' - -import gdata.apps -import gdata.apps.service -import gdata.service - -class ResCalService(gdata.apps.service.PropertyService): - """Client for the Google Apps Resource Calendar service.""" - - def _serviceUrl(self, domain=None): - if domain is None: - domain = self.domain - return '/a/feeds/calendar/resource/2.0/%s' % domain - - def CreateResourceCalendar(self, id, common_name, description=None, type=None): - - uri = self._serviceUrl() - properties = {} - properties['resourceId'] = id - properties['resourceCommonName'] = common_name - if description != None: - properties['resourceDescription'] = description - if type != None: - properties['resourceType'] = type - return self._PostProperties(uri, properties) - - def RetrieveResourceCalendar(self, id): - - uri = self._serviceUrl()+'/'+id - return self._GetProperties(uri) - - def RetrieveAllResourceCalendars(self): - - uri = self._serviceUrl()+'/' - return self._GetPropertiesList(uri) - - def UpdateResourceCalendar(self, id, common_name=None, description=None, type=None): - - uri = self._serviceUrl()+'/'+id - properties = {} - properties['resourceId'] = id - if common_name != None: - properties['resourceCommonName'] = common_name - if description != None: - properties['resourceDescription'] = description - if type != None: - properties['resourceType'] = type - return self._PutProperties(uri, properties) - - def DeleteResourceCalendar(self, id): - - uri = self._serviceUrl()+'/'+id - return self._DeleteProperties(uri) \ No newline at end of file From 6fd107c2305de1a91605803e0eaef9ccde6f0d70 Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Tue, 22 Dec 2015 16:39:56 -0800 Subject: [PATCH 02/11] CSV debug check inadvertently dropped --- src/gam.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gam.py b/src/gam.py index 449c64fc..b27b6135 100755 --- a/src/gam.py +++ b/src/gam.py @@ -8982,6 +8982,9 @@ try: run_batch(items) sys.exit(0) elif sys.argv[1].lower() == u'csv': + if httplib2.debuglevel > 0: + print u'Sorry, CSV commands are not compatible with debug. Delete debug.gam and try again.' + sys.exit(1) csv_filename = sys.argv[2] f = openFile(csv_filename) input_file = csv.DictReader(f) From 14bc340e56012f3a5197d3f42242a5ad0f777b54 Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Tue, 22 Dec 2015 17:23:43 -0800 Subject: [PATCH 03/11] Commit Jays changes --- src/gam.py | 1070 ++++++++++++++++++++-------------------------------- 1 file changed, 418 insertions(+), 652 deletions(-) diff --git a/src/gam.py b/src/gam.py index b27b6135..cd156c6e 100755 --- a/src/gam.py +++ b/src/gam.py @@ -57,6 +57,7 @@ GAM_APPSPOT_LATEST_VERSION_ANNOUNCEMENT = GAM_APPSPOT+u'/latest-version-announce TRUE = u'true' FALSE = u'false' +extra_args = {u'prettyPrint': False} true_values = [u'on', u'yes', u'enabled', u'true', u'1'] false_values = [u'off', u'no', u'disabled', u'false', u'0'] usergroup_types = [u'user', u'users', u'group', u'ou', u'org', @@ -73,180 +74,17 @@ FN_LAST_UPDATE_CHECK_TXT = u'lastupdatecheck.txt' FN_OAUTH2SERVICE_JSON = u'oauth2service.json' FN_OAUTH2_TXT = u'oauth2.txt' MY_CUSTOMER = u'my_customer' -UNKNOWN = u'Unknown' -# -# Global variables -# -# The following GM_XXX constants are arbitrary but must be unique -# Most errors print a message and bail out with a return code -# Some commands want to set a non-zero return code but not bail -GM_SYSEXITRC = u'sxrc' -# Path to gam -GM_GAM_PATH = u'gpth' -# Are we on Windows? -GM_WINDOWS = u'wndo' -# Encodings -GM_SYS_ENCODING = u'syen' -# Shared by batch_worker and run_batch -GM_BATCH_QUEUE = u'batq' -# Extra arguments to pass to GAPI functions -GM_EXTRA_ARGS_DICT = u'exad' -# Values retrieved from oauth2service.json -GM_OAUTH2SERVICE_KEY = u'oauk' -GM_OAUTH2SERVICE_ACCOUNT_EMAIL = u'oaae' -GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID = u'oaci' -# File containing time of last GAM update check -GM_LAST_UPDATE_CHECK_TXT = u'lupc' -# Dictionary mapping OrgUnit ID to Name -GM_MAP_ORGUNIT_ID_TO_NAME = u'oi2n' -# Dictionary mapping Role ID to Name -GM_MAP_ROLE_ID_TO_NAME = u'ri2n' -# Dictionary mapping Role Name to ID -GM_MAP_ROLE_NAME_TO_ID = u'rn2i' -# Dictionary mapping User ID to Name -GM_MAP_USER_ID_TO_NAME = u'ui2n' -# -GM_Globals = { - GM_SYSEXITRC: 0, - GM_GAM_PATH: os.path.dirname(os.path.realpath(__file__)), - GM_WINDOWS: os.name == u'nt', - GM_SYS_ENCODING: sys.getfilesystemencoding() if os.name == u'nt' else u'utf-8', - GM_BATCH_QUEUE: None, - GM_EXTRA_ARGS_DICT: {u'prettyPrint': False}, - GM_OAUTH2SERVICE_KEY: None, - GM_OAUTH2SERVICE_ACCOUNT_EMAIL: None, - GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID: None, - GM_LAST_UPDATE_CHECK_TXT: u'', - GM_MAP_ORGUNIT_ID_TO_NAME: None, - GM_MAP_ROLE_ID_TO_NAME: None, - GM_MAP_ROLE_NAME_TO_ID: None, - GM_MAP_USER_ID_TO_NAME: None, - } -# -# Global variables defined by environment variables/signal files -# -# When retrieving lists of Google Drive activities from API, how many should be retrieved in each chunk -GC_ACTIVITY_MAX_RESULTS = u'activity_max_results' -# Automatically generate gam batch command if number of users specified in gam users xxx command exceeds this number -# Default: 0, don't automatically generate gam batch commands -GC_AUTO_BATCH_MIN = u'auto_batch_min' -# GAM cache directory. If no_cache is specified, this variable will be set to None -GC_CACHE_DIR = u'cache_dir' -# Character set of batch, csv, data files -GC_CHARSET = u'charset' -# Path to client_secrets.json -GC_CLIENT_SECRETS_JSON = u'client_secrets_json' -# GAM config directory containing client_secrets.json, oauth2.txt, oauth2service.json, extra_args.txt -GC_CONFIG_DIR = u'config_dir' -# custmerId from gam.cfg or retrieved from Google -GC_CUSTOMER_ID = u'customer_id' -# If debug_level > 0: extra_args[u'prettyPrint'] = True, httplib2.debuglevel = gam_debug_level, appsObj.debug = True -GC_DEBUG_LEVEL = u'debug_level' -# When retrieving lists of ChromeOS/Mobile devices from API, how many should be retrieved in each chunk -GC_DEVICE_MAX_RESULTS = u'device_max_results' -# Domain obtained from gam.cfg or oauth2.txt -GC_DOMAIN = u'domain' -# Google Drive download directory -GC_DRIVE_DIR = u'drive_dir' -# When retrieving lists of Drive files/folders from API, how many should be retrieved in each chunk -GC_DRIVE_MAX_RESULTS = u'drive_max_results' -# If no_browser is False, writeCSVfile won't open a browser when todrive is set -# and doRequestOAuth prints a link and waits for the verification code when oauth2.txt is being created -GC_NO_BROWSER = u'no_browser' -# Disable GAM API caching -GC_NO_CACHE = u'no_cache' -# Disable GAM update check -GC_NO_UPDATE_CHECK = u'no_update_check' -# Disable SSL certificate validation -GC_NO_VERIFY_SSL = u'no_verify_ssl' -# Number of threads for gam batch -GC_NUM_THREADS = u'num_threads' -# Path to oauth2.txt -GC_OAUTH2_TXT = u'oauth2_txt' -# Path to oauth2service.json -GC_OAUTH2SERVICE_JSON = u'oauth2service_json' -# Default section to use for processing -GC_SECTION = u'section' -# Add (n/m) to end of messages if number of items to be processed exceeds this number -GC_SHOW_COUNTS_MIN = u'show_counts_min' -# Enable/disable "Getting ... " messages -GC_SHOW_GETTINGS = u'show_gettings' -# GAM config directory containing admin-settings-v1.json, cloudprint-v2.json -GC_SITE_DIR = u'site_dir' -# When adding Users to Groups/Org Units, how many should be processed in each batch -GC_USER_BATCH_SIZE = u'user_batch_size' -# When retrieving lists of Users from API, how many should be retrieved in each chunk -GC_USER_MAX_RESULTS = u'user_max_results' +UNKNOWN_DOMAIN = u'Unknown' -GC_Defaults = { - GC_ACTIVITY_MAX_RESULTS: 100, - GC_AUTO_BATCH_MIN: 0, - GC_CACHE_DIR: u'', - GC_CHARSET: u'utf-8', - GC_CLIENT_SECRETS_JSON: FN_CLIENT_SECRETS_JSON, - GC_CONFIG_DIR: u'', - GC_CUSTOMER_ID: u'', - GC_DEBUG_LEVEL: 0, - GC_DEVICE_MAX_RESULTS: 500, - GC_DOMAIN: u'', - GC_DRIVE_DIR: u'', - GC_DRIVE_MAX_RESULTS: 1000, - GC_NO_BROWSER: FALSE, - GC_NO_CACHE: FALSE, - GC_NO_UPDATE_CHECK: FALSE, - GC_NO_VERIFY_SSL: FALSE, - GC_NUM_THREADS: 5, - GC_OAUTH2_TXT: FN_OAUTH2_TXT, - GC_OAUTH2SERVICE_JSON: FN_OAUTH2SERVICE_JSON, - GC_SECTION: u'', - GC_SHOW_COUNTS_MIN: 1, - GC_SHOW_GETTINGS: TRUE, - GC_SITE_DIR: u'', - GC_USER_BATCH_SIZE: 50, - GC_USER_MAX_RESULTS: 500, - } +customerId = None +domain = None +q = None -GC_Values = {} - -GC_TYPE_BOOLEAN = u'bool' -GC_TYPE_CHOICE = u'choi' -GC_TYPE_DIRECTORY = u'dire' -GC_TYPE_EMAIL = u'emai' -GC_TYPE_FILE = u'file' -GC_TYPE_INTEGER = u'inte' -GC_TYPE_LANGUAGE = u'lang' -GC_TYPE_STRING = u'stri' - -GC_VAR_TYPE_KEY = u'type' -GC_VAR_LIMITS_KEY = u'lmit' - -GC_VAR_INFO = { - GC_ACTIVITY_MAX_RESULTS: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, 500)}, - GC_AUTO_BATCH_MIN: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (0, None)}, - GC_CACHE_DIR: {GC_VAR_TYPE_KEY: GC_TYPE_DIRECTORY}, - GC_CHARSET: {GC_VAR_TYPE_KEY: GC_TYPE_STRING}, - GC_CLIENT_SECRETS_JSON: {GC_VAR_TYPE_KEY: GC_TYPE_FILE}, - GC_CONFIG_DIR: {GC_VAR_TYPE_KEY: GC_TYPE_DIRECTORY}, - GC_CUSTOMER_ID: {GC_VAR_TYPE_KEY: GC_TYPE_STRING}, - GC_DEBUG_LEVEL: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (0, None)}, - GC_DEVICE_MAX_RESULTS: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, 1000)}, - GC_DOMAIN: {GC_VAR_TYPE_KEY: GC_TYPE_STRING}, - GC_DRIVE_DIR: {GC_VAR_TYPE_KEY: GC_TYPE_DIRECTORY}, - GC_DRIVE_MAX_RESULTS: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, 1000)}, - GC_NO_BROWSER: {GC_VAR_TYPE_KEY: GC_TYPE_BOOLEAN}, - GC_NO_CACHE: {GC_VAR_TYPE_KEY: GC_TYPE_BOOLEAN}, - GC_NO_UPDATE_CHECK: {GC_VAR_TYPE_KEY: GC_TYPE_BOOLEAN}, - GC_NO_VERIFY_SSL: {GC_VAR_TYPE_KEY: GC_TYPE_BOOLEAN}, - GC_NUM_THREADS: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, None)}, - GC_OAUTH2_TXT: {GC_VAR_TYPE_KEY: GC_TYPE_FILE}, - GC_OAUTH2SERVICE_JSON: {GC_VAR_TYPE_KEY: GC_TYPE_FILE}, - GC_SECTION: {GC_VAR_TYPE_KEY: GC_TYPE_STRING}, - GC_SHOW_COUNTS_MIN: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (0, None)}, - GC_SHOW_GETTINGS: {GC_VAR_TYPE_KEY: GC_TYPE_BOOLEAN}, - GC_SITE_DIR: {GC_VAR_TYPE_KEY: GC_TYPE_DIRECTORY}, - GC_USER_BATCH_SIZE: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, 1000)}, - GC_USER_MAX_RESULTS: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, 500)}, - } +gamPath = None +gamSiteConfigDir = None +gamUserConfigDir = None +gamDriveDir = None +gamCacheDir = None MESSAGE_CLIENT_API_ACCESS_DENIED = u'Access Denied. Please make sure the Client Name:\n\n{0}\n\nis authorized for the API Scope(s):\n\n{1}\n\nThis can be configured in your Control Panel under:\n\nSecurity -->\nAdvanced Settings -->\nManage API client access' MESSAGE_GAM_EXITING_FOR_UPDATE = u'GAM is now exiting so that you can overwrite this old version with the latest release' @@ -267,9 +105,9 @@ def convertUTF8(data): if isinstance(data, str): return data if isinstance(data, unicode): - if GM_Globals[GM_WINDOWS]: + if os.name == u'nt': return data - return data.encode(GM_Globals[GM_SYS_ENCODING]) + return data.encode('utf-8') if isinstance(data, collections.Mapping): return dict(map(convertUTF8, data.iteritems())) if isinstance(data, collections.Iterable): @@ -418,95 +256,28 @@ def writeFile(filename, data, mode=u'wb', continueOnError=False, displayError=Tr sys.stderr.write(u'{0}{1}\n'.format(ERROR_PREFIX, e)) return False systemErrorExit(6, e) -# -# Set global variables -# Check for GAM updates based on status of noupdatecheck.txt -# + def SetGlobalVariables(): - - def _getOldEnvVar(itemName, envVar): - value = os.environ.get(envVar, GC_Defaults[itemName]) - if GC_VAR_INFO[itemName][GC_VAR_TYPE_KEY] == GC_TYPE_INTEGER: - try: - number = int(value) - minVal, maxVal = GC_VAR_INFO[itemName][GC_VAR_LIMITS_KEY] - if number < minVal: - number = minVal - elif maxVal and (number > maxVal): - number = maxVal - except ValueError: - number = GC_Defaults[itemName] - value = number - GC_Defaults[itemName] = value - - def _getOldSignalFile(itemName, fileName, trueValue=True, falseValue=False): - GC_Defaults[itemName] = trueValue if os.path.isfile(os.path.join(GC_Defaults[GC_CONFIG_DIR], fileName)) else falseValue - - def _getCfgDirectory(itemName): - return GC_Defaults[itemName] - - def _getCfgFile(itemName): - value = os.path.expanduser(GC_Defaults[itemName]) - if not os.path.isabs(value): - value = os.path.expanduser(os.path.join(GC_Values[GC_CONFIG_DIR], value)) - return value - - GC_Defaults[GC_CONFIG_DIR] = GM_Globals[GM_GAM_PATH] - GC_Defaults[GC_CACHE_DIR] = os.path.join(GM_Globals[GM_GAM_PATH], u'gamcache') - GC_Defaults[GC_DRIVE_DIR] = GM_Globals[GM_GAM_PATH] - GC_Defaults[GC_SITE_DIR] = GM_Globals[GM_GAM_PATH] - - _getOldEnvVar(GC_CONFIG_DIR, u'GAMUSERCONFIGDIR') - _getOldEnvVar(GC_SITE_DIR, u'GAMSITECONFIGDIR') - _getOldEnvVar(GC_CACHE_DIR, u'GAMCACHEDIR') - _getOldEnvVar(GC_DRIVE_DIR, u'GAMDRIVEDIR') - _getOldEnvVar(GC_OAUTH2_TXT, u'OAUTHFILE') - _getOldEnvVar(GC_OAUTH2SERVICE_JSON, u'OAUTHSERVICEFILE') - if GC_Defaults[GC_OAUTH2SERVICE_JSON].find(u'.') == -1: - GC_Defaults[GC_OAUTH2SERVICE_JSON] += u'.json' - _getOldEnvVar(GC_CLIENT_SECRETS_JSON, u'CLIENTSECRETS') - _getOldEnvVar(GC_DOMAIN, u'GA_DOMAIN') - _getOldEnvVar(GC_CUSTOMER_ID, u'CUSTOMER_ID') - _getOldEnvVar(GC_CHARSET, u'GAM_CHARSET') - _getOldEnvVar(GC_NUM_THREADS, u'GAM_THREADS') - _getOldEnvVar(GC_AUTO_BATCH_MIN, u'GAM_AUTOBATCH') - _getOldEnvVar(GC_ACTIVITY_MAX_RESULTS, u'GAM_ACTIVITY_MAX_RESULTS') - _getOldEnvVar(GC_DEVICE_MAX_RESULTS, u'GAM_DEVICE_MAX_RESULTS') - _getOldEnvVar(GC_DRIVE_MAX_RESULTS, u'GAM_DRIVE_MAX_RESULTS') - _getOldEnvVar(GC_USER_MAX_RESULTS, u'GAM_USER_MAX_RESULTS') - _getOldSignalFile(GC_DEBUG_LEVEL, u'debug.gam', trueValue=4, falseValue=0) - _getOldSignalFile(GC_NO_VERIFY_SSL, u'noverifyssl.txt') - _getOldSignalFile(GC_NO_BROWSER, u'nobrowser.txt') - _getOldSignalFile(GC_NO_CACHE, u'nocache.txt') - _getOldSignalFile(GC_NO_UPDATE_CHECK, u'noupdatecheck.txt') -# Assign directories first - for itemName in GC_VAR_INFO: - if GC_VAR_INFO[itemName][GC_VAR_TYPE_KEY] == GC_TYPE_DIRECTORY: - GC_Values[itemName] = _getCfgDirectory(itemName) - for itemName in GC_VAR_INFO: - varType = GC_VAR_INFO[itemName][GC_VAR_TYPE_KEY] - if varType == GC_TYPE_FILE: - GC_Values[itemName] = _getCfgFile(itemName) - else: - GC_Values[itemName] = GC_Defaults[itemName] - GM_Globals[GM_LAST_UPDATE_CHECK_TXT] = os.path.join(GC_Values[GC_CONFIG_DIR], FN_LAST_UPDATE_CHECK_TXT) - if not GC_Values[GC_NO_UPDATE_CHECK]: + global gamPath, gamSiteConfigDir, gamUserConfigDir, gamDriveDir, gamCacheDir + 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) + if not os.path.isfile(os.path.join(gamUserConfigDir, u'noupdatecheck.txt')): doGAMCheckForUpdates() -# Globals derived from config file values - GM_Globals[GM_OAUTH2SERVICE_KEY] = None - GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_EMAIL] = None - GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID] = None - GM_Globals[GM_EXTRA_ARGS_DICT] = {u'prettyPrint': GC_Values[GC_DEBUG_LEVEL] > 0} - httplib2.debuglevel = GC_Values[GC_DEBUG_LEVEL] - if os.path.isfile(os.path.join(GC_Values[GC_CONFIG_DIR], FN_EXTRA_ARGS_TXT)): + if os.path.isfile(os.path.join(gamUserConfigDir, u'debug.gam')): + httplib2.debuglevel = 4 + extra_args[u'prettyPrint'] = True + if os.path.isfile(os.path.join(gamUserConfigDir, FN_EXTRA_ARGS_TXT)): import ConfigParser - ea_config = ConfigParser.ConfigParser() - ea_config.optionxform = str - ea_config.read(os.path.join(GC_Values[GC_CONFIG_DIR], FN_EXTRA_ARGS_TXT)) - GM_Globals[GM_EXTRA_ARGS_DICT].update(dict(ea_config.items(u'extra-args'))) - if GC_Values[GC_NO_CACHE]: - GC_Values[GC_CACHE_DIR] = None - return True + config = ConfigParser.ConfigParser() + config.optionxform = str + config.read(os.path.join(gamUserConfigDir, FN_EXTRA_ARGS_TXT)) + extra_args.update(dict(config.items(u'extra-args'))) def doGAMCheckForUpdates(forceCheck=False): import urllib2 @@ -516,7 +287,7 @@ def doGAMCheckForUpdates(forceCheck=False): return now_time = calendar.timegm(time.gmtime()) if not forceCheck: - last_check_time = readFile(GM_Globals[GM_LAST_UPDATE_CHECK_TXT], continueOnError=True, displayError=forceCheck) + last_check_time = readFile(os.path.join(gamUserConfigDir, FN_LAST_UPDATE_CHECK_TXT), continueOnError=True, displayError=forceCheck) if last_check_time == None: last_check_time = 0 if last_check_time > now_time-604800: @@ -530,7 +301,7 @@ def doGAMCheckForUpdates(forceCheck=False): if forceCheck or (latest_version > current_version): print u'Version: Check, Current: {0:.2f}, Latest: {1:.2f}'.format(current_version, latest_version) if latest_version <= current_version: - writeFile(GM_Globals[GM_LAST_UPDATE_CHECK_TXT], str(now_time), continueOnError=True, displayError=forceCheck) + writeFile(os.path.join(gamUserConfigDir, FN_LAST_UPDATE_CHECK_TXT), str(now_time), continueOnError=True, displayError=forceCheck) return a = urllib2.urlopen(GAM_APPSPOT_LATEST_VERSION_ANNOUNCEMENT) announcement = a.read() @@ -543,7 +314,7 @@ def doGAMCheckForUpdates(forceCheck=False): webbrowser.open(GAM_RELEASES) printLine(MESSAGE_GAM_EXITING_FOR_UPDATE) sys.exit(0) - writeFile(GM_Globals[GM_LAST_UPDATE_CHECK_TXT], str(now_time), continueOnError=True, displayError=forceCheck) + writeFile(os.path.join(gamUserConfigDir, FN_LAST_UPDATE_CHECK_TXT), str(now_time), continueOnError=True, displayError=forceCheck) return except (urllib2.HTTPError, urllib2.URLError): return @@ -556,22 +327,22 @@ def doGAMVersion(): struct.calcsize('P')*8, sys.version_info[3], googleapiclient.__version__, platform.platform(), platform.machine(), - GM_Globals[GM_GAM_PATH]) + gamPath) def tryOAuth(gdataObject): - storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) + global domain + global customerId + storage = oauth2client.file.Storage(os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', FN_OAUTH2_TXT))) credentials = storage.get() if credentials is None or credentials.invalid: doRequestOAuth() credentials = storage.get() if credentials.access_token_expired: - credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL])) + credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt')))) gdataObject.additional_headers = {u'Authorization': u'Bearer %s' % credentials.access_token} - if not GC_Values[GC_DOMAIN]: - GC_Values[GC_DOMAIN] = credentials.id_token.get(u'hd', UNKNOWN).lower() - if not GC_Values[GC_CUSTOMER_ID]: - GC_Values[GC_CUSTOMER_ID] = MY_CUSTOMER - gdataObject.domain = GC_Values[GC_DOMAIN] + 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 def checkGDataError(e, service): @@ -656,7 +427,7 @@ def callGData(service, function, soft_errors=False, throw_errors=[], **kwargs): def callGAPI(service, function, silent_errors=False, soft_errors=False, throw_reasons=[], retry_reasons=[], **kwargs): method = getattr(service, function) retries = 10 - parameters = dict(kwargs.items() + GM_Globals[GM_EXTRA_ARGS_DICT].items()) + parameters = dict(kwargs.items() + extra_args.items()) for n in range(1, retries+1): try: return method(**parameters).execute() @@ -665,7 +436,7 @@ def callGAPI(service, function, silent_errors=False, soft_errors=False, throw_re error = json.loads(e.content) except ValueError: if n < 3: - service._http.request.credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL])) + service._http.request.credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt')))) continue if (e.resp[u'status'] == u'503') and (e.content == u'Quota exceeded for the current request'): time.sleep(1) @@ -784,7 +555,7 @@ def getAPIScope(api): def getServiceFromDiscoveryDocument(api, version, http): disc_filename = u'%s-%s.json' % (api, version) - disc_file = os.path.join(GC_Values[GC_SITE_DIR], disc_filename) + disc_file = os.path.join(gamSiteConfigDir, disc_filename) if hasattr(sys, '_MEIPASS'): pyinstaller_disc_file = os.path.join(sys._MEIPASS, disc_filename) else: @@ -798,13 +569,14 @@ def getServiceFromDiscoveryDocument(api, version, http): return googleapiclient.discovery.build_from_document(discovery, base=u'https://www.googleapis.com', http=http) def buildGAPIObject(api): - storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) + global domain, customerId + storage = oauth2client.file.Storage(os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', FN_OAUTH2_TXT))) credentials = storage.get() - if not credentials or credentials.invalid: + if credentials is None or credentials.invalid: doRequestOAuth() credentials = storage.get() credentials.user_agent = GAM_INFO - http = credentials.authorize(httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL], cache=GC_Values[GC_CACHE_DIR])) + http = credentials.authorize(httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt')), cache=gamCacheDir)) version = getAPIVer(api) if api in [u'directory', u'reports', u'datatransfer']: api = u'admin' @@ -816,58 +588,44 @@ def buildGAPIObject(api): systemErrorExit(4, e) except httplib2.CertificateValidationUnsupported: noPythonSSLExit() - if GC_Values[GC_DOMAIN]: - if not GC_Values[GC_CUSTOMER_ID]: - resp, result = service._http.request(u'https://www.googleapis.com/admin/directory/v1/users?domain={0}&maxResults=1&fields=users(customerId)'.format(GC_Values[GC_DOMAIN])) - try: - resultObj = json.loads(result) - except ValueError: - systemErrorExit(8, u'Unexpected response: {0}'.format(result)) - if resp[u'status'] in [u'403', u'404']: - try: - message = resultObj[u'error'][u'errors'][0][u'message'] - except KeyError: - message = resultObj[u'error'][u'message'] - systemErrorExit(8, u'{0} - {1}'.format(message, GC_Values[GC_DOMAIN])) - try: - GC_Values[GC_CUSTOMER_ID] = resultObj[u'users'][0][u'customerId'] - except KeyError: - GC_Values[GC_CUSTOMER_ID] = MY_CUSTOMER - else: - GC_Values[GC_DOMAIN] = credentials.id_token.get(u'hd', UNKNOWN).lower() - if not GC_Values[GC_CUSTOMER_ID]: - GC_Values[GC_CUSTOMER_ID] = MY_CUSTOMER + try: + domain = os.environ[u'GA_DOMAIN'] + _, customerId_result = service._http.request(u'https://www.googleapis.com/admin/directory/v1/users?domain=%s&maxResults=1&fields=users(customerId)' % domain) + customerId_obj = json.loads(customerId_result) + customerId = customerId_obj[u'users'][0][u'customerId'] + except KeyError: + try: + domain = credentials.id_token[u'hd'] + except (TypeError, KeyError): + domain = UNKNOWN_DOMAIN + customerId = MY_CUSTOMER return service -def buildGAPIServiceObject(api, act_as, soft_errors=False): - if not GM_Globals[GM_OAUTH2SERVICE_KEY]: - json_string = readFile(GC_Values[GC_OAUTH2SERVICE_JSON], continueOnError=True, displayError=True) - if not json_string: - printLine(MESSAGE_WIKI_INSTRUCTIONS_OAUTH2SERVICE_JSON) - printLine(GAM_WIKI_CREATE_CLIENT_SECRETS) - systemErrorExit(6, None) - json_data = json.loads(json_string) - try: - # new format with config and key in the .json file... - GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_EMAIL] = json_data[u'client_email'] - GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID] = json_data[u'client_id'] - GM_Globals[GM_OAUTH2SERVICE_KEY] = json_data[u'private_key'] - except KeyError: - try: - # old format with config in the .json file and key in the .p12 file... - GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_EMAIL] = json_data[u'web'][u'client_email'] - GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID] = json_data[u'web'][u'client_id'] - GM_Globals[GM_OAUTH2SERVICE_KEY] = readFile(GC_Values[GC_OAUTH2SERVICE_JSON].replace(u'.json', u'.p12')) - except KeyError: - printLine(MESSAGE_WIKI_INSTRUCTIONS_OAUTH2SERVICE_JSON) - printLine(GAM_WIKI_CREATE_CLIENT_SECRETS) - systemErrorExit(17, MESSAGE_OAUTH2SERVICE_JSON_INVALID.format(GC_Values[GC_OAUTH2SERVICE_JSON])) +def buildGAPIServiceObject(api, act_as=None, soft_errors=False): + oauth2servicefile = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHSERVICEFILE', 'oauth2service')) + oauth2servicefilejson = u'%s.json' % oauth2servicefile + oauth2servicefilep12 = u'%s.p12' % oauth2servicefile + json_string = readFile(oauth2servicefilejson, continueOnError=True, displayError=True) + if not json_string: + printLine(MESSAGE_WIKI_INSTRUCTIONS_OAUTH2SERVICE_JSON) + printLine(GAM_WIKI_CREATE_CLIENT_SECRETS) + sys.exit(6) + json_data = json.loads(json_string) + try: + SERVICE_ACCOUNT_EMAIL = json_data[u'web'][u'client_email'] + SERVICE_ACCOUNT_CLIENT_ID = json_data[u'web'][u'client_id'] + key = readFile(oauth2servicefilep12) + except KeyError: + # new format with config and data in the .json file... + SERVICE_ACCOUNT_EMAIL = json_data[u'client_email'] + SERVICE_ACCOUNT_CLIENT_ID = json_data[u'client_id'] + key = json_data[u'private_key'] scope = getAPIScope(api) - credentials = oauth2client.client.SignedJwtAssertionCredentials(GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_EMAIL], - GM_Globals[GM_OAUTH2SERVICE_KEY], - scope=scope, user_agent=GAM_INFO, sub=act_as) - http = credentials.authorize(httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL], - cache=GC_Values[GC_CACHE_DIR])) + if act_as == None: + credentials = oauth2client.client.SignedJwtAssertionCredentials(SERVICE_ACCOUNT_EMAIL, key, scope=scope, user_agent=GAM_INFO) + else: + credentials = oauth2client.client.SignedJwtAssertionCredentials(SERVICE_ACCOUNT_EMAIL, key, scope=scope, user_agent=GAM_INFO, sub=act_as) + http = credentials.authorize(httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt')), cache=gamCacheDir)) version = getAPIVer(api) try: return googleapiclient.discovery.build(api, version, http=http) @@ -877,7 +635,7 @@ def buildGAPIServiceObject(api, act_as, soft_errors=False): systemErrorExit(4, e) except oauth2client.client.AccessTokenRefreshError, e: if e.message in [u'access_denied', u'unauthorized_client: Unauthorized client or scope in request.']: - systemErrorExit(5, MESSAGE_CLIENT_API_ACCESS_DENIED.format(GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID], u','.join(scope))) + systemErrorExit(5, MESSAGE_CLIENT_API_ACCESS_DENIED.format(SERVICE_ACCOUNT_CLIENT_ID, u','.join(scope))) sys.stderr.write(u'{0}{1}\n'.format(ERROR_PREFIX, e)) if soft_errors: return False @@ -889,7 +647,7 @@ def buildDiscoveryObject(api): if api in [u'directory', u'reports']: api = u'admin' params = {'api': api, 'apiVersion': version} - http = httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL], cache=GC_Values[GC_CACHE_DIR]) + http = httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt')), cache=gamCacheDir) requested_url = uritemplate.expand(googleapiclient.discovery.DISCOVERY_URI, params) resp, content = http.request(requested_url) if resp.status == 404: @@ -909,7 +667,7 @@ def commonAppsObjInit(appsObj): #Identify GAM to Google's Servers appsObj.source = GAM_INFO #Show debugging output if debug.gam exists - if GC_Values[GC_DEBUG_LEVEL] > 0: + if os.path.isfile(os.path.join(gamUserConfigDir, u'debug.gam')): appsObj.debug = True return appsObj @@ -951,9 +709,9 @@ def geturl(url, dst): closeFile(f) def showReport(): - rep = buildGAPIObject(u'reports') report = sys.argv[2].lower() - customerId = GC_Values[GC_CUSTOMER_ID] + global customerId + rep = buildGAPIObject(u'reports') if customerId == MY_CUSTOMER: customerId = None date = filters = parameters = actorIpAddress = startTime = endTime = eventName = None @@ -1118,7 +876,7 @@ def doDelegates(users): if sys.argv[4].lower() == u'to': delegate = sys.argv[5].lower() if not delegate.find(u'@') > 0: - delegate_domain = GC_Values[GC_DOMAIN].lower() + delegate_domain = domain.lower() delegate_email = u'%s@%s' % (delegate, delegate_domain) else: delegate_domain = delegate[delegate.find(u'@')+1:].lower() @@ -1134,7 +892,7 @@ def doDelegates(users): delegator_email = delegator delegator = delegator[:delegator.find('@')] else: - delegator_domain = GC_Values[GC_DOMAIN].lower() + delegator_domain = domain.lower() delegator_email = u'%s@%s' % (delegator, delegator_domain) emailsettings.domain = delegator_domain print u"Giving %s delegate access to %s (%s of %s)" % (delegate_email, delegator_email, i, count) @@ -1236,7 +994,7 @@ def getDelegates(users): emailsettings.domain = user[user.find('@')+1:] user = user[:user.find('@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] + emailsettings.domain = domain sys.stderr.write(u"Getting delegates for %s...\n" % (user + '@' + emailsettings.domain)) delegates = callGData(service=emailsettings, function=u'GetDelegates', soft_errors=True, delegator=user) try: @@ -1255,7 +1013,7 @@ def deleteDelegate(users): if users[0].find(u'@') > 0: delegatedomain = users[0][users[0].find(u'@')+1:] else: - delegatedomain = GC_Values[GC_DOMAIN] + delegatedomain = domain delegate = delegate+u'@'+delegatedomain count = len(users) i = 1 @@ -1264,7 +1022,7 @@ def deleteDelegate(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain + emailsettings.domain = domain #make sure it's back at default domain print u"Deleting %s delegate access to %s (%s of %s)" % (delegate, user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'DeleteDelegate', delegate=delegate, delegator=user) @@ -1399,7 +1157,7 @@ def doCreateDomain(): cd = buildGAPIObject(u'directory') domain_name = sys.argv[3] body = {u'domainName': domain_name} - callGAPI(service=cd.domains(), function=u'insert', customer=GC_Values[GC_CUSTOMER_ID], body=body) + callGAPI(service=cd.domains(), function=u'insert', customer=customerId, body=body) print u'Added domain %s' % domain_name def doCreateDomainAlias(): @@ -1407,7 +1165,7 @@ def doCreateDomainAlias(): body = {} body[u'domainAliasName'] = sys.argv[3] body[u'parentDomainName'] = sys.argv[4] - callGAPI(service=cd.domainAliases(), function=u'insert', customer=GC_Values[GC_CUSTOMER_ID], body=body) + callGAPI(service=cd.domainAliases(), function=u'insert', customer=customerId, body=body) def doUpdateDomain(): cd = buildGAPIObject(u'directory') @@ -1421,16 +1179,16 @@ def doUpdateDomain(): else: print u'ERROR: %s is not a valid argument for "gam update domain"' % sys.argv[i] sys.exit(2) - callGAPI(service=cd.customers(), function=u'update', customerKey=GC_Values[GC_CUSTOMER_ID], body=body) + callGAPI(service=cd.customers(), function=u'update', customerKey=customerId, body=body) print u'%s is now the primary domain.' % domain_name def doGetDomainInfo(): if (len(sys.argv) < 4) or (sys.argv[3] == u'logo'): doGetInstanceInfo() return - cd = buildGAPIObject(u'directory') domainName = sys.argv[3] - result = callGAPI(service=cd.domains(), function=u'get', customer=GC_Values[GC_CUSTOMER_ID], domainName=domainName) + cd = buildGAPIObject(u'directory') + result = callGAPI(service=cd.domains(), function=u'get', customer=customerId, domainName=domainName) if u'creationTime' in result: result[u'creationTime'] = unicode(datetime.datetime.fromtimestamp(int(result[u'creationTime'])/1000)) if u'domainAliases' in result: @@ -1440,16 +1198,16 @@ def doGetDomainInfo(): print_json(None, result) def doGetDomainAliasInfo(): - cd = buildGAPIObject(u'directory') alias = sys.argv[3] - result = callGAPI(service=cd.domainAliases(), function=u'get', customer=GC_Values[GC_CUSTOMER_ID], domainAliasName=alias) + cd = buildGAPIObject(u'directory') + result = callGAPI(service=cd.domainAliases(), function=u'get', customer=customerId, domainAliasName=alias) if u'creationTime' in result: result[u'creationTime'] = unicode(datetime.datetime.fromtimestamp(int(result[u'creationTime'])/1000)) print_json(None, result) def doGetCustomerInfo(): cd = buildGAPIObject(u'directory') - customer_info = callGAPI(service=cd.customers(), function=u'get', customerKey=GC_Values[GC_CUSTOMER_ID]) + customer_info = callGAPI(service=cd.customers(), function=u'get', customerKey=customerId) print_json(None, customer_info) def doUpdateCustomer(): @@ -1489,25 +1247,25 @@ def doUpdateCustomer(): else: print u'ERROR: %s is not a valid argument for "gam update customer"' % myarg sys.exit(2) - callGAPI(service=cd.customers(), function=u'update', customerKey=GC_Values[GC_CUSTOMER_ID], body=body) + callGAPI(service=cd.customers(), function=u'update', customerKey=customerId, body=body) print u'Updated customer' def doDelDomain(): - cd = buildGAPIObject(u'directory') domainName = sys.argv[3] - callGAPI(service=cd.domains(), function=u'delete', customer=GC_Values[GC_CUSTOMER_ID], domainName=domainName) + cd = buildGAPIObject(u'directory') + callGAPI(service=cd.domains(), function=u'delete', customer=customerId, domainName=domainName) def doDelDomainAlias(): - cd = buildGAPIObject(u'directory') domainAliasName = sys.argv[3] - callGAPI(service=cd.domainAliases(), function=u'delete', customer=GC_Values[GC_CUSTOMER_ID], domainAliasName=domainAliasName) + cd = buildGAPIObject(u'directory') + callGAPI(service=cd.domainAliases(), function=u'delete', customer=customerId, domainAliasName=domainAliasName) def doPrintDomains(): - cd = buildGAPIObject(u'directory') titles = [] domains_attributes = [{}] todrive = False - domains = callGAPI(service=cd.domains(), function=u'list', customer=GC_Values[GC_CUSTOMER_ID]) + cd = buildGAPIObject(u'directory') + domains = callGAPI(service=cd.domains(), function=u'list', customer=customerId) i = 3 while i < len(sys.argv): if sys.argv[i].lower() == u'todrive': @@ -1555,7 +1313,7 @@ def doDelAdmin(): roleAssignmentId = sys.argv[3] print u'Deleting Admin Role Assignment %s' % roleAssignmentId callGAPI(service=cd.roleAssignments(), function=u'delete', - customer=GC_Values[GC_CUSTOMER_ID], roleAssignmentId=roleAssignmentId) + customer=customerId, roleAssignmentId=roleAssignmentId) def doCreateAdmin(): cd = buildGAPIObject(u'directory') @@ -1565,8 +1323,8 @@ def doCreateAdmin(): body[u'assignedTo'] = user[4:] else: print user[:3] - body[u'assignedTo'] = callGAPI(service=cd.users(), function=u'get', - userKey=user, projection=u'basic', fields=u'id')[u'id'] + body[u'assignedTo'] = callGAPI(service=cd.users(), function=u'get', userKey=user, + projection=u'basic', fields=u'id')[u'id'] role = sys.argv[4] if role[:4].lower() == u'uid:': body[u'roleId'] = role[4:] @@ -1587,15 +1345,15 @@ def doCreateAdmin(): if orgUnit[0] == u'/': orgUnit = orgUnit[1:] body[u'orgUnitId'] = callGAPI(service=cd.orgunits(), function=u'get', - customerId=GC_Values[GC_CUSTOMER_ID], orgUnitPath=orgUnit, - fields=u'orgUnitId')[u'orgUnitId'][3:] + customerId=customerId, orgUnitPath=orgUnit, + fields=u'orgUnitId')[u'orgUnitId'][3:] if body[u'scopeType'] == u'CUSTOMER': scope = u'customer' else: scope = orgUnit print u'Giving %s admin role %s for %s' % (user, role, scope) callGAPI(service=cd.roleAssignments(), function=u'insert', - customer=GC_Values[GC_CUSTOMER_ID], body=body) + customer=customerId, body=body) def doPrintAdmins(): cd = buildGAPIObject(u'directory') @@ -1617,7 +1375,7 @@ def doPrintAdmins(): sys.exit(5) i += 2 admins = callGAPIpages(service=cd.roleAssignments(), function=u'list', - customer=GC_Values[GC_CUSTOMER_ID], userKey=userKey, roleId=roleId, maxResults=200) + customer=customerId, maxResults=200, userKey=userKey, roleId=roleId) admins_attrib = [{}] for admin in admins: admin_attrib = {} @@ -1645,56 +1403,57 @@ def doPrintAdmins(): admins_attrib.append(admin_attrib) output_csv(admins_attrib, admins_attrib[0], u'Admins', False) -def buildOrgUnitIdToNameMap(): - cd = buildGAPIObject(u'directory') - result = callGAPI(service=cd.orgunits(), function=u'list', - customerId=GC_Values[GC_CUSTOMER_ID], - fields=u'organizationUnits(orgUnitPath,orgUnitId)') - GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME] = {} - for orgUnit in result[u'organizationUnits']: - GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME][orgUnit[u'orgUnitId']] = orgUnit[u'orgUnitPath'] - def orgunit_from_orgunitid(orgunitid): - if not GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME]: - buildOrgUnitIdToNameMap() - return GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME][u'id:%s' % orgunitid] - -def buildRoleIdToNameToIdMap(): - cd = buildGAPIObject(u'directory') - result = callGAPIpages(service=cd.roles(), function=u'list', items=u'items', - customer=GC_Values[GC_CUSTOMER_ID], - fields=u'nextPageToken,items(roleId,roleName)', - maxResults=100) - GM_Globals[GM_MAP_ROLE_ID_TO_NAME] = {} - GM_Globals[GM_MAP_ROLE_NAME_TO_ID] = {} - for role in result: - GM_Globals[GM_MAP_ROLE_ID_TO_NAME][role[u'roleId']] = role[u'roleName'] - GM_Globals[GM_MAP_ROLE_NAME_TO_ID][role[u'roleName']] = role[u'roleId'] + global orgunit_mappings + try: + orgunit_mappings + except NameError: + cd = buildGAPIObject(u'directory') + orgunit_mappings = callGAPI(service=cd.orgunits(), function=u'list', + customerId=customerId, + fields=u'organizationUnits(orgUnitPath,orgUnitId)') + for orgunit_mapping in orgunit_mappings[u'organizationUnits']: + if orgunit_mapping[u'orgUnitId'] == u'id:%s' % orgunitid: + return orgunit_mapping[u'orgUnitPath'] def role_from_roleid(roleid): - if not GM_Globals[GM_MAP_ROLE_ID_TO_NAME]: - buildRoleIdToNameToIdMap() - return GM_Globals[GM_MAP_ROLE_ID_TO_NAME][roleid] + global roleid_mappings + try: + roleid_mappings + except NameError: + cd = buildGAPIObject(u'directory') + roleid_mappings = callGAPIpages(service=cd.roles(), function=u'list', + items=u'items', customer=customerId, maxResults=100, + fields=u'nextPageToken,items(roleId,roleName)') + for roleid_mapping in roleid_mappings: + if roleid_mapping[u'roleId'] == roleid: + return roleid_mapping[u'roleName'] def roleid_from_role(role): - if not GM_Globals[GM_MAP_ROLE_NAME_TO_ID]: - buildRoleIdToNameToIdMap() - return GM_Globals[GM_MAP_ROLE_NAME_TO_ID][role] - -def buildUserIdToNameMap(): - cd = buildGAPIObject(u'directory') - result = callGAPIpages(service=cd.users(), function=u'list', items=u'users', - customer=GC_Values[GC_CUSTOMER_ID], - fields=u'nextPageToken,users(id,primaryEmail)', - maxResults=GC_Values[GC_USER_MAX_RESULTS]) - GM_Globals[GM_MAP_USER_ID_TO_NAME] = {} - for user in result: - GM_Globals[GM_MAP_USER_ID_TO_NAME][user[u'id']] = user[u'primaryEmail'] + global roleid_mappings + try: + roleid_mappings + except NameError: + cd = buildGAPIObject(u'directory') + roleid_mappings = callGAPIpages(service=cd.roles(), function=u'list', + items=u'items', customer=customerId, maxResults=100, + fields=u'nextPageToken,items(roleId,roleName)') + for roleid_mapping in roleid_mappings: + if roleid_mapping[u'roleName'] == role: + return roleid_mapping[u'roleId'] def user_from_userid(userid): - if not GM_Globals[GM_MAP_USER_ID_TO_NAME]: - buildUserIdToNameMap() - return GM_Globals[GM_MAP_USER_ID_TO_NAME][userid] + global userid_mappings + try: + userid_mappings + except NameError: + cd = buildGAPIObject(u'directory') + userid_mappings = callGAPIpages(service=cd.users(), function=u'list', + items=u'users', customer=customerId, maxResults=500, + fields=u'nextPageToken,users(id,primaryEmail)') + for user in userid_mappings: + if user[u'id'] == userid: + return user[u'primaryEmail'] SERVICE_NAME_TO_ID_MAP = { u'Drive': u'55656082996', @@ -1705,7 +1464,7 @@ def appID2app(dt, appID): for serviceName, serviceID in SERVICE_NAME_TO_ID_MAP.items(): if appID == serviceID: return serviceName - online_services = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=GC_Values[GC_CUSTOMER_ID]) + online_services = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=customerId) for online_service in online_services: if appID == online_service[u'id']: return online_service[u'name'] @@ -1724,7 +1483,7 @@ def app2appID(dt, app): serviceName = app.lower() if serviceName in SERVICE_NAME_CHOICES_MAP: return (SERVICE_NAME_CHOICES_MAP[serviceName], SERVICE_NAME_TO_ID_MAP[SERVICE_NAME_CHOICES_MAP[serviceName]]) - online_services = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=GC_Values[GC_CUSTOMER_ID]) + online_services = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=customerId) for online_service in online_services: if serviceName == online_service[u'name'].lower(): return online_service[u'id'] @@ -1734,9 +1493,9 @@ def app2appID(dt, app): def convertToUserID(user): if user[:4].lower() == u'uid:': return user[4:] - cd = buildGAPIObject(u'directory') if user.find(u'@') == -1: - user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) + user = u'%s@%s' % (user, domain) + cd = buildGAPIObject(u'directory') try: return callGAPI(service=cd.users(), function=u'get', throw_reasons=[u'notFound'], userKey=user, fields=u'id')[u'id'] except googleapiclient.errors.HttpError: @@ -1774,7 +1533,7 @@ def doCreateDataTranfer(): def doPrintTransferApps(): dt = buildGAPIObject(u'datatransfer') - apps = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=GC_Values[GC_CUSTOMER_ID]) + apps = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=customerId) for app in apps: print_json(None, app) print @@ -1804,7 +1563,7 @@ def doPrintDataTransfers(): sys.exit(2) transfers_attributes = [{}] transfers = callGAPIpages(service=dt.transfers(), function=u'list', - items=u'dataTransfers', customerId=GC_Values[GC_CUSTOMER_ID], status=status, + items=u'dataTransfers', customerId=customerId, status=status, newOwnerUserId=newOwnerUserId, oldOwnerUserId=oldOwnerUserId) for transfer in transfers: for i in range(0, len(transfer[u'applicationDataTransfers'])): @@ -1886,10 +1645,10 @@ def doCreateCourse(): print u'Created course %s' % result[u'id'] def doGetCourseInfo(): - croom = buildGAPIObject(u'classroom') courseId = sys.argv[3] if not courseId.isdigit(): courseId = u'd:%s' % courseId + croom = buildGAPIObject(u'classroom') info = callGAPI(service=croom.courses(), function=u'get', id=courseId) print_json(None, info) teachers = callGAPIpages(service=croom.courses().teachers(), function=u'list', items=u'teachers', courseId=courseId) @@ -2211,7 +1970,7 @@ def changeCalendarAttendees(users): for user in users: sys.stdout.write(u'Checking user %s\n' % user) if user.find(u'@') == -1: - user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) + user = u'%s@%s' % (user, domain) cal = buildGAPIServiceObject(u'calendar', user) page_token = None while True: @@ -2265,10 +2024,10 @@ def deleteCalendar(users): cal = buildGAPIServiceObject(u'calendar', users[0]) calendarId = sys.argv[5] if calendarId.find(u'@') == -1: - calendarId = u'%s@%s' % (calendarId, GC_Values[GC_DOMAIN]) + calendarId = u'%s@%s' % (calendarId, domain) for user in users: if user.find(u'@') == -1: - user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) + user = u'%s@%s' % (user, domain) cal = buildGAPIServiceObject(u'calendar', user) callGAPI(service=cal.calendarList(), function=u'delete', calendarId=calendarId) @@ -2278,7 +2037,7 @@ def addCalendar(users): body[u'defaultReminders'] = list() body[u'id'] = sys.argv[5] if body[u'id'].find(u'@') == -1: - body[u'id'] = u'%s@%s' % (body[u'id'], GC_Values[GC_DOMAIN]) + body[u'id'] = u'%s@%s' % (body[u'id'], domain) body[u'selected'] = True body[u'hidden'] = False colorRgbFormat = False @@ -2335,7 +2094,7 @@ def addCalendar(users): count = len(users) for user in users: if user.find(u'@') == -1: - user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) + user = u'%s@%s' % (user, domain) print u"Subscribing %s to %s calendar (%s of %s)" % (user, body['id'], i, count) cal = buildGAPIServiceObject(u'calendar', user) callGAPI(service=cal.calendarList(), function=u'insert', body=body, colorRgbFormat=colorRgbFormat) @@ -2406,8 +2165,8 @@ def updateCalendar(users): callGAPI(service=cal.calendarList(), function=u'update', calendarId=calendarId, body=body, colorRgbFormat=colorRgbFormat) def doPrinterShowACL(): - cp = buildGAPIObject(u'cloudprint') show_printer = sys.argv[2] + cp = buildGAPIObject(u'cloudprint') printer_info = callGAPI(service=cp.printers(), function=u'get', printerid=show_printer) checkCloudPrintResult(printer_info) for acl in printer_info[u'printers'][0][u'access']: @@ -2417,7 +2176,6 @@ def doPrinterShowACL(): print def doPrinterAddACL(): - cp = buildGAPIObject(u'cloudprint') printer = sys.argv[2] role = sys.argv[4].upper() scope = sys.argv[5] @@ -2430,6 +2188,7 @@ def doPrinterAddACL(): skip_notification = None elif scope.find(u'@') == -1: scope = u'/hd/domain/%s' % scope + cp = buildGAPIObject(u'cloudprint') result = callGAPI(service=cp.printers(), function=u'share', printerid=printer, role=role, scope=scope, public=public, skip_notification=skip_notification) checkCloudPrintResult(result) who = scope @@ -2439,7 +2198,6 @@ def doPrinterAddACL(): print u'Added %s %s' % (role, who) def doPrinterDelACL(): - cp = buildGAPIObject(u'cloudprint') printer = sys.argv[2] scope = sys.argv[4] public = None @@ -2448,6 +2206,7 @@ def doPrinterDelACL(): scope = None elif scope.find(u'@') == -1: scope = u'/hd/domain/%s' % scope + cp = buildGAPIObject(u'cloudprint') result = callGAPI(service=cp.printers(), function=u'unshare', printerid=printer, scope=scope, public=public) checkCloudPrintResult(result) who = scope @@ -2679,9 +2438,9 @@ def doPrinterRegister(): print u'Created printer %s' % result[u'printers'][0][u'id'] def doPrintJobResubmit(): - cp = buildGAPIObject(u'cloudprint') jobid = sys.argv[2] printerid = sys.argv[4] + cp = buildGAPIObject(u'cloudprint') ssd = '''{ "state": {"type": "HELD"} }''' @@ -2693,8 +2452,8 @@ def doPrintJobResubmit(): print u'Success resubmitting %s as job %s to printer %s' % (jobid, result[u'job'][u'id'], printerid) def doPrintJobSubmit(): - cp = buildGAPIObject(u'cloudprint') printer = sys.argv[2] + cp = buildGAPIObject(u'cloudprint') content = sys.argv[4] form_fields = {u'printerid': printer, u'title': content, @@ -2734,15 +2493,15 @@ def doPrintJobSubmit(): print u'Submitted print job %s' % result[u'job'][u'id'] def doDeletePrintJob(): - cp = buildGAPIObject(u'cloudprint') job = sys.argv[2] + cp = buildGAPIObject(u'cloudprint') result = callGAPI(service=cp.jobs(), function=u'delete', jobid=job) checkCloudPrintResult(result) print u'Print Job %s deleted' % job def doCancelPrintJob(): - cp = buildGAPIObject(u'cloudprint') job = sys.argv[2] + cp = buildGAPIObject(u'cloudprint') ssd = '{"state": {"type": "ABORTED", "user_action_cause": {"action_code": "CANCELLED"}}}' result = callGAPI(service=cp.jobs(), function=u'update', jobid=job, semantic_state_diff=ssd) checkCloudPrintResult(result) @@ -2760,10 +2519,10 @@ def checkCloudPrintResult(result): sys.exit(result[u'errorCode']) def doCalendarShowACL(): - cal = buildGAPIObject(u'calendar') show_cal = sys.argv[2] + cal = buildGAPIObject(u'calendar') if show_cal.find(u'@') == -1: - show_cal = u'%s@%s' % (show_cal, GC_Values[GC_DOMAIN]) + show_cal = u'%s@%s' % (show_cal, domain) acls = callGAPI(service=cal.acl(), function=u'list', calendarId=show_cal) try: for rule in acls[u'items']: @@ -2783,7 +2542,7 @@ def doCalendarAddACL(calendarId=None, act_as=None, role=None, scope=None, entity if calendarId == None: calendarId = sys.argv[2] if calendarId.find(u'@') == -1: - calendarId = u'%s@%s' % (calendarId, GC_Values[GC_DOMAIN]) + calendarId = u'%s@%s' % (calendarId, domain) if role != None: body[u'role'] = role else: @@ -2811,14 +2570,14 @@ def doCalendarAddACL(calendarId=None, act_as=None, role=None, scope=None, entity else: body[u'scope'][u'value'] = sys.argv[i].lower() if (body[u'scope'][u'type'] in [u'user', u'group']) and body[u'scope'][u'value'].find(u'@') == -1: - body[u'scope'][u'value'] = u'%s@%s' % (body[u'scope'][u'value'], GC_Values[GC_DOMAIN]) + body[u'scope'][u'value'] = u'%s@%s' % (body[u'scope'][u'value'], domain) except IndexError: pass if body[u'scope'][u'type'] == u'domain': try: body[u'scope'][u'value'] = sys.argv[6].lower() except IndexError: - body[u'scope'][u'value'] = GC_Values[GC_DOMAIN] + body[u'scope'][u'value'] = domain callGAPI(service=cal.acl(), function=u'insert', calendarId=calendarId, body=body) def doCalendarUpdateACL(): @@ -2846,7 +2605,7 @@ def doCalendarWipeData(): calendarId = sys.argv[2] cal = buildGAPIServiceObject(u'calendar', calendarId) if calendarId.find(u'@') == -1: - calendarId = u'%s@%s' % (calendarId, GC_Values[GC_DOMAIN]) + calendarId = u'%s@%s' % (calendarId, domain) callGAPI(service=cal.calendars(), function=u'clear', calendarId=calendarId) def doCalendarAddEvent(): @@ -2970,7 +2729,6 @@ def doCalendarAddEvent(): def doProfile(users): - cd = buildGAPIObject(u'directory') if sys.argv[4].lower() == u'share' or sys.argv[4].lower() == u'shared': body = {u'includeInGlobalAddressList': True} elif sys.argv[4].lower() == u'unshare' or sys.argv[4].lower() == u'unshared': @@ -2978,26 +2736,27 @@ def doProfile(users): else: print u'ERROR: value for "gam profile" must be true or false, got %s' % sys.argv[4] sys.exit(2) + cd = buildGAPIObject(u'directory') count = len(users) i = 1 for user in users: if user[:4].lower() == u'uid:': user = user[4:] elif user.find(u'@') == -1: - user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) + user = u'%s@%s' % (user, domain) print u'Setting Profile Sharing to %s for %s (%s of %s)' % (body[u'includeInGlobalAddressList'], user, i, count) callGAPI(service=cd.users(), function=u'patch', soft_errors=True, userKey=user, body=body) i += 1 def showProfile(users): - cd = buildGAPIObject(u'directory') i = 1 count = len(users) + cd = buildGAPIObject(u'directory') for user in users: if user[:4].lower() == u'uid:': user = user[4:] elif user.find(u'@') == -1: - user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) + user = u'%s@%s' % (user, domain) result = callGAPI(service=cd.users(), function=u'get', userKey=user, fields=u'includeInGlobalAddressList') try: print u'User: %s Profile Shared: %s (%s/%s)' % (user, result[u'includeInGlobalAddressList'], i, count) @@ -3013,7 +2772,7 @@ def doPhoto(users): if user[:4].lower() == u'uid:': user = user[4:] elif user.find('@') == -1: - user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) + user = u'%s@%s' % (user, domain) filename = sys.argv[5].replace(u'#user#', user) filename = filename.replace(u'#email#', user) filename = filename.replace(u'#username#', user[:user.find(u'@')]) @@ -3046,7 +2805,7 @@ def getPhoto(users): if user[:4].lower() == u'uid:': user = user[4:] elif user.find(u'@') == -1: - user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) + user = u'%s@%s' % (user, domain) filename = u'%s.jpg' % user print u"Saving photo to %s (%s/%s)" % (filename, i, count) i += 1 @@ -3072,7 +2831,7 @@ def deletePhoto(users): if user[:4].lower() == u'uid:': user = user[4:] elif user.find('@') == -1: - user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) + user = u'%s@%s' % (user, domain) print u"Deleting photo for %s (%s of %s)" % (user, i, count) callGAPI(service=cd.users().photos(), function='delete', userKey=user) i += 1 @@ -3185,7 +2944,7 @@ def doDriveActivity(users): feed = callGAPIpages(service=activity.activities(), function=u'list', items=u'activities', page_message=page_message, source=u'drive.google.com', userId=u'me', drive_ancestorId=drive_ancestorId, groupingStrategy=u'none', - drive_fileId=drive_fileId, pageSize=GC_Values[GC_ACTIVITY_MAX_RESULTS]) + drive_fileId=drive_fileId, pageSize=100) for item in feed: activity_attributes.append(flatten_json(item[u'combinedEvent'])) for an_item in activity_attributes[-1]: @@ -3397,7 +3156,7 @@ def showDriveFiles(users): page_message = u' got %%%%total_items%%%% files for %s...\n' % user feed = callGAPIpages(service=drive.files(), function=u'list', page_message=page_message, soft_errors=True, - q=query, fields=fields, maxResults=GC_Values[GC_DRIVE_MAX_RESULTS]) + q=query, fields=fields, maxResults=1000) for f_file in feed: a_file = {u'Owner': user} for attrib in f_file: @@ -3437,7 +3196,7 @@ def doDriveSearch(drive, query=None): page_message = u' got %%total_items%% files...\n' files = callGAPIpages(service=drive.files(), function=u'list', page_message=page_message, - q=query, fields=u'nextPageToken,items(id)', maxResults=GC_Values[GC_DRIVE_MAX_RESULTS]) + q=query, fields=u'nextPageToken,items(id)', maxResults=1000) ids = list() for f_file in files: ids.append(f_file[u'id']) @@ -3490,7 +3249,7 @@ def showDriveFileTree(users): sys.stderr.write(u'Getting all files for %s...\n' % user) page_message = u' got %%%%total_items%%%% files for %s...\n' % user feed = callGAPIpages(service=drive.files(), function=u'list', page_message=page_message, - fields=u'items(id,title,parents(id),mimeType),nextPageToken', maxResults=GC_Values[GC_DRIVE_MAX_RESULTS]) + fields=u'items(id,title,parents(id),mimeType),nextPageToken', maxResults=1000) printDriveFolderContents(feed, root_folder, 0) def deleteEmptyDriveFolders(users): @@ -3505,7 +3264,7 @@ def deleteEmptyDriveFolders(users): sys.stderr.write(u'Getting folders for %s...\n' % user) page_message = u' got %%%%total_items%%%% folders for %s...\n' % user feed = callGAPIpages(service=drive.files(), function=u'list', page_message=page_message, - q=query, fields=u'items(title,id),nextPageToken', maxResults=GC_Values[GC_DRIVE_MAX_RESULTS]) + q=query, fields=u'items(title,id),nextPageToken', maxResults=1000) deleted_empty = False for folder in feed: children = callGAPI(service=drive.children(), function=u'list', @@ -3783,7 +3542,7 @@ def downloadDriveFile(users): i = 5 query = fileIds = None gdownload_format = u'openoffice' - target_folder = GC_Values[GC_DRIVE_DIR] + target_folder = gamDriveDir safe_filename_chars = "-_.() %s%s" % (string.ascii_letters, string.digits) while i < len(sys.argv): if sys.argv[i].lower() == u'id': @@ -4039,7 +3798,7 @@ def doImap(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain + emailsettings.domain = domain #make sure it's back at default domain print u"Setting IMAP Access to %s for %s (%s of %s)" % (str(enable), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateImap', soft_errors=True, username=user, enable=enable) @@ -4053,7 +3812,7 @@ def getImap(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] + emailsettings.domain = domain imapsettings = callGData(service=emailsettings, function=u'GetImap', soft_errors=True, username=user) try: print u'User %s IMAP Enabled:%s (%s of %s)' % (user+u'@'+emailsettings.domain, imapsettings[u'enable'], i, count) @@ -4107,7 +3866,7 @@ def doLicense(users, operation): productId, skuId = getProductAndSKU(sku) for user in users: if user.find(u'@') == -1: - user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) + user = u'%s@%s' % (user, domain) if operation == u'delete': callGAPI(service=lic.licenseAssignments(), function=operation, soft_errors=True, productId=productId, skuId=skuId, userId=user) elif operation == u'insert': @@ -4171,7 +3930,7 @@ def doPop(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain + emailsettings.domain = domain #make sure it's back at default domain print u"Setting POP Access to %s for %s (%s of %s)" % (str(enable), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdatePop', soft_errors=True, username=user, enable=enable, enable_for=enable_for, action=action) @@ -4183,7 +3942,7 @@ def getPop(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] + emailsettings.domain = domain popsettings = callGData(service=emailsettings, function=u'GetPop', soft_errors=True, username=user) try: print u'User %s POP Enabled:%s Action:%s' % (user+u'@'+emailsettings.domain, popsettings[u'enable'], popsettings[u'action']) @@ -4207,7 +3966,7 @@ def doSendAs(users): sys.exit(2) emailsettings = getEmailSettingsObject() if sendas.find(u'@') < 0: - sendas = sendas+u'@'+GC_Values[GC_DOMAIN] + sendas = sendas+u'@'+domain count = len(users) i = 1 for user in users: @@ -4215,7 +3974,7 @@ def doSendAs(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain + emailsettings.domain = domain #make sure it's back at default domain print u"Allowing %s to send as %s (%s of %s)" % (user+u'@'+emailsettings.domain, sendas, i, count) i += 1 callGData(service=emailsettings, function=u'CreateSendAsAlias', soft_errors=True, username=user, name=sendasName, address=sendas, make_default=make_default, reply_to=reply_to) @@ -4227,7 +3986,7 @@ def showSendAs(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] + emailsettings.domain = domain print u'%s has the following send as aliases:' % (user+u'@'+emailsettings.domain) sendases = callGData(service=emailsettings, function=u'GetSendAsAlias', soft_errors=True, username=user) try: @@ -4259,7 +4018,7 @@ def doLanguage(users): emailsettings.domain = user[user.find('@')+1:] user = user[:user.find('@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain + emailsettings.domain = domain #make sure it's back at default domain print u"Setting the language for %s to %s (%s of %s)" % (user+u'@'+emailsettings.domain, language, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateLanguage', soft_errors=True, username=user, language=language) @@ -4280,7 +4039,7 @@ def doUTF(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain + emailsettings.domain = domain #make sure it's back at default domain print u"Setting UTF-8 to %s for %s (%s of %s)" % (str(SetUTF), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateGeneral', soft_errors=True, username=user, unicode=SetUTF) @@ -4299,7 +4058,7 @@ def doPageSize(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain + emailsettings.domain = domain #make sure it's back at default domain print u"Setting Page Size to %s for %s (%s of %s)" % (PageSize, user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateGeneral', soft_errors=True, username=user, page_size=PageSize) @@ -4320,7 +4079,7 @@ def doShortCuts(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain + emailsettings.domain = domain #make sure it's back at default domain print u"Setting Keyboard Short Cuts to %s for %s (%s of %s)" % (str(SetShortCuts), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateGeneral', soft_errors=True, username=user, shortcuts=SetShortCuts) @@ -4341,7 +4100,7 @@ def doArrows(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain + emailsettings.domain = domain #make sure it's back at default domain print u"Setting Personal Indicator Arrows to %s for %s (%s of %s)" % (str(SetArrows), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateGeneral', soft_errors=True, username=user, arrows=SetArrows) @@ -4362,7 +4121,7 @@ def doSnippets(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain + emailsettings.domain = domain #make sure it's back at default domain print u"Setting Preview Snippets to %s for %s (%s of %s)" % (str(SetSnippets), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateGeneral', soft_errors=True, username=user, snippets=SetSnippets) @@ -4401,7 +4160,7 @@ def doLabel(users): print u'ERROR: %s is not a valid argument for this command.' % sys.argv[n] sys.exit(2) for user in users: - gmail = buildGAPIServiceObject(u'gmail', user) + gmail = buildGAPIServiceObject(u'gmail', act_as=user) print u"Creating label %s for %s (%s of %s)" % (label, user, i, count) i += 1 callGAPI(service=gmail.users().labels(), function=u'create', soft_errors=True, userId=user, body=body) @@ -4428,7 +4187,7 @@ def doDeleteMessages(trashOrDelete, users): print u'ERROR: No query specified. You must specify some query!' sys.exit(2) for user in users: - gmail = buildGAPIServiceObject(u'gmail', user) + gmail = buildGAPIServiceObject(u'gmail', act_as=user) page_message = u'Got %%%%total_items%%%% messages for user %s' % user listResult = callGAPIpages(service=gmail.users().messages(), function=u'list', items=u'messages', page_message=page_message, @@ -4440,17 +4199,17 @@ def doDeleteMessages(trashOrDelete, users): elif del_count > maxToDelete: print u'WARNING: refusing to delete ANY messages for %s since max_to_delete is %s and messages to be deleted is %s\n' % (user, maxToDelete, del_count) continue - i = 0 + i = 1 for del_me in listResult: - i += 1 print u' %s message %s for user %s (%s/%s)' % (trashOrDelete, del_me[u'id'], user, i, del_count) + i += 1 callGAPI(service=gmail.users().messages(), function=trashOrDelete, id=del_me[u'id'], userId=u'me') def doDeleteLabel(users): label = sys.argv[5] for user in users: - gmail = buildGAPIServiceObject(u'gmail', user) + gmail = buildGAPIServiceObject(u'gmail', act_as=user) print u'Getting all labels for %s...' % user labels = callGAPI(service=gmail.users().labels(), function=u'list', userId=user, fields=u'labels(name,id,type)') del_labels = [] @@ -4505,7 +4264,7 @@ def showLabels(users): print u'ERROR: %s is not a valid argument for "gam show labels"' % sys.argv[i] sys.exit(2) for user in users: - gmail = buildGAPIServiceObject(u'gmail', user) + gmail = buildGAPIServiceObject(u'gmail', act_as=user) labels = callGAPI(service=gmail.users().labels(), function=u'list', userId=user) for label in labels[u'labels']: if label[u'type'] == u'system' and not show_system: @@ -4530,7 +4289,7 @@ def showGmailProfile(users): profiles = [{}] for user in users: print 'Getting Gmail profile for %s' % user - gmail = buildGAPIServiceObject(u'gmail', user, soft_errors=True) + gmail = buildGAPIServiceObject(u'gmail', act_as=user, soft_errors=True) if not gmail: continue results = callGAPI(service=gmail.users(), function=u'getProfile', userId=u'me', soft_errors=True) @@ -4569,7 +4328,7 @@ def updateLabels(users): print u'ERROR: %s is not a valid argument for "gam update labels"' % sys.argv[i] sys.exit(2) for user in users: - gmail = buildGAPIServiceObject(u'gmail', user) + gmail = buildGAPIServiceObject(u'gmail', act_as=user) labels = callGAPI(service=gmail.users().labels(), function=u'list', userId=user, fields=u'labels(id,name)') label_id = None for label in labels[u'labels']: @@ -4600,7 +4359,7 @@ def renameLabels(users): sys.exit(2) pattern = re.compile(search, re.IGNORECASE) for user in users: - gmail = buildGAPIServiceObject(u'gmail', user) + gmail = buildGAPIServiceObject(u'gmail', act_as=user) labels = callGAPI(service=gmail.users().labels(), function=u'list', userId=user) for label in labels[u'labels']: if label[u'type'] == u'system': @@ -4710,7 +4469,7 @@ def doFilter(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain + emailsettings.domain = domain #make sure it's back at default domain print u"Creating filter for %s (%s of %s)" % (user+'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'CreateFilter', soft_errors=True, @@ -4754,7 +4513,7 @@ def doForward(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain + emailsettings.domain = domain #make sure it's back at default domain print u"Turning forward %s for %s, emails will be %s (%s of %s)" % (sys.argv[4], user+'@'+emailsettings.domain, action, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateForwarding', soft_errors=True, username=user, enable=enable, action=action, forward_to=forward_to) @@ -4766,7 +4525,7 @@ def getForward(users): emailsettings.domain = user[user.find('@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] + emailsettings.domain = domain forward = callGData(service=emailsettings, function=u'GetForward', soft_errors=True, username=user) try: print u"User %s: Forward To:%s Enabled:%s Action:%s" % (user+u'@'+emailsettings.domain, forward[u'forwardTo'], forward[u'enable'], forward[u'action']) @@ -4791,7 +4550,7 @@ def doSignature(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain + emailsettings.domain = domain #make sure it's back at default domain print u"Setting Signature for %s (%s of %s)" % (user+u'@'+emailsettings.domain, i, count) uri = u'https://apps-apis.google.com/a/feeds/emailsettings/2.0/%s/%s/signature' % (emailsettings.domain, user) i += 1 @@ -4804,7 +4563,7 @@ def getSignature(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] + emailsettings.domain = domain signature = callGData(service=emailsettings, function=u'GetSignature', soft_errors=True, username=user) try: sys.stderr.write(u"User %s signature:\n " % (user+u'@'+emailsettings.domain)) @@ -4828,7 +4587,7 @@ def doWebClips(users): emailsettings.domain = user[user.find('@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain + emailsettings.domain = domain #make sure it's back at default domain print u"Turning Web Clips %s for %s (%s of %s)" % (sys.argv[4], user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateWebClipSettings', soft_errors=True, username=user, enable=enable) @@ -4879,7 +4638,7 @@ def doVacation(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain + emailsettings.domain = domain #make sure it's back at default domain print u"Setting Vacation for %s (%s of %s)" % (user+'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateVacation', @@ -4894,7 +4653,7 @@ def getVacation(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = GC_Values[GC_DOMAIN] + emailsettings.domain = domain vacationsettings = callGData(service=emailsettings, function=u'GetVacation', soft_errors=True, username=user) try: print convertUTF8(u'''User %s @@ -4913,7 +4672,7 @@ def getVacation(users): def doDelSchema(): cd = buildGAPIObject(u'directory') schemaKey = sys.argv[3] - callGAPI(service=cd.schemas(), function=u'delete', customerId=GC_Values[GC_CUSTOMER_ID], schemaKey=schemaKey) + callGAPI(service=cd.schemas(), function=u'delete', customerId=customerId, schemaKey=schemaKey) print u'Deleted schema %s' % schemaKey def doCreateOrUpdateUserSchema(): @@ -4955,15 +4714,15 @@ def doCreateOrUpdateUserSchema(): print 'ERROR: %s is not a valid argument for "gam create schema"' % sys.argv[i] sys.exit(2) if sys.argv[1].lower() == u'create': - result = callGAPI(service=cd.schemas(), function=u'insert', customerId=GC_Values[GC_CUSTOMER_ID], body=body) + result = callGAPI(service=cd.schemas(), function=u'insert', customerId=customerId, body=body) print 'Created user schema %s' % result[u'schemaName'] elif sys.argv[1].lower() == u'update': - result = callGAPI(service=cd.schemas(), function=u'update', customerId=GC_Values[GC_CUSTOMER_ID], body=body, schemaKey=schemaName) + result = callGAPI(service=cd.schemas(), function=u'update', customerId=customerId, body=body, schemaKey=schemaName) print 'Updated user schema %s' % result[u'schemaName'] def doPrintUserSchemas(): cd = buildGAPIObject(u'directory') - schemas = callGAPI(service=cd.schemas(), function=u'list', customerId=GC_Values[GC_CUSTOMER_ID]) + schemas = callGAPI(service=cd.schemas(), function=u'list', customerId=customerId) if not schemas or u'schemas' not in schemas: return for schema in schemas[u'schemas']: @@ -4983,7 +4742,7 @@ def doPrintUserSchemas(): def doGetUserSchema(): cd = buildGAPIObject(u'directory') schemaKey = sys.argv[3] - schema = callGAPI(service=cd.schemas(), function=u'get', customerId=GC_Values[GC_CUSTOMER_ID], schemaKey=schemaKey) + schema = callGAPI(service=cd.schemas(), function=u'get', customerId=customerId, schemaKey=schemaKey) print u'Schema: %s' % schema[u'schemaName'] for a_key in schema: if a_key not in [u'schemaName', u'fields', u'etag', u'kind']: @@ -5002,7 +4761,7 @@ def doCreateUser(): body[u'name'] = dict() body[u'primaryEmail'] = sys.argv[3] if body[u'primaryEmail'].find(u'@') == -1: - body[u'primaryEmail'] = u'%s@%s' % (body[u'primaryEmail'], GC_Values[GC_DOMAIN]) + body[u'primaryEmail'] = u'%s@%s' % (body[u'primaryEmail'], domain) gotFirstName = gotLastName = do_admin = False need_to_hash_password = need_password = True i = 4 @@ -5342,12 +5101,12 @@ def doCreateUser(): callGAPI(service=cd.users(), function=u'makeAdmin', userKey=body[u'primaryEmail'], body=admin_body) def doCreateGroup(): - cd = buildGAPIObject(u'directory') use_gs_api = False + cd = buildGAPIObject(u'directory') body = dict() body[u'email'] = sys.argv[3] if body[u'email'].find(u'@') == -1: - body[u'email'] = u'%s@%s' % (body[u'email'], GC_Values[GC_DOMAIN]) + body[u'email'] = u'%s@%s' % (body[u'email'], domain) got_name = False i = 4 gs_body = dict() @@ -5408,14 +5167,14 @@ def doCreateAlias(): body = dict() body[u'alias'] = sys.argv[3] if body[u'alias'].find(u'@') == -1: - body[u'alias'] = u'%s@%s' % (body[u'alias'], GC_Values[GC_DOMAIN]) + body[u'alias'] = u'%s@%s' % (body[u'alias'], domain) target_type = sys.argv[4].lower() if target_type not in [u'user', u'group', u'target']: print u'ERROR: type of target should be user or group. Got %s' % target_type sys.exit(2) targetKey = sys.argv[5] if targetKey.find(u'@') == -1: - targetKey = u'%s@%s' % (targetKey, GC_Values[GC_DOMAIN]) + targetKey = u'%s@%s' % (targetKey, domain) print u'Creating alias %s for %s %s' % (body[u'alias'], target_type, targetKey) if target_type == u'user': callGAPI(service=cd.users().aliases(), function=u'insert', userKey=targetKey, body=body) @@ -5448,12 +5207,11 @@ def doCreateOrg(): else: print u'ERROR: %s is not a valid argument for "gam create org"' % sys.argv[i] sys.exit(2) - callGAPI(service=cd.orgunits(), function=u'insert', customerId=GC_Values[GC_CUSTOMER_ID], body=body) + callGAPI(service=cd.orgunits(), function=u'insert', customerId=customerId, body=body) -def doCreateResourceCalendar(): - cd = buildGAPIObject(u'directory') +def doCreateResource(): body = {u'resourceId': sys.argv[3], - u'resourceName': sys.argv[4]} + u'resourceName': sys.argv[4]} i = 5 while i < len(sys.argv): if sys.argv[i].lower() == u'description': @@ -5465,9 +5223,10 @@ def doCreateResourceCalendar(): else: print u'ERROR: %s is not a valid argument for "gam create resource"' % sys.argv[i] sys.exit(2) + cd = buildGAPIObject(u'directory') print u'Creating resource %s...' % body[u'resourceId'] callGAPI(service=cd.resources().calendars(), function=u'insert', - customer=GC_Values[GC_CUSTOMER_ID], body=body) + customer=customerId, body=body) def doUpdateUser(users): cd = buildGAPIObject(u'directory') @@ -5497,7 +5256,7 @@ def doUpdateUser(users): do_update_user = True body[u'primaryEmail'] = sys.argv[i+1] if body[u'primaryEmail'].find(u'@') == -1: - body[u'primaryEmail'] = u'%s@%s' % (body[u'primaryEmail'], GC_Values[GC_DOMAIN]) + body[u'primaryEmail'] = u'%s@%s' % (body[u'primaryEmail'], domain) i += 2 elif sys.argv[i].lower() == u'password': do_update_user = True @@ -5843,7 +5602,7 @@ def doUpdateUser(users): if user[:4].lower() == u'uid:': user = user[4:] elif user.find(u'@') == -1: - user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) + user = u'%s@%s' % (user, domain) if u'primaryEmail' in body and body[u'primaryEmail'][:4].lower() == u'vfe@': user_primary = callGAPI(service=cd.users(), function=u'get', userKey=user, fields=u'primaryEmail,id') user = user_primary[u'id'] @@ -5886,13 +5645,13 @@ def doRemoveUsersGroups(users): print u'' def doUpdateGroup(): - cd = buildGAPIObject(u'directory') group = sys.argv[3] if sys.argv[4].lower() in [u'add', u'update', u'sync', u'remove']: + cd = buildGAPIObject(u'directory') if group[0:3].lower() == u'uid:': group = group[4:] elif group.find(u'@') == -1: - group = u'%s@%s' % (group, GC_Values[GC_DOMAIN]) + group = u'%s@%s' % (group, domain) if sys.argv[4].lower() in [u'add', u'update']: role = sys.argv[5].upper() i = 6 @@ -5905,7 +5664,7 @@ def doUpdateGroup(): users_email = [sys.argv[i],] for user_email in users_email: if user_email != u'*' and user_email.find(u'@') == -1: - user_email = u'%s@%s' % (user_email, GC_Values[GC_DOMAIN]) + user_email = u'%s@%s' % (user_email, domain) sys.stderr.write(u' %sing %s %s...' % (sys.argv[4].lower(), role.lower(), user_email)) try: if sys.argv[4].lower() == u'add': @@ -5954,7 +5713,7 @@ def doUpdateGroup(): user_emails = [sys.argv[i],] for user_email in user_emails: if user_email != u'*' and user_email.find(u'@') == -1: - user_email = u'%s@%s' % (user_email, GC_Values[GC_DOMAIN]) + user_email = u'%s@%s' % (user_email, domain) sys.stderr.write(u' removing %s\n' % user_email) result = callGAPI(service=cd.members(), function=u'delete', soft_errors=True, groupKey=group, memberKey=user_email) else: @@ -6015,11 +5774,13 @@ def doUpdateGroup(): use_cd_api = True group = group[4:] elif group.find(u'@') == -1: - group = u'%s@%s' % (group, GC_Values[GC_DOMAIN]) + cd = buildGAPIObject(u'directory') + group = u'%s@%s' % (group, domain) if use_cd_api: + cd = buildGAPIObject(u'directory') try: if cd_body[u'email'].find('@') == -1: - cd_body[u'email'] = u'%s@%s' % (cd_body[u'email'], GC_Values[GC_DOMAIN]) + cd_body[u'email'] = u'%s@%s' % (cd_body[u'email'], domain) except KeyError: pass cd_result = callGAPI(service=cd.groups(), function=u'patch', groupKey=group, body=cd_body) @@ -6031,17 +5792,17 @@ def doUpdateGroup(): print u'updated group %s' % group def doUpdateAlias(): - cd = buildGAPIObject(u'directory') alias = sys.argv[3] target_type = sys.argv[4].lower() if target_type not in [u'user', u'group', u'target']: print u'ERROR: target type should be "user", "group" or "target", got %s' % target_type sys.exit(2) target_email = sys.argv[5] + cd = buildGAPIObject(u'directory') if alias.find(u'@') == -1: - alias = u'%s@%s' % (alias, GC_Values[GC_DOMAIN]) + alias = u'%s@%s' % (alias, domain) if target_email.find(u'@') == -1: - target_email = u'%s@%s' % (target_email, GC_Values[GC_DOMAIN]) + target_email = u'%s@%s' % (target_email, domain) try: callGAPI(service=cd.users().aliases(), function=u'delete', throw_reasons=[u'invalid'], userKey=alias, alias=alias) except googleapiclient.errors.HttpError: @@ -6058,7 +5819,6 @@ def doUpdateAlias(): print u'updated alias %s' % alias def doUpdateResourceCalendar(): - cd = buildGAPIObject(u'directory') resId = sys.argv[3] body = {} i = 4 @@ -6075,20 +5835,21 @@ def doUpdateResourceCalendar(): else: print u'ERROR: %s is not a valid argument for "gam update resource"' % sys.argv[i] sys.exit(2) + cd = buildGAPIObject(u'directory') # Use patch since it seems to work better. # update requires name to be set. callGAPI(service=cd.resources().calendars(), function=u'patch', - customer=GC_Values[GC_CUSTOMER_ID], calendarResourceId=resId, body=body, - fields=u'') + customer=customerId, calendarResourceId=resId, body=body, + fields=u'') print u'updated resource %s' % resId def doUpdateCros(): - cd = buildGAPIObject(u'directory') deviceId = sys.argv[3] + cd = buildGAPIObject(u'directory') if deviceId[:6].lower() == u'query:': query = deviceId[6:] devices_result = callGAPIpages(service=cd.chromeosdevices(), function=u'list', items=u'chromeosdevices', - query=query, customerId=GC_Values[GC_CUSTOMER_ID], fields=u'chromeosdevices/deviceId,nextPageToken') + query=query, customerId=customerId, fields=u'chromeosdevices/deviceId,nextPageToken') devices = list() for a_device in devices_result: devices.append(a_device[u'deviceId']) @@ -6128,12 +5889,12 @@ def doUpdateCros(): i = 1 for this_device in devices: print u' updating %s (%s of %s)' % (this_device, i, device_count) - callGAPI(service=cd.chromeosdevices(), function=u'patch', deviceId=this_device, body=body, customerId=GC_Values[GC_CUSTOMER_ID]) + callGAPI(service=cd.chromeosdevices(), function=u'patch', deviceId=this_device, body=body, customerId=customerId) i += 1 def doUpdateMobile(): - cd = buildGAPIObject(u'directory') resourceId = sys.argv[3] + cd = buildGAPIObject(u'directory') i = 4 action_body = patch_body = dict() doPatch = doAction = False @@ -6165,18 +5926,18 @@ def doUpdateMobile(): print u'ERROR: %s is not a valid argument for "gam update mobile"' % sys.argv[i] sys.exit(2) if doPatch: - callGAPI(service=cd.mobiledevices(), function=u'patch', resourceId=resourceId, body=patch_body, customerId=GC_Values[GC_CUSTOMER_ID]) + callGAPI(service=cd.mobiledevices(), function=u'patch', resourceId=resourceId, body=patch_body, customerId=customerId) if doAction: - callGAPI(service=cd.mobiledevices(), function=u'action', resourceId=resourceId, body=action_body, customerId=GC_Values[GC_CUSTOMER_ID]) + callGAPI(service=cd.mobiledevices(), function=u'action', resourceId=resourceId, body=action_body, customerId=customerId) def doDeleteMobile(): cd = buildGAPIObject(u'directory') resourceId = sys.argv[3] - callGAPI(service=cd.mobiledevices(), function='delete', resourceId=resourceId, customerId=GC_Values[GC_CUSTOMER_ID]) + callGAPI(service=cd.mobiledevices(), function='delete', resourceId=resourceId, customerId=customerId) def doUpdateOrg(): - cd = buildGAPIObject(u'directory') orgUnitPath = sys.argv[3] + 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].lower(), entity=sys.argv[6]) @@ -6188,7 +5949,7 @@ def doUpdateOrg(): for cros in users: sys.stderr.write(u' moving %s to %s (%s/%s)\n' % (cros, orgUnitPath, current_cros, cros_count)) callGAPI(service=cd.chromeosdevices(), function=u'patch', soft_errors=True, - customerId=GC_Values[GC_CUSTOMER_ID], deviceId=cros, body={u'orgUnitPath': '//%s' % orgUnitPath}) + customerId=customerId, deviceId=cros, body={u'orgUnitPath': '//%s' % orgUnitPath}) current_cros += 1 else: user_count = len(users) @@ -6228,13 +5989,13 @@ 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'update', customerId=GC_Values[GC_CUSTOMER_ID], orgUnitPath=orgUnitPath, body=body) + callGAPI(service=cd.orgunits(), function=u'update', customerId=customerId, orgUnitPath=orgUnitPath, body=body) def doWhatIs(): - cd = buildGAPIObject(u'directory') email = sys.argv[2] + cd = buildGAPIObject(u'directory') if email.find(u'@') == -1: - email = u'%s@%s' % (email, GC_Values[GC_DOMAIN]) + email = u'%s@%s' % (email, domain) try: user_or_alias = callGAPI(service=cd.users(), function=u'get', throw_reasons=[u'notFound', u'badRequest', u'invalid'], userKey=email, fields=u'primaryEmail') if user_or_alias[u'primaryEmail'].lower() == email.lower(): @@ -6266,7 +6027,7 @@ def doGetUserInfo(user_email=None): try: user_email = sys.argv[3] except IndexError: - storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) + storage = oauth2client.file.Storage(os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE'), FN_OAUTH2_TXT)) credentials = storage.get() if credentials is None or credentials.invalid: doRequestOAuth() @@ -6275,7 +6036,7 @@ def doGetUserInfo(user_email=None): if user_email[:4].lower() == u'uid:': user_email = user_email[4:] elif user_email.find(u'@') == -1: - user_email = u'%s@%s' % (user_email, GC_Values[GC_DOMAIN]) + user_email = u'%s@%s' % (user_email, domain) getSchemas = getAliases = getGroups = getLicenses = True projection = u'full' customFieldMask = viewType = None @@ -6451,8 +6212,6 @@ def doGetUserInfo(user_email=None): print u' %s' % result[u'skuId'] def doGetGroupInfo(group_name=None): - cd = buildGAPIObject(u'directory') - gs = buildGAPIObject(u'groupssettings') if group_name == None: group_name = sys.argv[3] get_users = True @@ -6461,10 +6220,12 @@ def doGetGroupInfo(group_name=None): get_users = False except IndexError: pass + cd = buildGAPIObject(u'directory') + gs = buildGAPIObject(u'groupssettings') if group_name[:4].lower() == u'uid:': group_name = group_name[4:] elif group_name.find(u'@') == -1: - group_name = group_name+u'@'+GC_Values[GC_DOMAIN] + group_name = group_name+u'@'+domain basic_info = callGAPI(service=cd.groups(), function=u'get', groupKey=group_name) try: settings = callGAPI(service=gs.groups(), function=u'get', retry_reasons=[u'serviceLimit'], throw_reasons=u'authError', @@ -6508,11 +6269,11 @@ def doGetGroupInfo(group_name=None): print u'Total %s users in group' % len(members) def doGetAliasInfo(alias_email=None): - cd = buildGAPIObject(u'directory') if alias_email == None: alias_email = sys.argv[3] + cd = buildGAPIObject(u'directory') if alias_email.find(u'@') == -1: - alias_email = u'%s@%s' % (alias_email, GC_Values[GC_DOMAIN]) + alias_email = u'%s@%s' % (alias_email, domain) try: result = callGAPI(service=cd.users(), function=u'get', throw_reasons=[u'invalid', u'badRequest'], userKey=alias_email) except googleapiclient.errors.HttpError: @@ -6528,25 +6289,25 @@ def doGetAliasInfo(alias_email=None): print u' Unique ID: %s' % result[u'id'] def doGetResourceCalendarInfo(): - cd = buildGAPIObject(u'directory') resId = sys.argv[3] + cd = buildGAPIObject(u'directory') resource = callGAPI(service=cd.resources().calendars(), function=u'get', - customer=GC_Values[GC_CUSTOMER_ID], calendarResourceId=resId) + customer=customerId, calendarResourceId=resId) for key, value in resource.items(): if key in [u'kind', u'etag', u'etags']: continue print u'%s: %s' % (key, value) def doGetCrosInfo(): - cd = buildGAPIObject(u'directory') deviceId = sys.argv[3] - info = callGAPI(service=cd.chromeosdevices(), function=u'get', customerId=GC_Values[GC_CUSTOMER_ID], deviceId=deviceId) + cd = buildGAPIObject(u'directory') + info = callGAPI(service=cd.chromeosdevices(), function=u'get', customerId=customerId, deviceId=deviceId) print_json(None, info) def doGetMobileInfo(): - cd = buildGAPIObject(u'directory') deviceId = sys.argv[3] - info = callGAPI(service=cd.mobiledevices(), function=u'get', customerId=GC_Values[GC_CUSTOMER_ID], resourceId=deviceId) + cd = buildGAPIObject(u'directory') + info = callGAPI(service=cd.mobiledevices(), function=u'get', customerId=customerId, resourceId=deviceId) print_json(None, info) def print_json(object_name, object_value, spacing=u''): @@ -6598,13 +6359,13 @@ def doUpdateNotification(): print u'ERROR: notifications need to be marked as read or unread.' sys.exit(2) if get_all: - notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=GC_Values[GC_CUSTOMER_ID], fields=u'items(notificationId,isUnread),nextPageToken') + notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=customerId, fields=u'items(notificationId,isUnread),nextPageToken') for noti in notifications: if noti[u'isUnread'] != isUnread: ids.append(noti[u'notificationId']) print u'Marking %s notification(s) as %s...' % (len(ids), mark_as) for notificationId in ids: - result = callGAPI(service=cd.notifications(), function=u'patch', customer=GC_Values[GC_CUSTOMER_ID], notificationId=notificationId, body={u'isUnread': isUnread}, fields=u'notificationId,isUnread') + result = callGAPI(service=cd.notifications(), function=u'patch', customer=customerId, notificationId=notificationId, body={u'isUnread': isUnread}, fields=u'notificationId,isUnread') if result[u'isUnread']: read_result = u'unread' else: @@ -6627,12 +6388,12 @@ def doDeleteNotification(): print 'ERROR: %s is not a valid argument for "gam delete notification", expected id' % sys.argv[i] sys.exit(2) if get_all: - notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=GC_Values[GC_CUSTOMER_ID], fields=u'items(notificationId),nextPageToken') + notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=customerId, fields=u'items(notificationId),nextPageToken') for noti in notifications: ids.append(noti[u'notificationId']) print u'Deleting %s notification(s)...' % len(ids) for notificationId in ids: - callGAPI(service=cd.notifications(), function=u'delete', customer=GC_Values[GC_CUSTOMER_ID], notificationId=notificationId) + callGAPI(service=cd.notifications(), function=u'delete', customer=customerId, notificationId=notificationId) print u'deleted %s' % id def doSiteVerifyShow(): @@ -6740,7 +6501,7 @@ def doSiteVerifyAttempt(): except KeyError: pass print - print u'You can now add %s or it\'s subdomains as secondary or domain aliases of the %s Google Apps Account.' % (a_domain, GC_Values[GC_DOMAIN]) + print u'You can now add %s or it\'s subdomains as secondary or domain aliases of the %s Google Apps Account.' % (a_domain, domain) def doGetNotifications(): cd = buildGAPIObject(u'directory') @@ -6753,7 +6514,7 @@ def doGetNotifications(): print 'ERROR: %s is not a valid argument for "gam info notification", expected unreadonly' % sys.argv[i] sys.exit(2) i += 1 - notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=GC_Values[GC_CUSTOMER_ID]) + notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=customerId) for notification in notifications: if unread_only and not notification[u'isUnread']: continue @@ -6785,20 +6546,20 @@ def doGetOrgInfo(): pass if name == u'/': orgs = callGAPI(service=cd.orgunits(), function=u'list', - customerId=GC_Values[GC_CUSTOMER_ID], type=u'children', + customerId=customerId, type=u'children', fields=u'organizationUnits/parentOrgUnitId') name = orgs[u'organizationUnits'][0][u'parentOrgUnitId'] if len(name) > 1 and name[0] == u'/': name = name[1:] - result = callGAPI(service=cd.orgunits(), function=u'get', customerId=GC_Values[GC_CUSTOMER_ID], orgUnitPath=name) + result = callGAPI(service=cd.orgunits(), function=u'get', customerId=customerId, orgUnitPath=name) print_json(None, result) if get_users: name = result[u'orgUnitPath'] print u'Users: ' page_message = u'Got %%total_items%% users: %%first_item%% - %%last_item%%\n' users = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - message_attribute=u'primaryEmail', customer=GC_Values[GC_CUSTOMER_ID], query=u"orgUnitPath='%s'" % name, - fields=u'users(primaryEmail,orgUnitPath),nextPageToken', maxResults=GC_Values[GC_USER_MAX_RESULTS]) + message_attribute=u'primaryEmail', customer=customerId, query=u"orgUnitPath='%s'" % name, + fields=u'users(primaryEmail,orgUnitPath),nextPageToken', maxResults=500) for user in users: if show_children or (name.lower() == user[u'orgUnitPath'].lower()): sys.stdout.write(u' %s' % user[u'primaryEmail']) @@ -6827,8 +6588,8 @@ def doGetASPs(users): print u' no ASPs for %s\n' % user def doDelASP(users): - cd = buildGAPIObject(u'directory') codeId = sys.argv[5] + cd = buildGAPIObject(u'directory') for user in users: callGAPI(service=cd.asps(), function=u'delete', userKey=user, codeId=codeId) print u'deleted ASP %s for %s' % (codeId, user) @@ -7107,52 +6868,48 @@ def doGetInstanceInfo(): adm = buildGAPIObject(u'admin-settings') if len(sys.argv) > 4 and sys.argv[3].lower() == u'logo': target_file = sys.argv[4] - url = 'http://www.google.com/a/cpanel/%s/images/logo.gif' % (GC_Values[GC_DOMAIN]) + url = 'http://www.google.com/a/cpanel/%s/images/logo.gif' % (domain) geturl(url, target_file) - sys.exit(0) - print u'Google Apps Domain: %s' % (GC_Values[GC_DOMAIN]) + return + print u'Google Apps Domain: %s' % domain cd = buildGAPIObject(u'directory') - if GC_Values[GC_CUSTOMER_ID] != MY_CUSTOMER: - customerId = GC_Values[GC_CUSTOMER_ID] + if customerId != MY_CUSTOMER: + customer_id = customerId else: - result = callGAPI(service=cd.users(), function=u'list', - fields=u'users(customerId)', customer=GC_Values[GC_CUSTOMER_ID], maxResults=1) - try: - customerId = result[u'users'][0][u'customerId'] - except KeyError: - customerId = UNKNOWN - print u'Customer ID: %s' % customerId - default_language = callGAPI(service=adm.defaultLanguage(), function=u'get', domainName=GC_Values[GC_DOMAIN]) + 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=GC_Values[GC_DOMAIN]) + org_name = callGAPI(service=adm.organizationName(), function='get', domainName=domain) 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=GC_Values[GC_DOMAIN]) + 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=GC_Values[GC_DOMAIN]) + max_users = callGAPI(service=adm.maximumNumberOfUsers(), function=u'get', domainName=domain) print u'Maximum Users: %s' % max_users[u'entry'][u'apps$property'][0][u'value'] - current_users = callGAPI(service=adm.currentNumberOfUsers(), function=u'get', domainName=GC_Values[GC_DOMAIN]) + current_users = callGAPI(service=adm.currentNumberOfUsers(), function=u'get', domainName=domain) print u'Current Users: %s' % current_users[u'entry'][u'apps$property'][0][u'value'] - is_dom_verified = callGAPI(service=adm.isVerified(), function=u'get', domainName=GC_Values[GC_DOMAIN]) + is_dom_verified = callGAPI(service=adm.isVerified(), function=u'get', domainName=domain) print u'Domain is Verified: %s' % is_dom_verified[u'entry'][u'apps$property'][0][u'value'] - domain_edition = callGAPI(service=adm.edition(), function=u'get', domainName=GC_Values[GC_DOMAIN]) + domain_edition = callGAPI(service=adm.edition(), function=u'get', domainName=domain) print u'Domain Edition: %s' % domain_edition[u'entry'][u'apps$property'][0][u'value'] - customer_pin = callGAPI(service=adm.customerPIN(), function=u'get', domainName=GC_Values[GC_DOMAIN]) + customer_pin = callGAPI(service=adm.customerPIN(), function=u'get', domainName=domain) print u'Customer PIN: %s' % customer_pin[u'entry'][u'apps$property'][0][u'value'] - creation_time = callGAPI(service=adm.creationTime(), function=u'get', domainName=GC_Values[GC_DOMAIN]) + creation_time = callGAPI(service=adm.creationTime(), function=u'get', domainName=domain) my_date = creation_time[u'entry'][u'apps$property'][0][u'value'] my_date = my_date[:15] my_offset = creation_time[u'entry'][u'apps$property'][0][u'value'][19:] nice_time = datetime.datetime.strptime(my_date, u"%Y%m%dT%H%M%S") print u'Domain Creation Time: %s %s' % (nice_time, my_offset) - country_code = callGAPI(service=adm.countryCode(), function=u'get', domainName=GC_Values[GC_DOMAIN]) + country_code = callGAPI(service=adm.countryCode(), function=u'get', domainName=domain) print u'Domain Country Code: %s' % country_code[u'entry'][u'apps$property'][0][u'value'] - mxverificationstatus = callGAPI(service=adm.mxVerification(), function=u'get', domainName=GC_Values[GC_DOMAIN]) + mxverificationstatus = callGAPI(service=adm.mxVerification(), function=u'get', domainName=domain) for entry in mxverificationstatus[u'entry'][u'apps$property']: if entry[u'name'] == u'verified': print u'MX Verification Verified: %s' % entry[u'value'] elif entry[u'name'] == u'verificationMethod': print u'MX Verification Method: %s' % entry[u'value'] - ssosettings = callGAPI(service=adm.ssoGeneral(), function=u'get', domainName=GC_Values[GC_DOMAIN]) + ssosettings = callGAPI(service=adm.ssoGeneral(), function=u'get', domainName=domain) for entry in ssosettings[u'entry'][u'apps$property']: if entry[u'name'] == u'enableSSO': print u'SSO Enabled: %s' % entry[u'value'] @@ -7166,7 +6923,7 @@ def doGetInstanceInfo(): print u'SSO Whitelist IPs: %s' % entry[u'value'] elif entry[u'name'] == u'useDomainSpecificIssuer': print u'SSO Use Domain Specific Issuer: %s' % entry[u'value'] - ssokey = callGAPI(service=adm.ssoSigningKey(), function=u'get', silent_errors=True, soft_errors=True, domainName=GC_Values[GC_DOMAIN]) + ssokey = callGAPI(service=adm.ssoSigningKey(), function=u'get', silent_errors=True, soft_errors=True, domainName=domain) try: for entry in ssokey[u'entry'][u'apps$property']: if entry[u'name'] == u'algorithm': @@ -7183,10 +6940,10 @@ def doGetInstanceInfo(): print u'Full SSO Key: %s' % entry[u'value'] except TypeError: pass - migration_status = callGAPI(service=adm.userEmailMigrationEnabled(), function=u'get', domainName=GC_Values[GC_DOMAIN]) + migration_status = callGAPI(service=adm.userEmailMigrationEnabled(), function=u'get', domainName=domain) print u'User Migration Enabled: %s' % migration_status[u'entry'][u'apps$property'][0][u'value'] outbound_gateway_settings = {u'smartHost': u'', u'smtpMode': u''} # Initialize blank in case we get an 1801 Error - outbound_gateway_settings = callGAPI(service=adm.outboundGateway(), function=u'get', domainName=GC_Values[GC_DOMAIN]) + outbound_gateway_settings = callGAPI(service=adm.outboundGateway(), function=u'get', domainName=domain) try: for entry in outbound_gateway_settings[u'entry'][u'apps$property']: if entry[u'name'] == u'smartHost': @@ -7198,17 +6955,16 @@ def doGetInstanceInfo(): print u'Outbound Gateway SMTP Mode: None' def doDeleteUser(): - cd = buildGAPIObject(u'directory') user_email = sys.argv[3] + cd = buildGAPIObject(u'directory') if user_email[:4].lower() == u'uid:': user_email = user_email[4:] elif user_email.find(u'@') == -1: - user_email = u'%s@%s' % (user_email, GC_Values[GC_DOMAIN]) + user_email = u'%s@%s' % (user_email, domain) print u"Deleting account for %s" % (user_email) callGAPI(service=cd.users(), function=u'delete', userKey=user_email) def doUndeleteUser(): - cd = buildGAPIObject(u'directory') user = sys.argv[3].lower() user_uid = False orgUnit = u'/' @@ -7217,14 +6973,15 @@ def doUndeleteUser(): orgUnit = sys.argv[5] except IndexError: pass + cd = buildGAPIObject(u'directory') if user[:4].lower() == u'uid:': user_uid = user[4:] elif user.find(u'@') == -1: - user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) + user = u'%s@%s' % (user, domain) if not user_uid: print u'Looking up UID for %s...' % user deleted_users = callGAPIpages(service=cd.users(), function=u'list', - items=u'users', customer=GC_Values[GC_CUSTOMER_ID], showDeleted=True, maxResults=GC_Values[GC_USER_MAX_RESULTS]) + items=u'users', customer=customerId, showDeleted=True, maxResults=500) matching_users = list() for deleted_user in deleted_users: if str(deleted_user[u'primaryEmail']).lower() == user: @@ -7252,17 +7009,16 @@ def doUndeleteUser(): callGAPI(service=cd.users(), function=u'undelete', userKey=user_uid, body={u'orgUnitPath': orgUnit}) def doDeleteGroup(): - cd = buildGAPIObject(u'directory') group = sys.argv[3] + cd = buildGAPIObject(u'directory') if group[:4].lower() == u'uid:': group = group[4:] elif group.find(u'@') == -1: - group = u'%s@%s' % (group, GC_Values[GC_DOMAIN]) + group = u'%s@%s' % (group, domain) print u"Deleting group %s" % group callGAPI(service=cd.groups(), function=u'delete', groupKey=group) def doDeleteAlias(alias_email=None): - cd = buildGAPIObject(u'directory') is_user = is_group = False if alias_email == None: alias_email = sys.argv[3] @@ -7272,8 +7028,9 @@ def doDeleteAlias(alias_email=None): elif alias_email.lower() == u'group': is_group = True alias_email = sys.argv[4] + cd = buildGAPIObject(u'directory') if alias_email.find(u'@') == -1: - alias_email = u'%s@%s' % (alias_email, GC_Values[GC_DOMAIN]) + alias_email = u'%s@%s' % (alias_email, domain) print u"Deleting alias %s" % alias_email if is_user or (not is_user and not is_group): try: @@ -7289,19 +7046,19 @@ def doDeleteAlias(alias_email=None): callGAPI(service=cd.groups().aliases(), function=u'delete', groupKey=alias_email, alias=alias_email) def doDeleteResourceCalendar(): - resId = sys.argv[3] + res_id = sys.argv[3] cd = buildGAPIObject(u'directory') - print u"Deleting resource calendar %s" % resId + print u"Deleting resource calendar %s" % res_id callGAPI(service=cd.resources().calendars(), function=u'delete', - customer=GC_Values[GC_CUSTOMER_ID], calendarResourceId=resId) + calendarResourceId=res_id, customer=customerId) def doDeleteOrg(): - cd = buildGAPIObject(u'directory') name = sys.argv[3] + cd = buildGAPIObject(u'directory') if name[0] == u'/': name = name[1:] print u"Deleting organization %s" % name - callGAPI(service=cd.orgunits(), function=u'delete', customerId=GC_Values[GC_CUSTOMER_ID], orgUnitPath=name) + callGAPI(service=cd.orgunits(), function=u'delete', customerId=customerId, orgUnitPath=name) def output_csv(csv_list, titles, list_type, todrive): csv.register_dialect(u'nixstdout', lineterminator=u'\n') @@ -7321,12 +7078,12 @@ def output_csv(csv_list, titles, list_type, todrive): convert = False drive = buildGAPIObject(u'drive') result = callGAPI(service=drive.files(), function=u'insert', convert=convert, - body={u'description': u' '.join(sys.argv), u'title': u'%s - %s' % (GC_Values[GC_DOMAIN], list_type), u'mimeType': u'text/csv'}, + body={u'description': u' '.join(sys.argv), u'title': u'%s - %s' % (domain, list_type), u'mimeType': u'text/csv'}, media_body=googleapiclient.http.MediaInMemoryUpload(string_file.getvalue(), mimetype=u'text/csv')) file_url = result[u'alternateLink'] - if GC_Values[GC_NO_BROWSER]: + if os.path.isfile(os.path.join(gamUserConfigDir, u'nobrowser.txt')): msg_txt = u'Drive file uploaded to:\n %s' % file_url - msg_subj = u'%s - %s' % (GC_Values[GC_DOMAIN], list_type) + msg_subj = u'%s - %s' % (domain, list_type) send_email(msg_subj, msg_txt) print msg_txt else: @@ -7354,7 +7111,7 @@ def doPrintUsers(): cd = buildGAPIObject(u'directory') user_fields = [u'primaryEmail',] fields = u'' - customer = GC_Values[GC_CUSTOMER_ID] + customer = customerId domain = None query = None projection = u'basic' @@ -7487,7 +7244,7 @@ def doPrintUsers(): all_users = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, message_attribute=u'primaryEmail', customer=customer, domain=domain, fields=fields, showDeleted=deleted_only, orderBy=orderBy, sortOrder=sortOrder, viewType=viewType, - query=query, projection=projection, customFieldMask=customFieldMask, maxResults=GC_Values[GC_USER_MAX_RESULTS]) + query=query, projection=projection, customFieldMask=customFieldMask, maxResults=500) titles = [u'primaryEmail',] attributes = [] for user in all_users: @@ -7540,10 +7297,8 @@ def doPrintUsers(): output_csv(attributes, titles, u'Users', todrive) def doPrintGroups(): - cd = buildGAPIObject(u'directory') i = 3 printname = printdesc = printid = members = owners = managers = settings = admin_created = aliases = todrive = False - customer = GC_Values[GC_CUSTOMER_ID] usedomain = usemember = None listDelimiter = u'\n' group_attributes = [{u'Email': u'Email'}] @@ -7552,7 +7307,6 @@ def doPrintGroups(): while i < len(sys.argv): if sys.argv[i].lower() == u'domain': usedomain = sys.argv[i+1].lower() - customer = None i += 2 elif sys.argv[i].lower() == u'todrive': todrive = True @@ -7562,7 +7316,6 @@ def doPrintGroups(): i += 2 elif sys.argv[i].lower() == u'member': usemember = sys.argv[i+1].lower() - customer = None i += 2 elif sys.argv[i].lower() == u'name': fields += u',groups(name)' @@ -7617,10 +7370,14 @@ def doPrintGroups(): else: print 'ERROR: %s is not a valid argument for "gam print groups"' % sys.argv[i] sys.exit(2) + cd = buildGAPIObject(u'directory') + global customerId + if usedomain or usemember: + customerId = None sys.stderr.write(u"Retrieving All Groups for Google Apps account (may take some time on a large account)...\n") page_message = u'Got %%num_items%% groups: %%first_item%% - %%last_item%%\n' all_groups = callGAPIpages(service=cd.groups(), function=u'list', items=u'groups', page_message=page_message, - message_attribute=u'email', customer=customer, domain=usedomain, userKey=usemember, fields=fields) + message_attribute=u'email', customer=customerId, domain=usedomain, userKey=usemember, fields=fields) total_groups = len(all_groups) count = 0 for group_vals in all_groups: @@ -7714,7 +7471,6 @@ def doPrintGroups(): output_csv(group_attributes, titles, u'Groups', todrive) def doPrintOrgs(): - cd = buildGAPIObject(u'directory') i = 3 printname = printdesc = printparent = printinherit = todrive = False listType = u'all' @@ -7765,8 +7521,9 @@ def doPrintOrgs(): if fields: org_attributes[0][u'Path'] = u'Path' titles.append(u'Path') + cd = buildGAPIObject(u'directory') sys.stderr.write(u"Retrieving All Organizational Units for your account (may take some time on large domain)...") - orgs = callGAPI(service=cd.orgunits(), function=u'list', customerId=GC_Values[GC_CUSTOMER_ID], fields=fields, type=listType, orgUnitPath=orgUnitPath) + orgs = callGAPI(service=cd.orgunits(), function=u'list', customerId=customerId, fields=fields, type=listType, orgUnitPath=orgUnitPath) sys.stderr.write(u"done\n") if not u'organizationUnits' in orgs: print u'0 org units in this Google Apps instance...' @@ -7808,7 +7565,6 @@ def doPrintOrgs(): output_csv(org_attributes, titles, u'Orgs', todrive) def doPrintAliases(): - cd = buildGAPIObject(u'directory') todrive = False i = 3 while i < len(sys.argv): @@ -7818,26 +7574,27 @@ def doPrintAliases(): else: print u'ERROR: %s is not a valid argument for "gam print aliases"' % sys.argv[i] sys.exit(2) + cd = buildGAPIObject(u'directory') alias_attributes = [] alias_attributes.append({u'Alias': u'Alias'}) alias_attributes[0].update(Target=u'Target') alias_attributes[0].update(TargetType=u'TargetType') titles = [u'Alias', u'Target', u'TargetType'] - sys.stderr.write(u"Retrieving All User Aliases for %s organization (may take some time on large domain)...\n" % GC_Values[GC_DOMAIN]) + sys.stderr.write(u"Retrieving All User Aliases for %s organization (may take some time on large domain)...\n" % domain) page_message = u'Got %%num_items%% users %%first_item%% - %%last_item%%\n' all_users = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - message_attribute=u'primaryEmail', customer=GC_Values[GC_CUSTOMER_ID], - fields=u'users(primaryEmail,aliases),nextPageToken', maxResults=GC_Values[GC_USER_MAX_RESULTS]) + message_attribute=u'primaryEmail', customer=customerId, + fields=u'users(primaryEmail,aliases),nextPageToken', maxResults=500) for user in all_users: try: for alias in user[u'aliases']: alias_attributes.append({u'Alias': alias, u'Target': user[u'primaryEmail'], u'TargetType': u'User'}) except KeyError: continue - sys.stderr.write(u"Retrieving All User Aliases for %s organization (may take some time on large domain)...\n" % GC_Values[GC_DOMAIN]) + sys.stderr.write(u"Retrieving All User Aliases for %s organization (may take some time on large domain)...\n" % domain) page_message = u'Got %%num_items%% groups %%first_item%% - %%last_item%%\n' all_groups = callGAPIpages(service=cd.groups(), function=u'list', items=u'groups', page_message=page_message, - message_attribute=u'email', customer=GC_Values[GC_CUSTOMER_ID], + message_attribute=u'email', customer=customerId, fields=u'groups(email,aliases),nextPageToken') for group in all_groups: try: @@ -7848,7 +7605,6 @@ def doPrintAliases(): output_csv(alias_attributes, titles, u'Aliases', todrive) def doPrintGroupMembers(): - cd = buildGAPIObject(u'directory') todrive = all_groups = False i = 3 while i < len(sys.argv): @@ -7861,10 +7617,11 @@ def doPrintGroupMembers(): else: print 'ERROR: %s is not a valid argument for "gam print group-members"' % sys.argv[i] sys.exit(2) + cd = buildGAPIObject(u'directory') member_attributes = [{u'group': u'group'},] if not all_groups: all_groups = callGAPIpages(service=cd.groups(), function=u'list', items=u'groups', message_attribute=u'email', - customer=GC_Values[GC_CUSTOMER_ID], fields=u'nextPageToken,groups(email)') + customer=customerId, fields=u'nextPageToken,groups(email)') total_groups = len(all_groups) i = 1 for group in all_groups: @@ -7920,8 +7677,8 @@ def doPrintMobileDevices(): sys.stderr.write(u'Retrieving All Mobile Devices for organization (may take some time for large accounts)...\n') page_message = u'Got %%num_items%% mobile devices...\n' all_mobile = callGAPIpages(service=cd.mobiledevices(), function=u'list', items=u'mobiledevices', page_message=page_message, - customerId=GC_Values[GC_CUSTOMER_ID], query=query, - orderBy=orderBy, sortOrder=sortOrder, maxResults=GC_Values[GC_DEVICE_MAX_RESULTS]) + customerId=customerId, query=query, + orderBy=orderBy, sortOrder=sortOrder, maxResults=500) for mobile in all_mobile: mobiledevice = dict() for title in mobile: @@ -8002,8 +7759,8 @@ def doPrintCrosDevices(): sys.stderr.write(u'Retrieving All Chrome OS Devices for organization (may take some time for large accounts)...\n') page_message = u'Got %%num_items%% Chrome devices...\n' all_cros = callGAPIpages(service=cd.chromeosdevices(), function=u'list', items=u'chromeosdevices', page_message=page_message, - query=query, customerId=GC_Values[GC_CUSTOMER_ID], projection=projection, - orderBy=orderBy, sortOrder=sortOrder, maxResults=GC_Values[GC_DEVICE_MAX_RESULTS]) + query=query, customerId=customerId, projection=projection, + orderBy=orderBy, sortOrder=sortOrder, maxResults=500) if all_cros: if (not noLists) and (not selectAttrib): for cros in all_cros: @@ -8069,7 +7826,7 @@ def doPrintLicenses(return_list=False, skus=None): page_message = u'Got %%%%total_items%%%% Licenses for %s...\n' % sku try: licenses += callGAPIpages(service=lic.licenseAssignments(), function=u'listForProductAndSku', throw_reasons=[u'invalid', u'forbidden'], page_message=page_message, - customerId=GC_Values[GC_DOMAIN], productId=product, skuId=sku, fields=u'items(productId,skuId,userId),nextPageToken') + customerId=domain, productId=product, skuId=sku, fields=u'items(productId,skuId,userId),nextPageToken') except googleapiclient.errors.HttpError: licenses += [] else: @@ -8077,7 +7834,7 @@ def doPrintLicenses(return_list=False, skus=None): page_message = u'Got %%%%total_items%%%% Licenses for %s...\n' % productId try: licenses += callGAPIpages(service=lic.licenseAssignments(), function=u'listForProduct', throw_reasons=[u'invalid', u'forbidden'], page_message=page_message, - customerId=GC_Values[GC_DOMAIN], productId=productId, fields=u'items(productId,skuId,userId),nextPageToken') + customerId=domain, productId=productId, fields=u'items(productId,skuId,userId),nextPageToken') except googleapiclient.errors.HttpError: licenses = +[] for u_license in licenses: @@ -8094,7 +7851,6 @@ def doPrintLicenses(return_list=False, skus=None): output_csv(lic_attributes, lic_attributes[0], u'Licenses', todrive) def doPrintTokens(): - cd = buildGAPIObject(u'directory') todrive = False i = 3 entity_type = u'all' @@ -8110,6 +7866,7 @@ def doPrintTokens(): else: print u'ERROR: %s is not a valid argument for "gam print tokens"' % sys.argv[i] sys.exit(2) + cd = buildGAPIObject(u'directory') all_users = getUsersToModify(entity_type=entity_type, entity=entity, silent=False) titles = [u'user', u'displayText', u'clientId', u'nativeApp', u'anonymous', u'scopes'] token_attributes = [{}] @@ -8135,11 +7892,10 @@ def doPrintTokens(): pass output_csv(token_attributes, titles, u'OAuth Tokens', todrive) -def doPrintResourceCalendars(): - cd = buildGAPIObject(u'directory') +def doPrintResources(): + i = 3 todrive = False fields = [u'resourceId', u'resourceName', u'resourceEmail'] - i = 3 while i < len(sys.argv): if sys.argv[i].lower() == u'allfields': fields = None @@ -8162,19 +7918,19 @@ def doPrintResourceCalendars(): sys.exit(2) if fields: fields = u'nextPageToken,items(%s)' % u','.join(fields) + cd = buildGAPIObject(u'directory') sys.stderr.write(u"Retrieving All Resource Calendars for your account (may take some time on a large domain)\n") page_message = u'Got %%total_items%% resources: %%first_item%% - %%last_item%%\n' - resources = callGAPIpages(service=cd.resources().calendars(), function=u'list', items=u'items', - page_message=page_message, message_attribute=u'resourceId', - customer=GC_Values[GC_CUSTOMER_ID], fields=fields, maxResults=500) + resources = callGAPIpages(service=cd.resources().calendars(), + function=u'list', items=u'items', fields=fields, + page_message=page_message, message_attribute=u'resourceId', + maxResults=500, customer=customerId) resources_attrib = [{u'resourceId':u'resourceId', - u'resourceEmail': u'resourceEmail', - u'resourceName': u'resourceName'}] + u'resourceEmail': u'resourceEmail', + u'resourceName': u'resourceName'}] for resource in resources: resource_attrib = {} for key, value in resource.items(): - if key in [u'kind', u'etags']: - continue if key not in resources_attrib[0]: resources_attrib[0][key] = key resource_attrib[key] = value @@ -8539,7 +8295,7 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa else: member_type_message = u'%ss' % member_type.lower() if group.find(u'@') == -1: - group = u'%s@%s' % (group, GC_Values[GC_DOMAIN]) + group = u'%s@%s' % (group, domain) page_message = None if not silent: sys.stderr.write(u"Getting %s of %s (may take some time for large groups)..." % (member_type_message, group)) @@ -8563,8 +8319,8 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa sys.stderr.write(u"Getting all users in the Google Apps organization (may take some time on a large domain)...\n") page_message = u'Got %%total_items%% users...' members = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - customer=GC_Values[GC_CUSTOMER_ID], fields=u'nextPageToken,users(primaryEmail,id,orgUnitPath)', - query=u"orgUnitPath='%s'" % ou, maxResults=GC_Values[GC_USER_MAX_RESULTS]) + customer=customerId, fields=u'nextPageToken,users(primaryEmail,id,orgUnitPath)', + query=u"orgUnitPath='%s'" % ou, maxResults=500) for member in members: if ou.lower() != member[u'orgUnitPath'].lower(): continue @@ -8585,8 +8341,8 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa sys.stderr.write(u"Getting all users in the Google Apps organization (may take some time on a large domain)...\n") page_message = u'Got %%total_items%% users..' members = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - customer=GC_Values[GC_CUSTOMER_ID], fields=u'nextPageToken,users(primaryEmail,id)', - query=u"orgUnitPath='%s'" % ou, maxResults=GC_Values[GC_USER_MAX_RESULTS]) + customer=customerId, fields=u'nextPageToken,users(primaryEmail,id)', + query=u"orgUnitPath='%s'" % ou, maxResults=500) for member in members: if return_uids: users.append(member[u'id']) @@ -8601,8 +8357,8 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa sys.stderr.write(u"Getting all users that match query %s (may take some time on a large domain)...\n" % entity) page_message = u'Got %%total_items%% users...' members = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - customer=GC_Values[GC_CUSTOMER_ID], fields=u'nextPageToken,users(primaryEmail,id)', - query=entity, maxResults=GC_Values[GC_USER_MAX_RESULTS]) + customer=customerId, fields=u'nextPageToken,users(primaryEmail,id)', + query=entity, maxResults=500) for member in members: if return_uids: users.append(member[u'id']) @@ -8654,8 +8410,8 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa 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...' all_users = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - customer=GC_Values[GC_CUSTOMER_ID], - fields=u'nextPageToken,users(primaryEmail,suspended,id)', maxResults=GC_Values[GC_USER_MAX_RESULTS]) + customer=customerId, + fields=u'nextPageToken,users(primaryEmail,suspended,id)', maxResults=500) for member in all_users: if member[u'suspended'] == False: if return_uids: @@ -8668,8 +8424,8 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa 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=GC_Values[GC_CUSTOMER_ID], fields=u'nextPageToken,chromeosdevices(deviceId)', - maxResults=GC_Values[GC_DEVICE_MAX_RESULTS]) + customerId=customerId, fields=u'nextPageToken,chromeosdevices(deviceId)', + maxResults=500) for member in all_cros: users.append(member[u'deviceId']) if not silent: @@ -8689,7 +8445,7 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa if user[:4] == u'uid:': full_users.append(user[4:]) elif user.find(u'@') == -1: - full_users.append(u'%s@%s' % (user, GC_Values[GC_DOMAIN])) + full_users.append(u'%s@%s' % (user, domain)) else: full_users.append(user) else: @@ -8706,17 +8462,18 @@ def OAuthInfo(): try: access_token = sys.argv[3] except IndexError: - storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) + oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', FN_OAUTH2_TXT)) + storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() if credentials is None or credentials.invalid: doRequestOAuth() credentials = storage.get() credentials.user_agent = GAM_INFO - http = httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL]) + http = httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt'))) if credentials.access_token_expired: credentials.refresh(http) access_token = credentials.access_token - print u"\nOAuth File: %s" % GC_Values[GC_OAUTH2_TXT] + print u"\nOAuth File: %s" % oauth2file oa2 = buildGAPIObject(u'oauth2') token_info = callGAPI(service=oa2, function=u'tokeninfo', access_token=access_token) print u"Client ID: %s" % token_info[u'issued_to'] @@ -8733,13 +8490,14 @@ def OAuthInfo(): print u'Google Apps Admin: Unknown' def doDeleteOAuth(): - storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) + oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', FN_OAUTH2_TXT)) + storage = oauth2client.file.Storage(oauth2file) credentials = storage.get() try: credentials.revoke_uri = oauth2client.GOOGLE_REVOKE_URI except AttributeError: systemErrorExit(1, u'Authorization doesn\'t exist') - http = httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL]) + http = httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt'))) sys.stderr.write(u'This OAuth token will self-destruct in 3...') time.sleep(1) sys.stderr.write(u'2...') @@ -8751,7 +8509,7 @@ def doDeleteOAuth(): credentials.revoke(http) except oauth2client.client.TokenRevokeError, e: sys.stderr.write(u'{0}{1}\n'.format(ERROR_PREFIX, e.message)) - os.remove(GC_Values[GC_OAUTH2_TXT]) + os.remove(oauth2file) class cmd_flags(object): def __init__(self, noLocalWebserver): @@ -8767,7 +8525,7 @@ possible_scopes = [u'https://www.googleapis.com/auth/admin.directory.group', u'https://www.googleapis.com/auth/admin.directory.device.chromeos', # Chrome OS Devices Directory Scope u'https://www.googleapis.com/auth/admin.directory.device.mobile', # Mobile Device Directory Scope u'https://apps-apis.google.com/a/feeds/emailsettings/2.0/', # Email Settings API - u'https://www.googleapis.com/auth/admin.directory.resource.calendar',# Resource Calendar API + u'https://www.googleapis.com/auth/admin.directory.resource.calendar',# Calendar Resource API u'https://apps-apis.google.com/a/feeds/compliance/audit/', # Email Audit API u'https://apps-apis.google.com/a/feeds/domain/', # Admin Settings API u'https://www.googleapis.com/auth/apps.groups.settings', # Group Settings API @@ -8786,10 +8544,10 @@ possible_scopes = [u'https://www.googleapis.com/auth/admin.directory.group', u'https://www.googleapis.com/auth/admin.datatransfer', # Data Transfer API u'https://www.googleapis.com/auth/admin.directory.customer', # Customer API u'https://www.googleapis.com/auth/admin.directory.domain', # Domain API - u'https://www.googleapis.com/auth/admin.directory.rolemanagement', # Roles API - ] + u'https://www.googleapis.com/auth/admin.directory.rolemanagement'] # Roles API def doRequestOAuth(incremental_auth=False): + CLIENT_SECRETS = os.path.join(gamUserConfigDir, os.environ.get(u'CLIENTSECRETSFILE', FN_CLIENT_SECRETS_JSON)) MISSING_CLIENT_SECRETS_MESSAGE = u""" WARNING: Please configure OAuth 2.0 @@ -8806,7 +8564,7 @@ https://github.com/jay0lee/GAM/wiki/CreatingClientSecretsFile for instructions. -""" % GC_Values[GC_CLIENT_SECRETS_JSON] +""" % CLIENT_SECRETS num_scopes = len(possible_scopes) menu = u'''Select the authorized scopes for this token. Include a 'r' to grant read-only access or an 'a' to grant action-only access. @@ -8817,7 +8575,7 @@ access or an 'a' to grant action-only access. [%%s] %s) Chrome OS Device Directory API (supports read-only) [%%s] %s) Mobile Device Directory API (supports read-only and action) [%%s] %s) User Email Settings API -[%%s] %s) Resource Calendar API (supports read-only) +[%%s] %s) Calendar Resources API (supports read-only [%%s] %s) Audit Monitors, Activity and Mailbox Exports API [%%s] %s) Admin Settings API [%%s] %s) Groups Settings API @@ -8844,6 +8602,7 @@ access or an 'a' to grant action-only access. ''' % tuple(range(0, num_scopes)) selected_scopes = [u'*'] * num_scopes selected_scopes[16] = u' ' + # turn off notifications API by default to prevent 500 due to scope length select_all_scopes = unicode(str(num_scopes)) unselect_all_scopes = unicode(str(num_scopes+1)) authorize_scopes = unicode(str(num_scopes+2)) @@ -8912,14 +8671,14 @@ access or an 'a' to grant action-only access. elif selected_scopes[i] == u'A': scopes.append(u'%s.action' % possible_scopes[i]) try: - FLOW = oauth2client.client.flow_from_clientsecrets(GC_Values[GC_CLIENT_SECRETS_JSON], scope=scopes) + FLOW = oauth2client.client.flow_from_clientsecrets(CLIENT_SECRETS, scope=scopes) except oauth2client.client.clientsecrets.InvalidClientSecretsError: systemErrorExit(14, MISSING_CLIENT_SECRETS_MESSAGE) - storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) + storage = oauth2client.file.Storage(os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', FN_OAUTH2_TXT))) credentials = storage.get() - flags = cmd_flags(noLocalWebserver=GC_Values[GC_NO_BROWSER]) + flags = cmd_flags(noLocalWebserver=os.path.isfile(os.path.join(gamUserConfigDir, u'nobrowser.txt'))) if credentials is None or credentials.invalid or incremental_auth: - http = httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL]) + http = httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt'))) try: credentials = oauth2client.tools.run_flow(flow=FLOW, storage=storage, flags=flags, http=http) except httplib2.CertificateValidationUnsupported: @@ -8927,19 +8686,24 @@ access or an 'a' to grant action-only access. def batch_worker(): while True: - item = GM_Globals[GM_BATCH_QUEUE].get() + item = q.get() subprocess.call(item, stderr=subprocess.STDOUT) - GM_Globals[GM_BATCH_QUEUE].task_done() + q.task_done() def run_batch(items): import Queue, threading + global q total_items = len(items) current_item = 0 python_cmd = [sys.executable.lower(),] if not getattr(sys, 'frozen', False): # we're not frozen python_cmd.append(os.path.realpath(sys.argv[0])) - num_worker_threads = min(total_items, GC_Values[GC_NUM_THREADS]) - GM_Globals[GM_BATCH_QUEUE] = Queue.Queue(maxsize=num_worker_threads) # GM_Globals[GM_BATCH_QUEUE].put() gets blocked when trying to create more items than there are workers + try: + num_worker_threads = int(os.environ.get(u'GAM_THREADS', '5')) + except TypeError: + num_worker_threads = 5 + num_worker_threads = min(total_items, num_worker_threads) + q = Queue.Queue(maxsize=num_worker_threads) # q.put() gets blocked when trying to create more items than there are workers print u'starting %s worker threads...' % num_worker_threads for i in range(num_worker_threads): t = threading.Thread(target=batch_worker) @@ -8951,17 +8715,17 @@ def run_batch(items): print u'starting job %s / %s' % (current_item, total_items) if item[0] == u'commit-batch': sys.stderr.write(u'commit-batch - waiting for running processes to finish before proceeding...') - GM_Globals[GM_BATCH_QUEUE].join() + q.join() sys.stderr.write(u'done with commit-batch\n') continue - GM_Globals[GM_BATCH_QUEUE].put(python_cmd+item) - GM_Globals[GM_BATCH_QUEUE].join() + q.put(python_cmd+item) + q.join() # Main reload(sys) sys.setdefaultencoding(u'UTF-8') try: - if GM_Globals[GM_WINDOWS]: + if os.name == u'nt': sys.argv = win32_unicode_argv() # cleanup sys.argv on Windows SetGlobalVariables() if sys.argv[1].lower() == u'batch': @@ -9001,7 +8765,8 @@ try: try: arg = arg.replace(u'~~%s~~' % substring_replacement, row[substring_replacement]) except KeyError: - systemErrorExit(3, u'%s is not in %s' % (substring_replacement, row)) + print u'%s is not in %s' % (substring_replacement, row) + sys.exit(3) if arg[0] != '~': argv.append(arg) elif arg[1:] in row: @@ -9025,7 +8790,7 @@ try: elif sys.argv[2].lower() in [u'org', 'ou']: doCreateOrg() elif sys.argv[2].lower() == u'resource': - doCreateResourceCalendar() + doCreateResource() elif sys.argv[2].lower() in [u'verify', u'verification']: doSiteVerifyShow() elif sys.argv[2].lower() in [u'schema']: @@ -9211,7 +8976,7 @@ try: elif sys.argv[2].lower() in [u'orgs', u'ous']: doPrintOrgs() elif sys.argv[2].lower() == u'resources': - doPrintResourceCalendars() + doPrintResources() elif sys.argv[2].lower() == u'cros': doPrintCrosDevices() elif sys.argv[2].lower() == u'mobile': @@ -9324,7 +9089,8 @@ try: print user sys.exit(0) try: - if (GC_Values[GC_AUTO_BATCH_MIN] > 0) and (len(users) > GC_Values[GC_AUTO_BATCH_MIN]): + autoBatch = int(os.environ.get(u'GAM_AUTOBATCH', '0')) + if (autoBatch > 0) and (len(users) > autoBatch): items = [] for user in users: items.append([u'user', user] + sys.argv[3:]) From c04ae91dc5ffdcac7029d9b53b88ca3029649f9f Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Tue, 22 Dec 2015 17:37:56 -0800 Subject: [PATCH 04/11] Commit Jay changes --- src/gam.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/gam.py b/src/gam.py index cd156c6e..406acad5 100755 --- a/src/gam.py +++ b/src/gam.py @@ -634,7 +634,9 @@ def buildGAPIServiceObject(api, act_as=None, soft_errors=False): except httplib2.ServerNotFoundError as e: systemErrorExit(4, e) except oauth2client.client.AccessTokenRefreshError, e: - if e.message in [u'access_denied', u'unauthorized_client: Unauthorized client or scope in request.']: + if e.message in [u'access_denied', + u'unauthorized_client: Unauthorized client or scope in request.', + u'access_denied: Requested client not authorized.']: systemErrorExit(5, MESSAGE_CLIENT_API_ACCESS_DENIED.format(SERVICE_ACCOUNT_CLIENT_ID, u','.join(scope))) sys.stderr.write(u'{0}{1}\n'.format(ERROR_PREFIX, e)) if soft_errors: @@ -4187,11 +4189,12 @@ def doDeleteMessages(trashOrDelete, users): print u'ERROR: No query specified. You must specify some query!' sys.exit(2) for user in users: + print u'Searching messages for %s' % user gmail = buildGAPIServiceObject(u'gmail', act_as=user) page_message = u'Got %%%%total_items%%%% messages for user %s' % user listResult = callGAPIpages(service=gmail.users().messages(), function=u'list', items=u'messages', page_message=page_message, - userId=u'me', q=query, includeSpamTrash=True) + userId=u'me', q=query, includeSpamTrash=True, soft_errors=True) del_count = len(listResult) if not doIt: print u'would try to delete %s messages for user %s (max %s)\n' % (del_count, user, maxToDelete) From fe6430edc6e36ba424a87df6d304c707f2658fad Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Tue, 22 Dec 2015 17:56:37 -0800 Subject: [PATCH 05/11] Global variables do-over Global variables not from environment variables/signal files in GM_Globals Global variables from environment variables/signal files in GC_Values SetGlobalVariables processes all environment variables/signal files buildGAPIObject reworked buildGAPIServiceObject reworked Switch resource calendar processing from GData to GAPI Implement role assignments --- src/gam.py | 1070 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 652 insertions(+), 418 deletions(-) diff --git a/src/gam.py b/src/gam.py index 406acad5..1179ab88 100755 --- a/src/gam.py +++ b/src/gam.py @@ -57,7 +57,6 @@ GAM_APPSPOT_LATEST_VERSION_ANNOUNCEMENT = GAM_APPSPOT+u'/latest-version-announce TRUE = u'true' FALSE = u'false' -extra_args = {u'prettyPrint': False} true_values = [u'on', u'yes', u'enabled', u'true', u'1'] false_values = [u'off', u'no', u'disabled', u'false', u'0'] usergroup_types = [u'user', u'users', u'group', u'ou', u'org', @@ -74,17 +73,180 @@ FN_LAST_UPDATE_CHECK_TXT = u'lastupdatecheck.txt' FN_OAUTH2SERVICE_JSON = u'oauth2service.json' FN_OAUTH2_TXT = u'oauth2.txt' MY_CUSTOMER = u'my_customer' -UNKNOWN_DOMAIN = u'Unknown' +UNKNOWN = u'Unknown' +# +# Global variables +# +# The following GM_XXX constants are arbitrary but must be unique +# Most errors print a message and bail out with a return code +# Some commands want to set a non-zero return code but not bail +GM_SYSEXITRC = u'sxrc' +# Path to gam +GM_GAM_PATH = u'gpth' +# Are we on Windows? +GM_WINDOWS = u'wndo' +# Encodings +GM_SYS_ENCODING = u'syen' +# Shared by batch_worker and run_batch +GM_BATCH_QUEUE = u'batq' +# Extra arguments to pass to GAPI functions +GM_EXTRA_ARGS_DICT = u'exad' +# Values retrieved from oauth2service.json +GM_OAUTH2SERVICE_KEY = u'oauk' +GM_OAUTH2SERVICE_ACCOUNT_EMAIL = u'oaae' +GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID = u'oaci' +# File containing time of last GAM update check +GM_LAST_UPDATE_CHECK_TXT = u'lupc' +# Dictionary mapping OrgUnit ID to Name +GM_MAP_ORGUNIT_ID_TO_NAME = u'oi2n' +# Dictionary mapping Role ID to Name +GM_MAP_ROLE_ID_TO_NAME = u'ri2n' +# Dictionary mapping Role Name to ID +GM_MAP_ROLE_NAME_TO_ID = u'rn2i' +# Dictionary mapping User ID to Name +GM_MAP_USER_ID_TO_NAME = u'ui2n' +# +GM_Globals = { + GM_SYSEXITRC: 0, + GM_GAM_PATH: os.path.dirname(os.path.realpath(__file__)), + GM_WINDOWS: os.name == u'nt', + GM_SYS_ENCODING: sys.getfilesystemencoding() if os.name == u'nt' else u'utf-8', + GM_BATCH_QUEUE: None, + GM_EXTRA_ARGS_DICT: {u'prettyPrint': False}, + GM_OAUTH2SERVICE_KEY: None, + GM_OAUTH2SERVICE_ACCOUNT_EMAIL: None, + GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID: None, + GM_LAST_UPDATE_CHECK_TXT: u'', + GM_MAP_ORGUNIT_ID_TO_NAME: None, + GM_MAP_ROLE_ID_TO_NAME: None, + GM_MAP_ROLE_NAME_TO_ID: None, + GM_MAP_USER_ID_TO_NAME: None, + } +# +# Global variables defined by environment variables/signal files +# +# When retrieving lists of Google Drive activities from API, how many should be retrieved in each chunk +GC_ACTIVITY_MAX_RESULTS = u'activity_max_results' +# Automatically generate gam batch command if number of users specified in gam users xxx command exceeds this number +# Default: 0, don't automatically generate gam batch commands +GC_AUTO_BATCH_MIN = u'auto_batch_min' +# GAM cache directory. If no_cache is specified, this variable will be set to None +GC_CACHE_DIR = u'cache_dir' +# Character set of batch, csv, data files +GC_CHARSET = u'charset' +# Path to client_secrets.json +GC_CLIENT_SECRETS_JSON = u'client_secrets_json' +# GAM config directory containing client_secrets.json, oauth2.txt, oauth2service.json, extra_args.txt +GC_CONFIG_DIR = u'config_dir' +# custmerId from gam.cfg or retrieved from Google +GC_CUSTOMER_ID = u'customer_id' +# If debug_level > 0: extra_args[u'prettyPrint'] = True, httplib2.debuglevel = gam_debug_level, appsObj.debug = True +GC_DEBUG_LEVEL = u'debug_level' +# When retrieving lists of ChromeOS/Mobile devices from API, how many should be retrieved in each chunk +GC_DEVICE_MAX_RESULTS = u'device_max_results' +# Domain obtained from gam.cfg or oauth2.txt +GC_DOMAIN = u'domain' +# Google Drive download directory +GC_DRIVE_DIR = u'drive_dir' +# When retrieving lists of Drive files/folders from API, how many should be retrieved in each chunk +GC_DRIVE_MAX_RESULTS = u'drive_max_results' +# If no_browser is False, writeCSVfile won't open a browser when todrive is set +# and doRequestOAuth prints a link and waits for the verification code when oauth2.txt is being created +GC_NO_BROWSER = u'no_browser' +# Disable GAM API caching +GC_NO_CACHE = u'no_cache' +# Disable GAM update check +GC_NO_UPDATE_CHECK = u'no_update_check' +# Disable SSL certificate validation +GC_NO_VERIFY_SSL = u'no_verify_ssl' +# Number of threads for gam batch +GC_NUM_THREADS = u'num_threads' +# Path to oauth2.txt +GC_OAUTH2_TXT = u'oauth2_txt' +# Path to oauth2service.json +GC_OAUTH2SERVICE_JSON = u'oauth2service_json' +# Default section to use for processing +GC_SECTION = u'section' +# Add (n/m) to end of messages if number of items to be processed exceeds this number +GC_SHOW_COUNTS_MIN = u'show_counts_min' +# Enable/disable "Getting ... " messages +GC_SHOW_GETTINGS = u'show_gettings' +# GAM config directory containing admin-settings-v1.json, cloudprint-v2.json +GC_SITE_DIR = u'site_dir' +# When adding Users to Groups/Org Units, how many should be processed in each batch +GC_USER_BATCH_SIZE = u'user_batch_size' +# When retrieving lists of Users from API, how many should be retrieved in each chunk +GC_USER_MAX_RESULTS = u'user_max_results' -customerId = None -domain = None -q = None +GC_Defaults = { + GC_ACTIVITY_MAX_RESULTS: 100, + GC_AUTO_BATCH_MIN: 0, + GC_CACHE_DIR: u'', + GC_CHARSET: u'utf-8', + GC_CLIENT_SECRETS_JSON: FN_CLIENT_SECRETS_JSON, + GC_CONFIG_DIR: u'', + GC_CUSTOMER_ID: u'', + GC_DEBUG_LEVEL: 0, + GC_DEVICE_MAX_RESULTS: 500, + GC_DOMAIN: u'', + GC_DRIVE_DIR: u'', + GC_DRIVE_MAX_RESULTS: 1000, + GC_NO_BROWSER: FALSE, + GC_NO_CACHE: FALSE, + GC_NO_UPDATE_CHECK: FALSE, + GC_NO_VERIFY_SSL: FALSE, + GC_NUM_THREADS: 5, + GC_OAUTH2_TXT: FN_OAUTH2_TXT, + GC_OAUTH2SERVICE_JSON: FN_OAUTH2SERVICE_JSON, + GC_SECTION: u'', + GC_SHOW_COUNTS_MIN: 1, + GC_SHOW_GETTINGS: TRUE, + GC_SITE_DIR: u'', + GC_USER_BATCH_SIZE: 50, + GC_USER_MAX_RESULTS: 500, + } -gamPath = None -gamSiteConfigDir = None -gamUserConfigDir = None -gamDriveDir = None -gamCacheDir = None +GC_Values = {} + +GC_TYPE_BOOLEAN = u'bool' +GC_TYPE_CHOICE = u'choi' +GC_TYPE_DIRECTORY = u'dire' +GC_TYPE_EMAIL = u'emai' +GC_TYPE_FILE = u'file' +GC_TYPE_INTEGER = u'inte' +GC_TYPE_LANGUAGE = u'lang' +GC_TYPE_STRING = u'stri' + +GC_VAR_TYPE_KEY = u'type' +GC_VAR_LIMITS_KEY = u'lmit' + +GC_VAR_INFO = { + GC_ACTIVITY_MAX_RESULTS: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, 500)}, + GC_AUTO_BATCH_MIN: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (0, None)}, + GC_CACHE_DIR: {GC_VAR_TYPE_KEY: GC_TYPE_DIRECTORY}, + GC_CHARSET: {GC_VAR_TYPE_KEY: GC_TYPE_STRING}, + GC_CLIENT_SECRETS_JSON: {GC_VAR_TYPE_KEY: GC_TYPE_FILE}, + GC_CONFIG_DIR: {GC_VAR_TYPE_KEY: GC_TYPE_DIRECTORY}, + GC_CUSTOMER_ID: {GC_VAR_TYPE_KEY: GC_TYPE_STRING}, + GC_DEBUG_LEVEL: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (0, None)}, + GC_DEVICE_MAX_RESULTS: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, 1000)}, + GC_DOMAIN: {GC_VAR_TYPE_KEY: GC_TYPE_STRING}, + GC_DRIVE_DIR: {GC_VAR_TYPE_KEY: GC_TYPE_DIRECTORY}, + GC_DRIVE_MAX_RESULTS: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, 1000)}, + GC_NO_BROWSER: {GC_VAR_TYPE_KEY: GC_TYPE_BOOLEAN}, + GC_NO_CACHE: {GC_VAR_TYPE_KEY: GC_TYPE_BOOLEAN}, + GC_NO_UPDATE_CHECK: {GC_VAR_TYPE_KEY: GC_TYPE_BOOLEAN}, + GC_NO_VERIFY_SSL: {GC_VAR_TYPE_KEY: GC_TYPE_BOOLEAN}, + GC_NUM_THREADS: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, None)}, + GC_OAUTH2_TXT: {GC_VAR_TYPE_KEY: GC_TYPE_FILE}, + GC_OAUTH2SERVICE_JSON: {GC_VAR_TYPE_KEY: GC_TYPE_FILE}, + GC_SECTION: {GC_VAR_TYPE_KEY: GC_TYPE_STRING}, + GC_SHOW_COUNTS_MIN: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (0, None)}, + GC_SHOW_GETTINGS: {GC_VAR_TYPE_KEY: GC_TYPE_BOOLEAN}, + GC_SITE_DIR: {GC_VAR_TYPE_KEY: GC_TYPE_DIRECTORY}, + GC_USER_BATCH_SIZE: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, 1000)}, + GC_USER_MAX_RESULTS: {GC_VAR_TYPE_KEY: GC_TYPE_INTEGER, GC_VAR_LIMITS_KEY: (1, 500)}, + } MESSAGE_CLIENT_API_ACCESS_DENIED = u'Access Denied. Please make sure the Client Name:\n\n{0}\n\nis authorized for the API Scope(s):\n\n{1}\n\nThis can be configured in your Control Panel under:\n\nSecurity -->\nAdvanced Settings -->\nManage API client access' MESSAGE_GAM_EXITING_FOR_UPDATE = u'GAM is now exiting so that you can overwrite this old version with the latest release' @@ -105,9 +267,9 @@ def convertUTF8(data): if isinstance(data, str): return data if isinstance(data, unicode): - if os.name == u'nt': + if GM_Globals[GM_WINDOWS]: return data - return data.encode('utf-8') + return data.encode(GM_Globals[GM_SYS_ENCODING]) if isinstance(data, collections.Mapping): return dict(map(convertUTF8, data.iteritems())) if isinstance(data, collections.Iterable): @@ -256,28 +418,95 @@ def writeFile(filename, data, mode=u'wb', continueOnError=False, displayError=Tr sys.stderr.write(u'{0}{1}\n'.format(ERROR_PREFIX, e)) return False systemErrorExit(6, e) - +# +# Set global variables +# Check for GAM updates based on status of noupdatecheck.txt +# def SetGlobalVariables(): - global gamPath, gamSiteConfigDir, gamUserConfigDir, gamDriveDir, gamCacheDir - 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) - if not os.path.isfile(os.path.join(gamUserConfigDir, u'noupdatecheck.txt')): + + def _getOldEnvVar(itemName, envVar): + value = os.environ.get(envVar, GC_Defaults[itemName]) + if GC_VAR_INFO[itemName][GC_VAR_TYPE_KEY] == GC_TYPE_INTEGER: + try: + number = int(value) + minVal, maxVal = GC_VAR_INFO[itemName][GC_VAR_LIMITS_KEY] + if number < minVal: + number = minVal + elif maxVal and (number > maxVal): + number = maxVal + except ValueError: + number = GC_Defaults[itemName] + value = number + GC_Defaults[itemName] = value + + def _getOldSignalFile(itemName, fileName, trueValue=True, falseValue=False): + GC_Defaults[itemName] = trueValue if os.path.isfile(os.path.join(GC_Defaults[GC_CONFIG_DIR], fileName)) else falseValue + + def _getCfgDirectory(itemName): + return GC_Defaults[itemName] + + def _getCfgFile(itemName): + value = os.path.expanduser(GC_Defaults[itemName]) + if not os.path.isabs(value): + value = os.path.expanduser(os.path.join(GC_Values[GC_CONFIG_DIR], value)) + return value + + GC_Defaults[GC_CONFIG_DIR] = GM_Globals[GM_GAM_PATH] + GC_Defaults[GC_CACHE_DIR] = os.path.join(GM_Globals[GM_GAM_PATH], u'gamcache') + GC_Defaults[GC_DRIVE_DIR] = GM_Globals[GM_GAM_PATH] + GC_Defaults[GC_SITE_DIR] = GM_Globals[GM_GAM_PATH] + + _getOldEnvVar(GC_CONFIG_DIR, u'GAMUSERCONFIGDIR') + _getOldEnvVar(GC_SITE_DIR, u'GAMSITECONFIGDIR') + _getOldEnvVar(GC_CACHE_DIR, u'GAMCACHEDIR') + _getOldEnvVar(GC_DRIVE_DIR, u'GAMDRIVEDIR') + _getOldEnvVar(GC_OAUTH2_TXT, u'OAUTHFILE') + _getOldEnvVar(GC_OAUTH2SERVICE_JSON, u'OAUTHSERVICEFILE') + if GC_Defaults[GC_OAUTH2SERVICE_JSON].find(u'.') == -1: + GC_Defaults[GC_OAUTH2SERVICE_JSON] += u'.json' + _getOldEnvVar(GC_CLIENT_SECRETS_JSON, u'CLIENTSECRETS') + _getOldEnvVar(GC_DOMAIN, u'GA_DOMAIN') + _getOldEnvVar(GC_CUSTOMER_ID, u'CUSTOMER_ID') + _getOldEnvVar(GC_CHARSET, u'GAM_CHARSET') + _getOldEnvVar(GC_NUM_THREADS, u'GAM_THREADS') + _getOldEnvVar(GC_AUTO_BATCH_MIN, u'GAM_AUTOBATCH') + _getOldEnvVar(GC_ACTIVITY_MAX_RESULTS, u'GAM_ACTIVITY_MAX_RESULTS') + _getOldEnvVar(GC_DEVICE_MAX_RESULTS, u'GAM_DEVICE_MAX_RESULTS') + _getOldEnvVar(GC_DRIVE_MAX_RESULTS, u'GAM_DRIVE_MAX_RESULTS') + _getOldEnvVar(GC_USER_MAX_RESULTS, u'GAM_USER_MAX_RESULTS') + _getOldSignalFile(GC_DEBUG_LEVEL, u'debug.gam', trueValue=4, falseValue=0) + _getOldSignalFile(GC_NO_VERIFY_SSL, u'noverifyssl.txt') + _getOldSignalFile(GC_NO_BROWSER, u'nobrowser.txt') + _getOldSignalFile(GC_NO_CACHE, u'nocache.txt') + _getOldSignalFile(GC_NO_UPDATE_CHECK, u'noupdatecheck.txt') +# Assign directories first + for itemName in GC_VAR_INFO: + if GC_VAR_INFO[itemName][GC_VAR_TYPE_KEY] == GC_TYPE_DIRECTORY: + GC_Values[itemName] = _getCfgDirectory(itemName) + for itemName in GC_VAR_INFO: + varType = GC_VAR_INFO[itemName][GC_VAR_TYPE_KEY] + if varType == GC_TYPE_FILE: + GC_Values[itemName] = _getCfgFile(itemName) + else: + GC_Values[itemName] = GC_Defaults[itemName] + GM_Globals[GM_LAST_UPDATE_CHECK_TXT] = os.path.join(GC_Values[GC_CONFIG_DIR], FN_LAST_UPDATE_CHECK_TXT) + if not GC_Values[GC_NO_UPDATE_CHECK]: doGAMCheckForUpdates() - if os.path.isfile(os.path.join(gamUserConfigDir, u'debug.gam')): - httplib2.debuglevel = 4 - extra_args[u'prettyPrint'] = True - if os.path.isfile(os.path.join(gamUserConfigDir, FN_EXTRA_ARGS_TXT)): +# Globals derived from config file values + GM_Globals[GM_OAUTH2SERVICE_KEY] = None + GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_EMAIL] = None + GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID] = None + GM_Globals[GM_EXTRA_ARGS_DICT] = {u'prettyPrint': GC_Values[GC_DEBUG_LEVEL] > 0} + httplib2.debuglevel = GC_Values[GC_DEBUG_LEVEL] + if os.path.isfile(os.path.join(GC_Values[GC_CONFIG_DIR], FN_EXTRA_ARGS_TXT)): import ConfigParser - config = ConfigParser.ConfigParser() - config.optionxform = str - config.read(os.path.join(gamUserConfigDir, FN_EXTRA_ARGS_TXT)) - extra_args.update(dict(config.items(u'extra-args'))) + ea_config = ConfigParser.ConfigParser() + ea_config.optionxform = str + ea_config.read(os.path.join(GC_Values[GC_CONFIG_DIR], FN_EXTRA_ARGS_TXT)) + GM_Globals[GM_EXTRA_ARGS_DICT].update(dict(ea_config.items(u'extra-args'))) + if GC_Values[GC_NO_CACHE]: + GC_Values[GC_CACHE_DIR] = None + return True def doGAMCheckForUpdates(forceCheck=False): import urllib2 @@ -287,7 +516,7 @@ def doGAMCheckForUpdates(forceCheck=False): return now_time = calendar.timegm(time.gmtime()) if not forceCheck: - last_check_time = readFile(os.path.join(gamUserConfigDir, FN_LAST_UPDATE_CHECK_TXT), continueOnError=True, displayError=forceCheck) + last_check_time = readFile(GM_Globals[GM_LAST_UPDATE_CHECK_TXT], continueOnError=True, displayError=forceCheck) if last_check_time == None: last_check_time = 0 if last_check_time > now_time-604800: @@ -301,7 +530,7 @@ def doGAMCheckForUpdates(forceCheck=False): if forceCheck or (latest_version > current_version): print u'Version: Check, Current: {0:.2f}, Latest: {1:.2f}'.format(current_version, latest_version) if latest_version <= current_version: - writeFile(os.path.join(gamUserConfigDir, FN_LAST_UPDATE_CHECK_TXT), str(now_time), continueOnError=True, displayError=forceCheck) + writeFile(GM_Globals[GM_LAST_UPDATE_CHECK_TXT], str(now_time), continueOnError=True, displayError=forceCheck) return a = urllib2.urlopen(GAM_APPSPOT_LATEST_VERSION_ANNOUNCEMENT) announcement = a.read() @@ -314,7 +543,7 @@ def doGAMCheckForUpdates(forceCheck=False): webbrowser.open(GAM_RELEASES) printLine(MESSAGE_GAM_EXITING_FOR_UPDATE) sys.exit(0) - writeFile(os.path.join(gamUserConfigDir, FN_LAST_UPDATE_CHECK_TXT), str(now_time), continueOnError=True, displayError=forceCheck) + writeFile(GM_Globals[GM_LAST_UPDATE_CHECK_TXT], str(now_time), continueOnError=True, displayError=forceCheck) return except (urllib2.HTTPError, urllib2.URLError): return @@ -327,22 +556,22 @@ def doGAMVersion(): struct.calcsize('P')*8, sys.version_info[3], googleapiclient.__version__, platform.platform(), platform.machine(), - gamPath) + GM_Globals[GM_GAM_PATH]) def tryOAuth(gdataObject): - global domain - global customerId - storage = oauth2client.file.Storage(os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', FN_OAUTH2_TXT))) + storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) credentials = storage.get() if credentials is None or credentials.invalid: doRequestOAuth() credentials = storage.get() if credentials.access_token_expired: - credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt')))) + credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL])) 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') - gdataObject.domain = domain + if not GC_Values[GC_DOMAIN]: + GC_Values[GC_DOMAIN] = credentials.id_token.get(u'hd', UNKNOWN).lower() + if not GC_Values[GC_CUSTOMER_ID]: + GC_Values[GC_CUSTOMER_ID] = MY_CUSTOMER + gdataObject.domain = GC_Values[GC_DOMAIN] return True def checkGDataError(e, service): @@ -427,7 +656,7 @@ def callGData(service, function, soft_errors=False, throw_errors=[], **kwargs): def callGAPI(service, function, silent_errors=False, soft_errors=False, throw_reasons=[], retry_reasons=[], **kwargs): method = getattr(service, function) retries = 10 - parameters = dict(kwargs.items() + extra_args.items()) + parameters = dict(kwargs.items() + GM_Globals[GM_EXTRA_ARGS_DICT].items()) for n in range(1, retries+1): try: return method(**parameters).execute() @@ -436,7 +665,7 @@ def callGAPI(service, function, silent_errors=False, soft_errors=False, throw_re error = json.loads(e.content) except ValueError: if n < 3: - service._http.request.credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt')))) + service._http.request.credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL])) continue if (e.resp[u'status'] == u'503') and (e.content == u'Quota exceeded for the current request'): time.sleep(1) @@ -555,7 +784,7 @@ def getAPIScope(api): def getServiceFromDiscoveryDocument(api, version, http): disc_filename = u'%s-%s.json' % (api, version) - disc_file = os.path.join(gamSiteConfigDir, disc_filename) + disc_file = os.path.join(GC_Values[GC_SITE_DIR], disc_filename) if hasattr(sys, '_MEIPASS'): pyinstaller_disc_file = os.path.join(sys._MEIPASS, disc_filename) else: @@ -569,14 +798,13 @@ def getServiceFromDiscoveryDocument(api, version, http): return googleapiclient.discovery.build_from_document(discovery, base=u'https://www.googleapis.com', http=http) def buildGAPIObject(api): - global domain, customerId - storage = oauth2client.file.Storage(os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', FN_OAUTH2_TXT))) + storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) credentials = storage.get() - if credentials is None or credentials.invalid: + if not credentials or credentials.invalid: doRequestOAuth() credentials = storage.get() credentials.user_agent = GAM_INFO - http = credentials.authorize(httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt')), cache=gamCacheDir)) + http = credentials.authorize(httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL], cache=GC_Values[GC_CACHE_DIR])) version = getAPIVer(api) if api in [u'directory', u'reports', u'datatransfer']: api = u'admin' @@ -588,44 +816,58 @@ def buildGAPIObject(api): systemErrorExit(4, e) except httplib2.CertificateValidationUnsupported: noPythonSSLExit() - try: - domain = os.environ[u'GA_DOMAIN'] - _, customerId_result = service._http.request(u'https://www.googleapis.com/admin/directory/v1/users?domain=%s&maxResults=1&fields=users(customerId)' % domain) - customerId_obj = json.loads(customerId_result) - customerId = customerId_obj[u'users'][0][u'customerId'] - except KeyError: - try: - domain = credentials.id_token[u'hd'] - except (TypeError, KeyError): - domain = UNKNOWN_DOMAIN - customerId = MY_CUSTOMER + if GC_Values[GC_DOMAIN]: + if not GC_Values[GC_CUSTOMER_ID]: + resp, result = service._http.request(u'https://www.googleapis.com/admin/directory/v1/users?domain={0}&maxResults=1&fields=users(customerId)'.format(GC_Values[GC_DOMAIN])) + try: + resultObj = json.loads(result) + except ValueError: + systemErrorExit(8, u'Unexpected response: {0}'.format(result)) + if resp[u'status'] in [u'403', u'404']: + try: + message = resultObj[u'error'][u'errors'][0][u'message'] + except KeyError: + message = resultObj[u'error'][u'message'] + systemErrorExit(8, u'{0} - {1}'.format(message, GC_Values[GC_DOMAIN])) + try: + GC_Values[GC_CUSTOMER_ID] = resultObj[u'users'][0][u'customerId'] + except KeyError: + GC_Values[GC_CUSTOMER_ID] = MY_CUSTOMER + else: + GC_Values[GC_DOMAIN] = credentials.id_token.get(u'hd', UNKNOWN).lower() + if not GC_Values[GC_CUSTOMER_ID]: + GC_Values[GC_CUSTOMER_ID] = MY_CUSTOMER return service -def buildGAPIServiceObject(api, act_as=None, soft_errors=False): - oauth2servicefile = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHSERVICEFILE', 'oauth2service')) - oauth2servicefilejson = u'%s.json' % oauth2servicefile - oauth2servicefilep12 = u'%s.p12' % oauth2servicefile - json_string = readFile(oauth2servicefilejson, continueOnError=True, displayError=True) - if not json_string: - printLine(MESSAGE_WIKI_INSTRUCTIONS_OAUTH2SERVICE_JSON) - printLine(GAM_WIKI_CREATE_CLIENT_SECRETS) - sys.exit(6) - json_data = json.loads(json_string) - try: - SERVICE_ACCOUNT_EMAIL = json_data[u'web'][u'client_email'] - SERVICE_ACCOUNT_CLIENT_ID = json_data[u'web'][u'client_id'] - key = readFile(oauth2servicefilep12) - except KeyError: - # new format with config and data in the .json file... - SERVICE_ACCOUNT_EMAIL = json_data[u'client_email'] - SERVICE_ACCOUNT_CLIENT_ID = json_data[u'client_id'] - key = json_data[u'private_key'] +def buildGAPIServiceObject(api, act_as, soft_errors=False): + if not GM_Globals[GM_OAUTH2SERVICE_KEY]: + json_string = readFile(GC_Values[GC_OAUTH2SERVICE_JSON], continueOnError=True, displayError=True) + if not json_string: + printLine(MESSAGE_WIKI_INSTRUCTIONS_OAUTH2SERVICE_JSON) + printLine(GAM_WIKI_CREATE_CLIENT_SECRETS) + systemErrorExit(6, None) + json_data = json.loads(json_string) + try: + # new format with config and key in the .json file... + GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_EMAIL] = json_data[u'client_email'] + GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID] = json_data[u'client_id'] + GM_Globals[GM_OAUTH2SERVICE_KEY] = json_data[u'private_key'] + except KeyError: + try: + # old format with config in the .json file and key in the .p12 file... + GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_EMAIL] = json_data[u'web'][u'client_email'] + GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID] = json_data[u'web'][u'client_id'] + GM_Globals[GM_OAUTH2SERVICE_KEY] = readFile(GC_Values[GC_OAUTH2SERVICE_JSON].replace(u'.json', u'.p12')) + except KeyError: + printLine(MESSAGE_WIKI_INSTRUCTIONS_OAUTH2SERVICE_JSON) + printLine(GAM_WIKI_CREATE_CLIENT_SECRETS) + systemErrorExit(17, MESSAGE_OAUTH2SERVICE_JSON_INVALID.format(GC_Values[GC_OAUTH2SERVICE_JSON])) scope = getAPIScope(api) - if act_as == None: - credentials = oauth2client.client.SignedJwtAssertionCredentials(SERVICE_ACCOUNT_EMAIL, key, scope=scope, user_agent=GAM_INFO) - else: - credentials = oauth2client.client.SignedJwtAssertionCredentials(SERVICE_ACCOUNT_EMAIL, key, scope=scope, user_agent=GAM_INFO, sub=act_as) - http = credentials.authorize(httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt')), cache=gamCacheDir)) + credentials = oauth2client.client.SignedJwtAssertionCredentials(GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_EMAIL], + GM_Globals[GM_OAUTH2SERVICE_KEY], + scope=scope, user_agent=GAM_INFO, sub=act_as) + http = credentials.authorize(httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL], + cache=GC_Values[GC_CACHE_DIR])) version = getAPIVer(api) try: return googleapiclient.discovery.build(api, version, http=http) @@ -637,7 +879,7 @@ def buildGAPIServiceObject(api, act_as=None, soft_errors=False): if e.message in [u'access_denied', u'unauthorized_client: Unauthorized client or scope in request.', u'access_denied: Requested client not authorized.']: - systemErrorExit(5, MESSAGE_CLIENT_API_ACCESS_DENIED.format(SERVICE_ACCOUNT_CLIENT_ID, u','.join(scope))) + systemErrorExit(5, MESSAGE_CLIENT_API_ACCESS_DENIED.format(GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID], u','.join(scope))) sys.stderr.write(u'{0}{1}\n'.format(ERROR_PREFIX, e)) if soft_errors: return False @@ -649,7 +891,7 @@ def buildDiscoveryObject(api): if api in [u'directory', u'reports']: api = u'admin' params = {'api': api, 'apiVersion': version} - http = httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt')), cache=gamCacheDir) + http = httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL], cache=GC_Values[GC_CACHE_DIR]) requested_url = uritemplate.expand(googleapiclient.discovery.DISCOVERY_URI, params) resp, content = http.request(requested_url) if resp.status == 404: @@ -669,7 +911,7 @@ def commonAppsObjInit(appsObj): #Identify GAM to Google's Servers appsObj.source = GAM_INFO #Show debugging output if debug.gam exists - if os.path.isfile(os.path.join(gamUserConfigDir, u'debug.gam')): + if GC_Values[GC_DEBUG_LEVEL] > 0: appsObj.debug = True return appsObj @@ -711,9 +953,9 @@ def geturl(url, dst): closeFile(f) def showReport(): - report = sys.argv[2].lower() - global customerId rep = buildGAPIObject(u'reports') + report = sys.argv[2].lower() + customerId = GC_Values[GC_CUSTOMER_ID] if customerId == MY_CUSTOMER: customerId = None date = filters = parameters = actorIpAddress = startTime = endTime = eventName = None @@ -878,7 +1120,7 @@ def doDelegates(users): if sys.argv[4].lower() == u'to': delegate = sys.argv[5].lower() if not delegate.find(u'@') > 0: - delegate_domain = domain.lower() + delegate_domain = GC_Values[GC_DOMAIN].lower() delegate_email = u'%s@%s' % (delegate, delegate_domain) else: delegate_domain = delegate[delegate.find(u'@')+1:].lower() @@ -894,7 +1136,7 @@ def doDelegates(users): delegator_email = delegator delegator = delegator[:delegator.find('@')] else: - delegator_domain = domain.lower() + delegator_domain = GC_Values[GC_DOMAIN].lower() delegator_email = u'%s@%s' % (delegator, delegator_domain) emailsettings.domain = delegator_domain print u"Giving %s delegate access to %s (%s of %s)" % (delegate_email, delegator_email, i, count) @@ -996,7 +1238,7 @@ def getDelegates(users): emailsettings.domain = user[user.find('@')+1:] user = user[:user.find('@')] else: - emailsettings.domain = domain + emailsettings.domain = GC_Values[GC_DOMAIN] sys.stderr.write(u"Getting delegates for %s...\n" % (user + '@' + emailsettings.domain)) delegates = callGData(service=emailsettings, function=u'GetDelegates', soft_errors=True, delegator=user) try: @@ -1015,7 +1257,7 @@ def deleteDelegate(users): if users[0].find(u'@') > 0: delegatedomain = users[0][users[0].find(u'@')+1:] else: - delegatedomain = domain + delegatedomain = GC_Values[GC_DOMAIN] delegate = delegate+u'@'+delegatedomain count = len(users) i = 1 @@ -1024,7 +1266,7 @@ def deleteDelegate(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Deleting %s delegate access to %s (%s of %s)" % (delegate, user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'DeleteDelegate', delegate=delegate, delegator=user) @@ -1159,7 +1401,7 @@ def doCreateDomain(): cd = buildGAPIObject(u'directory') domain_name = sys.argv[3] body = {u'domainName': domain_name} - callGAPI(service=cd.domains(), function=u'insert', customer=customerId, body=body) + callGAPI(service=cd.domains(), function=u'insert', customer=GC_Values[GC_CUSTOMER_ID], body=body) print u'Added domain %s' % domain_name def doCreateDomainAlias(): @@ -1167,7 +1409,7 @@ def doCreateDomainAlias(): body = {} body[u'domainAliasName'] = sys.argv[3] body[u'parentDomainName'] = sys.argv[4] - callGAPI(service=cd.domainAliases(), function=u'insert', customer=customerId, body=body) + callGAPI(service=cd.domainAliases(), function=u'insert', customer=GC_Values[GC_CUSTOMER_ID], body=body) def doUpdateDomain(): cd = buildGAPIObject(u'directory') @@ -1181,16 +1423,16 @@ def doUpdateDomain(): else: print u'ERROR: %s is not a valid argument for "gam update domain"' % sys.argv[i] sys.exit(2) - callGAPI(service=cd.customers(), function=u'update', customerKey=customerId, body=body) + callGAPI(service=cd.customers(), function=u'update', customerKey=GC_Values[GC_CUSTOMER_ID], body=body) print u'%s is now the primary domain.' % domain_name def doGetDomainInfo(): if (len(sys.argv) < 4) or (sys.argv[3] == u'logo'): doGetInstanceInfo() return - domainName = sys.argv[3] cd = buildGAPIObject(u'directory') - result = callGAPI(service=cd.domains(), function=u'get', customer=customerId, domainName=domainName) + domainName = sys.argv[3] + result = callGAPI(service=cd.domains(), function=u'get', customer=GC_Values[GC_CUSTOMER_ID], domainName=domainName) if u'creationTime' in result: result[u'creationTime'] = unicode(datetime.datetime.fromtimestamp(int(result[u'creationTime'])/1000)) if u'domainAliases' in result: @@ -1200,16 +1442,16 @@ def doGetDomainInfo(): print_json(None, result) def doGetDomainAliasInfo(): - alias = sys.argv[3] cd = buildGAPIObject(u'directory') - result = callGAPI(service=cd.domainAliases(), function=u'get', customer=customerId, domainAliasName=alias) + alias = sys.argv[3] + result = callGAPI(service=cd.domainAliases(), function=u'get', customer=GC_Values[GC_CUSTOMER_ID], domainAliasName=alias) if u'creationTime' in result: result[u'creationTime'] = unicode(datetime.datetime.fromtimestamp(int(result[u'creationTime'])/1000)) print_json(None, result) def doGetCustomerInfo(): cd = buildGAPIObject(u'directory') - customer_info = callGAPI(service=cd.customers(), function=u'get', customerKey=customerId) + customer_info = callGAPI(service=cd.customers(), function=u'get', customerKey=GC_Values[GC_CUSTOMER_ID]) print_json(None, customer_info) def doUpdateCustomer(): @@ -1249,25 +1491,25 @@ def doUpdateCustomer(): else: print u'ERROR: %s is not a valid argument for "gam update customer"' % myarg sys.exit(2) - callGAPI(service=cd.customers(), function=u'update', customerKey=customerId, body=body) + callGAPI(service=cd.customers(), function=u'update', customerKey=GC_Values[GC_CUSTOMER_ID], body=body) print u'Updated customer' def doDelDomain(): - domainName = sys.argv[3] cd = buildGAPIObject(u'directory') - callGAPI(service=cd.domains(), function=u'delete', customer=customerId, domainName=domainName) + domainName = sys.argv[3] + callGAPI(service=cd.domains(), function=u'delete', customer=GC_Values[GC_CUSTOMER_ID], domainName=domainName) def doDelDomainAlias(): - domainAliasName = sys.argv[3] cd = buildGAPIObject(u'directory') - callGAPI(service=cd.domainAliases(), function=u'delete', customer=customerId, domainAliasName=domainAliasName) + domainAliasName = sys.argv[3] + callGAPI(service=cd.domainAliases(), function=u'delete', customer=GC_Values[GC_CUSTOMER_ID], domainAliasName=domainAliasName) def doPrintDomains(): + cd = buildGAPIObject(u'directory') titles = [] domains_attributes = [{}] todrive = False - cd = buildGAPIObject(u'directory') - domains = callGAPI(service=cd.domains(), function=u'list', customer=customerId) + domains = callGAPI(service=cd.domains(), function=u'list', customer=GC_Values[GC_CUSTOMER_ID]) i = 3 while i < len(sys.argv): if sys.argv[i].lower() == u'todrive': @@ -1315,7 +1557,7 @@ def doDelAdmin(): roleAssignmentId = sys.argv[3] print u'Deleting Admin Role Assignment %s' % roleAssignmentId callGAPI(service=cd.roleAssignments(), function=u'delete', - customer=customerId, roleAssignmentId=roleAssignmentId) + customer=GC_Values[GC_CUSTOMER_ID], roleAssignmentId=roleAssignmentId) def doCreateAdmin(): cd = buildGAPIObject(u'directory') @@ -1325,8 +1567,8 @@ def doCreateAdmin(): body[u'assignedTo'] = user[4:] else: print user[:3] - body[u'assignedTo'] = callGAPI(service=cd.users(), function=u'get', userKey=user, - projection=u'basic', fields=u'id')[u'id'] + body[u'assignedTo'] = callGAPI(service=cd.users(), function=u'get', + userKey=user, projection=u'basic', fields=u'id')[u'id'] role = sys.argv[4] if role[:4].lower() == u'uid:': body[u'roleId'] = role[4:] @@ -1347,15 +1589,15 @@ def doCreateAdmin(): if orgUnit[0] == u'/': orgUnit = orgUnit[1:] body[u'orgUnitId'] = callGAPI(service=cd.orgunits(), function=u'get', - customerId=customerId, orgUnitPath=orgUnit, - fields=u'orgUnitId')[u'orgUnitId'][3:] + customerId=GC_Values[GC_CUSTOMER_ID], orgUnitPath=orgUnit, + fields=u'orgUnitId')[u'orgUnitId'][3:] if body[u'scopeType'] == u'CUSTOMER': scope = u'customer' else: scope = orgUnit print u'Giving %s admin role %s for %s' % (user, role, scope) callGAPI(service=cd.roleAssignments(), function=u'insert', - customer=customerId, body=body) + customer=GC_Values[GC_CUSTOMER_ID], body=body) def doPrintAdmins(): cd = buildGAPIObject(u'directory') @@ -1377,7 +1619,7 @@ def doPrintAdmins(): sys.exit(5) i += 2 admins = callGAPIpages(service=cd.roleAssignments(), function=u'list', - customer=customerId, maxResults=200, userKey=userKey, roleId=roleId) + customer=GC_Values[GC_CUSTOMER_ID], userKey=userKey, roleId=roleId, maxResults=200) admins_attrib = [{}] for admin in admins: admin_attrib = {} @@ -1405,57 +1647,56 @@ def doPrintAdmins(): admins_attrib.append(admin_attrib) output_csv(admins_attrib, admins_attrib[0], u'Admins', False) +def buildOrgUnitIdToNameMap(): + cd = buildGAPIObject(u'directory') + result = callGAPI(service=cd.orgunits(), function=u'list', + customerId=GC_Values[GC_CUSTOMER_ID], + fields=u'organizationUnits(orgUnitPath,orgUnitId)') + GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME] = {} + for orgUnit in result[u'organizationUnits']: + GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME][orgUnit[u'orgUnitId']] = orgUnit[u'orgUnitPath'] + def orgunit_from_orgunitid(orgunitid): - global orgunit_mappings - try: - orgunit_mappings - except NameError: - cd = buildGAPIObject(u'directory') - orgunit_mappings = callGAPI(service=cd.orgunits(), function=u'list', - customerId=customerId, - fields=u'organizationUnits(orgUnitPath,orgUnitId)') - for orgunit_mapping in orgunit_mappings[u'organizationUnits']: - if orgunit_mapping[u'orgUnitId'] == u'id:%s' % orgunitid: - return orgunit_mapping[u'orgUnitPath'] + if not GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME]: + buildOrgUnitIdToNameMap() + return GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME][u'id:%s' % orgunitid] + +def buildRoleIdToNameToIdMap(): + cd = buildGAPIObject(u'directory') + result = callGAPIpages(service=cd.roles(), function=u'list', items=u'items', + customer=GC_Values[GC_CUSTOMER_ID], + fields=u'nextPageToken,items(roleId,roleName)', + maxResults=100) + GM_Globals[GM_MAP_ROLE_ID_TO_NAME] = {} + GM_Globals[GM_MAP_ROLE_NAME_TO_ID] = {} + for role in result: + GM_Globals[GM_MAP_ROLE_ID_TO_NAME][role[u'roleId']] = role[u'roleName'] + GM_Globals[GM_MAP_ROLE_NAME_TO_ID][role[u'roleName']] = role[u'roleId'] def role_from_roleid(roleid): - global roleid_mappings - try: - roleid_mappings - except NameError: - cd = buildGAPIObject(u'directory') - roleid_mappings = callGAPIpages(service=cd.roles(), function=u'list', - items=u'items', customer=customerId, maxResults=100, - fields=u'nextPageToken,items(roleId,roleName)') - for roleid_mapping in roleid_mappings: - if roleid_mapping[u'roleId'] == roleid: - return roleid_mapping[u'roleName'] + if not GM_Globals[GM_MAP_ROLE_ID_TO_NAME]: + buildRoleIdToNameToIdMap() + return GM_Globals[GM_MAP_ROLE_ID_TO_NAME][roleid] def roleid_from_role(role): - global roleid_mappings - try: - roleid_mappings - except NameError: - cd = buildGAPIObject(u'directory') - roleid_mappings = callGAPIpages(service=cd.roles(), function=u'list', - items=u'items', customer=customerId, maxResults=100, - fields=u'nextPageToken,items(roleId,roleName)') - for roleid_mapping in roleid_mappings: - if roleid_mapping[u'roleName'] == role: - return roleid_mapping[u'roleId'] + if not GM_Globals[GM_MAP_ROLE_NAME_TO_ID]: + buildRoleIdToNameToIdMap() + return GM_Globals[GM_MAP_ROLE_NAME_TO_ID][role] + +def buildUserIdToNameMap(): + cd = buildGAPIObject(u'directory') + result = callGAPIpages(service=cd.users(), function=u'list', items=u'users', + customer=GC_Values[GC_CUSTOMER_ID], + fields=u'nextPageToken,users(id,primaryEmail)', + maxResults=GC_Values[GC_USER_MAX_RESULTS]) + GM_Globals[GM_MAP_USER_ID_TO_NAME] = {} + for user in result: + GM_Globals[GM_MAP_USER_ID_TO_NAME][user[u'id']] = user[u'primaryEmail'] def user_from_userid(userid): - global userid_mappings - try: - userid_mappings - except NameError: - cd = buildGAPIObject(u'directory') - userid_mappings = callGAPIpages(service=cd.users(), function=u'list', - items=u'users', customer=customerId, maxResults=500, - fields=u'nextPageToken,users(id,primaryEmail)') - for user in userid_mappings: - if user[u'id'] == userid: - return user[u'primaryEmail'] + if not GM_Globals[GM_MAP_USER_ID_TO_NAME]: + buildUserIdToNameMap() + return GM_Globals[GM_MAP_USER_ID_TO_NAME][userid] SERVICE_NAME_TO_ID_MAP = { u'Drive': u'55656082996', @@ -1466,7 +1707,7 @@ def appID2app(dt, appID): for serviceName, serviceID in SERVICE_NAME_TO_ID_MAP.items(): if appID == serviceID: return serviceName - online_services = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=customerId) + online_services = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=GC_Values[GC_CUSTOMER_ID]) for online_service in online_services: if appID == online_service[u'id']: return online_service[u'name'] @@ -1485,7 +1726,7 @@ def app2appID(dt, app): serviceName = app.lower() if serviceName in SERVICE_NAME_CHOICES_MAP: return (SERVICE_NAME_CHOICES_MAP[serviceName], SERVICE_NAME_TO_ID_MAP[SERVICE_NAME_CHOICES_MAP[serviceName]]) - online_services = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=customerId) + online_services = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=GC_Values[GC_CUSTOMER_ID]) for online_service in online_services: if serviceName == online_service[u'name'].lower(): return online_service[u'id'] @@ -1495,9 +1736,9 @@ def app2appID(dt, app): def convertToUserID(user): if user[:4].lower() == u'uid:': return user[4:] - if user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) cd = buildGAPIObject(u'directory') + if user.find(u'@') == -1: + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) try: return callGAPI(service=cd.users(), function=u'get', throw_reasons=[u'notFound'], userKey=user, fields=u'id')[u'id'] except googleapiclient.errors.HttpError: @@ -1535,7 +1776,7 @@ def doCreateDataTranfer(): def doPrintTransferApps(): dt = buildGAPIObject(u'datatransfer') - apps = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=customerId) + apps = callGAPIpages(service=dt.applications(), function=u'list', items=u'applications', customerId=GC_Values[GC_CUSTOMER_ID]) for app in apps: print_json(None, app) print @@ -1565,7 +1806,7 @@ def doPrintDataTransfers(): sys.exit(2) transfers_attributes = [{}] transfers = callGAPIpages(service=dt.transfers(), function=u'list', - items=u'dataTransfers', customerId=customerId, status=status, + items=u'dataTransfers', customerId=GC_Values[GC_CUSTOMER_ID], status=status, newOwnerUserId=newOwnerUserId, oldOwnerUserId=oldOwnerUserId) for transfer in transfers: for i in range(0, len(transfer[u'applicationDataTransfers'])): @@ -1647,10 +1888,10 @@ def doCreateCourse(): print u'Created course %s' % result[u'id'] def doGetCourseInfo(): + croom = buildGAPIObject(u'classroom') courseId = sys.argv[3] if not courseId.isdigit(): courseId = u'd:%s' % courseId - croom = buildGAPIObject(u'classroom') info = callGAPI(service=croom.courses(), function=u'get', id=courseId) print_json(None, info) teachers = callGAPIpages(service=croom.courses().teachers(), function=u'list', items=u'teachers', courseId=courseId) @@ -1972,7 +2213,7 @@ def changeCalendarAttendees(users): for user in users: sys.stdout.write(u'Checking user %s\n' % user) if user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) cal = buildGAPIServiceObject(u'calendar', user) page_token = None while True: @@ -2026,10 +2267,10 @@ def deleteCalendar(users): cal = buildGAPIServiceObject(u'calendar', users[0]) calendarId = sys.argv[5] if calendarId.find(u'@') == -1: - calendarId = u'%s@%s' % (calendarId, domain) + calendarId = u'%s@%s' % (calendarId, GC_Values[GC_DOMAIN]) for user in users: if user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) cal = buildGAPIServiceObject(u'calendar', user) callGAPI(service=cal.calendarList(), function=u'delete', calendarId=calendarId) @@ -2039,7 +2280,7 @@ def addCalendar(users): body[u'defaultReminders'] = list() body[u'id'] = sys.argv[5] if body[u'id'].find(u'@') == -1: - body[u'id'] = u'%s@%s' % (body[u'id'], domain) + body[u'id'] = u'%s@%s' % (body[u'id'], GC_Values[GC_DOMAIN]) body[u'selected'] = True body[u'hidden'] = False colorRgbFormat = False @@ -2096,7 +2337,7 @@ def addCalendar(users): count = len(users) for user in users: if user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) print u"Subscribing %s to %s calendar (%s of %s)" % (user, body['id'], i, count) cal = buildGAPIServiceObject(u'calendar', user) callGAPI(service=cal.calendarList(), function=u'insert', body=body, colorRgbFormat=colorRgbFormat) @@ -2167,8 +2408,8 @@ def updateCalendar(users): callGAPI(service=cal.calendarList(), function=u'update', calendarId=calendarId, body=body, colorRgbFormat=colorRgbFormat) def doPrinterShowACL(): - show_printer = sys.argv[2] cp = buildGAPIObject(u'cloudprint') + show_printer = sys.argv[2] printer_info = callGAPI(service=cp.printers(), function=u'get', printerid=show_printer) checkCloudPrintResult(printer_info) for acl in printer_info[u'printers'][0][u'access']: @@ -2178,6 +2419,7 @@ def doPrinterShowACL(): print def doPrinterAddACL(): + cp = buildGAPIObject(u'cloudprint') printer = sys.argv[2] role = sys.argv[4].upper() scope = sys.argv[5] @@ -2190,7 +2432,6 @@ def doPrinterAddACL(): skip_notification = None elif scope.find(u'@') == -1: scope = u'/hd/domain/%s' % scope - cp = buildGAPIObject(u'cloudprint') result = callGAPI(service=cp.printers(), function=u'share', printerid=printer, role=role, scope=scope, public=public, skip_notification=skip_notification) checkCloudPrintResult(result) who = scope @@ -2200,6 +2441,7 @@ def doPrinterAddACL(): print u'Added %s %s' % (role, who) def doPrinterDelACL(): + cp = buildGAPIObject(u'cloudprint') printer = sys.argv[2] scope = sys.argv[4] public = None @@ -2208,7 +2450,6 @@ def doPrinterDelACL(): scope = None elif scope.find(u'@') == -1: scope = u'/hd/domain/%s' % scope - cp = buildGAPIObject(u'cloudprint') result = callGAPI(service=cp.printers(), function=u'unshare', printerid=printer, scope=scope, public=public) checkCloudPrintResult(result) who = scope @@ -2440,9 +2681,9 @@ def doPrinterRegister(): print u'Created printer %s' % result[u'printers'][0][u'id'] def doPrintJobResubmit(): + cp = buildGAPIObject(u'cloudprint') jobid = sys.argv[2] printerid = sys.argv[4] - cp = buildGAPIObject(u'cloudprint') ssd = '''{ "state": {"type": "HELD"} }''' @@ -2454,8 +2695,8 @@ def doPrintJobResubmit(): print u'Success resubmitting %s as job %s to printer %s' % (jobid, result[u'job'][u'id'], printerid) def doPrintJobSubmit(): - printer = sys.argv[2] cp = buildGAPIObject(u'cloudprint') + printer = sys.argv[2] content = sys.argv[4] form_fields = {u'printerid': printer, u'title': content, @@ -2495,15 +2736,15 @@ def doPrintJobSubmit(): print u'Submitted print job %s' % result[u'job'][u'id'] def doDeletePrintJob(): - job = sys.argv[2] cp = buildGAPIObject(u'cloudprint') + job = sys.argv[2] result = callGAPI(service=cp.jobs(), function=u'delete', jobid=job) checkCloudPrintResult(result) print u'Print Job %s deleted' % job def doCancelPrintJob(): - job = sys.argv[2] cp = buildGAPIObject(u'cloudprint') + job = sys.argv[2] ssd = '{"state": {"type": "ABORTED", "user_action_cause": {"action_code": "CANCELLED"}}}' result = callGAPI(service=cp.jobs(), function=u'update', jobid=job, semantic_state_diff=ssd) checkCloudPrintResult(result) @@ -2521,10 +2762,10 @@ def checkCloudPrintResult(result): sys.exit(result[u'errorCode']) def doCalendarShowACL(): - show_cal = sys.argv[2] cal = buildGAPIObject(u'calendar') + show_cal = sys.argv[2] if show_cal.find(u'@') == -1: - show_cal = u'%s@%s' % (show_cal, domain) + show_cal = u'%s@%s' % (show_cal, GC_Values[GC_DOMAIN]) acls = callGAPI(service=cal.acl(), function=u'list', calendarId=show_cal) try: for rule in acls[u'items']: @@ -2544,7 +2785,7 @@ def doCalendarAddACL(calendarId=None, act_as=None, role=None, scope=None, entity if calendarId == None: calendarId = sys.argv[2] if calendarId.find(u'@') == -1: - calendarId = u'%s@%s' % (calendarId, domain) + calendarId = u'%s@%s' % (calendarId, GC_Values[GC_DOMAIN]) if role != None: body[u'role'] = role else: @@ -2572,14 +2813,14 @@ def doCalendarAddACL(calendarId=None, act_as=None, role=None, scope=None, entity else: body[u'scope'][u'value'] = sys.argv[i].lower() if (body[u'scope'][u'type'] in [u'user', u'group']) and body[u'scope'][u'value'].find(u'@') == -1: - body[u'scope'][u'value'] = u'%s@%s' % (body[u'scope'][u'value'], domain) + body[u'scope'][u'value'] = u'%s@%s' % (body[u'scope'][u'value'], GC_Values[GC_DOMAIN]) except IndexError: pass if body[u'scope'][u'type'] == u'domain': try: body[u'scope'][u'value'] = sys.argv[6].lower() except IndexError: - body[u'scope'][u'value'] = domain + body[u'scope'][u'value'] = GC_Values[GC_DOMAIN] callGAPI(service=cal.acl(), function=u'insert', calendarId=calendarId, body=body) def doCalendarUpdateACL(): @@ -2607,7 +2848,7 @@ def doCalendarWipeData(): calendarId = sys.argv[2] cal = buildGAPIServiceObject(u'calendar', calendarId) if calendarId.find(u'@') == -1: - calendarId = u'%s@%s' % (calendarId, domain) + calendarId = u'%s@%s' % (calendarId, GC_Values[GC_DOMAIN]) callGAPI(service=cal.calendars(), function=u'clear', calendarId=calendarId) def doCalendarAddEvent(): @@ -2731,6 +2972,7 @@ def doCalendarAddEvent(): def doProfile(users): + cd = buildGAPIObject(u'directory') if sys.argv[4].lower() == u'share' or sys.argv[4].lower() == u'shared': body = {u'includeInGlobalAddressList': True} elif sys.argv[4].lower() == u'unshare' or sys.argv[4].lower() == u'unshared': @@ -2738,27 +2980,26 @@ def doProfile(users): else: print u'ERROR: value for "gam profile" must be true or false, got %s' % sys.argv[4] sys.exit(2) - cd = buildGAPIObject(u'directory') count = len(users) i = 1 for user in users: if user[:4].lower() == u'uid:': user = user[4:] elif user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) print u'Setting Profile Sharing to %s for %s (%s of %s)' % (body[u'includeInGlobalAddressList'], user, i, count) callGAPI(service=cd.users(), function=u'patch', soft_errors=True, userKey=user, body=body) i += 1 def showProfile(users): + cd = buildGAPIObject(u'directory') i = 1 count = len(users) - cd = buildGAPIObject(u'directory') for user in users: if user[:4].lower() == u'uid:': user = user[4:] elif user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) result = callGAPI(service=cd.users(), function=u'get', userKey=user, fields=u'includeInGlobalAddressList') try: print u'User: %s Profile Shared: %s (%s/%s)' % (user, result[u'includeInGlobalAddressList'], i, count) @@ -2774,7 +3015,7 @@ def doPhoto(users): if user[:4].lower() == u'uid:': user = user[4:] elif user.find('@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) filename = sys.argv[5].replace(u'#user#', user) filename = filename.replace(u'#email#', user) filename = filename.replace(u'#username#', user[:user.find(u'@')]) @@ -2807,7 +3048,7 @@ def getPhoto(users): if user[:4].lower() == u'uid:': user = user[4:] elif user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) filename = u'%s.jpg' % user print u"Saving photo to %s (%s/%s)" % (filename, i, count) i += 1 @@ -2833,7 +3074,7 @@ def deletePhoto(users): if user[:4].lower() == u'uid:': user = user[4:] elif user.find('@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) print u"Deleting photo for %s (%s of %s)" % (user, i, count) callGAPI(service=cd.users().photos(), function='delete', userKey=user) i += 1 @@ -2946,7 +3187,7 @@ def doDriveActivity(users): feed = callGAPIpages(service=activity.activities(), function=u'list', items=u'activities', page_message=page_message, source=u'drive.google.com', userId=u'me', drive_ancestorId=drive_ancestorId, groupingStrategy=u'none', - drive_fileId=drive_fileId, pageSize=100) + drive_fileId=drive_fileId, pageSize=GC_Values[GC_ACTIVITY_MAX_RESULTS]) for item in feed: activity_attributes.append(flatten_json(item[u'combinedEvent'])) for an_item in activity_attributes[-1]: @@ -3158,7 +3399,7 @@ def showDriveFiles(users): page_message = u' got %%%%total_items%%%% files for %s...\n' % user feed = callGAPIpages(service=drive.files(), function=u'list', page_message=page_message, soft_errors=True, - q=query, fields=fields, maxResults=1000) + q=query, fields=fields, maxResults=GC_Values[GC_DRIVE_MAX_RESULTS]) for f_file in feed: a_file = {u'Owner': user} for attrib in f_file: @@ -3198,7 +3439,7 @@ def doDriveSearch(drive, query=None): page_message = u' got %%total_items%% files...\n' files = callGAPIpages(service=drive.files(), function=u'list', page_message=page_message, - q=query, fields=u'nextPageToken,items(id)', maxResults=1000) + q=query, fields=u'nextPageToken,items(id)', maxResults=GC_Values[GC_DRIVE_MAX_RESULTS]) ids = list() for f_file in files: ids.append(f_file[u'id']) @@ -3251,7 +3492,7 @@ def showDriveFileTree(users): sys.stderr.write(u'Getting all files for %s...\n' % user) page_message = u' got %%%%total_items%%%% files for %s...\n' % user feed = callGAPIpages(service=drive.files(), function=u'list', page_message=page_message, - fields=u'items(id,title,parents(id),mimeType),nextPageToken', maxResults=1000) + fields=u'items(id,title,parents(id),mimeType),nextPageToken', maxResults=GC_Values[GC_DRIVE_MAX_RESULTS]) printDriveFolderContents(feed, root_folder, 0) def deleteEmptyDriveFolders(users): @@ -3266,7 +3507,7 @@ def deleteEmptyDriveFolders(users): sys.stderr.write(u'Getting folders for %s...\n' % user) page_message = u' got %%%%total_items%%%% folders for %s...\n' % user feed = callGAPIpages(service=drive.files(), function=u'list', page_message=page_message, - q=query, fields=u'items(title,id),nextPageToken', maxResults=1000) + q=query, fields=u'items(title,id),nextPageToken', maxResults=GC_Values[GC_DRIVE_MAX_RESULTS]) deleted_empty = False for folder in feed: children = callGAPI(service=drive.children(), function=u'list', @@ -3544,7 +3785,7 @@ def downloadDriveFile(users): i = 5 query = fileIds = None gdownload_format = u'openoffice' - target_folder = gamDriveDir + target_folder = GC_Values[GC_DRIVE_DIR] safe_filename_chars = "-_.() %s%s" % (string.ascii_letters, string.digits) while i < len(sys.argv): if sys.argv[i].lower() == u'id': @@ -3800,7 +4041,7 @@ def doImap(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting IMAP Access to %s for %s (%s of %s)" % (str(enable), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateImap', soft_errors=True, username=user, enable=enable) @@ -3814,7 +4055,7 @@ def getImap(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain + emailsettings.domain = GC_Values[GC_DOMAIN] imapsettings = callGData(service=emailsettings, function=u'GetImap', soft_errors=True, username=user) try: print u'User %s IMAP Enabled:%s (%s of %s)' % (user+u'@'+emailsettings.domain, imapsettings[u'enable'], i, count) @@ -3868,7 +4109,7 @@ def doLicense(users, operation): productId, skuId = getProductAndSKU(sku) for user in users: if user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) if operation == u'delete': callGAPI(service=lic.licenseAssignments(), function=operation, soft_errors=True, productId=productId, skuId=skuId, userId=user) elif operation == u'insert': @@ -3932,7 +4173,7 @@ def doPop(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting POP Access to %s for %s (%s of %s)" % (str(enable), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdatePop', soft_errors=True, username=user, enable=enable, enable_for=enable_for, action=action) @@ -3944,7 +4185,7 @@ def getPop(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain + emailsettings.domain = GC_Values[GC_DOMAIN] popsettings = callGData(service=emailsettings, function=u'GetPop', soft_errors=True, username=user) try: print u'User %s POP Enabled:%s Action:%s' % (user+u'@'+emailsettings.domain, popsettings[u'enable'], popsettings[u'action']) @@ -3968,7 +4209,7 @@ def doSendAs(users): sys.exit(2) emailsettings = getEmailSettingsObject() if sendas.find(u'@') < 0: - sendas = sendas+u'@'+domain + sendas = sendas+u'@'+GC_Values[GC_DOMAIN] count = len(users) i = 1 for user in users: @@ -3976,7 +4217,7 @@ def doSendAs(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Allowing %s to send as %s (%s of %s)" % (user+u'@'+emailsettings.domain, sendas, i, count) i += 1 callGData(service=emailsettings, function=u'CreateSendAsAlias', soft_errors=True, username=user, name=sendasName, address=sendas, make_default=make_default, reply_to=reply_to) @@ -3988,7 +4229,7 @@ def showSendAs(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain + emailsettings.domain = GC_Values[GC_DOMAIN] print u'%s has the following send as aliases:' % (user+u'@'+emailsettings.domain) sendases = callGData(service=emailsettings, function=u'GetSendAsAlias', soft_errors=True, username=user) try: @@ -4020,7 +4261,7 @@ def doLanguage(users): emailsettings.domain = user[user.find('@')+1:] user = user[:user.find('@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting the language for %s to %s (%s of %s)" % (user+u'@'+emailsettings.domain, language, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateLanguage', soft_errors=True, username=user, language=language) @@ -4041,7 +4282,7 @@ def doUTF(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting UTF-8 to %s for %s (%s of %s)" % (str(SetUTF), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateGeneral', soft_errors=True, username=user, unicode=SetUTF) @@ -4060,7 +4301,7 @@ def doPageSize(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting Page Size to %s for %s (%s of %s)" % (PageSize, user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateGeneral', soft_errors=True, username=user, page_size=PageSize) @@ -4081,7 +4322,7 @@ def doShortCuts(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting Keyboard Short Cuts to %s for %s (%s of %s)" % (str(SetShortCuts), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateGeneral', soft_errors=True, username=user, shortcuts=SetShortCuts) @@ -4102,7 +4343,7 @@ def doArrows(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting Personal Indicator Arrows to %s for %s (%s of %s)" % (str(SetArrows), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateGeneral', soft_errors=True, username=user, arrows=SetArrows) @@ -4123,7 +4364,7 @@ def doSnippets(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting Preview Snippets to %s for %s (%s of %s)" % (str(SetSnippets), user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateGeneral', soft_errors=True, username=user, snippets=SetSnippets) @@ -4162,7 +4403,7 @@ def doLabel(users): print u'ERROR: %s is not a valid argument for this command.' % sys.argv[n] sys.exit(2) for user in users: - gmail = buildGAPIServiceObject(u'gmail', act_as=user) + gmail = buildGAPIServiceObject(u'gmail', user) print u"Creating label %s for %s (%s of %s)" % (label, user, i, count) i += 1 callGAPI(service=gmail.users().labels(), function=u'create', soft_errors=True, userId=user, body=body) @@ -4190,7 +4431,7 @@ def doDeleteMessages(trashOrDelete, users): sys.exit(2) for user in users: print u'Searching messages for %s' % user - gmail = buildGAPIServiceObject(u'gmail', act_as=user) + gmail = buildGAPIServiceObject(u'gmail', user) page_message = u'Got %%%%total_items%%%% messages for user %s' % user listResult = callGAPIpages(service=gmail.users().messages(), function=u'list', items=u'messages', page_message=page_message, @@ -4202,17 +4443,17 @@ def doDeleteMessages(trashOrDelete, users): elif del_count > maxToDelete: print u'WARNING: refusing to delete ANY messages for %s since max_to_delete is %s and messages to be deleted is %s\n' % (user, maxToDelete, del_count) continue - i = 1 + i = 0 for del_me in listResult: - print u' %s message %s for user %s (%s/%s)' % (trashOrDelete, del_me[u'id'], user, i, del_count) i += 1 + print u' %s message %s for user %s (%s/%s)' % (trashOrDelete, del_me[u'id'], user, i, del_count) callGAPI(service=gmail.users().messages(), function=trashOrDelete, id=del_me[u'id'], userId=u'me') def doDeleteLabel(users): label = sys.argv[5] for user in users: - gmail = buildGAPIServiceObject(u'gmail', act_as=user) + gmail = buildGAPIServiceObject(u'gmail', user) print u'Getting all labels for %s...' % user labels = callGAPI(service=gmail.users().labels(), function=u'list', userId=user, fields=u'labels(name,id,type)') del_labels = [] @@ -4267,7 +4508,7 @@ def showLabels(users): print u'ERROR: %s is not a valid argument for "gam show labels"' % sys.argv[i] sys.exit(2) for user in users: - gmail = buildGAPIServiceObject(u'gmail', act_as=user) + gmail = buildGAPIServiceObject(u'gmail', user) labels = callGAPI(service=gmail.users().labels(), function=u'list', userId=user) for label in labels[u'labels']: if label[u'type'] == u'system' and not show_system: @@ -4292,7 +4533,7 @@ def showGmailProfile(users): profiles = [{}] for user in users: print 'Getting Gmail profile for %s' % user - gmail = buildGAPIServiceObject(u'gmail', act_as=user, soft_errors=True) + gmail = buildGAPIServiceObject(u'gmail', user, soft_errors=True) if not gmail: continue results = callGAPI(service=gmail.users(), function=u'getProfile', userId=u'me', soft_errors=True) @@ -4331,7 +4572,7 @@ def updateLabels(users): print u'ERROR: %s is not a valid argument for "gam update labels"' % sys.argv[i] sys.exit(2) for user in users: - gmail = buildGAPIServiceObject(u'gmail', act_as=user) + gmail = buildGAPIServiceObject(u'gmail', user) labels = callGAPI(service=gmail.users().labels(), function=u'list', userId=user, fields=u'labels(id,name)') label_id = None for label in labels[u'labels']: @@ -4362,7 +4603,7 @@ def renameLabels(users): sys.exit(2) pattern = re.compile(search, re.IGNORECASE) for user in users: - gmail = buildGAPIServiceObject(u'gmail', act_as=user) + gmail = buildGAPIServiceObject(u'gmail', user) labels = callGAPI(service=gmail.users().labels(), function=u'list', userId=user) for label in labels[u'labels']: if label[u'type'] == u'system': @@ -4472,7 +4713,7 @@ def doFilter(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Creating filter for %s (%s of %s)" % (user+'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'CreateFilter', soft_errors=True, @@ -4516,7 +4757,7 @@ def doForward(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Turning forward %s for %s, emails will be %s (%s of %s)" % (sys.argv[4], user+'@'+emailsettings.domain, action, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateForwarding', soft_errors=True, username=user, enable=enable, action=action, forward_to=forward_to) @@ -4528,7 +4769,7 @@ def getForward(users): emailsettings.domain = user[user.find('@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain + emailsettings.domain = GC_Values[GC_DOMAIN] forward = callGData(service=emailsettings, function=u'GetForward', soft_errors=True, username=user) try: print u"User %s: Forward To:%s Enabled:%s Action:%s" % (user+u'@'+emailsettings.domain, forward[u'forwardTo'], forward[u'enable'], forward[u'action']) @@ -4553,7 +4794,7 @@ def doSignature(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting Signature for %s (%s of %s)" % (user+u'@'+emailsettings.domain, i, count) uri = u'https://apps-apis.google.com/a/feeds/emailsettings/2.0/%s/%s/signature' % (emailsettings.domain, user) i += 1 @@ -4566,7 +4807,7 @@ def getSignature(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain + emailsettings.domain = GC_Values[GC_DOMAIN] signature = callGData(service=emailsettings, function=u'GetSignature', soft_errors=True, username=user) try: sys.stderr.write(u"User %s signature:\n " % (user+u'@'+emailsettings.domain)) @@ -4590,7 +4831,7 @@ def doWebClips(users): emailsettings.domain = user[user.find('@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Turning Web Clips %s for %s (%s of %s)" % (sys.argv[4], user+u'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateWebClipSettings', soft_errors=True, username=user, enable=enable) @@ -4641,7 +4882,7 @@ def doVacation(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain #make sure it's back at default domain + emailsettings.domain = GC_Values[GC_DOMAIN] #make sure it's back at default domain print u"Setting Vacation for %s (%s of %s)" % (user+'@'+emailsettings.domain, i, count) i += 1 callGData(service=emailsettings, function=u'UpdateVacation', @@ -4656,7 +4897,7 @@ def getVacation(users): emailsettings.domain = user[user.find(u'@')+1:] user = user[:user.find(u'@')] else: - emailsettings.domain = domain + emailsettings.domain = GC_Values[GC_DOMAIN] vacationsettings = callGData(service=emailsettings, function=u'GetVacation', soft_errors=True, username=user) try: print convertUTF8(u'''User %s @@ -4675,7 +4916,7 @@ def getVacation(users): def doDelSchema(): cd = buildGAPIObject(u'directory') schemaKey = sys.argv[3] - callGAPI(service=cd.schemas(), function=u'delete', customerId=customerId, schemaKey=schemaKey) + callGAPI(service=cd.schemas(), function=u'delete', customerId=GC_Values[GC_CUSTOMER_ID], schemaKey=schemaKey) print u'Deleted schema %s' % schemaKey def doCreateOrUpdateUserSchema(): @@ -4717,15 +4958,15 @@ def doCreateOrUpdateUserSchema(): print 'ERROR: %s is not a valid argument for "gam create schema"' % sys.argv[i] sys.exit(2) if sys.argv[1].lower() == u'create': - result = callGAPI(service=cd.schemas(), function=u'insert', customerId=customerId, body=body) + result = callGAPI(service=cd.schemas(), function=u'insert', customerId=GC_Values[GC_CUSTOMER_ID], body=body) print 'Created user schema %s' % result[u'schemaName'] elif sys.argv[1].lower() == u'update': - result = callGAPI(service=cd.schemas(), function=u'update', customerId=customerId, body=body, schemaKey=schemaName) + result = callGAPI(service=cd.schemas(), function=u'update', customerId=GC_Values[GC_CUSTOMER_ID], body=body, schemaKey=schemaName) print 'Updated user schema %s' % result[u'schemaName'] def doPrintUserSchemas(): cd = buildGAPIObject(u'directory') - schemas = callGAPI(service=cd.schemas(), function=u'list', customerId=customerId) + schemas = callGAPI(service=cd.schemas(), function=u'list', customerId=GC_Values[GC_CUSTOMER_ID]) if not schemas or u'schemas' not in schemas: return for schema in schemas[u'schemas']: @@ -4745,7 +4986,7 @@ def doPrintUserSchemas(): def doGetUserSchema(): cd = buildGAPIObject(u'directory') schemaKey = sys.argv[3] - schema = callGAPI(service=cd.schemas(), function=u'get', customerId=customerId, schemaKey=schemaKey) + schema = callGAPI(service=cd.schemas(), function=u'get', customerId=GC_Values[GC_CUSTOMER_ID], schemaKey=schemaKey) print u'Schema: %s' % schema[u'schemaName'] for a_key in schema: if a_key not in [u'schemaName', u'fields', u'etag', u'kind']: @@ -4764,7 +5005,7 @@ def doCreateUser(): body[u'name'] = dict() body[u'primaryEmail'] = sys.argv[3] if body[u'primaryEmail'].find(u'@') == -1: - body[u'primaryEmail'] = u'%s@%s' % (body[u'primaryEmail'], domain) + body[u'primaryEmail'] = u'%s@%s' % (body[u'primaryEmail'], GC_Values[GC_DOMAIN]) gotFirstName = gotLastName = do_admin = False need_to_hash_password = need_password = True i = 4 @@ -5104,12 +5345,12 @@ def doCreateUser(): callGAPI(service=cd.users(), function=u'makeAdmin', userKey=body[u'primaryEmail'], body=admin_body) def doCreateGroup(): - use_gs_api = False cd = buildGAPIObject(u'directory') + use_gs_api = False body = dict() body[u'email'] = sys.argv[3] if body[u'email'].find(u'@') == -1: - body[u'email'] = u'%s@%s' % (body[u'email'], domain) + body[u'email'] = u'%s@%s' % (body[u'email'], GC_Values[GC_DOMAIN]) got_name = False i = 4 gs_body = dict() @@ -5170,14 +5411,14 @@ def doCreateAlias(): body = dict() body[u'alias'] = sys.argv[3] if body[u'alias'].find(u'@') == -1: - body[u'alias'] = u'%s@%s' % (body[u'alias'], domain) + body[u'alias'] = u'%s@%s' % (body[u'alias'], GC_Values[GC_DOMAIN]) target_type = sys.argv[4].lower() if target_type not in [u'user', u'group', u'target']: print u'ERROR: type of target should be user or group. Got %s' % target_type sys.exit(2) targetKey = sys.argv[5] if targetKey.find(u'@') == -1: - targetKey = u'%s@%s' % (targetKey, domain) + targetKey = u'%s@%s' % (targetKey, GC_Values[GC_DOMAIN]) print u'Creating alias %s for %s %s' % (body[u'alias'], target_type, targetKey) if target_type == u'user': callGAPI(service=cd.users().aliases(), function=u'insert', userKey=targetKey, body=body) @@ -5210,11 +5451,12 @@ def doCreateOrg(): else: print u'ERROR: %s is not a valid argument for "gam create org"' % sys.argv[i] sys.exit(2) - callGAPI(service=cd.orgunits(), function=u'insert', customerId=customerId, body=body) + callGAPI(service=cd.orgunits(), function=u'insert', customerId=GC_Values[GC_CUSTOMER_ID], body=body) -def doCreateResource(): +def doCreateResourceCalendar(): + cd = buildGAPIObject(u'directory') body = {u'resourceId': sys.argv[3], - u'resourceName': sys.argv[4]} + u'resourceName': sys.argv[4]} i = 5 while i < len(sys.argv): if sys.argv[i].lower() == u'description': @@ -5226,10 +5468,9 @@ def doCreateResource(): else: print u'ERROR: %s is not a valid argument for "gam create resource"' % sys.argv[i] sys.exit(2) - cd = buildGAPIObject(u'directory') print u'Creating resource %s...' % body[u'resourceId'] callGAPI(service=cd.resources().calendars(), function=u'insert', - customer=customerId, body=body) + customer=GC_Values[GC_CUSTOMER_ID], body=body) def doUpdateUser(users): cd = buildGAPIObject(u'directory') @@ -5259,7 +5500,7 @@ def doUpdateUser(users): do_update_user = True body[u'primaryEmail'] = sys.argv[i+1] if body[u'primaryEmail'].find(u'@') == -1: - body[u'primaryEmail'] = u'%s@%s' % (body[u'primaryEmail'], domain) + body[u'primaryEmail'] = u'%s@%s' % (body[u'primaryEmail'], GC_Values[GC_DOMAIN]) i += 2 elif sys.argv[i].lower() == u'password': do_update_user = True @@ -5605,7 +5846,7 @@ def doUpdateUser(users): if user[:4].lower() == u'uid:': user = user[4:] elif user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) if u'primaryEmail' in body and body[u'primaryEmail'][:4].lower() == u'vfe@': user_primary = callGAPI(service=cd.users(), function=u'get', userKey=user, fields=u'primaryEmail,id') user = user_primary[u'id'] @@ -5648,13 +5889,13 @@ def doRemoveUsersGroups(users): print u'' def doUpdateGroup(): + cd = buildGAPIObject(u'directory') group = sys.argv[3] if sys.argv[4].lower() in [u'add', u'update', u'sync', u'remove']: - cd = buildGAPIObject(u'directory') if group[0:3].lower() == u'uid:': group = group[4:] elif group.find(u'@') == -1: - group = u'%s@%s' % (group, domain) + group = u'%s@%s' % (group, GC_Values[GC_DOMAIN]) if sys.argv[4].lower() in [u'add', u'update']: role = sys.argv[5].upper() i = 6 @@ -5667,7 +5908,7 @@ def doUpdateGroup(): users_email = [sys.argv[i],] for user_email in users_email: if user_email != u'*' and user_email.find(u'@') == -1: - user_email = u'%s@%s' % (user_email, domain) + user_email = u'%s@%s' % (user_email, GC_Values[GC_DOMAIN]) sys.stderr.write(u' %sing %s %s...' % (sys.argv[4].lower(), role.lower(), user_email)) try: if sys.argv[4].lower() == u'add': @@ -5716,7 +5957,7 @@ def doUpdateGroup(): user_emails = [sys.argv[i],] for user_email in user_emails: if user_email != u'*' and user_email.find(u'@') == -1: - user_email = u'%s@%s' % (user_email, domain) + user_email = u'%s@%s' % (user_email, GC_Values[GC_DOMAIN]) sys.stderr.write(u' removing %s\n' % user_email) result = callGAPI(service=cd.members(), function=u'delete', soft_errors=True, groupKey=group, memberKey=user_email) else: @@ -5777,13 +6018,11 @@ def doUpdateGroup(): use_cd_api = True group = group[4:] elif group.find(u'@') == -1: - cd = buildGAPIObject(u'directory') - group = u'%s@%s' % (group, domain) + group = u'%s@%s' % (group, GC_Values[GC_DOMAIN]) if use_cd_api: - cd = buildGAPIObject(u'directory') try: if cd_body[u'email'].find('@') == -1: - cd_body[u'email'] = u'%s@%s' % (cd_body[u'email'], domain) + cd_body[u'email'] = u'%s@%s' % (cd_body[u'email'], GC_Values[GC_DOMAIN]) except KeyError: pass cd_result = callGAPI(service=cd.groups(), function=u'patch', groupKey=group, body=cd_body) @@ -5795,17 +6034,17 @@ def doUpdateGroup(): print u'updated group %s' % group def doUpdateAlias(): + cd = buildGAPIObject(u'directory') alias = sys.argv[3] target_type = sys.argv[4].lower() if target_type not in [u'user', u'group', u'target']: print u'ERROR: target type should be "user", "group" or "target", got %s' % target_type sys.exit(2) target_email = sys.argv[5] - cd = buildGAPIObject(u'directory') if alias.find(u'@') == -1: - alias = u'%s@%s' % (alias, domain) + alias = u'%s@%s' % (alias, GC_Values[GC_DOMAIN]) if target_email.find(u'@') == -1: - target_email = u'%s@%s' % (target_email, domain) + target_email = u'%s@%s' % (target_email, GC_Values[GC_DOMAIN]) try: callGAPI(service=cd.users().aliases(), function=u'delete', throw_reasons=[u'invalid'], userKey=alias, alias=alias) except googleapiclient.errors.HttpError: @@ -5822,6 +6061,7 @@ def doUpdateAlias(): print u'updated alias %s' % alias def doUpdateResourceCalendar(): + cd = buildGAPIObject(u'directory') resId = sys.argv[3] body = {} i = 4 @@ -5838,21 +6078,20 @@ def doUpdateResourceCalendar(): else: print u'ERROR: %s is not a valid argument for "gam update resource"' % sys.argv[i] sys.exit(2) - cd = buildGAPIObject(u'directory') # Use patch since it seems to work better. # update requires name to be set. callGAPI(service=cd.resources().calendars(), function=u'patch', - customer=customerId, calendarResourceId=resId, body=body, - fields=u'') + customer=GC_Values[GC_CUSTOMER_ID], calendarResourceId=resId, body=body, + fields=u'') print u'updated resource %s' % resId def doUpdateCros(): - deviceId = sys.argv[3] cd = buildGAPIObject(u'directory') + deviceId = sys.argv[3] if deviceId[:6].lower() == u'query:': query = deviceId[6:] devices_result = callGAPIpages(service=cd.chromeosdevices(), function=u'list', items=u'chromeosdevices', - query=query, customerId=customerId, fields=u'chromeosdevices/deviceId,nextPageToken') + query=query, customerId=GC_Values[GC_CUSTOMER_ID], fields=u'chromeosdevices/deviceId,nextPageToken') devices = list() for a_device in devices_result: devices.append(a_device[u'deviceId']) @@ -5892,12 +6131,12 @@ def doUpdateCros(): i = 1 for this_device in devices: print u' updating %s (%s of %s)' % (this_device, i, device_count) - callGAPI(service=cd.chromeosdevices(), function=u'patch', deviceId=this_device, body=body, customerId=customerId) + callGAPI(service=cd.chromeosdevices(), function=u'patch', deviceId=this_device, body=body, customerId=GC_Values[GC_CUSTOMER_ID]) i += 1 def doUpdateMobile(): - resourceId = sys.argv[3] cd = buildGAPIObject(u'directory') + resourceId = sys.argv[3] i = 4 action_body = patch_body = dict() doPatch = doAction = False @@ -5929,18 +6168,18 @@ def doUpdateMobile(): print u'ERROR: %s is not a valid argument for "gam update mobile"' % sys.argv[i] sys.exit(2) if doPatch: - callGAPI(service=cd.mobiledevices(), function=u'patch', resourceId=resourceId, body=patch_body, customerId=customerId) + callGAPI(service=cd.mobiledevices(), function=u'patch', resourceId=resourceId, body=patch_body, customerId=GC_Values[GC_CUSTOMER_ID]) if doAction: - callGAPI(service=cd.mobiledevices(), function=u'action', resourceId=resourceId, body=action_body, customerId=customerId) + callGAPI(service=cd.mobiledevices(), function=u'action', resourceId=resourceId, body=action_body, customerId=GC_Values[GC_CUSTOMER_ID]) def doDeleteMobile(): cd = buildGAPIObject(u'directory') resourceId = sys.argv[3] - callGAPI(service=cd.mobiledevices(), function='delete', resourceId=resourceId, customerId=customerId) + callGAPI(service=cd.mobiledevices(), function='delete', resourceId=resourceId, customerId=GC_Values[GC_CUSTOMER_ID]) def doUpdateOrg(): - orgUnitPath = sys.argv[3] cd = buildGAPIObject(u'directory') + orgUnitPath = sys.argv[3] 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].lower(), entity=sys.argv[6]) @@ -5952,7 +6191,7 @@ def doUpdateOrg(): for cros in users: sys.stderr.write(u' moving %s to %s (%s/%s)\n' % (cros, orgUnitPath, current_cros, cros_count)) callGAPI(service=cd.chromeosdevices(), function=u'patch', soft_errors=True, - customerId=customerId, deviceId=cros, body={u'orgUnitPath': '//%s' % orgUnitPath}) + customerId=GC_Values[GC_CUSTOMER_ID], deviceId=cros, body={u'orgUnitPath': '//%s' % orgUnitPath}) current_cros += 1 else: user_count = len(users) @@ -5992,13 +6231,13 @@ 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'update', customerId=customerId, orgUnitPath=orgUnitPath, body=body) + callGAPI(service=cd.orgunits(), function=u'update', customerId=GC_Values[GC_CUSTOMER_ID], orgUnitPath=orgUnitPath, body=body) def doWhatIs(): - email = sys.argv[2] cd = buildGAPIObject(u'directory') + email = sys.argv[2] if email.find(u'@') == -1: - email = u'%s@%s' % (email, domain) + email = u'%s@%s' % (email, GC_Values[GC_DOMAIN]) try: user_or_alias = callGAPI(service=cd.users(), function=u'get', throw_reasons=[u'notFound', u'badRequest', u'invalid'], userKey=email, fields=u'primaryEmail') if user_or_alias[u'primaryEmail'].lower() == email.lower(): @@ -6030,7 +6269,7 @@ def doGetUserInfo(user_email=None): try: user_email = sys.argv[3] except IndexError: - storage = oauth2client.file.Storage(os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE'), FN_OAUTH2_TXT)) + storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) credentials = storage.get() if credentials is None or credentials.invalid: doRequestOAuth() @@ -6039,7 +6278,7 @@ def doGetUserInfo(user_email=None): if user_email[:4].lower() == u'uid:': user_email = user_email[4:] elif user_email.find(u'@') == -1: - user_email = u'%s@%s' % (user_email, domain) + user_email = u'%s@%s' % (user_email, GC_Values[GC_DOMAIN]) getSchemas = getAliases = getGroups = getLicenses = True projection = u'full' customFieldMask = viewType = None @@ -6215,6 +6454,8 @@ def doGetUserInfo(user_email=None): print u' %s' % result[u'skuId'] def doGetGroupInfo(group_name=None): + cd = buildGAPIObject(u'directory') + gs = buildGAPIObject(u'groupssettings') if group_name == None: group_name = sys.argv[3] get_users = True @@ -6223,12 +6464,10 @@ def doGetGroupInfo(group_name=None): get_users = False except IndexError: pass - cd = buildGAPIObject(u'directory') - gs = buildGAPIObject(u'groupssettings') if group_name[:4].lower() == u'uid:': group_name = group_name[4:] elif group_name.find(u'@') == -1: - group_name = group_name+u'@'+domain + group_name = group_name+u'@'+GC_Values[GC_DOMAIN] basic_info = callGAPI(service=cd.groups(), function=u'get', groupKey=group_name) try: settings = callGAPI(service=gs.groups(), function=u'get', retry_reasons=[u'serviceLimit'], throw_reasons=u'authError', @@ -6272,11 +6511,11 @@ def doGetGroupInfo(group_name=None): print u'Total %s users in group' % len(members) def doGetAliasInfo(alias_email=None): + cd = buildGAPIObject(u'directory') if alias_email == None: alias_email = sys.argv[3] - cd = buildGAPIObject(u'directory') if alias_email.find(u'@') == -1: - alias_email = u'%s@%s' % (alias_email, domain) + alias_email = u'%s@%s' % (alias_email, GC_Values[GC_DOMAIN]) try: result = callGAPI(service=cd.users(), function=u'get', throw_reasons=[u'invalid', u'badRequest'], userKey=alias_email) except googleapiclient.errors.HttpError: @@ -6292,25 +6531,25 @@ def doGetAliasInfo(alias_email=None): print u' Unique ID: %s' % result[u'id'] def doGetResourceCalendarInfo(): - resId = sys.argv[3] cd = buildGAPIObject(u'directory') + resId = sys.argv[3] resource = callGAPI(service=cd.resources().calendars(), function=u'get', - customer=customerId, calendarResourceId=resId) + customer=GC_Values[GC_CUSTOMER_ID], calendarResourceId=resId) for key, value in resource.items(): if key in [u'kind', u'etag', u'etags']: continue print u'%s: %s' % (key, value) def doGetCrosInfo(): - deviceId = sys.argv[3] cd = buildGAPIObject(u'directory') - info = callGAPI(service=cd.chromeosdevices(), function=u'get', customerId=customerId, deviceId=deviceId) + deviceId = sys.argv[3] + info = callGAPI(service=cd.chromeosdevices(), function=u'get', customerId=GC_Values[GC_CUSTOMER_ID], deviceId=deviceId) print_json(None, info) def doGetMobileInfo(): - deviceId = sys.argv[3] cd = buildGAPIObject(u'directory') - info = callGAPI(service=cd.mobiledevices(), function=u'get', customerId=customerId, resourceId=deviceId) + deviceId = sys.argv[3] + info = callGAPI(service=cd.mobiledevices(), function=u'get', customerId=GC_Values[GC_CUSTOMER_ID], resourceId=deviceId) print_json(None, info) def print_json(object_name, object_value, spacing=u''): @@ -6362,13 +6601,13 @@ def doUpdateNotification(): print u'ERROR: notifications need to be marked as read or unread.' sys.exit(2) if get_all: - notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=customerId, fields=u'items(notificationId,isUnread),nextPageToken') + notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=GC_Values[GC_CUSTOMER_ID], fields=u'items(notificationId,isUnread),nextPageToken') for noti in notifications: if noti[u'isUnread'] != isUnread: ids.append(noti[u'notificationId']) print u'Marking %s notification(s) as %s...' % (len(ids), mark_as) for notificationId in ids: - result = callGAPI(service=cd.notifications(), function=u'patch', customer=customerId, notificationId=notificationId, body={u'isUnread': isUnread}, fields=u'notificationId,isUnread') + result = callGAPI(service=cd.notifications(), function=u'patch', customer=GC_Values[GC_CUSTOMER_ID], notificationId=notificationId, body={u'isUnread': isUnread}, fields=u'notificationId,isUnread') if result[u'isUnread']: read_result = u'unread' else: @@ -6391,12 +6630,12 @@ def doDeleteNotification(): print 'ERROR: %s is not a valid argument for "gam delete notification", expected id' % sys.argv[i] sys.exit(2) if get_all: - notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=customerId, fields=u'items(notificationId),nextPageToken') + notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=GC_Values[GC_CUSTOMER_ID], fields=u'items(notificationId),nextPageToken') for noti in notifications: ids.append(noti[u'notificationId']) print u'Deleting %s notification(s)...' % len(ids) for notificationId in ids: - callGAPI(service=cd.notifications(), function=u'delete', customer=customerId, notificationId=notificationId) + callGAPI(service=cd.notifications(), function=u'delete', customer=GC_Values[GC_CUSTOMER_ID], notificationId=notificationId) print u'deleted %s' % id def doSiteVerifyShow(): @@ -6504,7 +6743,7 @@ def doSiteVerifyAttempt(): except KeyError: pass print - print u'You can now add %s or it\'s subdomains as secondary or domain aliases of the %s Google Apps Account.' % (a_domain, domain) + print u'You can now add %s or it\'s subdomains as secondary or domain aliases of the %s Google Apps Account.' % (a_domain, GC_Values[GC_DOMAIN]) def doGetNotifications(): cd = buildGAPIObject(u'directory') @@ -6517,7 +6756,7 @@ def doGetNotifications(): print 'ERROR: %s is not a valid argument for "gam info notification", expected unreadonly' % sys.argv[i] sys.exit(2) i += 1 - notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=customerId) + notifications = callGAPIpages(service=cd.notifications(), function=u'list', customer=GC_Values[GC_CUSTOMER_ID]) for notification in notifications: if unread_only and not notification[u'isUnread']: continue @@ -6549,20 +6788,20 @@ def doGetOrgInfo(): pass if name == u'/': orgs = callGAPI(service=cd.orgunits(), function=u'list', - customerId=customerId, type=u'children', + customerId=GC_Values[GC_CUSTOMER_ID], type=u'children', fields=u'organizationUnits/parentOrgUnitId') name = orgs[u'organizationUnits'][0][u'parentOrgUnitId'] if len(name) > 1 and name[0] == u'/': name = name[1:] - result = callGAPI(service=cd.orgunits(), function=u'get', customerId=customerId, orgUnitPath=name) + result = callGAPI(service=cd.orgunits(), function=u'get', customerId=GC_Values[GC_CUSTOMER_ID], orgUnitPath=name) print_json(None, result) if get_users: name = result[u'orgUnitPath'] print u'Users: ' page_message = u'Got %%total_items%% users: %%first_item%% - %%last_item%%\n' users = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - message_attribute=u'primaryEmail', customer=customerId, query=u"orgUnitPath='%s'" % name, - fields=u'users(primaryEmail,orgUnitPath),nextPageToken', maxResults=500) + message_attribute=u'primaryEmail', customer=GC_Values[GC_CUSTOMER_ID], query=u"orgUnitPath='%s'" % name, + fields=u'users(primaryEmail,orgUnitPath),nextPageToken', maxResults=GC_Values[GC_USER_MAX_RESULTS]) for user in users: if show_children or (name.lower() == user[u'orgUnitPath'].lower()): sys.stdout.write(u' %s' % user[u'primaryEmail']) @@ -6591,8 +6830,8 @@ def doGetASPs(users): print u' no ASPs for %s\n' % user def doDelASP(users): - codeId = sys.argv[5] cd = buildGAPIObject(u'directory') + codeId = sys.argv[5] for user in users: callGAPI(service=cd.asps(), function=u'delete', userKey=user, codeId=codeId) print u'deleted ASP %s for %s' % (codeId, user) @@ -6871,48 +7110,52 @@ def doGetInstanceInfo(): adm = buildGAPIObject(u'admin-settings') if len(sys.argv) > 4 and sys.argv[3].lower() == u'logo': target_file = sys.argv[4] - url = 'http://www.google.com/a/cpanel/%s/images/logo.gif' % (domain) + url = 'http://www.google.com/a/cpanel/%s/images/logo.gif' % (GC_Values[GC_DOMAIN]) geturl(url, target_file) - return - print u'Google Apps Domain: %s' % domain + sys.exit(0) + print u'Google Apps Domain: %s' % (GC_Values[GC_DOMAIN]) cd = buildGAPIObject(u'directory') - if customerId != MY_CUSTOMER: - customer_id = customerId + if GC_Values[GC_CUSTOMER_ID] != MY_CUSTOMER: + customerId = GC_Values[GC_CUSTOMER_ID] else: - 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) + result = callGAPI(service=cd.users(), function=u'list', + fields=u'users(customerId)', customer=GC_Values[GC_CUSTOMER_ID], maxResults=1) + try: + customerId = result[u'users'][0][u'customerId'] + except KeyError: + customerId = UNKNOWN + print u'Customer ID: %s' % customerId + default_language = callGAPI(service=adm.defaultLanguage(), function=u'get', domainName=GC_Values[GC_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) + org_name = callGAPI(service=adm.organizationName(), function='get', domainName=GC_Values[GC_DOMAIN]) 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) + admin_email = callGAPI(service=adm.adminSecondaryEmail(), function='get', domainName=GC_Values[GC_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) + max_users = callGAPI(service=adm.maximumNumberOfUsers(), function=u'get', domainName=GC_Values[GC_DOMAIN]) print u'Maximum Users: %s' % max_users[u'entry'][u'apps$property'][0][u'value'] - current_users = callGAPI(service=adm.currentNumberOfUsers(), function=u'get', domainName=domain) + current_users = callGAPI(service=adm.currentNumberOfUsers(), function=u'get', domainName=GC_Values[GC_DOMAIN]) print u'Current Users: %s' % current_users[u'entry'][u'apps$property'][0][u'value'] - is_dom_verified = callGAPI(service=adm.isVerified(), function=u'get', domainName=domain) + is_dom_verified = callGAPI(service=adm.isVerified(), function=u'get', domainName=GC_Values[GC_DOMAIN]) print u'Domain is Verified: %s' % is_dom_verified[u'entry'][u'apps$property'][0][u'value'] - domain_edition = callGAPI(service=adm.edition(), function=u'get', domainName=domain) + domain_edition = callGAPI(service=adm.edition(), function=u'get', domainName=GC_Values[GC_DOMAIN]) print u'Domain Edition: %s' % domain_edition[u'entry'][u'apps$property'][0][u'value'] - customer_pin = callGAPI(service=adm.customerPIN(), function=u'get', domainName=domain) + customer_pin = callGAPI(service=adm.customerPIN(), function=u'get', domainName=GC_Values[GC_DOMAIN]) print u'Customer PIN: %s' % customer_pin[u'entry'][u'apps$property'][0][u'value'] - creation_time = callGAPI(service=adm.creationTime(), function=u'get', domainName=domain) + creation_time = callGAPI(service=adm.creationTime(), function=u'get', domainName=GC_Values[GC_DOMAIN]) my_date = creation_time[u'entry'][u'apps$property'][0][u'value'] my_date = my_date[:15] my_offset = creation_time[u'entry'][u'apps$property'][0][u'value'][19:] nice_time = datetime.datetime.strptime(my_date, u"%Y%m%dT%H%M%S") print u'Domain Creation Time: %s %s' % (nice_time, my_offset) - country_code = callGAPI(service=adm.countryCode(), function=u'get', domainName=domain) + country_code = callGAPI(service=adm.countryCode(), function=u'get', domainName=GC_Values[GC_DOMAIN]) print u'Domain Country Code: %s' % country_code[u'entry'][u'apps$property'][0][u'value'] - mxverificationstatus = callGAPI(service=adm.mxVerification(), function=u'get', domainName=domain) + mxverificationstatus = callGAPI(service=adm.mxVerification(), function=u'get', domainName=GC_Values[GC_DOMAIN]) for entry in mxverificationstatus[u'entry'][u'apps$property']: if entry[u'name'] == u'verified': print u'MX Verification Verified: %s' % entry[u'value'] elif entry[u'name'] == u'verificationMethod': print u'MX Verification Method: %s' % entry[u'value'] - ssosettings = callGAPI(service=adm.ssoGeneral(), function=u'get', domainName=domain) + ssosettings = callGAPI(service=adm.ssoGeneral(), function=u'get', domainName=GC_Values[GC_DOMAIN]) for entry in ssosettings[u'entry'][u'apps$property']: if entry[u'name'] == u'enableSSO': print u'SSO Enabled: %s' % entry[u'value'] @@ -6926,7 +7169,7 @@ def doGetInstanceInfo(): print u'SSO Whitelist IPs: %s' % entry[u'value'] elif entry[u'name'] == u'useDomainSpecificIssuer': print u'SSO Use Domain Specific Issuer: %s' % entry[u'value'] - ssokey = callGAPI(service=adm.ssoSigningKey(), function=u'get', silent_errors=True, soft_errors=True, domainName=domain) + ssokey = callGAPI(service=adm.ssoSigningKey(), function=u'get', silent_errors=True, soft_errors=True, domainName=GC_Values[GC_DOMAIN]) try: for entry in ssokey[u'entry'][u'apps$property']: if entry[u'name'] == u'algorithm': @@ -6943,10 +7186,10 @@ def doGetInstanceInfo(): print u'Full SSO Key: %s' % entry[u'value'] except TypeError: pass - migration_status = callGAPI(service=adm.userEmailMigrationEnabled(), function=u'get', domainName=domain) + migration_status = callGAPI(service=adm.userEmailMigrationEnabled(), function=u'get', domainName=GC_Values[GC_DOMAIN]) print u'User Migration Enabled: %s' % migration_status[u'entry'][u'apps$property'][0][u'value'] outbound_gateway_settings = {u'smartHost': u'', u'smtpMode': u''} # Initialize blank in case we get an 1801 Error - outbound_gateway_settings = callGAPI(service=adm.outboundGateway(), function=u'get', domainName=domain) + outbound_gateway_settings = callGAPI(service=adm.outboundGateway(), function=u'get', domainName=GC_Values[GC_DOMAIN]) try: for entry in outbound_gateway_settings[u'entry'][u'apps$property']: if entry[u'name'] == u'smartHost': @@ -6958,16 +7201,17 @@ def doGetInstanceInfo(): print u'Outbound Gateway SMTP Mode: None' def doDeleteUser(): - user_email = sys.argv[3] cd = buildGAPIObject(u'directory') + user_email = sys.argv[3] if user_email[:4].lower() == u'uid:': user_email = user_email[4:] elif user_email.find(u'@') == -1: - user_email = u'%s@%s' % (user_email, domain) + user_email = u'%s@%s' % (user_email, GC_Values[GC_DOMAIN]) print u"Deleting account for %s" % (user_email) callGAPI(service=cd.users(), function=u'delete', userKey=user_email) def doUndeleteUser(): + cd = buildGAPIObject(u'directory') user = sys.argv[3].lower() user_uid = False orgUnit = u'/' @@ -6976,15 +7220,14 @@ def doUndeleteUser(): orgUnit = sys.argv[5] except IndexError: pass - cd = buildGAPIObject(u'directory') if user[:4].lower() == u'uid:': user_uid = user[4:] elif user.find(u'@') == -1: - user = u'%s@%s' % (user, domain) + user = u'%s@%s' % (user, GC_Values[GC_DOMAIN]) if not user_uid: print u'Looking up UID for %s...' % user deleted_users = callGAPIpages(service=cd.users(), function=u'list', - items=u'users', customer=customerId, showDeleted=True, maxResults=500) + items=u'users', customer=GC_Values[GC_CUSTOMER_ID], showDeleted=True, maxResults=GC_Values[GC_USER_MAX_RESULTS]) matching_users = list() for deleted_user in deleted_users: if str(deleted_user[u'primaryEmail']).lower() == user: @@ -7012,16 +7255,17 @@ def doUndeleteUser(): callGAPI(service=cd.users(), function=u'undelete', userKey=user_uid, body={u'orgUnitPath': orgUnit}) def doDeleteGroup(): - group = sys.argv[3] cd = buildGAPIObject(u'directory') + group = sys.argv[3] if group[:4].lower() == u'uid:': group = group[4:] elif group.find(u'@') == -1: - group = u'%s@%s' % (group, domain) + group = u'%s@%s' % (group, GC_Values[GC_DOMAIN]) print u"Deleting group %s" % group callGAPI(service=cd.groups(), function=u'delete', groupKey=group) def doDeleteAlias(alias_email=None): + cd = buildGAPIObject(u'directory') is_user = is_group = False if alias_email == None: alias_email = sys.argv[3] @@ -7031,9 +7275,8 @@ def doDeleteAlias(alias_email=None): elif alias_email.lower() == u'group': is_group = True alias_email = sys.argv[4] - cd = buildGAPIObject(u'directory') if alias_email.find(u'@') == -1: - alias_email = u'%s@%s' % (alias_email, domain) + alias_email = u'%s@%s' % (alias_email, GC_Values[GC_DOMAIN]) print u"Deleting alias %s" % alias_email if is_user or (not is_user and not is_group): try: @@ -7049,19 +7292,19 @@ def doDeleteAlias(alias_email=None): callGAPI(service=cd.groups().aliases(), function=u'delete', groupKey=alias_email, alias=alias_email) def doDeleteResourceCalendar(): - res_id = sys.argv[3] + resId = sys.argv[3] cd = buildGAPIObject(u'directory') - print u"Deleting resource calendar %s" % res_id + print u"Deleting resource calendar %s" % resId callGAPI(service=cd.resources().calendars(), function=u'delete', - calendarResourceId=res_id, customer=customerId) + customer=GC_Values[GC_CUSTOMER_ID], calendarResourceId=resId) def doDeleteOrg(): - name = sys.argv[3] cd = buildGAPIObject(u'directory') + name = sys.argv[3] if name[0] == u'/': name = name[1:] print u"Deleting organization %s" % name - callGAPI(service=cd.orgunits(), function=u'delete', customerId=customerId, orgUnitPath=name) + callGAPI(service=cd.orgunits(), function=u'delete', customerId=GC_Values[GC_CUSTOMER_ID], orgUnitPath=name) def output_csv(csv_list, titles, list_type, todrive): csv.register_dialect(u'nixstdout', lineterminator=u'\n') @@ -7081,12 +7324,12 @@ def output_csv(csv_list, titles, list_type, todrive): convert = False drive = buildGAPIObject(u'drive') result = callGAPI(service=drive.files(), function=u'insert', convert=convert, - body={u'description': u' '.join(sys.argv), u'title': u'%s - %s' % (domain, list_type), u'mimeType': u'text/csv'}, + body={u'description': u' '.join(sys.argv), u'title': u'%s - %s' % (GC_Values[GC_DOMAIN], list_type), u'mimeType': u'text/csv'}, media_body=googleapiclient.http.MediaInMemoryUpload(string_file.getvalue(), mimetype=u'text/csv')) file_url = result[u'alternateLink'] - if os.path.isfile(os.path.join(gamUserConfigDir, u'nobrowser.txt')): + if GC_Values[GC_NO_BROWSER]: msg_txt = u'Drive file uploaded to:\n %s' % file_url - msg_subj = u'%s - %s' % (domain, list_type) + msg_subj = u'%s - %s' % (GC_Values[GC_DOMAIN], list_type) send_email(msg_subj, msg_txt) print msg_txt else: @@ -7114,7 +7357,7 @@ def doPrintUsers(): cd = buildGAPIObject(u'directory') user_fields = [u'primaryEmail',] fields = u'' - customer = customerId + customer = GC_Values[GC_CUSTOMER_ID] domain = None query = None projection = u'basic' @@ -7247,7 +7490,7 @@ def doPrintUsers(): all_users = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, message_attribute=u'primaryEmail', customer=customer, domain=domain, fields=fields, showDeleted=deleted_only, orderBy=orderBy, sortOrder=sortOrder, viewType=viewType, - query=query, projection=projection, customFieldMask=customFieldMask, maxResults=500) + query=query, projection=projection, customFieldMask=customFieldMask, maxResults=GC_Values[GC_USER_MAX_RESULTS]) titles = [u'primaryEmail',] attributes = [] for user in all_users: @@ -7300,8 +7543,10 @@ def doPrintUsers(): output_csv(attributes, titles, u'Users', todrive) def doPrintGroups(): + cd = buildGAPIObject(u'directory') i = 3 printname = printdesc = printid = members = owners = managers = settings = admin_created = aliases = todrive = False + customer = GC_Values[GC_CUSTOMER_ID] usedomain = usemember = None listDelimiter = u'\n' group_attributes = [{u'Email': u'Email'}] @@ -7310,6 +7555,7 @@ def doPrintGroups(): while i < len(sys.argv): if sys.argv[i].lower() == u'domain': usedomain = sys.argv[i+1].lower() + customer = None i += 2 elif sys.argv[i].lower() == u'todrive': todrive = True @@ -7319,6 +7565,7 @@ def doPrintGroups(): i += 2 elif sys.argv[i].lower() == u'member': usemember = sys.argv[i+1].lower() + customer = None i += 2 elif sys.argv[i].lower() == u'name': fields += u',groups(name)' @@ -7373,14 +7620,10 @@ def doPrintGroups(): else: print 'ERROR: %s is not a valid argument for "gam print groups"' % sys.argv[i] sys.exit(2) - cd = buildGAPIObject(u'directory') - global customerId - if usedomain or usemember: - customerId = None sys.stderr.write(u"Retrieving All Groups for Google Apps account (may take some time on a large account)...\n") page_message = u'Got %%num_items%% groups: %%first_item%% - %%last_item%%\n' all_groups = callGAPIpages(service=cd.groups(), function=u'list', items=u'groups', page_message=page_message, - message_attribute=u'email', customer=customerId, domain=usedomain, userKey=usemember, fields=fields) + message_attribute=u'email', customer=customer, domain=usedomain, userKey=usemember, fields=fields) total_groups = len(all_groups) count = 0 for group_vals in all_groups: @@ -7474,6 +7717,7 @@ def doPrintGroups(): output_csv(group_attributes, titles, u'Groups', todrive) def doPrintOrgs(): + cd = buildGAPIObject(u'directory') i = 3 printname = printdesc = printparent = printinherit = todrive = False listType = u'all' @@ -7524,9 +7768,8 @@ def doPrintOrgs(): if fields: org_attributes[0][u'Path'] = u'Path' titles.append(u'Path') - cd = buildGAPIObject(u'directory') sys.stderr.write(u"Retrieving All Organizational Units for your account (may take some time on large domain)...") - orgs = callGAPI(service=cd.orgunits(), function=u'list', customerId=customerId, fields=fields, type=listType, orgUnitPath=orgUnitPath) + orgs = callGAPI(service=cd.orgunits(), function=u'list', customerId=GC_Values[GC_CUSTOMER_ID], fields=fields, type=listType, orgUnitPath=orgUnitPath) sys.stderr.write(u"done\n") if not u'organizationUnits' in orgs: print u'0 org units in this Google Apps instance...' @@ -7568,6 +7811,7 @@ def doPrintOrgs(): output_csv(org_attributes, titles, u'Orgs', todrive) def doPrintAliases(): + cd = buildGAPIObject(u'directory') todrive = False i = 3 while i < len(sys.argv): @@ -7577,27 +7821,26 @@ def doPrintAliases(): else: print u'ERROR: %s is not a valid argument for "gam print aliases"' % sys.argv[i] sys.exit(2) - cd = buildGAPIObject(u'directory') alias_attributes = [] alias_attributes.append({u'Alias': u'Alias'}) alias_attributes[0].update(Target=u'Target') alias_attributes[0].update(TargetType=u'TargetType') titles = [u'Alias', u'Target', u'TargetType'] - sys.stderr.write(u"Retrieving All User Aliases for %s organization (may take some time on large domain)...\n" % domain) + sys.stderr.write(u"Retrieving All User Aliases for %s organization (may take some time on large domain)...\n" % GC_Values[GC_DOMAIN]) page_message = u'Got %%num_items%% users %%first_item%% - %%last_item%%\n' all_users = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - message_attribute=u'primaryEmail', customer=customerId, - fields=u'users(primaryEmail,aliases),nextPageToken', maxResults=500) + message_attribute=u'primaryEmail', customer=GC_Values[GC_CUSTOMER_ID], + fields=u'users(primaryEmail,aliases),nextPageToken', maxResults=GC_Values[GC_USER_MAX_RESULTS]) for user in all_users: try: for alias in user[u'aliases']: alias_attributes.append({u'Alias': alias, u'Target': user[u'primaryEmail'], u'TargetType': u'User'}) except KeyError: continue - sys.stderr.write(u"Retrieving All User Aliases for %s organization (may take some time on large domain)...\n" % domain) + sys.stderr.write(u"Retrieving All User Aliases for %s organization (may take some time on large domain)...\n" % GC_Values[GC_DOMAIN]) page_message = u'Got %%num_items%% groups %%first_item%% - %%last_item%%\n' all_groups = callGAPIpages(service=cd.groups(), function=u'list', items=u'groups', page_message=page_message, - message_attribute=u'email', customer=customerId, + message_attribute=u'email', customer=GC_Values[GC_CUSTOMER_ID], fields=u'groups(email,aliases),nextPageToken') for group in all_groups: try: @@ -7608,6 +7851,7 @@ def doPrintAliases(): output_csv(alias_attributes, titles, u'Aliases', todrive) def doPrintGroupMembers(): + cd = buildGAPIObject(u'directory') todrive = all_groups = False i = 3 while i < len(sys.argv): @@ -7620,11 +7864,10 @@ def doPrintGroupMembers(): else: print 'ERROR: %s is not a valid argument for "gam print group-members"' % sys.argv[i] sys.exit(2) - cd = buildGAPIObject(u'directory') member_attributes = [{u'group': u'group'},] if not all_groups: all_groups = callGAPIpages(service=cd.groups(), function=u'list', items=u'groups', message_attribute=u'email', - customer=customerId, fields=u'nextPageToken,groups(email)') + customer=GC_Values[GC_CUSTOMER_ID], fields=u'nextPageToken,groups(email)') total_groups = len(all_groups) i = 1 for group in all_groups: @@ -7680,8 +7923,8 @@ def doPrintMobileDevices(): sys.stderr.write(u'Retrieving All Mobile Devices for organization (may take some time for large accounts)...\n') page_message = u'Got %%num_items%% mobile devices...\n' all_mobile = callGAPIpages(service=cd.mobiledevices(), function=u'list', items=u'mobiledevices', page_message=page_message, - customerId=customerId, query=query, - orderBy=orderBy, sortOrder=sortOrder, maxResults=500) + customerId=GC_Values[GC_CUSTOMER_ID], query=query, + orderBy=orderBy, sortOrder=sortOrder, maxResults=GC_Values[GC_DEVICE_MAX_RESULTS]) for mobile in all_mobile: mobiledevice = dict() for title in mobile: @@ -7762,8 +8005,8 @@ def doPrintCrosDevices(): sys.stderr.write(u'Retrieving All Chrome OS Devices for organization (may take some time for large accounts)...\n') page_message = u'Got %%num_items%% Chrome devices...\n' all_cros = callGAPIpages(service=cd.chromeosdevices(), function=u'list', items=u'chromeosdevices', page_message=page_message, - query=query, customerId=customerId, projection=projection, - orderBy=orderBy, sortOrder=sortOrder, maxResults=500) + query=query, customerId=GC_Values[GC_CUSTOMER_ID], projection=projection, + orderBy=orderBy, sortOrder=sortOrder, maxResults=GC_Values[GC_DEVICE_MAX_RESULTS]) if all_cros: if (not noLists) and (not selectAttrib): for cros in all_cros: @@ -7829,7 +8072,7 @@ def doPrintLicenses(return_list=False, skus=None): page_message = u'Got %%%%total_items%%%% Licenses for %s...\n' % sku try: licenses += callGAPIpages(service=lic.licenseAssignments(), function=u'listForProductAndSku', throw_reasons=[u'invalid', u'forbidden'], page_message=page_message, - customerId=domain, productId=product, skuId=sku, fields=u'items(productId,skuId,userId),nextPageToken') + customerId=GC_Values[GC_DOMAIN], productId=product, skuId=sku, fields=u'items(productId,skuId,userId),nextPageToken') except googleapiclient.errors.HttpError: licenses += [] else: @@ -7837,7 +8080,7 @@ def doPrintLicenses(return_list=False, skus=None): page_message = u'Got %%%%total_items%%%% Licenses for %s...\n' % productId try: licenses += callGAPIpages(service=lic.licenseAssignments(), function=u'listForProduct', throw_reasons=[u'invalid', u'forbidden'], page_message=page_message, - customerId=domain, productId=productId, fields=u'items(productId,skuId,userId),nextPageToken') + customerId=GC_Values[GC_DOMAIN], productId=productId, fields=u'items(productId,skuId,userId),nextPageToken') except googleapiclient.errors.HttpError: licenses = +[] for u_license in licenses: @@ -7854,6 +8097,7 @@ def doPrintLicenses(return_list=False, skus=None): output_csv(lic_attributes, lic_attributes[0], u'Licenses', todrive) def doPrintTokens(): + cd = buildGAPIObject(u'directory') todrive = False i = 3 entity_type = u'all' @@ -7869,7 +8113,6 @@ def doPrintTokens(): else: print u'ERROR: %s is not a valid argument for "gam print tokens"' % sys.argv[i] sys.exit(2) - cd = buildGAPIObject(u'directory') all_users = getUsersToModify(entity_type=entity_type, entity=entity, silent=False) titles = [u'user', u'displayText', u'clientId', u'nativeApp', u'anonymous', u'scopes'] token_attributes = [{}] @@ -7895,10 +8138,11 @@ def doPrintTokens(): pass output_csv(token_attributes, titles, u'OAuth Tokens', todrive) -def doPrintResources(): - i = 3 +def doPrintResourceCalendars(): + cd = buildGAPIObject(u'directory') todrive = False fields = [u'resourceId', u'resourceName', u'resourceEmail'] + i = 3 while i < len(sys.argv): if sys.argv[i].lower() == u'allfields': fields = None @@ -7921,19 +8165,19 @@ def doPrintResources(): sys.exit(2) if fields: fields = u'nextPageToken,items(%s)' % u','.join(fields) - cd = buildGAPIObject(u'directory') sys.stderr.write(u"Retrieving All Resource Calendars for your account (may take some time on a large domain)\n") page_message = u'Got %%total_items%% resources: %%first_item%% - %%last_item%%\n' - resources = callGAPIpages(service=cd.resources().calendars(), - function=u'list', items=u'items', fields=fields, - page_message=page_message, message_attribute=u'resourceId', - maxResults=500, customer=customerId) + resources = callGAPIpages(service=cd.resources().calendars(), function=u'list', items=u'items', + page_message=page_message, message_attribute=u'resourceId', + customer=GC_Values[GC_CUSTOMER_ID], fields=fields, maxResults=500) resources_attrib = [{u'resourceId':u'resourceId', - u'resourceEmail': u'resourceEmail', - u'resourceName': u'resourceName'}] + u'resourceEmail': u'resourceEmail', + u'resourceName': u'resourceName'}] for resource in resources: resource_attrib = {} for key, value in resource.items(): + if key in [u'kind', u'etags']: + continue if key not in resources_attrib[0]: resources_attrib[0][key] = key resource_attrib[key] = value @@ -8298,7 +8542,7 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa else: member_type_message = u'%ss' % member_type.lower() if group.find(u'@') == -1: - group = u'%s@%s' % (group, domain) + group = u'%s@%s' % (group, GC_Values[GC_DOMAIN]) page_message = None if not silent: sys.stderr.write(u"Getting %s of %s (may take some time for large groups)..." % (member_type_message, group)) @@ -8322,8 +8566,8 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa sys.stderr.write(u"Getting all users in the Google Apps organization (may take some time on a large domain)...\n") page_message = u'Got %%total_items%% users...' members = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - customer=customerId, fields=u'nextPageToken,users(primaryEmail,id,orgUnitPath)', - query=u"orgUnitPath='%s'" % ou, maxResults=500) + customer=GC_Values[GC_CUSTOMER_ID], fields=u'nextPageToken,users(primaryEmail,id,orgUnitPath)', + query=u"orgUnitPath='%s'" % ou, maxResults=GC_Values[GC_USER_MAX_RESULTS]) for member in members: if ou.lower() != member[u'orgUnitPath'].lower(): continue @@ -8344,8 +8588,8 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa sys.stderr.write(u"Getting all users in the Google Apps organization (may take some time on a large domain)...\n") page_message = u'Got %%total_items%% users..' members = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - customer=customerId, fields=u'nextPageToken,users(primaryEmail,id)', - query=u"orgUnitPath='%s'" % ou, maxResults=500) + customer=GC_Values[GC_CUSTOMER_ID], fields=u'nextPageToken,users(primaryEmail,id)', + query=u"orgUnitPath='%s'" % ou, maxResults=GC_Values[GC_USER_MAX_RESULTS]) for member in members: if return_uids: users.append(member[u'id']) @@ -8360,8 +8604,8 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa sys.stderr.write(u"Getting all users that match query %s (may take some time on a large domain)...\n" % entity) page_message = u'Got %%total_items%% users...' members = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - customer=customerId, fields=u'nextPageToken,users(primaryEmail,id)', - query=entity, maxResults=500) + customer=GC_Values[GC_CUSTOMER_ID], fields=u'nextPageToken,users(primaryEmail,id)', + query=entity, maxResults=GC_Values[GC_USER_MAX_RESULTS]) for member in members: if return_uids: users.append(member[u'id']) @@ -8413,8 +8657,8 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa 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...' all_users = callGAPIpages(service=cd.users(), function=u'list', items=u'users', page_message=page_message, - customer=customerId, - fields=u'nextPageToken,users(primaryEmail,suspended,id)', maxResults=500) + customer=GC_Values[GC_CUSTOMER_ID], + fields=u'nextPageToken,users(primaryEmail,suspended,id)', maxResults=GC_Values[GC_USER_MAX_RESULTS]) for member in all_users: if member[u'suspended'] == False: if return_uids: @@ -8427,8 +8671,8 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa 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)', - maxResults=500) + customerId=GC_Values[GC_CUSTOMER_ID], fields=u'nextPageToken,chromeosdevices(deviceId)', + maxResults=GC_Values[GC_DEVICE_MAX_RESULTS]) for member in all_cros: users.append(member[u'deviceId']) if not silent: @@ -8448,7 +8692,7 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa if user[:4] == u'uid:': full_users.append(user[4:]) elif user.find(u'@') == -1: - full_users.append(u'%s@%s' % (user, domain)) + full_users.append(u'%s@%s' % (user, GC_Values[GC_DOMAIN])) else: full_users.append(user) else: @@ -8465,18 +8709,17 @@ def OAuthInfo(): try: access_token = sys.argv[3] except IndexError: - oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', FN_OAUTH2_TXT)) - storage = oauth2client.file.Storage(oauth2file) + storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) credentials = storage.get() if credentials is None or credentials.invalid: doRequestOAuth() credentials = storage.get() credentials.user_agent = GAM_INFO - http = httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt'))) + http = httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL]) if credentials.access_token_expired: credentials.refresh(http) access_token = credentials.access_token - print u"\nOAuth File: %s" % oauth2file + print u"\nOAuth File: %s" % GC_Values[GC_OAUTH2_TXT] oa2 = buildGAPIObject(u'oauth2') token_info = callGAPI(service=oa2, function=u'tokeninfo', access_token=access_token) print u"Client ID: %s" % token_info[u'issued_to'] @@ -8493,14 +8736,13 @@ def OAuthInfo(): print u'Google Apps Admin: Unknown' def doDeleteOAuth(): - oauth2file = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', FN_OAUTH2_TXT)) - storage = oauth2client.file.Storage(oauth2file) + storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) credentials = storage.get() try: credentials.revoke_uri = oauth2client.GOOGLE_REVOKE_URI except AttributeError: systemErrorExit(1, u'Authorization doesn\'t exist') - http = httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt'))) + http = httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL]) sys.stderr.write(u'This OAuth token will self-destruct in 3...') time.sleep(1) sys.stderr.write(u'2...') @@ -8512,7 +8754,7 @@ def doDeleteOAuth(): credentials.revoke(http) except oauth2client.client.TokenRevokeError, e: sys.stderr.write(u'{0}{1}\n'.format(ERROR_PREFIX, e.message)) - os.remove(oauth2file) + os.remove(GC_Values[GC_OAUTH2_TXT]) class cmd_flags(object): def __init__(self, noLocalWebserver): @@ -8528,7 +8770,7 @@ possible_scopes = [u'https://www.googleapis.com/auth/admin.directory.group', u'https://www.googleapis.com/auth/admin.directory.device.chromeos', # Chrome OS Devices Directory Scope u'https://www.googleapis.com/auth/admin.directory.device.mobile', # Mobile Device Directory Scope u'https://apps-apis.google.com/a/feeds/emailsettings/2.0/', # Email Settings API - u'https://www.googleapis.com/auth/admin.directory.resource.calendar',# Calendar Resource API + u'https://www.googleapis.com/auth/admin.directory.resource.calendar',# Resource Calendar API u'https://apps-apis.google.com/a/feeds/compliance/audit/', # Email Audit API u'https://apps-apis.google.com/a/feeds/domain/', # Admin Settings API u'https://www.googleapis.com/auth/apps.groups.settings', # Group Settings API @@ -8547,10 +8789,10 @@ possible_scopes = [u'https://www.googleapis.com/auth/admin.directory.group', u'https://www.googleapis.com/auth/admin.datatransfer', # Data Transfer API u'https://www.googleapis.com/auth/admin.directory.customer', # Customer API u'https://www.googleapis.com/auth/admin.directory.domain', # Domain API - u'https://www.googleapis.com/auth/admin.directory.rolemanagement'] # Roles API + u'https://www.googleapis.com/auth/admin.directory.rolemanagement', # Roles API + ] def doRequestOAuth(incremental_auth=False): - CLIENT_SECRETS = os.path.join(gamUserConfigDir, os.environ.get(u'CLIENTSECRETSFILE', FN_CLIENT_SECRETS_JSON)) MISSING_CLIENT_SECRETS_MESSAGE = u""" WARNING: Please configure OAuth 2.0 @@ -8567,7 +8809,7 @@ https://github.com/jay0lee/GAM/wiki/CreatingClientSecretsFile for instructions. -""" % CLIENT_SECRETS +""" % GC_Values[GC_CLIENT_SECRETS_JSON] num_scopes = len(possible_scopes) menu = u'''Select the authorized scopes for this token. Include a 'r' to grant read-only access or an 'a' to grant action-only access. @@ -8578,7 +8820,7 @@ access or an 'a' to grant action-only access. [%%s] %s) Chrome OS Device Directory API (supports read-only) [%%s] %s) Mobile Device Directory API (supports read-only and action) [%%s] %s) User Email Settings API -[%%s] %s) Calendar Resources API (supports read-only +[%%s] %s) Resource Calendar API (supports read-only) [%%s] %s) Audit Monitors, Activity and Mailbox Exports API [%%s] %s) Admin Settings API [%%s] %s) Groups Settings API @@ -8605,7 +8847,6 @@ access or an 'a' to grant action-only access. ''' % tuple(range(0, num_scopes)) selected_scopes = [u'*'] * num_scopes selected_scopes[16] = u' ' - # turn off notifications API by default to prevent 500 due to scope length select_all_scopes = unicode(str(num_scopes)) unselect_all_scopes = unicode(str(num_scopes+1)) authorize_scopes = unicode(str(num_scopes+2)) @@ -8674,14 +8915,14 @@ access or an 'a' to grant action-only access. elif selected_scopes[i] == u'A': scopes.append(u'%s.action' % possible_scopes[i]) try: - FLOW = oauth2client.client.flow_from_clientsecrets(CLIENT_SECRETS, scope=scopes) + FLOW = oauth2client.client.flow_from_clientsecrets(GC_Values[GC_CLIENT_SECRETS_JSON], scope=scopes) except oauth2client.client.clientsecrets.InvalidClientSecretsError: systemErrorExit(14, MISSING_CLIENT_SECRETS_MESSAGE) - storage = oauth2client.file.Storage(os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHFILE', FN_OAUTH2_TXT))) + storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) credentials = storage.get() - flags = cmd_flags(noLocalWebserver=os.path.isfile(os.path.join(gamUserConfigDir, u'nobrowser.txt'))) + flags = cmd_flags(noLocalWebserver=GC_Values[GC_NO_BROWSER]) if credentials is None or credentials.invalid or incremental_auth: - http = httplib2.Http(disable_ssl_certificate_validation=os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt'))) + http = httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL]) try: credentials = oauth2client.tools.run_flow(flow=FLOW, storage=storage, flags=flags, http=http) except httplib2.CertificateValidationUnsupported: @@ -8689,24 +8930,19 @@ access or an 'a' to grant action-only access. def batch_worker(): while True: - item = q.get() + item = GM_Globals[GM_BATCH_QUEUE].get() subprocess.call(item, stderr=subprocess.STDOUT) - q.task_done() + GM_Globals[GM_BATCH_QUEUE].task_done() def run_batch(items): import Queue, threading - global q total_items = len(items) current_item = 0 python_cmd = [sys.executable.lower(),] 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')) - except TypeError: - num_worker_threads = 5 - num_worker_threads = min(total_items, num_worker_threads) - q = Queue.Queue(maxsize=num_worker_threads) # q.put() gets blocked when trying to create more items than there are workers + num_worker_threads = min(total_items, GC_Values[GC_NUM_THREADS]) + GM_Globals[GM_BATCH_QUEUE] = Queue.Queue(maxsize=num_worker_threads) # GM_Globals[GM_BATCH_QUEUE].put() gets blocked when trying to create more items than there are workers print u'starting %s worker threads...' % num_worker_threads for i in range(num_worker_threads): t = threading.Thread(target=batch_worker) @@ -8718,17 +8954,17 @@ def run_batch(items): print u'starting job %s / %s' % (current_item, total_items) if item[0] == u'commit-batch': sys.stderr.write(u'commit-batch - waiting for running processes to finish before proceeding...') - q.join() + GM_Globals[GM_BATCH_QUEUE].join() sys.stderr.write(u'done with commit-batch\n') continue - q.put(python_cmd+item) - q.join() + GM_Globals[GM_BATCH_QUEUE].put(python_cmd+item) + GM_Globals[GM_BATCH_QUEUE].join() # Main reload(sys) sys.setdefaultencoding(u'UTF-8') try: - if os.name == u'nt': + if GM_Globals[GM_WINDOWS]: sys.argv = win32_unicode_argv() # cleanup sys.argv on Windows SetGlobalVariables() if sys.argv[1].lower() == u'batch': @@ -8768,8 +9004,7 @@ try: try: arg = arg.replace(u'~~%s~~' % substring_replacement, row[substring_replacement]) except KeyError: - print u'%s is not in %s' % (substring_replacement, row) - sys.exit(3) + systemErrorExit(3, u'%s is not in %s' % (substring_replacement, row)) if arg[0] != '~': argv.append(arg) elif arg[1:] in row: @@ -8793,7 +9028,7 @@ try: elif sys.argv[2].lower() in [u'org', 'ou']: doCreateOrg() elif sys.argv[2].lower() == u'resource': - doCreateResource() + doCreateResourceCalendar() elif sys.argv[2].lower() in [u'verify', u'verification']: doSiteVerifyShow() elif sys.argv[2].lower() in [u'schema']: @@ -8979,7 +9214,7 @@ try: elif sys.argv[2].lower() in [u'orgs', u'ous']: doPrintOrgs() elif sys.argv[2].lower() == u'resources': - doPrintResources() + doPrintResourceCalendars() elif sys.argv[2].lower() == u'cros': doPrintCrosDevices() elif sys.argv[2].lower() == u'mobile': @@ -9092,8 +9327,7 @@ try: print user sys.exit(0) try: - autoBatch = int(os.environ.get(u'GAM_AUTOBATCH', '0')) - if (autoBatch > 0) and (len(users) > autoBatch): + if (GC_Values[GC_AUTO_BATCH_MIN] > 0) and (len(users) > GC_Values[GC_AUTO_BATCH_MIN]): items = [] for user in users: items.append([u'user', user] + sys.argv[3:]) From 4f4bb316d0f1620e51c43f4600d3159b657d3971 Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Tue, 22 Dec 2015 18:09:22 -0800 Subject: [PATCH 06/11] Handle invalid argument in gam print admins --- src/gam.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gam.py b/src/gam.py index 1179ab88..5b37dcfa 100755 --- a/src/gam.py +++ b/src/gam.py @@ -1618,6 +1618,9 @@ def doPrintAdmins(): print u'ERROR: %s is not a valid role' % role sys.exit(5) i += 2 + else: + print u'ERROR: %s is not a valid argument for "gam print admins".' % sys.argv[i] + sys.exit(2) admins = callGAPIpages(service=cd.roleAssignments(), function=u'list', customer=GC_Values[GC_CUSTOMER_ID], userKey=userKey, roleId=roleId, maxResults=200) admins_attrib = [{}] From 84b6c1cb87e165f7e22ac5b0550da78d9cb1595e Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Tue, 22 Dec 2015 18:15:15 -0800 Subject: [PATCH 07/11] Handle undefined role --- src/gam.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gam.py b/src/gam.py index 5b37dcfa..4b9caafb 100755 --- a/src/gam.py +++ b/src/gam.py @@ -1684,7 +1684,7 @@ def role_from_roleid(roleid): def roleid_from_role(role): if not GM_Globals[GM_MAP_ROLE_NAME_TO_ID]: buildRoleIdToNameToIdMap() - return GM_Globals[GM_MAP_ROLE_NAME_TO_ID][role] + return GM_Globals[GM_MAP_ROLE_NAME_TO_ID].get(role, None) def buildUserIdToNameMap(): cd = buildGAPIObject(u'directory') From 3bb54f875dfcb1bc009f81212f74961457998dc2 Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Tue, 22 Dec 2015 20:34:42 -0800 Subject: [PATCH 08/11] In gam create admin, org unit id is id:abcdefghj not uid:abcdefhgi --- src/gam.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gam.py b/src/gam.py index 4b9caafb..df229dfc 100755 --- a/src/gam.py +++ b/src/gam.py @@ -1583,8 +1583,8 @@ def doCreateAdmin(): sys.exit(3) if body[u'scopeType'] == u'ORG_UNIT': orgUnit = sys.argv[6] - if orgUnit[:4] == u'uid:': - body[u'orgUnitId'] = orgUnit[4:] + if orgUnit[:3] == u'id:': + body[u'orgUnitId'] = orgUnit[3:] else: if orgUnit[0] == u'/': orgUnit = orgUnit[1:] From 1f1329c53692e9bcabaf95987c878e11ec23ef12 Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Tue, 22 Dec 2015 20:41:13 -0800 Subject: [PATCH 09/11] Ok, allow gam create admin to take uid: or id:abcdefghi for org unit --- src/gam.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gam.py b/src/gam.py index df229dfc..723aa09b 100755 --- a/src/gam.py +++ b/src/gam.py @@ -1585,6 +1585,8 @@ def doCreateAdmin(): orgUnit = sys.argv[6] if orgUnit[:3] == u'id:': body[u'orgUnitId'] = orgUnit[3:] + elif orgUnit[:4] == u'uid:': + body[u'orgUnitId'] = orgUnit[4:] else: if orgUnit[0] == u'/': orgUnit = orgUnit[1:] From 96dfa52dbaab40078b4d6632fa38de36f5100476 Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Tue, 22 Dec 2015 22:16:33 -0800 Subject: [PATCH 10/11] Clean up parsing transferSecCals, transferDriveFiles --- src/gam.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/gam.py b/src/gam.py index 723aa09b..204ba875 100755 --- a/src/gam.py +++ b/src/gam.py @@ -877,8 +877,8 @@ def buildGAPIServiceObject(api, act_as, soft_errors=False): systemErrorExit(4, e) except oauth2client.client.AccessTokenRefreshError, e: if e.message in [u'access_denied', - u'unauthorized_client: Unauthorized client or scope in request.', - u'access_denied: Requested client not authorized.']: + u'unauthorized_client: Unauthorized client or scope in request.', + u'access_denied: Requested client not authorized.']: systemErrorExit(5, MESSAGE_CLIENT_API_ACCESS_DENIED.format(GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID], u','.join(scope))) sys.stderr.write(u'{0}{1}\n'.format(ERROR_PREFIX, e)) if soft_errors: @@ -3933,11 +3933,15 @@ def showDriveFileInfo(users): def transferSecCals(users): target_user = sys.argv[5] - try: - if sys.argv[6].lower() == u'keepuser': + remove_source_user = True + i = 6 + while i < len(sys.argv): + if sys.argv[i].lower() == u'keepuser': remove_source_user = False - except IndexError: - remove_source_user = True + i += 1 + else: + print u'ERROR: %s is not a valid argument for "gam transfer seccals"' % sys.argv[i] + sys.exit(2) for user in users: source_cal = buildGAPIServiceObject(u'calendar', user) source_calendars = callGAPIpages(service=source_cal.calendarList(), function=u'list', minAccessRole=u'owner', showHidden=True, fields=u'items(id),nextPageToken') @@ -3950,11 +3954,14 @@ def transferSecCals(users): def transferDriveFiles(users): target_user = sys.argv[5] remove_source_user = True - try: - if sys.argv[6].lower() == u'keepuser': + i = 6 + while i < len(sys.argv): + if sys.argv[i].lower() == u'keepuser': remove_source_user = False - except IndexError: - pass + i += 1 + else: + print u'ERROR: %s is not a valid argument for "gam transfer drive"' % sys.argv[i] + sys.exit(2) target_drive = buildGAPIServiceObject(u'drive', target_user) target_about = callGAPI(service=target_drive.about(), function=u'get', fields=u'quotaBytesTotal,quotaBytesUsed,rootFolderId') target_drive_free = int(target_about[u'quotaBytesTotal']) - int(target_about[u'quotaBytesUsed']) From 4cc775bcae5a6ad95aec9df1d8d524f6f22aab62 Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Tue, 22 Dec 2015 23:27:42 -0800 Subject: [PATCH 11/11] Eliminate try except IndexError in argument parsing --- src/gam.py | 130 ++++++++++++++++++++++++++++------------------------- 1 file changed, 70 insertions(+), 60 deletions(-) diff --git a/src/gam.py b/src/gam.py index 204ba875..b40f62eb 100755 --- a/src/gam.py +++ b/src/gam.py @@ -1228,11 +1228,14 @@ def gen_sha512_hash(password): def getDelegates(users): emailsettings = getEmailSettingsObject() csv_format = False - try: - if sys.argv[5].lower() == u'csv': + i = 5 + while i < len(sys.argv): + if sys.argv[i].lower() == u'csv': csv_format = True - except IndexError: - pass + i += 1 + else: + print u'ERROR: %s is not a valid argument for "gam show delegates"' % sys.argv[i] + sys.exit(2) for user in users: if user.find(u'@') > 0: emailsettings.domain = user[user.find('@')+1:] @@ -2832,9 +2835,9 @@ def doCalendarUpdateACL(): calendarId = sys.argv[2] role = sys.argv[4].lower() scope = sys.argv[5].lower() - try: + if len(sys.argv) > 6: entity = sys.argv[6].lower() - except IndexError: + else: entity = None doCalendarAddACL(calendarId=calendarId, role=role, scope=scope, entity=entity) @@ -3127,11 +3130,14 @@ def showCalSettings(users): def showDriveSettings(users): todrive = False - try: - if sys.argv[5].lower() == u'todrive': + i = 5 + while i < len(sys.argv): + if sys.argv[i].lower() == u'todrive': todrive = True - except IndexError: - pass + i += 1 + else: + print u'ERROR: %s is not a valid argument for "gam show drivesettings"' % sys.argv[i] + sys.exit(2) dont_show = [u'kind', u'selfLink', u'exportFormats', u'importFormats', u'maxUploadSizes', u'additionalRoleInfo', u'etag', u'features', u'user', u'isCurrentAppInstalled'] count = 1 drive_attr = [] @@ -3453,11 +3459,14 @@ def doDriveSearch(drive, query=None): def deleteDriveFile(users): fileIds = sys.argv[5] function = u'trash' - try: - if sys.argv[6].lower() == u'purge': + i = 6 + while i < len(sys.argv): + if sys.argv[i].lower() == u'purge': function = u'delete' - except IndexError: - pass + i += 1 + else: + print u'ERROR: %s is not a valid argument for "gam delete drivefile"' % sys.argv[i] + sys.exit(2) for user in users: drive = buildGAPIServiceObject(u'drive', user) if fileIds[:6].lower() == u'query:': @@ -6277,10 +6286,12 @@ def doWhatIs(): def doGetUserInfo(user_email=None): cd = buildGAPIObject(u'directory') + i = 3 if user_email == None: - try: + if len(sys.argv) > 3: user_email = sys.argv[3] - except IndexError: + i = 4 + else: storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) credentials = storage.get() if credentials is None or credentials.invalid: @@ -6294,7 +6305,6 @@ def doGetUserInfo(user_email=None): getSchemas = getAliases = getGroups = getLicenses = True projection = u'full' customFieldMask = viewType = None - i = 4 while i < len(sys.argv): if sys.argv[i].lower() == u'noaliases': getAliases = False @@ -6468,14 +6478,19 @@ def doGetUserInfo(user_email=None): def doGetGroupInfo(group_name=None): cd = buildGAPIObject(u'directory') gs = buildGAPIObject(u'groupssettings') + get_users = True if group_name == None: group_name = sys.argv[3] - get_users = True - try: - if sys.argv[4].lower() == u'nousers': + i = 4 + else: + i = 3 + while i < len(sys.argv): + if sys.argv[i].lower() == u'nousers': get_users = False - except IndexError: - pass + i += 1 + else: + print u'ERROR: %s is not a valid argument for "gam info group"' % sys.argv[i] + sys.exit(2) if group_name[:4].lower() == u'uid:': group_name = group_name[4:] elif group_name.find(u'@') == -1: @@ -6791,13 +6806,17 @@ def doGetOrgInfo(): name = sys.argv[3] get_users = True show_children = False - try: - if sys.argv[4].lower() == u'nousers': + i = 4 + while i < len(sys.argv): + if sys.argv[i].lower() == u'nousers': get_users = False - elif sys.argv[4].lower() in [u'children', u'child']: + i += 1 + elif sys.argv[i].lower() in [u'children', u'child']: show_children = True - except IndexError: - pass + i += 1 + else: + print u'ERROR: %s is not a valid argument for "gam info org"' % sys.argv[i] + sys.exit(2) if name == u'/': orgs = callGAPI(service=cd.orgunits(), function=u'list', customerId=GC_Values[GC_CUSTOMER_ID], type=u'children', @@ -6848,44 +6867,32 @@ def doDelASP(users): callGAPI(service=cd.asps(), function=u'delete', userKey=user, codeId=codeId) print u'deleted ASP %s for %s' % (codeId, user) +def printBackupCodes(user, codes): + jcount = len(codes[u'items']) if (codes and (u'items' in codes)) else 0 + print u'Backup verification codes for {0}'.format(user) + print u'' + if jcount > 0: + j = 0 + for code in codes[u'items']: + j += 1 + print u'{0}. {1}'.format(j, code[u'verificationCode']) + print u'' + def doGetBackupCodes(users): cd = buildGAPIObject(u'directory') for user in users: try: codes = callGAPI(service=cd.verificationCodes(), function=u'list', throw_reasons=[u'invalidArgument', u'invalid'], userKey=user) except googleapiclient.errors.HttpError: - codes = dict() - codes[u'items'] = list() - print u'Backup verification codes for %s' % user - print u'' - try: - i = 0 - while True: - sys.stdout.write(u'%s. %s\n' % (i+1, codes[u'items'][i][u'verificationCode'])) - i += 1 - except IndexError: - print u'' - except KeyError: - print u'' - print u'' + codes = None + printBackupCodes(user, codes) def doGenBackupCodes(users): cd = buildGAPIObject(u'directory') for user in users: callGAPI(service=cd.verificationCodes(), function=u'generate', userKey=user) codes = callGAPI(service=cd.verificationCodes(), function=u'list', userKey=user) - print u'Backup verification codes for %s' % user - print u'' - try: - i = 0 - while True: - sys.stdout.write(u'%s. %s\n' % (i+1, codes[u'items'][i][u'verificationCode'])) - i += 1 - except IndexError: - print u'' - except KeyError: - print u'' - print u'' + printBackupCodes(user, codes) def doDelBackupCodes(users): cd = buildGAPIObject(u'directory') @@ -7227,11 +7234,14 @@ def doUndeleteUser(): user = sys.argv[3].lower() user_uid = False orgUnit = u'/' - try: - if sys.argv[4].lower() in [u'ou', u'org']: - orgUnit = sys.argv[5] - except IndexError: - pass + i = 4 + while i < len(sys.argv): + if sys.argv[i].lower() in [u'ou', u'org']: + orgUnit = sys.argv[i+1] + i += 2 + else: + print u'ERROR: %s is not a valid argument for "gam undelete user"' % sys.argv[i] + sys.exit(2) if user[:4].lower() == u'uid:': user_uid = user[4:] elif user.find(u'@') == -1: @@ -8718,9 +8728,9 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, return_uids=Fa return full_users def OAuthInfo(): - try: + if len(sys.argv) > 3: access_token = sys.argv[3] - except IndexError: + else: storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT]) credentials = storage.get() if credentials is None or credentials.invalid: