gam report updates

This commit is contained in:
Ross Scroggs
2024-06-27 10:11:06 -07:00
parent e66ff54c3c
commit 435388aa0b
5 changed files with 66 additions and 22 deletions

View File

@@ -21,6 +21,17 @@ Thanks to jay, added the following Colab License SKUs:
Thanks to Jay, updated `gam print|show admins` to properly display addresses Thanks to Jay, updated `gam print|show admins` to properly display addresses
of service accounts with admin role assignments. of service accounts with admin role assignments.
Added option `limitdatechanges <Integer>` to `gam report users|customers`.
If no report is available for the specified date, can an earlier date be used?
* `limitdatechanges -1' - Back up to earlier dates to find report data; this is the default.
* `limitdatechanges 0 | nodatechange' - Do not report on an earlier date if no report data is available for the specified date.
* `limitdatechanges N' - Back up to earlier dates to find report data; do not back up more than N times.
By default, when `gam report user user <UserItem>` is specified and no report data is available, there is no output.
If `csv_output_users_audit = true` in `gam.cfg`, then a row with columns `email,date` will be displayed
where `date` is the earliest date for which report data was requested.
### 6.77.02 ### 6.77.02
Cleaned up problems with some of the new Chat API asadmin commands. Cleaned up problems with some of the new Chat API asadmin commands.

View File

@@ -234,7 +234,7 @@ Customer reports are generally available up to two days before the current date.
gam report customers|customer|domain [todrive <ToDriveAttributes>*] gam report customers|customer|domain [todrive <ToDriveAttributes>*]
[(date <Date>)|(range <Date> <Date>)| [(date <Date>)|(range <Date> <Date>)|
yesterday|today|thismonth|(previousmonths <Integer>)] yesterday|today|thismonth|(previousmonths <Integer>)]
[nodatechange|(fulldatarequired all|<CustomerServiceNameList>)] [(nodatechange | limitdatechanges <Integer>) | (fulldatarequired all|<CustomerServiceNameList>)]
[(fields|parameters <String>)|(services <CustomerServiceNameList>)] [(fields|parameters <String>)|(services <CustomerServiceNameList>)]
[noauthorizedapps] [noauthorizedapps]
``` ```
@@ -247,7 +247,9 @@ Specify the report date; the default is today's date.
* `previousmonths <Integer>` - A number in the range 1 to 6 indicating calendar months previous to the current month; there is an API call per date * `previousmonths <Integer>` - A number in the range 1 to 6 indicating calendar months previous to the current month; there is an API call per date
If no report is available for the specified date, can an earlier date be used? If no report is available for the specified date, can an earlier date be used?
* `nodatechange` - Do not report on an earlier date if no report is available for the specified date. * `limitdatechanges -1' - Back up to earlier dates to find report data; this is the default.
* `limitdatechanges 0 | nodatechange' - Do not report on an earlier date if no report data is available for the specified date.
* `limitdatechanges N' - Back up to earlier dates to find report data; do not back up more than N times.
If only partial report data is available for the specified date and applications, can an earlier date be used? If only partial report data is available for the specified date and applications, can an earlier date be used?
* `fulldatarequired all` - Back up to an earlier date to get complete data until all applications have full report data * `fulldatarequired all` - Back up to an earlier date to get complete data until all applications have full report data
@@ -328,7 +330,7 @@ gam report users|user [todrive <ToDriveAttributes>*]
[allverifyuser <UserItem>] [allverifyuser <UserItem>]
[(date <Date>)|(range <Date> <Date>)| [(date <Date>)|(range <Date> <Date>)|
yesterday|today|thismonth|(previousmonths <Integer>)] yesterday|today|thismonth|(previousmonths <Integer>)]
[nodatechange|(fulldatarequired all|<UserServiceNameList>)] [(nodatechange | limitdatechanges <Integer>) | (fulldatarequired all|<UserServiceNameList>)]
[filtertime.* <Time>] [filter|filters <String>] [filtertime.* <Time>] [filter|filters <String>]
[(fields|parameters <String>)|(services <UserServiceNameList>)] [(fields|parameters <String>)|(services <UserServiceNameList>)]
[aggregatebydate|aggregatebyuser [Boolean]] [aggregatebydate|aggregatebyuser [Boolean]]
@@ -353,12 +355,18 @@ Specify the report date; the default is today's date.
* `previousmonths <Integer>` - A number in the range 1 to 6 indicating calendar months previous to the current month; there is an API call per date * `previousmonths <Integer>` - A number in the range 1 to 6 indicating calendar months previous to the current month; there is an API call per date
If no report is available for the specified date, can an earlier date be used? If no report is available for the specified date, can an earlier date be used?
* `nodatechange` - Do not report on an earlier date if no report is available for the specified date. * `limitdatechanges -1' - Back up to earlier dates to find report data; this is the default.
* `limitdatechanges 0 | nodatechange' - Do not report on an earlier date if no report data is available for the specified date.
* `limitdatechanges N' - Back up to earlier dates to find report data; do not back up more than N times.
If only partial report data is available for the specified date and applications, can an earlier date be used? If only partial report data is available for the specified date and applications, can an earlier date be used?
* `fulldatarequired all` - Back up to an earlier date to get complete data until all applications have full report data * `fulldatarequired all` - Back up to an earlier date to get complete data until all applications have full report data
* `fulldatarequired <UserServiceNameList>` - Back up to an earlier date to get complete data until all applications in `<UserServiceNameList>` have full report data * `fulldatarequired <UserServiceNameList>` - Back up to an earlier date to get complete data until all applications in `<UserServiceNameList>` have full report data
By default, when `user <UserItem>` is specified and no report data is available, there is no output.
If `csv_output_users_audit = true` in `gam.cfg`, then a row with columns `email,date` will be displayed
where `date` is the earliest date for which report data was requested.
Apply filters. Apply filters.
* `filter|filters <String>` - `<String>` is a comma separated list of filter expressions. * `filter|filters <String>` - `<String>` is a comma separated list of filter expressions.

View File

@@ -4331,7 +4331,7 @@ gam report <ActivityApplicationName> [todrive <ToDriveAttribute>*]
gam report customers|customer|domain [todrive <ToDriveAttribute>*] gam report customers|customer|domain [todrive <ToDriveAttribute>*]
[(date <Date>)|(range <Date> <Date>)| [(date <Date>)|(range <Date> <Date>)|
yesterday|today|thismonth|(previousmonths <Integer>)] yesterday|today|thismonth|(previousmonths <Integer>)]
[nodatechange | (fulldatarequired all|<CustomerServiceNameList>)] [(nodatechange | limitdatechanges <Integer>) | (fulldatarequired all|<CustomerServiceNameList>)]
[(fields|parameters <String>)|(services <CustomerServiceNameList>)] [noauthorizedapps] [(fields|parameters <String>)|(services <CustomerServiceNameList>)] [noauthorizedapps]
<UserServiceName> ::= <UserServiceName> ::=
@@ -4348,7 +4348,7 @@ gam report users|user [todrive <ToDriveAttribute>*]
[allverifyuser <UserItem>] [allverifyuser <UserItem>]
[(date <Date>)|(range <Date> <Date>)| [(date <Date>)|(range <Date> <Date>)|
yesterday|today|thismonth|(previousmonths <Integer>)] yesterday|today|thismonth|(previousmonths <Integer>)]
[nodatechange | (fulldatarequired all|<UserServiceNameList>)] [(nodatechange | limitdatechanges <Integer>) | (fulldatarequired all|<UserServiceNameList>)]
[filtertime.* <Time>] [filter|filters <String>] [filtertime.* <Time>] [filter|filters <String>]
[(fields|parameters <String>)|(services <UserServiceNameList>)] [(fields|parameters <String>)|(services <UserServiceNameList>)]
[aggregatebydate|aggregatebyuser [Boolean]] [aggregatebydate|aggregatebyuser [Boolean]]

View File

@@ -1,3 +1,14 @@
Added option `limitdatechanges <Integer>` to `gam report users|customers`.
If no report is available for the specified date, can an earlier date be used?
* `limitdatechanges -1' - Back up to earlier dates to find report data; this is the default.
* `limitdatechanges 0 | nodatechange' - Do not report on an earlier date if no report data is available for the specified date.
* `limitdatechanges N' - Back up to earlier dates to find report data; do not back up more than N times.
By default, when `gam report user user <UserItem>` is specified and no report data is available, there is no output.
If `csv_output_users_audit = true` in `gam.cfg`, then a row with columns `email,date` will be displayed
where `date` is the earliest date for which report data was requested.
7.00.00 7.00.00
Merged GAM-Team version Merged GAM-Team version

View File

@@ -11735,8 +11735,8 @@ def doCreateProject():
# (yubikey yubikey_pin yubikey_slot AUTHENTICATION yubikey_serialnumber <String>)] # (yubikey yubikey_pin yubikey_slot AUTHENTICATION yubikey_serialnumber <String>)]
def doUseProject(): def doUseProject():
_checkForExistingProjectFiles([GC.Values[GC.OAUTH2SERVICE_JSON], GC.Values[GC.CLIENT_SECRETS_JSON]]) _checkForExistingProjectFiles([GC.Values[GC.OAUTH2SERVICE_JSON], GC.Values[GC.CLIENT_SECRETS_JSON]])
_, httpObj, login_hint, _, projectInfo, svcAcctInfo = _getLoginHintProjectInfo(False) _, httpObj, login_hint, _, projectInfo, svcAcctInfo, create_key = _getLoginHintProjectInfo(False)
_createClientSecretsOauth2service(httpObj, login_hint, {}, projectInfo, svcAcctInfo) _createClientSecretsOauth2service(httpObj, login_hint, {}, projectInfo, svcAcctInfo, create_key)
# gam update project [[admin] <EmailAddress>] [<ProjectIDEntity>] # gam update project [[admin] <EmailAddress>] [<ProjectIDEntity>]
def doUpdateProject(): def doUpdateProject():
@@ -12910,7 +12910,7 @@ def doWhatIs():
entityUnknownWarning(Ent.EMAIL, email) entityUnknownWarning(Ent.EMAIL, email)
setSysExitRC(ENTITY_IS_UKNOWN_RC) setSysExitRC(ENTITY_IS_UKNOWN_RC)
def _adjustTryDate(errMsg, noDateChange, prevTryDate): def _adjustTryDate(errMsg, numDateChanges, limitDateChanges, prevTryDate):
match_date = re.match('Data for dates later than (.*) is not yet available. Please check back later', errMsg) match_date = re.match('Data for dates later than (.*) is not yet available. Please check back later', errMsg)
if match_date: if match_date:
tryDate = match_date.group(1) tryDate = match_date.group(1)
@@ -12923,7 +12923,7 @@ def _adjustTryDate(errMsg, noDateChange, prevTryDate):
if match_date: if match_date:
tryDateTime = datetime.datetime.strptime(prevTryDate, YYYYMMDD_FORMAT)-datetime.timedelta(days=1) tryDateTime = datetime.datetime.strptime(prevTryDate, YYYYMMDD_FORMAT)-datetime.timedelta(days=1)
tryDate = tryDateTime.strftime(YYYYMMDD_FORMAT) tryDate = tryDateTime.strftime(YYYYMMDD_FORMAT)
if (not match_date) or noDateChange: if (not match_date) or (numDateChanges > limitDateChanges >= 0):
printWarningMessage(DATA_NOT_AVALIABLE_RC, errMsg) printWarningMessage(DATA_NOT_AVALIABLE_RC, errMsg)
return None return None
return tryDate return tryDate
@@ -13034,7 +13034,7 @@ def doReportUsageParameters():
printErrorMessage(BAD_REQUEST_RC, Msg.BAD_REQUEST) printErrorMessage(BAD_REQUEST_RC, Msg.BAD_REQUEST)
return return
except GAPI.invalid as e: except GAPI.invalid as e:
tryDate = _adjustTryDate(str(e), False, tryDate) tryDate = _adjustTryDate(str(e), 0, -1, tryDate)
if not tryDate: if not tryDate:
break break
for parameter in sorted(allParameters): for parameter in sorted(allParameters):
@@ -13610,8 +13610,9 @@ def doReport():
filterTimes = {} filterTimes = {}
maxActivities = maxEvents = 0 maxActivities = maxEvents = 0
maxResults = 1000 maxResults = 1000
aggregateByDate = aggregateByUser = countsOnly = eventRowFilter = exitUserLoop = noAuthorizedApps = noDateChange = \ aggregateByDate = aggregateByUser = countsOnly = eventRowFilter = exitUserLoop = noAuthorizedApps = \
normalizeUsers = select = summary = userCustomerRange = False normalizeUsers = select = summary = userCustomerRange = False
limitDateChanges = -1
allVerifyUser = userKey = 'all' allVerifyUser = userKey = 'all'
cd = orgUnit = orgUnitId = None cd = orgUnit = orgUnitId = None
userOrgUnits = {} userOrgUnits = {}
@@ -13651,9 +13652,12 @@ def doReport():
startEndTime.Get('start' if myarg == 'date' else myarg) startEndTime.Get('start' if myarg == 'date' else myarg)
startEndTime.endDateTime = startEndTime.startDateTime startEndTime.endDateTime = startEndTime.startDateTime
userCustomerRange = False userCustomerRange = False
elif usageReports and myarg == 'nodatechange': elif usageReports and myarg in {'nodatechange', 'limitdatechanges'}:
noDateChange = True if myarg == 'nodatechange':
if (startEndTime.startDateTime is not None) and (startEndTime.endDateTime == startEndTime.startDateTime): limitDateChanges = 0
else:
limitDateChanges = getInteger(minVal=-1)
if (limitDateChanges == 0) and (startEndTime.startDateTime is not None) and (startEndTime.endDateTime == startEndTime.startDateTime):
userCustomerRange = True userCustomerRange = True
elif usageReports and myarg in {'fields', 'parameters'}: elif usageReports and myarg in {'fields', 'parameters'}:
for field in getString(Cmd.OB_STRING).replace(',', ' ').split(): for field in getString(Cmd.OB_STRING).replace(',', ' ').split():
@@ -13787,6 +13791,7 @@ def doReport():
startDateTime = startEndTime.startDateTime startDateTime = startEndTime.startDateTime
endDateTime = startEndTime.endDateTime endDateTime = startEndTime.endDateTime
lastDate = None lastDate = None
numDateChanges = 0
while startDateTime <= endDateTime: while startDateTime <= endDateTime:
tryDate = startDateTime.strftime(YYYYMMDD_FORMAT) tryDate = startDateTime.strftime(YYYYMMDD_FORMAT)
try: try:
@@ -13796,13 +13801,15 @@ def doReport():
userKey=verifyUser, date=tryDate, customerId=customerId, userKey=verifyUser, date=tryDate, customerId=customerId,
orgUnitID=orgUnitId, parameters=parameters, orgUnitID=orgUnitId, parameters=parameters,
fields='warnings,usageReports', maxResults=1) fields='warnings,usageReports', maxResults=1)
prevTryDate = tryDate
fullData, tryDate, usageReports = _checkDataRequiredServices(result, tryDate, fullData, tryDate, usageReports = _checkDataRequiredServices(result, tryDate,
dataRequiredServices, parameterServices, True) dataRequiredServices, parameterServices, True)
if fullData < 0: if fullData < 0:
printWarningMessage(DATA_NOT_AVALIABLE_RC, Msg.NO_REPORT_AVAILABLE.format(report)) printWarningMessage(DATA_NOT_AVALIABLE_RC, Msg.NO_REPORT_AVAILABLE.format(report))
break break
numDateChanges += 1
if fullData == 0: if fullData == 0:
if noDateChange: if numDateChanges > limitDateChanges >= 0:
break break
startDateTime = endDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT) startDateTime = endDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT)
continue continue
@@ -13810,6 +13817,7 @@ def doReport():
pageMessage = getPageMessageForWhom(forWhom, showDate=tryDate) pageMessage = getPageMessageForWhom(forWhom, showDate=tryDate)
else: else:
pageMessage = getPageMessageForWhom(user, showDate=tryDate) pageMessage = getPageMessageForWhom(user, showDate=tryDate)
prevTryDate = tryDate
usage = callGAPIpages(service, 'get', 'usageReports', usage = callGAPIpages(service, 'get', 'usageReports',
pageMessage=pageMessage, pageMessage=pageMessage,
throwReasons=[GAPI.INVALID, GAPI.INVALID_INPUT, GAPI.BAD_REQUEST, GAPI.FORBIDDEN], throwReasons=[GAPI.INVALID, GAPI.INVALID_INPUT, GAPI.BAD_REQUEST, GAPI.FORBIDDEN],
@@ -13825,7 +13833,8 @@ def doReport():
if not status: if not status:
break break
except GAPI.invalid as e: except GAPI.invalid as e:
tryDate = _adjustTryDate(str(e), noDateChange, tryDate) numDateChanges += 1
tryDate = _adjustTryDate(str(e), numDateChanges, limitDateChanges, tryDate)
if not tryDate: if not tryDate:
break break
startDateTime = endDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT) startDateTime = endDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT)
@@ -13844,6 +13853,8 @@ def doReport():
startDateTime += oneDay startDateTime += oneDay
if exitUserLoop: if exitUserLoop:
break break
if user != 'all' and lastDate is None and GC.Values[GC.CSV_OUTPUT_USERS_AUDIT]:
csvPF.WriteRowNoFilter({'date': prevTryDate, 'email': user})
if aggregateByDate: if aggregateByDate:
for usageDate, events in iter(eventCounts.items()): for usageDate, events in iter(eventCounts.items()):
row = {'date': usageDate} row = {'date': usageDate}
@@ -13875,6 +13886,7 @@ def doReport():
startDateTime = startEndTime.startDateTime startDateTime = startEndTime.startDateTime
endDateTime = startEndTime.endDateTime endDateTime = startEndTime.endDateTime
lastDate = None lastDate = None
numDateChanges = 0
while startDateTime <= endDateTime: while startDateTime <= endDateTime:
tryDate = startDateTime.strftime(YYYYMMDD_FORMAT) tryDate = startDateTime.strftime(YYYYMMDD_FORMAT)
try: try:
@@ -13887,8 +13899,9 @@ def doReport():
if fullData < 0: if fullData < 0:
printWarningMessage(DATA_NOT_AVALIABLE_RC, Msg.NO_REPORT_AVAILABLE.format(report)) printWarningMessage(DATA_NOT_AVALIABLE_RC, Msg.NO_REPORT_AVAILABLE.format(report))
break break
numDateChanges += 1
if fullData == 0: if fullData == 0:
if noDateChange: if numDateChanges > limitDateChanges >= 0:
break break
startDateTime = endDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT) startDateTime = endDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT)
continue continue
@@ -13902,7 +13915,8 @@ def doReport():
if not status: if not status:
break break
except GAPI.invalid as e: except GAPI.invalid as e:
tryDate = _adjustTryDate(str(e), noDateChange, tryDate) numDateChanges += 1
tryDate = _adjustTryDate(str(e), numDateChanges, limitDateChanges, tryDate)
if not tryDate: if not tryDate:
break break
startDateTime = endDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT) startDateTime = endDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT)
@@ -14016,7 +14030,7 @@ def doReport():
if addCSVData: if addCSVData:
row.update(addCSVData) row.update(addCSVData)
csvPF.WriteRowTitles(row) csvPF.WriteRowTitles(row)
if maxEvents > 0 and numEvents >= maxEvents: if numEvents >= maxEvents > 0:
break break
elif csvPF.CheckRowTitles(row): elif csvPF.CheckRowTitles(row):
if not summary: if not summary:
@@ -15836,7 +15850,7 @@ def _showCustomerLicenseInfo(customerInfo, FJQC):
continue continue
break break
except GAPI.invalid as e: except GAPI.invalid as e:
tryDate = _adjustTryDate(str(e), False, tryDate) tryDate = _adjustTryDate(str(e), 0, -1, tryDate)
if not tryDate: if not tryDate:
return return
continue continue
@@ -45495,7 +45509,7 @@ class CourseAttributes():
entityModifierItemValueListActionNotPerformedWarning([Ent.COURSE, newCourseId, Ent.COURSE_WORK, f'{body.get("title", courseWorkId)}'], Act.MODIFIER_FROM, entityModifierItemValueListActionNotPerformedWarning([Ent.COURSE, newCourseId, Ent.COURSE_WORK, f'{body.get("title", courseWorkId)}'], Act.MODIFIER_FROM,
[Ent.COURSE, self.courseId], 'individualStudentAssignments delete', j, jcount) [Ent.COURSE, self.courseId], 'individualStudentAssignments delete', j, jcount)
continue continue
elif self.individualStudentAssignments == 'maptoall': if self.individualStudentAssignments == 'maptoall':
body['assigneeMode'] = 'ALL_STUDENTS' body['assigneeMode'] = 'ALL_STUDENTS'
body.pop('individualStudentsOptions', None) body.pop('individualStudentsOptions', None)
if self.copyMaterialsFiles: if self.copyMaterialsFiles: