Compare commits

...

7 Commits

Author SHA1 Message Date
Ross Scroggs
3925166987 Fixed bug in gam print|show oushareddrives that caused a trap.
Improved getting Shared Drive names from IDs when accessing Shared Drives in external workspaces.
2025-05-26 12:41:09 -07:00
Ross Scroggs
5dece6c719 Update Groups.md
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / build (build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (build, 10, Build Intel Windows, windows-2022) (push) Has been cancelled
Build and test GAM / build (build, 11, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (build, 7, Build Intel MacOS, macos-13) (push) Has been cancelled
Build and test GAM / build (build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (test, 12, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (test, 13, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (test, 14, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (test, 15, Test Python 3.14-dev, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
Check for Google Root CA Updates / check-apis (push) Has been cancelled
2025-05-26 09:15:13 -07:00
Ross Scroggs
b48d316bd9 Update gam.cfg.md
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-05-25 17:45:11 -07:00
Ross Scroggs
1f2b33b805 Handle additional API errors
Some checks failed
Build and test GAM / build (build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (build, 10, Build Intel Windows, windows-2022) (push) Has been cancelled
Build and test GAM / build (build, 11, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (build, 7, Build Intel MacOS, macos-13) (push) Has been cancelled
Build and test GAM / build (build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (test, 12, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (test, 13, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (test, 14, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (test, 15, Test Python 3.14-dev, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-apis (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
2025-05-23 20:14:47 -07:00
Ross Scroggs
a6773901c9 Handle additional API errors 2025-05-23 20:14:36 -07:00
Ross Scroggs
840784fa98 Update Authorization.md
Some checks failed
Build and test GAM / build (build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (build, 10, Build Intel Windows, windows-2022) (push) Has been cancelled
Build and test GAM / build (build, 11, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (build, 7, Build Intel MacOS, macos-13) (push) Has been cancelled
Build and test GAM / build (build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (test, 12, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (test, 13, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (test, 14, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (test, 15, Test Python 3.14-dev, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-apis (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
2025-05-23 14:43:55 -07:00
Ross Scroggs
aecb17b9fe Handle API additional errors in update events, part II 2025-05-23 12:57:50 -07:00
10 changed files with 119 additions and 79 deletions

View File

@@ -1,3 +1,22 @@
7.07.12
Fixed bug in `gam print|show oushareddrives` that caused a trap.
Improved getting Shared Drive names from IDs when accessing Shared Drives in external workspaces.
7.07.11
Updated `gam calendars <CalendarEntity> update events` and `gam <UserTypeEntity> update events <UserCalendarEntity>`
to handle the following error:
```
ERROR: 400: badRequest - Bad Request
```
Updated `gam <UserTypeEntity> move drivefile` to handle the following error:
```
ERROR: 400: shareOutNotPermitted
```
7.07.10 7.07.10
Updated `gam calendars <CalendarEntity> update events` and `gam <UserTypeEntity> update events <UserCalendarEntity>` Updated `gam calendars <CalendarEntity> update events` and `gam <UserTypeEntity> update events <UserCalendarEntity>`

View File

@@ -3,7 +3,7 @@
# #
# GAM7 # GAM7
# #
# Copyright 2024, All Rights Reserved. # Copyright 2025, All Rights Reserved.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
""" """
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>' __author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
__version__ = '7.07.10' __version__ = '7.07.12'
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)' __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
#pylint: disable=wrong-import-position #pylint: disable=wrong-import-position
@@ -39299,7 +39299,7 @@ def _updateCalendarEvents(origUser, user, origCal, calIds, count, calendarEventE
throwReasons=GAPI.CALENDAR_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.DELETED, GAPI.FORBIDDEN, GAPI.BACKEND_ERROR, throwReasons=GAPI.CALENDAR_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.DELETED, GAPI.FORBIDDEN, GAPI.BACKEND_ERROR,
GAPI.INVALID, GAPI.REQUIRED, GAPI.TIME_RANGE_EMPTY, GAPI.EVENT_DURATION_EXCEEDS_LIMIT, GAPI.INVALID, GAPI.REQUIRED, GAPI.TIME_RANGE_EMPTY, GAPI.EVENT_DURATION_EXCEEDS_LIMIT,
GAPI.REQUIRED_ACCESS_LEVEL, GAPI.CANNOT_CHANGE_ORGANIZER_OF_INSTANCE, GAPI.REQUIRED_ACCESS_LEVEL, GAPI.CANNOT_CHANGE_ORGANIZER_OF_INSTANCE,
GAPI.MALFORMED_WORKING_LOCATION_EVENT, GAPI.EVENT_TYPE_RESTRICTION], GAPI.MALFORMED_WORKING_LOCATION_EVENT, GAPI.EVENT_TYPE_RESTRICTION, GAPI.BAD_REQUEST],
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS+[GAPI.BACKEND_ERROR], retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS+[GAPI.BACKEND_ERROR],
calendarId=calId, eventId=eventId, conferenceDataVersion=1, sendUpdates=parameters['sendUpdates'], supportsAttachments=True, calendarId=calId, eventId=eventId, conferenceDataVersion=1, sendUpdates=parameters['sendUpdates'], supportsAttachments=True,
body=body, fields=pfields) body=body, fields=pfields)
@@ -39316,7 +39316,7 @@ def _updateCalendarEvents(origUser, user, origCal, calIds, count, calendarEventE
entityActionFailedWarning([Ent.CALENDAR, calId, Ent.EVENT, eventId], str(e), j, jcount) entityActionFailedWarning([Ent.CALENDAR, calId, Ent.EVENT, eventId], str(e), j, jcount)
except (GAPI.forbidden, GAPI.backendError, GAPI.invalid, GAPI.required, GAPI.timeRangeEmpty, GAPI.eventDurationExceedsLimit, except (GAPI.forbidden, GAPI.backendError, GAPI.invalid, GAPI.required, GAPI.timeRangeEmpty, GAPI.eventDurationExceedsLimit,
GAPI.requiredAccessLevel, GAPI.cannotChangeOrganizerOfInstance, GAPI.malformedWorkingLocationEvent, GAPI.requiredAccessLevel, GAPI.cannotChangeOrganizerOfInstance, GAPI.malformedWorkingLocationEvent,
GAPI.eventTypeRestriction) as e: GAPI.eventTypeRestriction, GAPI.badRequest) as e:
entityActionFailedWarning([Ent.CALENDAR, calId, Ent.EVENT, eventId], str(e), j, jcount) entityActionFailedWarning([Ent.CALENDAR, calId, Ent.EVENT, eventId], str(e), j, jcount)
except GAPI.notACalendarUser: except GAPI.notACalendarUser:
userCalServiceNotEnabledWarning(calId, i, count) userCalServiceNotEnabledWarning(calId, i, count)
@@ -42021,22 +42021,21 @@ def printShowUserVaultHolds(entityList):
else: else:
printKeyValueList(['Total Holds', totalHolds]) printKeyValueList(['Total Holds', totalHolds])
def _cleanVaultQuery(query, cd): def _cleanVaultQuery(query, cd, drive):
if 'query' in query: if 'query' in query:
if cd is not None: if cd is not None and 'orgUnitInfo' in query['query']:
if 'orgUnitInfo' in query['query']: query['query']['orgUnitInfo']['orgUnitPath'] = convertOrgUnitIDtoPath(cd, query['query']['orgUnitInfo']['orgUnitId'])
query['query']['orgUnitInfo']['orgUnitPath'] = convertOrgUnitIDtoPath(cd, query['query']['orgUnitInfo']['orgUnitId']) if drive is not None and 'sharedDriveInfo' in query['query']:
if 'sharedDriveInfo' in query['query']: query['query']['sharedDriveInfo']['sharedDriveNames'] = []
query['query']['sharedDriveInfo']['sharedDriveNames'] = [] for sharedDriveId in query['query']['sharedDriveInfo']['sharedDriveIds']:
for sharedDriveId in query['query']['sharedDriveInfo']['sharedDriveIds']: query['query']['sharedDriveInfo']['sharedDriveNames'].append(_getSharedDriveNameFromId(drive, sharedDriveId, False))
query['query']['sharedDriveInfo']['sharedDriveNames'].append(_getSharedDriveNameFromId(sharedDriveId))
query['query'].pop('searchMethod', None) query['query'].pop('searchMethod', None)
query['query'].pop('teamDriveInfo', None) query['query'].pop('teamDriveInfo', None)
VAULT_QUERY_TIME_OBJECTS = {'createTime', 'endTime', 'startTime', 'versionDate'} VAULT_QUERY_TIME_OBJECTS = {'createTime', 'endTime', 'startTime', 'versionDate'}
def _showVaultQuery(matterNameId, query, cd, FJQC, k=0, kcount=0): def _showVaultQuery(matterNameId, query, cd, drive, FJQC, k=0, kcount=0):
_cleanVaultQuery(query, cd) _cleanVaultQuery(query, cd, drive)
if FJQC is not None and FJQC.formatJSON: if FJQC is not None and FJQC.formatJSON:
printLine(json.dumps(cleanJSON(query, timeObjects=VAULT_QUERY_TIME_OBJECTS), ensure_ascii=False, sort_keys=False)) printLine(json.dumps(cleanJSON(query, timeObjects=VAULT_QUERY_TIME_OBJECTS), ensure_ascii=False, sort_keys=False))
return return
@@ -42068,7 +42067,7 @@ def doInfoVaultQuery():
queryId, queryName, queryNameId = convertQueryNameToID(v, getString(Cmd.OB_QUERY_ITEM), matterId, matterNameId) queryId, queryName, queryNameId = convertQueryNameToID(v, getString(Cmd.OB_QUERY_ITEM), matterId, matterNameId)
else: else:
queryName = getString(Cmd.OB_QUERY_ITEM) queryName = getString(Cmd.OB_QUERY_ITEM)
cd = None cd = drive = None
fieldsList = [] fieldsList = []
FJQC = FormatJSONQuoteChar() FJQC = FormatJSONQuoteChar()
while Cmd.ArgumentsRemaining(): while Cmd.ArgumentsRemaining():
@@ -42078,8 +42077,8 @@ def doInfoVaultQuery():
queryId, queryName, queryNameId = convertQueryNameToID(v, queryName, matterId, matterNameId) queryId, queryName, queryNameId = convertQueryNameToID(v, queryName, matterId, matterNameId)
elif myarg == 'shownames': elif myarg == 'shownames':
cd = buildGAPIObject(API.DIRECTORY) cd = buildGAPIObject(API.DIRECTORY)
_, GM.Globals[GM.ADMIN_DRIVE] = buildGAPIServiceObject(API.DRIVE3, _getAdminEmail()) _, drive = buildGAPIServiceObject(API.DRIVE3, _getAdminEmail())
if GM.Globals[GM.ADMIN_DRIVE] is None: if drive is None:
return return
elif getFieldsList(myarg, VAULT_QUERY_FIELDS_CHOICE_MAP, fieldsList, initialField=['savedQueryId', 'displayName']): elif getFieldsList(myarg, VAULT_QUERY_FIELDS_CHOICE_MAP, fieldsList, initialField=['savedQueryId', 'displayName']):
pass pass
@@ -42090,7 +42089,7 @@ def doInfoVaultQuery():
query = callGAPI(v.matters().savedQueries(), 'get', query = callGAPI(v.matters().savedQueries(), 'get',
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT], throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
matterId=matterId, savedQueryId=queryId, fields=fields) matterId=matterId, savedQueryId=queryId, fields=fields)
_showVaultQuery(matterNameId, query, cd, FJQC) _showVaultQuery(matterNameId, query, cd, drive, FJQC)
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument) as e: except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_QUERY, queryNameId], str(e)) entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_QUERY, queryNameId], str(e))
@@ -42107,7 +42106,7 @@ def doPrintShowVaultQueries():
csvPF = CSVPrintFile(PRINT_VAULT_QUERIES_TITLES, 'sortall') if Act.csvFormat() else None csvPF = CSVPrintFile(PRINT_VAULT_QUERIES_TITLES, 'sortall') if Act.csvFormat() else None
FJQC = FormatJSONQuoteChar(csvPF) FJQC = FormatJSONQuoteChar(csvPF)
matters = [] matters = []
cd = None cd = drive = None
fieldsList = [] fieldsList = []
while Cmd.ArgumentsRemaining(): while Cmd.ArgumentsRemaining():
myarg = getArgument() myarg = getArgument()
@@ -42117,8 +42116,8 @@ def doPrintShowVaultQueries():
matters = shlexSplitList(getString(Cmd.OB_MATTER_ITEM_LIST)) matters = shlexSplitList(getString(Cmd.OB_MATTER_ITEM_LIST))
elif myarg == 'shownames': elif myarg == 'shownames':
cd = buildGAPIObject(API.DIRECTORY) cd = buildGAPIObject(API.DIRECTORY)
_, GM.Globals[GM.ADMIN_DRIVE] = buildGAPIServiceObject(API.DRIVE3, _getAdminEmail()) _, drive = buildGAPIServiceObject(API.DRIVE3, _getAdminEmail())
if GM.Globals[GM.ADMIN_DRIVE] is None: if drive is None:
return return
elif getFieldsList(myarg, VAULT_QUERY_FIELDS_CHOICE_MAP, fieldsList, initialField=['savedQueryId', 'displayName']): elif getFieldsList(myarg, VAULT_QUERY_FIELDS_CHOICE_MAP, fieldsList, initialField=['savedQueryId', 'displayName']):
pass pass
@@ -42180,11 +42179,11 @@ def doPrintShowVaultQueries():
k = 0 k = 0
for query in queries: for query in queries:
k += 1 k += 1
_showVaultQuery(matterNameId, query, cd, FJQC, k, kcount) _showVaultQuery(matterNameId, query, cd, drive, FJQC, k, kcount)
Ind.Decrement() Ind.Decrement()
else: else:
for query in queries: for query in queries:
_cleanVaultQuery(query, cd) _cleanVaultQuery(query, cd, drive)
row = flattenJSON(query, flattened={'matterId': matterId, 'matterName': matterName}, timeObjects=VAULT_QUERY_TIME_OBJECTS) row = flattenJSON(query, flattened={'matterId': matterId, 'matterName': matterName}, timeObjects=VAULT_QUERY_TIME_OBJECTS)
if not FJQC.formatJSON: if not FJQC.formatJSON:
csvPF.WriteRowTitles(row) csvPF.WriteRowTitles(row)
@@ -52447,20 +52446,15 @@ def _convertSharedDriveNameToId(drive, user, i, count, fileIdEntity, useDomainAd
','.join([td['id'] for td in tdlist])), i, count) ','.join([td['id'] for td in tdlist])), i, count)
return False return False
def _getSharedDriveNameFromId(sharedDriveId): def _getSharedDriveNameFromId(drive, sharedDriveId, useDomainAdminAccess=False):
sharedDriveName = GM.Globals[GM.MAP_SHAREDDRIVE_ID_TO_NAME].get(sharedDriveId) sharedDriveName = GM.Globals[GM.MAP_SHAREDDRIVE_ID_TO_NAME].get(sharedDriveId)
if not sharedDriveName: if not sharedDriveName:
if not GM.Globals[GM.ADMIN_DRIVE]: try:
_, GM.Globals[GM.ADMIN_DRIVE] = buildGAPIServiceObject(API.DRIVE3, _getAdminEmail()) sharedDriveName = callGAPI(drive.drives(), 'get',
if GM.Globals[GM.ADMIN_DRIVE]: throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.NOT_FOUND],
try: useDomainAdminAccess=useDomainAdminAccess,
sharedDriveName = callGAPI(GM.Globals[GM.ADMIN_DRIVE].drives(), 'get', driveId=sharedDriveId, fields='name')['name']
throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.NOT_FOUND], except (GAPI.notFound, GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy):
useDomainAdminAccess=True,
driveId=sharedDriveId, fields='name')['name']
except (GAPI.notFound, GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy):
sharedDriveName = TEAM_DRIVE
else:
sharedDriveName = TEAM_DRIVE sharedDriveName = TEAM_DRIVE
GM.Globals[GM.MAP_SHAREDDRIVE_ID_TO_NAME][sharedDriveId] = sharedDriveName GM.Globals[GM.MAP_SHAREDDRIVE_ID_TO_NAME][sharedDriveId] = sharedDriveName
return sharedDriveName return sharedDriveName
@@ -52473,7 +52467,7 @@ def _getDriveFileNameFromId(drive, fileId, combineTitleId=True, useDomainAdminAc
if result: if result:
fileName = result['name'] fileName = result['name']
if (result['mimeType'] == MIMETYPE_GA_FOLDER) and result.get('driveId') and (result['name'] == TEAM_DRIVE): if (result['mimeType'] == MIMETYPE_GA_FOLDER) and result.get('driveId') and (result['name'] == TEAM_DRIVE):
fileName = _getSharedDriveNameFromId(result['driveId']) fileName = _getSharedDriveNameFromId(drive, result['driveId'])
if combineTitleId: if combineTitleId:
fileName += '('+fileId+')' fileName += '('+fileId+')'
return (fileName, _getEntityMimeType(result), result['mimeType']) return (fileName, _getEntityMimeType(result), result['mimeType'])
@@ -53555,7 +53549,7 @@ def getFilePaths(drive, fileTree, initialResult, filePathInfo, addParentsToTree=
fullpath=False, showDepth=False, folderPathOnly=False): fullpath=False, showDepth=False, folderPathOnly=False):
def _getParentName(result): def _getParentName(result):
if (result['mimeType'] == MIMETYPE_GA_FOLDER) and result.get('driveId') and (result['name'] == TEAM_DRIVE): if (result['mimeType'] == MIMETYPE_GA_FOLDER) and result.get('driveId') and (result['name'] == TEAM_DRIVE):
parentName = _getSharedDriveNameFromId(result['driveId']) parentName = _getSharedDriveNameFromId(drive, result['driveId'])
if parentName != TEAM_DRIVE: if parentName != TEAM_DRIVE:
return f'{SHARED_DRIVES}{filePathInfo["delimiter"]}{parentName}' return f'{SHARED_DRIVES}{filePathInfo["delimiter"]}{parentName}'
return result['name'] return result['name']
@@ -54254,9 +54248,9 @@ def showFileInfo(users):
driveId = result.get('driveId') driveId = result.get('driveId')
if driveId: if driveId:
if result['mimeType'] == MIMETYPE_GA_FOLDER and result['name'] == TEAM_DRIVE: if result['mimeType'] == MIMETYPE_GA_FOLDER and result['name'] == TEAM_DRIVE:
result['name'] = _getSharedDriveNameFromId(driveId) result['name'] = _getSharedDriveNameFromId(drive, driveId)
if DFF.showSharedDriveNames: if DFF.showSharedDriveNames:
result['driveName'] = _getSharedDriveNameFromId(driveId) result['driveName'] = _getSharedDriveNameFromId(drive, driveId)
if showNoParents: if showNoParents:
result.setdefault('parents', []) result.setdefault('parents', [])
if getPermissionsForSharedDrives and driveId and 'permissions' not in result: if getPermissionsForSharedDrives and driveId and 'permissions' not in result:
@@ -54944,7 +54938,7 @@ def extendFileTreeParents(drive, fileTree, fields):
result['parents'] = [ORPHANS] if result.get('ownedByMe', False) and 'sharedWithMeTime' not in result else [SHARED_WITHME] result['parents'] = [ORPHANS] if result.get('ownedByMe', False) and 'sharedWithMeTime' not in result else [SHARED_WITHME]
else: else:
if result['name'] == TEAM_DRIVE: if result['name'] == TEAM_DRIVE:
result['name'] = _getSharedDriveNameFromId(result['driveId']) result['name'] = _getSharedDriveNameFromId(drive, result['driveId'])
result['parents'] = [SHARED_DRIVES] if 'sharedWithMeTime' not in result else [SHARED_WITHME] result['parents'] = [SHARED_DRIVES] if 'sharedWithMeTime' not in result else [SHARED_WITHME]
fileTree[fileId]['info'] = result fileTree[fileId]['info'] = result
fileTree[fileId]['info']['noDisplay'] = True fileTree[fileId]['info']['noDisplay'] = True
@@ -55689,7 +55683,7 @@ def printFileList(users):
if not pmselect and 'permissions' in fileInfo: if not pmselect and 'permissions' in fileInfo:
fileInfo['permissions'] = DLP.GetFileMatchingPermission(fileInfo) fileInfo['permissions'] = DLP.GetFileMatchingPermission(fileInfo)
if DFF.showSharedDriveNames and driveId: if DFF.showSharedDriveNames and driveId:
fileInfo['driveName'] = _getSharedDriveNameFromId(driveId) fileInfo['driveName'] = _getSharedDriveNameFromId(drive, driveId)
if filepath: if filepath:
if not FJQC.formatJSON or not addPathsToJSON: if not FJQC.formatJSON or not addPathsToJSON:
addFilePathsToRow(drive, fileTree, fileInfo, filePathInfo, csvPF, row, addFilePathsToRow(drive, fileTree, fileInfo, filePathInfo, csvPF, row,
@@ -56559,7 +56553,7 @@ def printShowFilePaths(users):
driveId = result.get('driveId') driveId = result.get('driveId')
if driveId: if driveId:
if result['mimeType'] == MIMETYPE_GA_FOLDER and result['name'] == TEAM_DRIVE: if result['mimeType'] == MIMETYPE_GA_FOLDER and result['name'] == TEAM_DRIVE:
result['name'] = _getSharedDriveNameFromId(driveId) result['name'] = _getSharedDriveNameFromId(drive, driveId)
if returnPathOnly: if returnPathOnly:
if fullpath: if fullpath:
writeStdout(f'{SHARED_DRIVES}/{result["name"]}\n') writeStdout(f'{SHARED_DRIVES}/{result["name"]}\n')
@@ -56649,7 +56643,7 @@ def printFileParentTree(users):
driveId = result.get('driveId') driveId = result.get('driveId')
if driveId: if driveId:
if result['mimeType'] == MIMETYPE_GA_FOLDER and result['name'] == TEAM_DRIVE: if result['mimeType'] == MIMETYPE_GA_FOLDER and result['name'] == TEAM_DRIVE:
result['name'] = _getSharedDriveNameFromId(driveId) result['name'] = _getSharedDriveNameFromId(drive, driveId)
result['isRoot'] = True result['isRoot'] = True
result['parents'] = [''] result['parents'] = ['']
fileList.append(result) fileList.append(result)
@@ -56886,7 +56880,7 @@ def printShowFileCounts(users):
if not drive: if not drive:
continue continue
sharedDriveId = fileIdEntity.get('shareddrive', {}).get('driveId', '') sharedDriveId = fileIdEntity.get('shareddrive', {}).get('driveId', '')
sharedDriveName = _getSharedDriveNameFromId(sharedDriveId) if sharedDriveId else '' sharedDriveName = _getSharedDriveNameFromId(drive, sharedDriveId) if sharedDriveId else ''
mimeTypeInfo = {} mimeTypeInfo = {}
userLastModification = _initLastModification() userLastModification = _initLastModification()
gettingEntity = _getGettingEntity(user, fileIdEntity) gettingEntity = _getGettingEntity(user, fileIdEntity)
@@ -57031,7 +57025,7 @@ def printShowDrivelastModifications(users):
if not drive: if not drive:
continue continue
sharedDriveId = fileIdEntity.get('shareddrive', {}).get('driveId', '') sharedDriveId = fileIdEntity.get('shareddrive', {}).get('driveId', '')
sharedDriveName = _getSharedDriveNameFromId(sharedDriveId) if sharedDriveId else '' sharedDriveName = _getSharedDriveNameFromId(drive, sharedDriveId) if sharedDriveId else ''
userLastModification = _initLastModification() userLastModification = _initLastModification()
gettingEntity = _getGettingEntity(user, fileIdEntity) gettingEntity = _getGettingEntity(user, fileIdEntity)
printGettingAllEntityItemsForWhom(Ent.DRIVE_FILE_OR_FOLDER, gettingEntity, i, count) printGettingAllEntityItemsForWhom(Ent.DRIVE_FILE_OR_FOLDER, gettingEntity, i, count)
@@ -57214,7 +57208,7 @@ def printDiskUsage(users):
includeOwner = False includeOwner = False
csvPF.RemoveTitles(['Owner', 'ownedByMe']) csvPF.RemoveTitles(['Owner', 'ownedByMe'])
if topFolder['name'] == TEAM_DRIVE and not topFolder.get('parents'): if topFolder['name'] == TEAM_DRIVE and not topFolder.get('parents'):
topFolder['name'] = _getSharedDriveNameFromId(driveId) topFolder['name'] = _getSharedDriveNameFromId(drive, driveId)
topFolder['path'] = f'{SHARED_DRIVES}{pathDelimiter}{topFolder["name"]}' topFolder['path'] = f'{SHARED_DRIVES}{pathDelimiter}{topFolder["name"]}'
else: else:
topFolder['path'] = topFolder['name'] topFolder['path'] = topFolder['name']
@@ -57654,7 +57648,7 @@ def printShowFileTree(users):
fileId=fileId, fields=fields, supportsAllDrives=True) fileId=fileId, fields=fields, supportsAllDrives=True)
if (fileEntryInfo['mimeType'] == MIMETYPE_GA_FOLDER and fileEntryInfo.get('driveId') and if (fileEntryInfo['mimeType'] == MIMETYPE_GA_FOLDER and fileEntryInfo.get('driveId') and
fileEntryInfo['name'] == TEAM_DRIVE and not fileEntryInfo.get('parents', [])): fileEntryInfo['name'] == TEAM_DRIVE and not fileEntryInfo.get('parents', [])):
fileEntryInfo['name'] = f"{SHARED_DRIVES}/{_getSharedDriveNameFromId(fileId)}" fileEntryInfo['name'] = f"{SHARED_DRIVES}/{_getSharedDriveNameFromId(drive, fileId)}"
if stripCRsFromName: if stripCRsFromName:
fileEntryInfo['name'] = _stripControlCharsFromName(fileEntryInfo['name']) fileEntryInfo['name'] = _stripControlCharsFromName(fileEntryInfo['name'])
if buildTree: if buildTree:
@@ -59295,7 +59289,7 @@ def _getCopyMoveParentInfo(drive, user, i, count, j, jcount, newParentId, statis
result['destParentType'] = DEST_PARENT_MYDRIVE_FOLDER result['destParentType'] = DEST_PARENT_MYDRIVE_FOLDER
else: else:
if result['name'] == TEAM_DRIVE and not result.get('parents', []): if result['name'] == TEAM_DRIVE and not result.get('parents', []):
result['name'] = _getSharedDriveNameFromId(result['driveId']) result['name'] = _getSharedDriveNameFromId(drive, result['driveId'])
result['destParentType'] = DEST_PARENT_SHAREDDRIVE_ROOT result['destParentType'] = DEST_PARENT_SHAREDDRIVE_ROOT
else: else:
result['destParentType'] = DEST_PARENT_SHAREDDRIVE_FOLDER result['destParentType'] = DEST_PARENT_SHAREDDRIVE_FOLDER
@@ -59844,7 +59838,7 @@ def copyDriveFile(users):
# Source at root of Shared Drive? # Source at root of Shared Drive?
sourceMimeType = source['mimeType'] sourceMimeType = source['mimeType']
if sourceMimeType == MIMETYPE_GA_FOLDER and source.get('driveId') and source['name'] == TEAM_DRIVE and not source.get('parents', []): if sourceMimeType == MIMETYPE_GA_FOLDER and source.get('driveId') and source['name'] == TEAM_DRIVE and not source.get('parents', []):
source['name'] = _getSharedDriveNameFromId(source['driveId']) source['name'] = _getSharedDriveNameFromId(drive, source['driveId'])
sourceName = source['name'] sourceName = source['name']
sourceNameId = f"{sourceName}({source['id']})" sourceNameId = f"{sourceName}({source['id']})"
copyMoveOptions['sourceDriveId'] = source.get('driveId') copyMoveOptions['sourceDriveId'] = source.get('driveId')
@@ -60450,6 +60444,7 @@ def moveDriveFile(users):
GAPI.FILE_OWNER_NOT_MEMBER_OF_TEAMDRIVE, GAPI.FILE_OWNER_NOT_MEMBER_OF_TEAMDRIVE,
GAPI.FILE_OWNER_NOT_MEMBER_OF_WRITER_DOMAIN, GAPI.FILE_OWNER_NOT_MEMBER_OF_WRITER_DOMAIN,
GAPI.FILE_WRITER_TEAMDRIVE_MOVE_IN_DISABLED, GAPI.FILE_WRITER_TEAMDRIVE_MOVE_IN_DISABLED,
GAPI.SHARE_OUT_NOT_PERMITTED,
GAPI.TARGET_USER_ROLE_LIMITED_BY_LICENSE_RESTRICTION, GAPI.TARGET_USER_ROLE_LIMITED_BY_LICENSE_RESTRICTION,
GAPI.CANNOT_MOVE_TRASHED_ITEM_INTO_TEAMDRIVE, GAPI.CANNOT_MOVE_TRASHED_ITEM_INTO_TEAMDRIVE,
GAPI.CANNOT_MOVE_TRASHED_ITEM_OUT_OF_TEAMDRIVE, GAPI.CANNOT_MOVE_TRASHED_ITEM_OUT_OF_TEAMDRIVE,
@@ -60464,7 +60459,7 @@ def moveDriveFile(users):
_incrStatistic(statistics, STAT_FILE_COPIED_MOVED) _incrStatistic(statistics, STAT_FILE_COPIED_MOVED)
return return
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.unknownError, GAPI.badRequest, except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.unknownError, GAPI.badRequest,
GAPI.targetUserRoleLimitedByLicenseRestriction, GAPI.shareOutNotPermitted, GAPI.targetUserRoleLimitedByLicenseRestriction,
GAPI.cannotMoveTrashedItemIntoTeamDrive, GAPI.cannotMoveTrashedItemOutOfTeamDrive, GAPI.cannotMoveTrashedItemIntoTeamDrive, GAPI.cannotMoveTrashedItemOutOfTeamDrive,
GAPI.teamDrivesShortcutFileNotSupported, GAPI.storageQuotaExceeded) as e: GAPI.teamDrivesShortcutFileNotSupported, GAPI.storageQuotaExceeded) as e:
entityActionFailedWarning(kvList, str(e), k, kcount) entityActionFailedWarning(kvList, str(e), k, kcount)
@@ -60614,7 +60609,7 @@ def moveDriveFile(users):
if sourceMimeType == MIMETYPE_GA_FOLDER and source['name'] in [MY_DRIVE, TEAM_DRIVE] and not source.get('parents', []): if sourceMimeType == MIMETYPE_GA_FOLDER and source['name'] in [MY_DRIVE, TEAM_DRIVE] and not source.get('parents', []):
copyMoveOptions['sourceIsMyDriveSharedDrive'] = True copyMoveOptions['sourceIsMyDriveSharedDrive'] = True
if source.get('driveId'): if source.get('driveId'):
source['name'] = _getSharedDriveNameFromId(source['driveId']) source['name'] = _getSharedDriveNameFromId(drive, source['driveId'])
sourceName = source['name'] sourceName = source['name']
sourceNameId = f"{sourceName}({source['id']})" sourceNameId = f"{sourceName}({source['id']})"
copyMoveOptions['sourceDriveId'] = source.get('driveId') copyMoveOptions['sourceDriveId'] = source.get('driveId')
@@ -63058,7 +63053,7 @@ def printEmptyDriveFolders(users):
fileIdEntity['shareddrive'] = {'driveId': sharedDriveId, 'corpora': 'drive', 'includeItemsFromAllDrives': True, 'supportsAllDrives': True} fileIdEntity['shareddrive'] = {'driveId': sharedDriveId, 'corpora': 'drive', 'includeItemsFromAllDrives': True, 'supportsAllDrives': True}
csvPF.AddTitles(['driveId']) csvPF.AddTitles(['driveId'])
csvPF.MoveTitlesToEnd(['name']) csvPF.MoveTitlesToEnd(['name'])
pathList = [f'{SHARED_DRIVES}/{_getSharedDriveNameFromId(sharedDriveId)}'] pathList = [f'{SHARED_DRIVES}/{_getSharedDriveNameFromId(drive, sharedDriveId)}']
else: else:
pathList = [fileEntryInfo['name']] pathList = [fileEntryInfo['name']]
mimeType = fileEntryInfo['mimeType'] mimeType = fileEntryInfo['mimeType']
@@ -63148,7 +63143,7 @@ def deleteEmptyDriveFolders(users):
if 'driveId' in fileEntryInfo: if 'driveId' in fileEntryInfo:
sharedDriveId = fileEntryInfo['driveId'] sharedDriveId = fileEntryInfo['driveId']
fileIdEntity['shareddrive'] = {'driveId': sharedDriveId, 'corpora': 'drive', 'includeItemsFromAllDrives': True, 'supportsAllDrives': True} fileIdEntity['shareddrive'] = {'driveId': sharedDriveId, 'corpora': 'drive', 'includeItemsFromAllDrives': True, 'supportsAllDrives': True}
pathList = [f'{SHARED_DRIVES}/{_getSharedDriveNameFromId(sharedDriveId)}'] pathList = [f'{SHARED_DRIVES}/{_getSharedDriveNameFromId(drive, sharedDriveId)}']
else: else:
pathList = [fileEntryInfo['name']] pathList = [fileEntryInfo['name']]
mimeType = fileEntryInfo['mimeType'] mimeType = fileEntryInfo['mimeType']
@@ -65585,7 +65580,7 @@ def doPrintShowSharedDrives():
def doPrintShowOrgunitSharedDrives(): def doPrintShowOrgunitSharedDrives():
def _getOrgUnitSharedDriveInfo(shareddrive): def _getOrgUnitSharedDriveInfo(shareddrive):
shareddrive['driveId'] = shareddrive['name'].rsplit(';')[1] shareddrive['driveId'] = shareddrive['name'].rsplit(';')[1]
shareddrive['driveName'] = _getSharedDriveNameFromId(shareddrive['driveId']) shareddrive['driveName'] = _getSharedDriveNameFromId(drive, shareddrive['driveId'], True)
shareddrive['orgUnitPath'] = orgUnitPath shareddrive['orgUnitPath'] = orgUnitPath
def _showOrgUnitSharedDrive(shareddrive, j, jcount, FJQC): def _showOrgUnitSharedDrive(shareddrive, j, jcount, FJQC):
@@ -65599,13 +65594,13 @@ def doPrintShowOrgunitSharedDrives():
printEntity([Ent.MEMBER_URI, shareddrive['memberUri']]) printEntity([Ent.MEMBER_URI, shareddrive['memberUri']])
printEntity([Ent.SHAREDDRIVE_ID, shareddrive['driveId']]) printEntity([Ent.SHAREDDRIVE_ID, shareddrive['driveId']])
printEntity([Ent.SHAREDDRIVE_NAME, shareddrive['driveName']]) printEntity([Ent.SHAREDDRIVE_NAME, shareddrive['driveName']])
printEntity([Ent.ORGANIZATIONAL_UNIT, shareddrive['orgUnit']]) printEntity([Ent.ORGANIZATIONAL_UNIT, shareddrive['orgUnitPath']])
Ind.Decrement() Ind.Decrement()
ci = buildGAPIObject(API.CLOUDIDENTITY_ORGUNITS_BETA) ci = buildGAPIObject(API.CLOUDIDENTITY_ORGUNITS_BETA)
cd = buildGAPIObject(API.DIRECTORY) cd = buildGAPIObject(API.DIRECTORY)
_, GM.Globals[GM.ADMIN_DRIVE] = buildGAPIServiceObject(API.DRIVE3, _getAdminEmail()) _, drive = buildGAPIServiceObject(API.DRIVE3, _getAdminEmail())
if not GM.Globals[GM.ADMIN_DRIVE]: if drive is None:
return return
csvPF = CSVPrintFile(['name', 'type', 'member', 'memberUri', 'driveId', 'driveName', 'orgUnitPath']) if Act.csvFormat() else None csvPF = CSVPrintFile(['name', 'type', 'member', 'memberUri', 'driveId', 'driveName', 'orgUnitPath']) if Act.csvFormat() else None
FJQC = FormatJSONQuoteChar(csvPF) FJQC = FormatJSONQuoteChar(csvPF)
@@ -65684,13 +65679,13 @@ def copySyncSharedDriveACLs(users, useDomainAdminAccess=False):
if not drive: if not drive:
continue continue
if not srcFileIdEntity.get('shareddrivename'): if not srcFileIdEntity.get('shareddrivename'):
srcFileIdEntity['shareddrivename'] = _getSharedDriveNameFromId(srcFileIdEntity['shareddrive']['driveId']) srcFileIdEntity['shareddrivename'] = _getSharedDriveNameFromId(drive, srcFileIdEntity['shareddrive']['driveId'])
if tgtFileIdEntity.get('shareddrivename'): if tgtFileIdEntity.get('shareddrivename'):
if not _convertSharedDriveNameToId(drive, user, i, count, tgtFileIdEntity, useDomainAdminAccess): if not _convertSharedDriveNameToId(drive, user, i, count, tgtFileIdEntity, useDomainAdminAccess):
continue continue
tgtFileIdEntity['shareddrive']['corpora'] = 'drive' tgtFileIdEntity['shareddrive']['corpora'] = 'drive'
else: else:
tgtFileIdEntity['shareddrivename'] = _getSharedDriveNameFromId(tgtFileIdEntity['shareddrive']['driveId']) tgtFileIdEntity['shareddrivename'] = _getSharedDriveNameFromId(drive, tgtFileIdEntity['shareddrive']['driveId'])
statistics = _initStatistics() statistics = _initStatistics()
copyMoveOptions['sourceDriveId'] = srcFileIdEntity['shareddrive']['driveId'] copyMoveOptions['sourceDriveId'] = srcFileIdEntity['shareddrive']['driveId']
copyMoveOptions['destDriveId'] = tgtFileIdEntity['shareddrive']['driveId'] copyMoveOptions['destDriveId'] = tgtFileIdEntity['shareddrive']['driveId']

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2024 Ross Scroggs All Rights Reserved. # Copyright (C) 2025 Ross Scroggs All Rights Reserved.
# #
# All Rights Reserved. # All Rights Reserved.
# #
@@ -260,12 +260,12 @@ SMTP_HOST = 'smtp_host'
SMTP_USERNAME = 'smtp_username' SMTP_USERNAME = 'smtp_username'
# SMTP password # SMTP password
SMTP_PASSWORD = 'smtp_password' SMTP_PASSWORD = 'smtp_password'
# Time Zone
TIMEZONE = 'timezone'
## Minimum TLS Version required for HTTPS connections ## Minimum TLS Version required for HTTPS connections
TLS_MIN_VERSION = 'tls_min_version' TLS_MIN_VERSION = 'tls_min_version'
## Maximum TLS Version used for HTTPS connections ## Maximum TLS Version used for HTTPS connections
TLS_MAX_VERSION = 'tls_max_version' TLS_MAX_VERSION = 'tls_max_version'
# Time Zone
TIMEZONE = 'timezone'
# Clear basic filter when updating an existing sheet # Clear basic filter when updating an existing sheet
TODRIVE_CLEARFILTER = 'todrive_clearfilter' TODRIVE_CLEARFILTER = 'todrive_clearfilter'
# Use client access for todrive # Use client access for todrive
@@ -431,9 +431,9 @@ Defaults = {
SMTP_HOST: '', SMTP_HOST: '',
SMTP_USERNAME: '', SMTP_USERNAME: '',
SMTP_PASSWORD: '', SMTP_PASSWORD: '',
TIMEZONE: 'utc',
TLS_MIN_VERSION: 'TLSv1_3', TLS_MIN_VERSION: 'TLSv1_3',
TLS_MAX_VERSION: '', TLS_MAX_VERSION: '',
TIMEZONE: 'utc',
TODRIVE_CLEARFILTER: FALSE, TODRIVE_CLEARFILTER: FALSE,
TODRIVE_CLIENTACCESS: FALSE, TODRIVE_CLIENTACCESS: FALSE,
TODRIVE_CONVERSION: TRUE, TODRIVE_CONVERSION: TRUE,
@@ -599,9 +599,9 @@ VAR_INFO = {
SMTP_HOST: {VAR_TYPE: TYPE_STRING, VAR_LIMITS: (0, None)}, SMTP_HOST: {VAR_TYPE: TYPE_STRING, VAR_LIMITS: (0, None)},
SMTP_USERNAME: {VAR_TYPE: TYPE_STRING, VAR_LIMITS: (0, None)}, SMTP_USERNAME: {VAR_TYPE: TYPE_STRING, VAR_LIMITS: (0, None)},
SMTP_PASSWORD: {VAR_TYPE: TYPE_PASSWORD, VAR_LIMITS: (0, None)}, SMTP_PASSWORD: {VAR_TYPE: TYPE_PASSWORD, VAR_LIMITS: (0, None)},
TIMEZONE: {VAR_TYPE: TYPE_TIMEZONE},
TLS_MIN_VERSION: {VAR_TYPE: TYPE_CHOICE, VAR_ENVVAR: 'GAM_TLS_MIN_VERSION', VAR_CHOICES: TLS_CHOICE_MAP}, TLS_MIN_VERSION: {VAR_TYPE: TYPE_CHOICE, VAR_ENVVAR: 'GAM_TLS_MIN_VERSION', VAR_CHOICES: TLS_CHOICE_MAP},
TLS_MAX_VERSION: {VAR_TYPE: TYPE_CHOICE, VAR_ENVVAR: 'GAM_TLS_MAX_VERSION', VAR_CHOICES: TLS_CHOICE_MAP}, TLS_MAX_VERSION: {VAR_TYPE: TYPE_CHOICE, VAR_ENVVAR: 'GAM_TLS_MAX_VERSION', VAR_CHOICES: TLS_CHOICE_MAP},
TIMEZONE: {VAR_TYPE: TYPE_TIMEZONE},
TODRIVE_CLEARFILTER: {VAR_TYPE: TYPE_BOOLEAN}, TODRIVE_CLEARFILTER: {VAR_TYPE: TYPE_BOOLEAN},
TODRIVE_CLIENTACCESS: {VAR_TYPE: TYPE_BOOLEAN}, TODRIVE_CLIENTACCESS: {VAR_TYPE: TYPE_BOOLEAN},
TODRIVE_CONVERSION: {VAR_TYPE: TYPE_BOOLEAN}, TODRIVE_CONVERSION: {VAR_TYPE: TYPE_BOOLEAN},

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2023 Ross Scroggs All Rights Reserved. # Copyright (C) 2025 Ross Scroggs All Rights Reserved.
# #
# All Rights Reserved. # All Rights Reserved.
# #
@@ -25,8 +25,6 @@
# Some commands want to set a non-zero return code but not bail # Some commands want to set a non-zero return code but not bail
# GAM admin user from oauth2.txt or oauth2service.json # GAM admin user from oauth2.txt or oauth2service.json
ADMIN = 'admn' ADMIN = 'admn'
# Drive service for admin; used to look up Shared Drive Names
ADMIN_DRIVE = 'addr'
# Number/length of API call retries # Number/length of API call retries
API_CALLS_RETRY_DATA = 'rtry' API_CALLS_RETRY_DATA = 'rtry'
# GAM cache directory. If no_cache is True, this variable will be set to None # GAM cache directory. If no_cache is True, this variable will be set to None
@@ -220,7 +218,6 @@ REDIRECT_QUEUE_EOF = 'eof'
# #
Globals = { Globals = {
ADMIN: None, ADMIN: None,
ADMIN_DRIVE: None,
API_CALLS_RETRY_DATA: {}, API_CALLS_RETRY_DATA: {},
CACHE_DIR: None, CACHE_DIR: None,
CACHE_DISCOVERY_ONLY: True, CACHE_DISCOVERY_ONLY: True,

View File

@@ -64,6 +64,7 @@ Verify the following steps:
* If groups are used to authenticate access, make sure the super admin is in one of the groups * If groups are used to authenticate access, make sure the super admin is in one of the groups
* Collapse "Service status" * Collapse "Service status"
* Expand "Cloud Resource Manager API settings" * Expand "Cloud Resource Manager API settings"
* Select the OU in the left that contains the super admin you'll be using
* Make sure that "Allow users to create projects" is checked * Make sure that "Allow users to create projects" is checked
Verify that all scopes are available: Verify that all scopes are available:

View File

@@ -10,6 +10,27 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
See [Downloads-Installs-GAM7](https://github.com/GAM-team/GAM/wiki/Downloads-Installs) for Windows or other options, including manual installation See [Downloads-Installs-GAM7](https://github.com/GAM-team/GAM/wiki/Downloads-Installs) for Windows or other options, including manual installation
### 7.07.11
Updated `gam calendars <CalendarEntity> update events` and `gam <UserTypeEntity> update events <UserCalendarEntity>`
to handle the following error:
```
ERROR: 400: badRequest - Bad Request
```
Updated `gam <UserTypeEntity> move drivefile` to handle the following error:
```
ERROR: 400: shareOutNotPermitted
```
### 7.07.10
Updated `gam calendars <CalendarEntity> update events` and `gam <UserTypeEntity> update events <UserCalendarEntity>`
to handle the following error:
```
ERROR: 400: eventTypeRestriction - Attendees cannot be added to 'fromGmail' event with this visibility setting.
```
### 7.07.09 ### 7.07.09
Updated `gam calendars <CalendarEntity> update events` and `gam <UserTypeEntity> update events <UserCalendarEntity>` Updated `gam calendars <CalendarEntity> update events` and `gam <UserTypeEntity> update events <UserCalendarEntity>`

View File

@@ -335,6 +335,11 @@ gam update group group@domain.com whoCanViewMembership ALL_MEMBERS_CAN_VIEW whoC
Group: group@domain.com, Updated Group: group@domain.com, Updated
``` ```
If you are entering a valid combination but an error message is returned, do the following and then re-issue your command.
```
gam update group group@domain.com whoCanViewMembership ALL_IN_DOMAIN_CAN_VIEW whoCanDiscoverGroup ALL_IN_DOMAIN_CAN_DISCOVER
```
## Manage groups ## Manage groups
These commands allow you to create, update and delete groups. These commands allow you to create, update and delete groups.

View File

@@ -251,7 +251,7 @@ writes the credentials into the file oauth2.txt.
admin@server:/Users/admin$ rm -f /Users/admin/GAMConfig/oauth2.txt admin@server:/Users/admin$ rm -f /Users/admin/GAMConfig/oauth2.txt
admin@server:/Users/admin$ gam version admin@server:/Users/admin$ gam version
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
GAM 7.07.09 - https://github.com/GAM-team/GAM - pyinstaller GAM 7.07.11 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com> GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.3 64-bit final Python 3.13.3 64-bit final
MacOS Sequoia 15.5 x86_64 MacOS Sequoia 15.5 x86_64
@@ -989,7 +989,7 @@ writes the credentials into the file oauth2.txt.
C:\>del C:\GAMConfig\oauth2.txt C:\>del C:\GAMConfig\oauth2.txt
C:\>gam version C:\>gam version
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
GAM 7.07.09 - https://github.com/GAM-team/GAM - pythonsource GAM 7.07.11 - https://github.com/GAM-team/GAM - pythonsource
GAM Team <google-apps-manager@googlegroups.com> GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.3 64-bit final Python 3.13.3 64-bit final
Windows-10-10.0.17134 AMD64 Windows-10-10.0.17134 AMD64

View File

@@ -3,7 +3,7 @@
Print the current version of Gam with details Print the current version of Gam with details
``` ```
gam version gam version
GAM 7.07.09 - https://github.com/GAM-team/GAM - pyinstaller GAM 7.07.11 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com> GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.3 64-bit final Python 3.13.3 64-bit final
MacOS Sequoia 15.5 x86_64 MacOS Sequoia 15.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 Print the current version of Gam with details and time offset information
``` ```
gam version timeoffset gam version timeoffset
GAM 7.07.09 - https://github.com/GAM-team/GAM - pyinstaller GAM 7.07.11 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com> GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.3 64-bit final Python 3.13.3 64-bit final
MacOS Sequoia 15.5 x86_64 MacOS Sequoia 15.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 Print the current version of Gam with extended details and SSL information
``` ```
gam version extended gam version extended
GAM 7.07.09 - https://github.com/GAM-team/GAM - pyinstaller GAM 7.07.11 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com> GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.3 64-bit final Python 3.13.3 64-bit final
MacOS Sequoia 15.5 x86_64 MacOS Sequoia 15.5 x86_64
@@ -64,7 +64,7 @@ MacOS High Sierra 10.13.6 x86_64
Path: /Users/Admin/bin/gam7 Path: /Users/Admin/bin/gam7
Version Check: Version Check:
Current: 5.35.08 Current: 5.35.08
Latest: 7.07.09 Latest: 7.07.11
echo $? echo $?
1 1
``` ```
@@ -72,7 +72,7 @@ echo $?
Print the current version number without details Print the current version number without details
``` ```
gam version simple gam version simple
7.07.09 7.07.11
``` ```
In Linux/MacOS you can do: In Linux/MacOS you can do:
``` ```
@@ -82,7 +82,7 @@ echo $VER
Print the current version of Gam and address of this Wiki Print the current version of Gam and address of this Wiki
``` ```
gam help gam help
GAM 7.07.09 - https://github.com/GAM-team/GAM GAM 7.07.11 - https://github.com/GAM-team/GAM
GAM Team <google-apps-manager@googlegroups.com> GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.3 64-bit final Python 3.13.3 64-bit final
MacOS Sequoia 15.5 x86_64 MacOS Sequoia 15.5 x86_64

View File

@@ -287,7 +287,7 @@ csv_output_users_audit
Default: False Default: False
customer_id customer_id
Google Customer ID Google Customer ID
Default: Blank Default: my_customer
Environment variable: CUSTOMER_ID Environment variable: CUSTOMER_ID
debug_level debug_level
If debug_level > 0, turn on API debugging output. If debug_level > 0, turn on API debugging output.
@@ -321,7 +321,7 @@ drive_v3_native_names
email_batch_size email_batch_size
When archiving, printing, showing, trashing, untrashing, marking as spam Gmail messages. When archiving, printing, showing, trashing, untrashing, marking as spam Gmail messages.
how many should be processed in each batch how many should be processed in each batch
Default: 100 Default: 50
Range: 1 - 100 Range: 1 - 100
enable_dasa enable_dasa
Enable/disable Delegated Admin Service Account API Access Enable/disable Delegated Admin Service Account API Access
@@ -384,7 +384,7 @@ message_batch_size
message_max_results message_max_results
When retrieving lists of Gmail messages from API, When retrieving lists of Gmail messages from API,
how many should be retrieved in each API call how many should be retrieved in each API call
Default: 1000 Default: 500
Range: 1 - 10000 Range: 1 - 10000
mobile_max_results mobile_max_results
When retrieving lists of Mobile devices from API, When retrieving lists of Mobile devices from API,
@@ -416,8 +416,10 @@ no_short_urls
the shortened URL redirects to the long URL. the shortened URL redirects to the long URL.
When True, the long scopes URLs in `gam oauth create` and When True, the long scopes URLs in `gam oauth create` and
`gam <UserTypeEntity> check|update serviceaccount` will be used as is. `gam <UserTypeEntity> check|update serviceaccount` will be used as is.
Default: True
no_verify_ssl no_verify_ssl
Disable SSL certificate validation Disable SSL certificate validation
Default: False
num_tbatch_threads num_tbatch_threads
Number of threads for gam tbatch Number of threads for gam tbatch
Default: 2 Default: 2