Added output_dateformat and output_timeformat variables to gam.cfg

This commit is contained in:
Ross Scroggs
2023-08-07 12:19:10 -07:00
parent 5cb7299b64
commit c9cda88f7f
4 changed files with 59 additions and 11 deletions

View File

@@ -2,6 +2,14 @@
Merged GAM-Team version Merged GAM-Team version
6.62.00
Added `output_dateformat` and `output_timeformat` variables to `gam.cfg` that provide alternate
output date and time formats that may be required by programs that will be processing the data.
GAM will not accept alternate date/time formats as input.
* See: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes
6.61.21 6.61.21
Updated `gam <UserTypeEntity> empty drivetrash <SharedDriveEntity>` to use new Drive API v3 Updated `gam <UserTypeEntity> empty drivetrash <SharedDriveEntity>` to use new Drive API v3

View File

@@ -2309,20 +2309,33 @@ def formatLocalTime(dateTimeStr):
return GC.Values[GC.NEVER_TIME] return GC.Values[GC.NEVER_TIME]
try: try:
timestamp, _ = iso8601.parse_date(dateTimeStr) timestamp, _ = iso8601.parse_date(dateTimeStr)
if not GC.Values[GC.OUTPUT_TIMEFORMAT]:
if GM.Globals[GM.CONVERT_TO_LOCAL_TIME]: if GM.Globals[GM.CONVERT_TO_LOCAL_TIME]:
return ISOformatTimeStamp(timestamp.astimezone(GC.Values[GC.TIMEZONE])) return ISOformatTimeStamp(timestamp.astimezone(GC.Values[GC.TIMEZONE]))
return timestamp.strftime(YYYYMMDDTHHMMSSZ_FORMAT) return timestamp.strftime(YYYYMMDDTHHMMSSZ_FORMAT)
if GM.Globals[GM.CONVERT_TO_LOCAL_TIME]:
return timestamp.astimezone(GC.Values[GC.TIMEZONE]).strftime(GC.Values[GC.OUTPUT_TIMEFORMAT])
return timestamp.strftime(GC.Values[GC.OUTPUT_TIMEFORMAT])
except (iso8601.ParseError, OverflowError): except (iso8601.ParseError, OverflowError):
return dateTimeStr return dateTimeStr
def formatLocalSecondsTimestamp(timestamp): def formatLocalSecondsTimestamp(timestamp):
if not GC.Values[GC.OUTPUT_TIMEFORMAT]:
return ISOformatTimeStamp(datetime.datetime.fromtimestamp(int(timestamp), GC.Values[GC.TIMEZONE])) return ISOformatTimeStamp(datetime.datetime.fromtimestamp(int(timestamp), GC.Values[GC.TIMEZONE]))
return datetime.datetime.fromtimestamp(int(timestamp), GC.Values[GC.TIMEZONE]).strftime(GC.Values[GC.OUTPUT_TIMEFORMAT])
def formatLocalTimestamp(timestamp): def formatLocalTimestamp(timestamp):
if not GC.Values[GC.OUTPUT_TIMEFORMAT]:
return ISOformatTimeStamp(datetime.datetime.fromtimestamp(int(timestamp)//1000, GC.Values[GC.TIMEZONE])) return ISOformatTimeStamp(datetime.datetime.fromtimestamp(int(timestamp)//1000, GC.Values[GC.TIMEZONE]))
return datetime.datetime.fromtimestamp(int(timestamp)//1000, GC.Values[GC.TIMEZONE]).strftime(GC.Values[GC.OUTPUT_TIMEFORMAT])
def formatLocalTimestampUTC(timestamp):
return ISOformatTimeStamp(datetime.datetime.fromtimestamp(int(timestamp)//1000, iso8601.UTC))
def formatLocalDatestamp(timestamp): def formatLocalDatestamp(timestamp):
if not GC.Values[GC.OUTPUT_DATEFORMAT]:
return datetime.datetime.fromtimestamp(int(timestamp)//1000, GC.Values[GC.TIMEZONE]).strftime(YYYYMMDD_FORMAT) return datetime.datetime.fromtimestamp(int(timestamp)//1000, GC.Values[GC.TIMEZONE]).strftime(YYYYMMDD_FORMAT)
return datetime.datetime.fromtimestamp(int(timestamp)//1000, GC.Values[GC.TIMEZONE]).strftime(GC.Values[GC.OUTPUT_DATEFORMAT])
def formatMaxMessageBytes(maxMessageBytes, oneKiloBytes, oneMegaBytes): def formatMaxMessageBytes(maxMessageBytes, oneKiloBytes, oneMegaBytes):
if maxMessageBytes < oneKiloBytes: if maxMessageBytes < oneKiloBytes:
@@ -3979,9 +3992,14 @@ def SetGlobalVariables():
GC.Values[GC.DOMAIN] = GC.Values[GC.DOMAIN].lower() GC.Values[GC.DOMAIN] = GC.Values[GC.DOMAIN].lower()
if not GC.Values[GC.SMTP_FQDN]: if not GC.Values[GC.SMTP_FQDN]:
GC.Values[GC.SMTP_FQDN] = None GC.Values[GC.SMTP_FQDN] = None
# Inherit debug_level if not locally defined # Inherit debug_level, output_dateformat, output_timeformat if not locally defined
if GM.Globals[GM.PID] != 0 and GC.Values[GC.DEBUG_LEVEL] == 0: if GM.Globals[GM.PID] != 0:
if GC.Values[GC.DEBUG_LEVEL] == 0:
GC.Values[GC.DEBUG_LEVEL] = GM.Globals[GM.DEBUG_LEVEL] GC.Values[GC.DEBUG_LEVEL] = GM.Globals[GM.DEBUG_LEVEL]
if not GC.Values[GC.OUTPUT_DATEFORMAT]:
GC.Values[GC.OUTPUT_DATEFORMAT] = GM.Globals[GM.OUTPUT_DATEFORMAT]
if not GC.Values[GC.OUTPUT_TIMEFORMAT]:
GC.Values[GC.OUTPUT_TIMEFORMAT] = GM.Globals[GM.OUTPUT_TIMEFORMAT]
# Create/set mode for oauth2.txt.lock # Create/set mode for oauth2.txt.lock
if not GM.Globals[GM.OAUTH2_TXT_LOCK]: if not GM.Globals[GM.OAUTH2_TXT_LOCK]:
fileName = f'{GC.Values[GC.OAUTH2_TXT]}.lock' fileName = f'{GC.Values[GC.OAUTH2_TXT]}.lock'
@@ -9251,6 +9269,7 @@ def terminateStdQueueHandler(mpQueue, mpQueueHandler):
def ProcessGAMCommandMulti(pid, numItems, logCmd, mpQueueCSVFile, mpQueueStdout, mpQueueStderr, def ProcessGAMCommandMulti(pid, numItems, logCmd, mpQueueCSVFile, mpQueueStdout, mpQueueStderr,
debugLevel, todrive, debugLevel, todrive,
output_dateformat, output_timeformat,
csvColumnDelimiter, csvQuoteChar, csvColumnDelimiter, csvQuoteChar,
csvTimestampColumn, csvTimestampColumn,
csvHeaderFilter, csvHeaderDropFilter, csvHeaderFilter, csvHeaderDropFilter,
@@ -9284,6 +9303,8 @@ def ProcessGAMCommandMulti(pid, numItems, logCmd, mpQueueCSVFile, mpQueueStdout,
GM.Globals[GM.CSV_OUTPUT_TIMESTAMP_COLUMN] = csvTimestampColumn GM.Globals[GM.CSV_OUTPUT_TIMESTAMP_COLUMN] = csvTimestampColumn
GM.Globals[GM.CSV_TODRIVE] = todrive.copy() GM.Globals[GM.CSV_TODRIVE] = todrive.copy()
GM.Globals[GM.DEBUG_LEVEL] = debugLevel GM.Globals[GM.DEBUG_LEVEL] = debugLevel
GM.Globals[GM.OUTPUT_DATEFORMAT] = output_dateformat
GM.Globals[GM.OUTPUT_TIMEFORMAT] = output_timeformat
GM.Globals[GM.NUM_BATCH_ITEMS] = numItems GM.Globals[GM.NUM_BATCH_ITEMS] = numItems
GM.Globals[GM.PID] = pid GM.Globals[GM.PID] = pid
GM.Globals[GM.SAVED_STDOUT] = None GM.Globals[GM.SAVED_STDOUT] = None
@@ -9455,6 +9476,7 @@ def MultiprocessGAMCommands(items, showCmds):
poolProcessResults[pid] = pool.apply_async(ProcessGAMCommandMulti, poolProcessResults[pid] = pool.apply_async(ProcessGAMCommandMulti,
[pid, numItems, logCmd, mpQueueCSVFile, mpQueueStdout, mpQueueStderr, [pid, numItems, logCmd, mpQueueCSVFile, mpQueueStdout, mpQueueStderr,
GC.Values[GC.DEBUG_LEVEL], GM.Globals[GM.CSV_TODRIVE], GC.Values[GC.DEBUG_LEVEL], GM.Globals[GM.CSV_TODRIVE],
GC.Values[GC.OUTPUT_DATEFORMAT], GC.Values[GC.OUTPUT_TIMEFORMAT],
GC.Values[GC.CSV_OUTPUT_COLUMN_DELIMITER], GC.Values[GC.CSV_OUTPUT_COLUMN_DELIMITER],
GC.Values[GC.CSV_OUTPUT_QUOTE_CHAR], GC.Values[GC.CSV_OUTPUT_QUOTE_CHAR],
GC.Values[GC.CSV_OUTPUT_TIMESTAMP_COLUMN], GC.Values[GC.CSV_OUTPUT_TIMESTAMP_COLUMN],
@@ -15315,6 +15337,10 @@ def doInfoCustomer(returnCustomerInfo=None, FJQC=None):
customerInfo = callGAPI(cd.customers(), 'get', customerInfo = callGAPI(cd.customers(), 'get',
throwReasons=[GAPI.BAD_REQUEST, GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN], throwReasons=[GAPI.BAD_REQUEST, GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
customerKey=customerId) customerKey=customerId)
if 'customerCreationTime' in customerInfo:
customerInfo['customerCreationTime'] = formatLocalTime(customerInfo['customerCreationTime'])
else:
customerInfo['customerCreationTime'] = UNKNOWN
primaryDomain = {'domainName': UNKNOWN, 'verified': UNKNOWN} primaryDomain = {'domainName': UNKNOWN, 'verified': UNKNOWN}
try: try:
domains = callGAPIitems(cd.domains(), 'list', 'domains', domains = callGAPIitems(cd.domains(), 'list', 'domains',
@@ -15329,10 +15355,10 @@ def doInfoCustomer(returnCustomerInfo=None, FJQC=None):
# We should get all domains and use oldest date # We should get all domains and use oldest date
customerCreationTime = UNKNOWN customerCreationTime = UNKNOWN
for domain in domains: for domain in domains:
domainCreationTime = formatLocalTimestamp(domain['creationTime']) domainCreationTime = formatLocalTimestampUTC(domain['creationTime'])
if customerCreationTime == UNKNOWN or domainCreationTime < customerCreationTime: if customerCreationTime == UNKNOWN or domainCreationTime < customerCreationTime:
customerCreationTime = domainCreationTime customerCreationTime = domainCreationTime
customerInfo['customerCreationTime'] = customerCreationTime customerInfo['customerCreationTime'] = formatLocalTime(customerCreationTime)
except (GAPI.badRequest, GAPI.notFound): except (GAPI.badRequest, GAPI.notFound):
pass pass
customerInfo['customerDomain'] = primaryDomain['domainName'] customerInfo['customerDomain'] = primaryDomain['domainName']
@@ -15347,7 +15373,7 @@ def doInfoCustomer(returnCustomerInfo=None, FJQC=None):
printKeyValueList(['Customer ID', customerInfo['id']]) printKeyValueList(['Customer ID', customerInfo['id']])
printKeyValueList(['Primary Domain', customerInfo['customerDomain']]) printKeyValueList(['Primary Domain', customerInfo['customerDomain']])
printKeyValueList(['Primary Domain Verified', customerInfo['verified']]) printKeyValueList(['Primary Domain Verified', customerInfo['verified']])
printKeyValueList(['Customer Creation Time', customerInfo.get('customerCreationTime', UNKNOWN)]) printKeyValueList(['Customer Creation Time', customerInfo['customerCreationTime']])
printKeyValueList(['Default Language', customerInfo.get('language', 'Unset or Unknown (defaults to en)')]) printKeyValueList(['Default Language', customerInfo.get('language', 'Unset or Unknown (defaults to en)')])
_showCustomerAddressPhoneNumber(customerInfo) _showCustomerAddressPhoneNumber(customerInfo)
printKeyValueList(['Admin Secondary Email', customerInfo.get('alternateEmail', UNKNOWN)]) printKeyValueList(['Admin Secondary Email', customerInfo.get('alternateEmail', UNKNOWN)])

View File

@@ -192,6 +192,10 @@ NUM_THREADS = 'num_threads'
OAUTH2_TXT = 'oauth2_txt' OAUTH2_TXT = 'oauth2_txt'
# Path to oauth2service.json # Path to oauth2service.json
OAUTH2SERVICE_JSON = 'oauth2service_json' OAUTH2SERVICE_JSON = 'oauth2service_json'
# Output date format, empty defalts to ISOFormat
OUTPUT_DATEFORMAT = 'output_dateformat'
# Output time format, empty defalts to ISOFormat
OUTPUT_TIMEFORMAT = 'output_timeformat'
# When retrieving lists of people from API, how many should be retrieved in each chunk # When retrieving lists of people from API, how many should be retrieved in each chunk
PEOPLE_MAX_RESULTS = 'people_max_results' PEOPLE_MAX_RESULTS = 'people_max_results'
# Use quick method to move Chromebooks to OU # Use quick method to move Chromebooks to OU
@@ -354,6 +358,8 @@ Defaults = {
NUM_THREADS: '5', NUM_THREADS: '5',
OAUTH2_TXT: FN_OAUTH2_TXT, OAUTH2_TXT: FN_OAUTH2_TXT,
OAUTH2SERVICE_JSON: FN_OAUTH2SERVICE_JSON, OAUTH2SERVICE_JSON: FN_OAUTH2SERVICE_JSON,
OUTPUT_DATEFORMAT: '',
OUTPUT_TIMEFORMAT: '',
PEOPLE_MAX_RESULTS: '100', PEOPLE_MAX_RESULTS: '100',
QUICK_CROS_MOVE: FALSE, QUICK_CROS_MOVE: FALSE,
QUICK_INFO_USER: FALSE, QUICK_INFO_USER: FALSE,
@@ -499,6 +505,8 @@ VAR_INFO = {
NUM_THREADS: {VAR_TYPE: TYPE_INTEGER, VAR_ENVVAR: 'GAM_THREADS', VAR_LIMITS: (1, 1000)}, NUM_THREADS: {VAR_TYPE: TYPE_INTEGER, VAR_ENVVAR: 'GAM_THREADS', VAR_LIMITS: (1, 1000)},
OAUTH2_TXT: {VAR_TYPE: TYPE_FILE, VAR_ENVVAR: 'OAUTHFILE', VAR_ACCESS: os.R_OK | os.W_OK}, OAUTH2_TXT: {VAR_TYPE: TYPE_FILE, VAR_ENVVAR: 'OAUTHFILE', VAR_ACCESS: os.R_OK | os.W_OK},
OAUTH2SERVICE_JSON: {VAR_TYPE: TYPE_FILE, VAR_ENVVAR: 'OAUTHSERVICEFILE', VAR_ACCESS: os.R_OK | os.W_OK}, OAUTH2SERVICE_JSON: {VAR_TYPE: TYPE_FILE, VAR_ENVVAR: 'OAUTHSERVICEFILE', VAR_ACCESS: os.R_OK | os.W_OK},
OUTPUT_DATEFORMAT: {VAR_TYPE: TYPE_STRING, VAR_LIMITS: (0, None)},
OUTPUT_TIMEFORMAT: {VAR_TYPE: TYPE_STRING, VAR_LIMITS: (0, None)},
PEOPLE_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (0, 1000)}, PEOPLE_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (0, 1000)},
QUICK_CROS_MOVE: {VAR_TYPE: TYPE_BOOLEAN}, QUICK_CROS_MOVE: {VAR_TYPE: TYPE_BOOLEAN},
QUICK_INFO_USER: {VAR_TYPE: TYPE_BOOLEAN}, QUICK_INFO_USER: {VAR_TYPE: TYPE_BOOLEAN},

View File

@@ -148,6 +148,10 @@ OAUTH2SERVICE_JSON_DATA = 'osjd'
OAUTH2_CLIENT_ID = 'oaci' OAUTH2_CLIENT_ID = 'oaci'
# oauth2.txt lock file # oauth2.txt lock file
OAUTH2_TXT_LOCK = 'oatl' OAUTH2_TXT_LOCK = 'oatl'
# Output date format, empty defalts to ISOFormat
OUTPUT_DATEFORMAT = 'oudf'
# Output time format, empty defalts to ISOFormat
OUTPUT_TIMEFORMAT = 'outf'
# gam.cfg parser # gam.cfg parser
PARSER = 'pars' PARSER = 'pars'
# Process ID # Process ID
@@ -261,6 +265,8 @@ Globals = {
OAUTH2SERVICE_JSON_DATA: {}, OAUTH2SERVICE_JSON_DATA: {},
OAUTH2_CLIENT_ID: None, OAUTH2_CLIENT_ID: None,
OAUTH2_TXT_LOCK: None, OAUTH2_TXT_LOCK: None,
OUTPUT_DATEFORMAT: '',
OUTPUT_TIMEFORMAT: '',
PARSER: None, PARSER: None,
PID: 0, PID: 0,
RATE_CHECK_COUNT: 0, RATE_CHECK_COUNT: 0,