Compare commits

...

5 Commits

8 changed files with 158 additions and 52 deletions

View File

@@ -10,6 +10,28 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
See [Downloads](https://github.com/taers232c/GAMADV-XTD3/wiki/Downloads) for Windows or other options, including manual installation
### 6.77.09
Added option `usertokencounts` to `gam <UserTypeEntity> print|show tokens` that causes GAM to display
each user and their number of access tokens; there are no details.
### 6.77.08
Fixed bugs in `gam <UserTypeEntity> delete chatmember <ChatSpace> ... group <GroupItem>`
and `gam <UserTypeEntity> sync chatmember <ChatSpace> ... groups <GroupEntity>` that caused an error.
### 6.77.07
Fixed bug in `gam <UserTypeEntity> create chatmember <ChatSpace> ... group <GroupItem>` that caused an error.
### 6.77.06
Updated `gam update ou <OrgUnitItem> ... parent <OrgUnitItem>` to handle the following error
that occurs when `parent <OrgUnitItem>` is the same as or a sub-OU of `ou <OrgUnitItem>`.
```
ERROR: 412: conditionNotMet - OrgUnit hierarchy has cycle
```
### 6.77.05
Added option `onlyusers <UserTypeEntity>` to `gam <UserTypeEntity> claim ownership <DriveFileEntity>`

View File

@@ -335,7 +335,7 @@ writes the credentials into the file oauth2.txt.
admin@server:/Users/admin/bin/gamadv-xtd3$ rm -f /Users/admin/GAMConfig/oauth2.txt
admin@server:/Users/admin/bin/gamadv-xtd3$ ./gam version
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
GAMADV-XTD3 6.77.05 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.77.09 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.4 64-bit final
MacOS Sonoma 14.5 x86_64
@@ -1009,7 +1009,7 @@ writes the credentials into the file oauth2.txt.
C:\GAMADV-XTD3>del C:\GAMConfig\oauth2.txt
C:\GAMADV-XTD3>gam version
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
GAMADV-XTD3 6.77.05 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.77.09 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.4 64-bit final
Windows-10-10.0.17134 AMD64

View File

@@ -619,11 +619,10 @@ You may get the following error from Google when trying to download a file:
Download Failed: This file has been identified as malware or spam and cannot be downloaded.
```
Use the `acknowledgeabuse` option to control downloading the file.
* `acknowledgeabuse` - Download the file
* `acknowledgeabuse true` - Download the file
* `acknowledgeabuse` - Download the file; `the user is acknowledging the risk of downloading known malware or other abusive files`
* `acknowledgeabuse true` - Download the file; `the user is acknowledging the risk of downloading known malware or other abusive files`
* `acknowledgeabuse false` - Do not download the file; this is the default
Whether the user is acknowledging the risk of downloading known malware or other abusive files.
### Example: Download a CSV file and execute a Gam command on its contents
Suppose you have a Google Sheets file UserSheet with multiple sheets, one of which is named NewUsers; it has a column labelled primaryEmail.

View File

@@ -3,6 +3,7 @@
- [Definitions](#definitions)
- [Delete a user's token](#delete-a-users-token)
- [Display individual user's tokens](#display-individual-users-tokens)
- [Display individual user's token counts](#display-individual-users-token-counts)
- [Display aggregated user's tokens](#display-aggregated-users-tokens)
## API documentation
@@ -27,6 +28,9 @@ gam <UserTypeEntity> show tokens|token|3lo|oauth [clientid <ClientID>]
gam print tokens|token [todrive <ToDriveAttributes>*] [clientid <ClientID>]
[orderby clientid|id|appname|displaytext] [delimiter <Character>]
[<UserTypeEntity>]
gam show tokens|token [clientid <ClientID>]
[orderby clientid|id|appname|displaytext] [delimiter <Character>]
[<UserTypeEntity>]
```
By default, all client tokens for a user are displayed, use `clientid <ClientID>` to display a specific client token.
@@ -43,6 +47,26 @@ This example shows which domain users have the Google Apps Sync for Microsoft Ou
gam all users print token clientid 1095133494869.apps.googleusercontent.com
```
## Display individual user's token counts
```
gam <UserTypeEntity> print tokens|token [todrive <ToDriveAttributes>*] [clientid <ClientID>]
usertokencounts
gam <UserTypeEntity> show tokens|token|3lo|oauth [clientid <ClientID>]
usertokencounts
gam print tokens|token [todrive <ToDriveAttributes>*] [clientid <ClientID>]
usertokencounts
[<UserTypeEntity>]
gam show tokens|token [clientid <ClientID>]
usertokencounts
[<UserTypeEntity>]
```
### Example
This example shows which domain users have any access tokens.
```
gam config csv_output_row_filter "tokenCount:count>0" all users print tokens usertokencounts
```
## Display aggregated user's tokens
```
gam <UserTypeEntity> print tokens|token [todrive <ToDriveAttributes>*] [clientid <ClientID>]

View File

@@ -3,7 +3,7 @@
Print the current version of Gam with details
```
gam version
GAMADV-XTD3 6.77.05 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.77.09 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.4 64-bit final
MacOS Sonoma 14.5 x86_64
@@ -15,7 +15,7 @@ Time: 2023-06-02T21:10:00-07:00
Print the current version of Gam with details and time offset information
```
gam version timeoffset
GAMADV-XTD3 6.77.05 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.77.09 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.4 64-bit final
MacOS Sonoma 14.5 x86_64
@@ -27,7 +27,7 @@ Your system time differs from www.googleapis.com by less than 1 second
Print the current version of Gam with extended details and SSL information
```
gam version extended
GAMADV-XTD3 6.77.05 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.77.09 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.4 64-bit final
MacOS Sonoma 14.5 x86_64
@@ -64,7 +64,7 @@ MacOS High Sierra 10.13.6 x86_64
Path: /Users/Admin/bin/gamadv-xtd3
Version Check:
Current: 5.35.08
Latest: 6.77.05
Latest: 6.77.09
echo $?
1
```
@@ -72,7 +72,7 @@ echo $?
Print the current version number without details
```
gam version simple
6.77.05
6.77.09
```
In Linux/MacOS you can do:
```
@@ -82,7 +82,7 @@ echo $VER
Print the current version of Gam and address of this Wiki
```
gam help
GAM 6.77.05 - https://github.com/taers232c/GAMADV-XTD3
GAM 6.77.09 - https://github.com/taers232c/GAMADV-XTD3
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.4 64-bit final
MacOS Sonoma 14.5 x86_64

View File

@@ -6462,6 +6462,7 @@ gam <UserTypeEntity> get drivefile <DriveFileEntity> [revision <DriveFileRevisio
[(format <FileFormatList>)|(gsheet|csvsheet <SheetEntity>)] [exportsheetaspdf <String>]
[targetfolder <FilePath>] [targetname <FileName>|-]
[donotfollowshortcuts [<Boolean>]] [overwrite [<Boolean>]] [showprogress [<Boolean>]]
[acknowledgeabuse [<Boolean>]]
gam <UserTypeEntity> delete drivefile <DriveFileEntity> [purge|untrash|trash]
gam <UserTypeEntity> purge drivefile <DriveFileEntity>
@@ -8180,11 +8181,18 @@ gam <UserTypeEntity> show sheetrange <DriveFileEntity>
gam <UserTypeEntity> delete tokens clientid <ClientID>
gam <UserTypeEntity> print tokens|token [todrive <ToDriveAttribute>*] [clientid <ClientID>]
[aggregateby|orderby clientid|id|appname|displaytext] [delimiter <Character>]
[usertokencounts|(aggregateusersby|orderby clientid|id|appname|displaytext)]
[delimiter <Character>]
gam <UserTypeEntity> show tokens|token|3lo|oauth [clientid <ClientID>]
[aggregateby|orderby clientid|id|appname|displaytext]
[usertokencounts|(aggregateusersby|orderby clientid|id|appname|displaytext)]
[delimiter <Character>]
gam print tokens|token [todrive <ToDriveAttribute>*] [clientid <ClientID>]
[aggregateby|orderby clientid|id|appname|displaytext] [delimiter <Character>]
[usertokencounts|(aggregateusersby|orderby clientid|id|appname|displaytext)]
[delimiter <Character>]
[<UserTypeEntity>]
gam show tokens|token [clientid <ClientID>]
[usertokencounts|(aggregateusersby|orderby clientid|id|appname|displaytext)]
[delimiter <Character>]
[<UserTypeEntity>]
# Users - YouTube

View File

@@ -2,6 +2,28 @@
Merged GAM-Team version
6.77.09
Added option `usertokencounts` to `gam <UserTypeEntity> print|show tokens` that causes GAM to display
each user and their number of access tokens; there are no details.
6.77.08
Fixed bugs in `gam <UserTypeEntity> delete chatmember <ChatSpace> ... group <GroupItem>`
and `gam <UserTypeEntity> sync chatmember <ChatSpace> ... groups <GroupEntity>` that caused an error.
6.77.07
Fixed bug in `gam <UserTypeEntity> create chatmember <ChatSpace> ... group <GroupItem>` that caused an error.
6.77.06
Updated `gam update ou <OrgUnitItem> ... parent <OrgUnitItem>` to handle the following error
that occurs when `parent <OrgUnitItem>` is the same as or a sub-OU of `ou <OrgUnitItem>`.
```
ERROR: 412: conditionNotMet - OrgUnit hierarchy has cycle
```
6.77.05
Added option `onlyusers <UserTypeEntity>` to `gam <UserTypeEntity> claim ownership <DriveFileEntity>`

View File

@@ -17213,13 +17213,15 @@ def _doUpdateOrgs(entityList):
try:
callGAPI(cd.orgunits(), 'update',
throwReasons=[GAPI.INVALID_ORGUNIT, GAPI.ORGUNIT_NOT_FOUND, GAPI.BACKEND_ERROR, GAPI.INVALID_ORGUNIT_NAME,
GAPI.BAD_REQUEST, GAPI.INVALID_CUSTOMER_ID, GAPI.LOGIN_REQUIRED],
GAPI.CONDITION_NOT_MET, GAPI.BAD_REQUEST, GAPI.INVALID_CUSTOMER_ID, GAPI.LOGIN_REQUIRED],
customerId=GC.Values[GC.CUSTOMER_ID], orgUnitPath=encodeOrgUnitPath(makeOrgUnitPathRelative(orgUnitPath)), body=body, fields='')
entityActionPerformed([Ent.ORGANIZATIONAL_UNIT, orgUnitPath], i, count)
except (GAPI.invalidOrgunit, GAPI.orgunitNotFound, GAPI.backendError):
entityActionFailedWarning([Ent.ORGANIZATIONAL_UNIT, orgUnitPath], Msg.DOES_NOT_EXIST, i, count)
except GAPI.invalidOrgunitName as e:
entityActionFailedWarning([Ent.ORGANIZATIONAL_UNIT, orgUnitPath, Ent.NAME, body['name']], str(e), i, count)
except GAPI.conditionNotMet as e:
entityActionFailedWarning([Ent.ORGANIZATIONAL_UNIT, orgUnitPath], str(e), i, count)
except (GAPI.badRequest, GAPI.invalidCustomerId, GAPI.loginRequired):
checkEntityAFDNEorAccessErrorExit(cd, Ent.ORGANIZATIONAL_UNIT, orgUnitPath)
@@ -25729,6 +25731,12 @@ def _getChatMemberEmail(cd, member):
_, memberUid = member['groupMember']['name'].split('/')
member['groupMember']['email'], _ = convertUIDtoEmailAddressWithType(f'uid:{memberUid}', cd, None, emailTypes=['group'])
def normalizeUserMember(cd, user, userList):
userList.append(convertEmailAddressToUID(user, cd, emailType='user'))
def normalizeGroupMember(cd, group, groupList):
groupList.append(convertEmailAddressToUID(group, cd, emailType='group'))
# gam <UserTypeEntity> create chatmember <ChatSpace>
# [type human|bot] [role member|manager]
# (user <UserItem>)* (members <UserTypeEntity>)*
@@ -25789,14 +25797,16 @@ def createChatMember(users):
if myarg == 'space' or myarg.startswith('spaces/') or myarg.startswith('space/'):
parent = getChatSpace(myarg)
elif myarg == 'user':
userList.append(getEmailAddress(returnUIDprefix='uid:'))
normalizeUserMember(cd, getEmailAddress(returnUIDprefix='uid:'), userList)
elif myarg in {'member', 'members'}:
_, members = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS)
userList.extend(members)
for user in members:
normalizeUserMember(cd, user, userList)
elif myarg == 'group':
groupList.append(getEmailAddress(returnUIDprefix='uid:'))
normalizeGroupMember(cd, getEmailAddress(returnUIDprefix='uid:'), groupList)
elif myarg == 'groups':
groupList.extend(getEntityList(Cmd.OB_GROUP_ENTITY))
for group in getEntityList(Cmd.OB_GROUP_ENTITY):
normalizeGroupMember(cd, group, groupList)
elif myarg == 'role':
role = getChoice(CHAT_MEMBER_ROLE_MAP, mapChoice=True)
elif myarg == 'type':
@@ -25812,12 +25822,10 @@ def createChatMember(users):
userEntityType = Ent.CHAT_MEMBER_USER if role == 'ROLE_MEMBER' else Ent.CHAT_MANAGER_USER
userMembers = []
for user in userList:
name = normalizeEmailAddressOrUID(user)
userMembers.append({'member': {'name': f'users/{name}', 'type': mtype}})
userMembers.append({'member': {'name': f'users/{user}', 'type': mtype}})
groupMembers = []
for group in groupList:
name = normalizeEmailAddressOrUID(group)
groupMembers.append({'groupMember': {'name': f'groups/{name}'}})
groupMembers.append({'groupMember': {'name': f'groups/{group}'}})
i, count, users = getEntityArgument(users)
if useAdminAccess:
_chkChatAdminAccess(count)
@@ -25879,7 +25887,8 @@ def deleteUpdateChatMember(users):
parent = None
body = {}
memberNames = []
userGroupList = []
userList = []
groupList = []
useAdminAccess, api, kwargsUAA = _getChatAdminAccess(API.CHAT_MEMBERSHIPS_ADMIN, API.CHAT_MEMBERSHIPS)
while Cmd.ArgumentsRemaining():
myarg = getArgument()
@@ -25895,14 +25904,16 @@ def deleteUpdateChatMember(users):
if myarg == 'space' or myarg.startswith('spaces/') or myarg.startswith('space/'):
parent = getChatSpace(myarg)
elif myarg == 'user':
userGroupList.append(getEmailAddress(returnUIDprefix='uid:'))
normalizeUserMember(cd, getEmailAddress(returnUIDprefix='uid:'), userList)
elif myarg in {'member', 'members'}:
_, members = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS)
userGroupList.extend(members)
for user in members:
normalizeUserMember(cd, user, userList)
elif deleteMode and myarg == 'group':
userGroupList.append(getEmailAddress(returnUIDprefix='uid:'))
normalizeGroupMember(cd, getEmailAddress(returnUIDprefix='uid:'), groupList)
elif deleteMode and myarg == 'groups':
userGroupList.extend(getEntityList(Cmd.OB_GROUP_ENTITY))
for group in getEntityList(Cmd.OB_GROUP_ENTITY):
normalizeGroupMember(cd, group, groupList)
else:
unknownArgumentExit()
if not deleteMode and 'role' not in body:
@@ -25913,11 +25924,12 @@ def deleteUpdateChatMember(users):
else: # {Act.DELETE, Act.UPDATE}
if not parent:
missingArgumentExit('space')
if not userGroupList:
if not userList and not groupList:
missingArgumentExit('user|members|group|groups')
for user in userGroupList:
name = normalizeEmailAddressOrUID(user)
memberNames.append(f'{parent}/members/{name}')
for user in userList:
memberNames.append(f'{parent}/members/{user}')
for group in groupList:
memberNames.append(f'{parent}/members/group-{group}')
i, count, users = getEntityArgument(users)
if useAdminAccess:
_chkChatAdminAccess(count)
@@ -26022,6 +26034,7 @@ def syncChatMembers(users):
role = CHAT_MEMBER_ROLE_MAP['member']
mtype = CHAT_MEMBER_TYPE_MAP['human']
syncOperation = 'addremove'
kwargs = {}
preview = False
csvPF = None
userList = []
@@ -26043,14 +26056,17 @@ def syncChatMembers(users):
elif myarg == 'actioncsv':
csvPF = CSVPrintFile(CHAT_SYNC_PREVIEW_TITLES)
elif myarg == 'users':
userList.extend(getEntityList(Cmd.OB_USER_ENTITY))
for user in getEntityList(Cmd.OB_USER_ENTITY):
normalizeUserMember(cd, user, userList)
usersSpecified = True
elif myarg in {'member', 'members'}:
_, members = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS)
userList.extend(members)
for user in members:
normalizeUserMember(cd, user, userList)
usersSpecified = True
elif myarg == 'groups':
groupList.extend(getEntityList(Cmd.OB_GROUP_ENTITY))
for group in getEntityList(Cmd.OB_GROUP_ENTITY):
normalizeGroupMember(cd, group, groupList)
groupsSpecified = True
else:
unknownArgumentExit()
@@ -26060,20 +26076,19 @@ def syncChatMembers(users):
userMembers = {}
syncUsersSet = set()
for user in userList:
name = normalizeEmailAddressOrUID(user)
memberName = f'{parent}/members/{name}'
userMembers[memberName] = {'member': {'name': f'users/{name}', 'type': mtype}}
memberName = f'{parent}/members/{user}'
userMembers[memberName] = {'member': {'name': f'users/{user}', 'type': mtype}}
syncUsersSet.add(memberName)
groupMembers = {}
syncGroupsSet = set()
for group in groupList:
name = normalizeEmailAddressOrUID(group)
memberName = f'{parent}/members/{name}'
groupMembers[memberName] = {'groupMember': {'name': f'groups/{name}'}}
memberName = f'{parent}/members/group-{group}'
groupMembers[memberName] = {'groupMember': {'name': f'groups/{group}'}}
syncGroupsSet.add(memberName)
qfilter = f'{Ent.Singular(Ent.CHAT_SPACE)}: {parent}'
i, count, users = getEntityArgument(users)
if useAdminAccess:
kwargs['filter'] = 'member.type != "BOT"'
_chkChatAdminAccess(count)
for user in users:
i += 1
@@ -26086,15 +26101,13 @@ def syncChatMembers(users):
members = callGAPIpages(chat.spaces().members(), 'list', 'memberships',
pageMessage=_getChatPageMessage(Ent.CHAT_MEMBER, user, i, count, qfilter),
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
pageSize=CHAT_PAGE_SIZE, parent=parent, showGroups=groupsSpecified, **kwargsUAA)
parent=parent, showGroups=groupsSpecified, pageSize=CHAT_PAGE_SIZE, **kwargs, **kwargsUAA)
for member in members:
if 'member' in member:
if member['member']['type'] == mtype and member['role'] == role:
_getChatMemberEmail(cd, member)
currentUsersSet.add(f"{parent}/members/{member['member']['email']}")
currentUsersSet.add(member['name'])
elif 'groupMember' in member:
_getChatMemberEmail(cd, member)
currentGroupsSet.add(f"{parent}/members/{member['groupMember']['email']}")
currentGroupsSet.add(member['name'])
except (GAPI.notFound, GAPI.invalidArgument, GAPI.permissionDenied) as e:
exitIfChatNotConfigured(chat, kvList, str(e), i, count)
continue
@@ -59160,6 +59173,7 @@ HTTP_ERROR_PATTERN = re.compile(r'^.*returned "(.*)">$')
# [(format <FileFormatList>)|(gsheet|csvsheet <SheetEntity>)] [exportsheetaspdf <String>]
# [targetfolder <FilePath>] [targetname -|<FileName>]
# [donotfollowshortcuts [<Boolean>]] [overwrite [<Boolean>]] [showprogress [<Boolean>]]
# [acknowledgeabuse [<Boolean>]]
def getDriveFile(users):
def closeRemoveTargetFile(f):
if f and not targetStdout:
@@ -66420,7 +66434,7 @@ def deleteTokens(users):
TOKENS_FIELDS_TITLES = ['clientId', 'displayText', 'anonymous', 'nativeApp', 'userKey', 'scopes']
TOKENS_AGGREGATE_FIELDS_TITLES = ['clientId', 'displayText', 'anonymous', 'nativeApp', 'users', 'scopes']
TOKENS_ORDERBY_CHOICE_MAP = {
TOKENS_AGGREGATE_ORDERBY_CHOICE_MAP = {
'clientid': 'clientId',
'id': 'clientId',
'displaytext': 'displayText',
@@ -66429,6 +66443,7 @@ TOKENS_ORDERBY_CHOICE_MAP = {
TOKENS_TITLE_MAP = {
'clientId': 'Client ID',
'displayText': 'App Name',
'user': 'user',
}
def _printShowTokens(entityType, users):
@@ -66470,11 +66485,13 @@ def _printShowTokens(entityType, users):
elif myarg == 'clientid':
clientId = commonClientIds(getString(Cmd.OB_CLIENT_ID))
elif myarg == 'orderby':
orderBy = getChoice(TOKENS_ORDERBY_CHOICE_MAP, mapChoice=True)
orderBy = getChoice(TOKENS_AGGREGATE_ORDERBY_CHOICE_MAP, mapChoice=True)
elif myarg == 'aggregateusersby':
aggregateUsersBy = getChoice(TOKENS_ORDERBY_CHOICE_MAP, mapChoice=True)
aggregateUsersBy = getChoice(TOKENS_AGGREGATE_ORDERBY_CHOICE_MAP, mapChoice=True)
if aggregateUsersBy == 'displayText':
tokenNameIdMap = {}
elif myarg == 'usertokencounts':
aggregateUsersBy = 'user'
elif myarg == 'delimiter':
delimiter = getCharacter()
elif not entityType:
@@ -66487,8 +66504,10 @@ def _printShowTokens(entityType, users):
if csvPF:
if not aggregateUsersBy:
csvPF.SetTitles(['user']+TOKENS_FIELDS_TITLES)
else:
elif aggregateUsersBy != 'user':
csvPF.SetTitles(TOKENS_AGGREGATE_FIELDS_TITLES)
else:
csvPF.SetTitles(['user', 'tokenCount'])
else:
if not aggregateUsersBy:
tokenTitle = TOKENS_TITLE_MAP[orderBy]
@@ -66513,8 +66532,8 @@ def _printShowTokens(entityType, users):
throwReasons=[GAPI.USER_NOT_FOUND, GAPI.DOMAIN_NOT_FOUND,
GAPI.DOMAIN_CANNOT_USE_APIS, GAPI.FORBIDDEN, GAPI.BAD_REQUEST],
userKey=user, fields=f'items({fields})')
jcount = len(results)
if not aggregateUsersBy:
jcount = len(results)
if not csvPF:
entityPerformActionNumItems([Ent.USER, user], jcount, Ent.ACCESS_TOKEN, i, count)
Ind.Increment()
@@ -66533,7 +66552,7 @@ def _printShowTokens(entityType, users):
csvPF.WriteRow(row)
elif GC.Values[GC.CSV_OUTPUT_USERS_AUDIT]:
csvPF.WriteRowNoFilter({'user': user})
else:
elif aggregateUsersBy != 'user':
if results:
for token in results:
tokcid = token['clientId']
@@ -66547,6 +66566,8 @@ def _printShowTokens(entityType, users):
if tokname not in tokenNameIdMap:
tokenNameIdMap[tokname] = set()
tokenNameIdMap[tokname].add(tokcid)
else: # aggregateUsersBy == 'user':
aggregateTokensById[user] = jcount
except (GAPI.notFound, GAPI.resourceNotFound) as e:
entityActionFailedWarning([Ent.USER, user, Ent.ACCESS_TOKEN, clientId], str(e), i, count)
except (GAPI.userNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden, GAPI.badRequest):
@@ -66579,6 +66600,16 @@ def _printShowTokens(entityType, users):
for _, tokenIds in sorted(iter(tokenNameIdMap.items())):
for tokcid in sorted(tokenIds):
_printToken(aggregateTokensById[tokcid])
else: # aggregateUsersBy == 'user':
if not csvPF:
jcount = len(aggregateTokensById)
j = 0
for user, count in sorted(iter(aggregateTokensById.items())):
j += 1
printEntityKVList([Ent.USER, user], [Ent.Plural(Ent.ACCESS_TOKEN), count], j, jcount)
else:
for user, count in sorted(iter(aggregateTokensById.items())):
csvPF.WriteRow({'user': user, 'tokenCount': count})
if csvPF:
csvPF.writeCSVfile('OAuth Tokens')