Compare commits

..

3 Commits

Author SHA1 Message Date
Ross Scroggs
226781766b Add drive/sheets read command data scopes 2025-10-03 17:34:33 -07:00
Ross Scroggs
434e30d57c Update Vault-Takeout.md
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
2025-10-03 13:17:13 -07:00
Ross Scroggs
2ab059926b Fixed bug in gam print|show admins
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 7, Build Intel MacOS, macos-13) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.14-dev, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14-dev freethread, 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-certs (push) Has been cancelled
2025-10-03 08:50:29 -07:00
7 changed files with 69 additions and 33 deletions

View File

@@ -1,3 +1,16 @@
7.24.00
If you want to disable a user's service account access to Drive and Sheets but still allow reading command data from Google Docs and Sheets,
issue the following command and make these settings:
```
gam user user@domain.com update serviceaccount
[ ] 20) Drive API (supports readonly)
[*] 21) Drive API - read command data
[ ] 42) Sheets API (supports readonly)
[*] 43) Sheets API - read command data
```
7.23.07 7.23.07
Fixed bug in `gam print|show admins` where all admin assignments were not displayed when Fixed bug in `gam print|show admins` where all admin assignments were not displayed when

View File

@@ -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.23.07' __version__ = '7.24.00'
__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
@@ -3049,9 +3049,10 @@ def getGDocData(gformat):
mimeType = GDOC_FORMAT_MIME_TYPES[gformat] mimeType = GDOC_FORMAT_MIME_TYPES[gformat]
user = getEmailAddress() user = getEmailAddress()
fileIdEntity = getDriveFileEntity(queryShortcutsOK=False) fileIdEntity = getDriveFileEntity(queryShortcutsOK=False)
user, drive, jcount = _validateUserGetFileIDs(user, 0, 0, fileIdEntity) _, drive = buildGAPIServiceObject(chooseSaAPI(API.DRIVECD, API.DRIVE3), user)
if not drive: if not drive:
sys.exit(GM.Globals[GM.SYSEXITRC]) sys.exit(GM.Globals[GM.SYSEXITRC])
_, _, jcount = _validateUserGetFileIDs(user, 0, 0, fileIdEntity, drive=drive)
if jcount == 0: if jcount == 0:
getGDocSheetDataFailedExit([Ent.USER, user], Msg.NO_ENTITIES_FOUND.format(Ent.Singular(Ent.DRIVE_FILE))) getGDocSheetDataFailedExit([Ent.USER, user], Msg.NO_ENTITIES_FOUND.format(Ent.Singular(Ent.DRIVE_FILE)))
if jcount > 1: if jcount > 1:
@@ -3105,14 +3106,15 @@ def getGSheetData():
user = getEmailAddress() user = getEmailAddress()
fileIdEntity = getDriveFileEntity(queryShortcutsOK=False) fileIdEntity = getDriveFileEntity(queryShortcutsOK=False)
sheetEntity = getSheetEntity(False) sheetEntity = getSheetEntity(False)
user, drive, jcount = _validateUserGetFileIDs(user, 0, 0, fileIdEntity) user, drive = buildGAPIServiceObject(chooseSaAPI(API.DRIVECD, API.DRIVE3), user)
if not drive: if not drive:
sys.exit(GM.Globals[GM.SYSEXITRC]) sys.exit(GM.Globals[GM.SYSEXITRC])
_, _, jcount = _validateUserGetFileIDs(user, 0, 0, fileIdEntity, drive=drive)
if jcount == 0: if jcount == 0:
getGDocSheetDataFailedExit([Ent.USER, user], Msg.NO_ENTITIES_FOUND.format(Ent.Singular(Ent.DRIVE_FILE))) getGDocSheetDataFailedExit([Ent.USER, user], Msg.NO_ENTITIES_FOUND.format(Ent.Singular(Ent.DRIVE_FILE)))
if jcount > 1: if jcount > 1:
getGDocSheetDataFailedExit([Ent.USER, user], Msg.MULTIPLE_ENTITIES_FOUND.format(Ent.Plural(Ent.DRIVE_FILE), jcount, ','.join(fileIdEntity['list']))) getGDocSheetDataFailedExit([Ent.USER, user], Msg.MULTIPLE_ENTITIES_FOUND.format(Ent.Plural(Ent.DRIVE_FILE), jcount, ','.join(fileIdEntity['list'])))
_, sheet = buildGAPIServiceObject(API.SHEETS, user) _, sheet = buildGAPIServiceObject(chooseSaAPI(API.SHEETSCD, API.SHEETS), user)
if not sheet: if not sheet:
sys.exit(GM.Globals[GM.SYSEXITRC]) sys.exit(GM.Globals[GM.SYSEXITRC])
fileId = fileIdEntity['list'][0] fileId = fileIdEntity['list'][0]
@@ -4801,8 +4803,6 @@ def defaultSvcAcctScopes():
saScopes[scope['api']].extend(scope['scope']) saScopes[scope['api']].extend(scope['scope'])
saScopes[API.DRIVEACTIVITY].append(API.DRIVE_SCOPE) saScopes[API.DRIVEACTIVITY].append(API.DRIVE_SCOPE)
saScopes[API.DRIVE2] = saScopes[API.DRIVE3] saScopes[API.DRIVE2] = saScopes[API.DRIVE3]
saScopes[API.DRIVETD] = saScopes[API.DRIVE3]
saScopes[API.SHEETSTD] = saScopes[API.SHEETS]
return saScopes return saScopes
def _getSvcAcctData(): def _getSvcAcctData():
@@ -5609,6 +5609,12 @@ def getSaUser(user):
GM.Globals[GM.CURRENT_CLIENT_API_SCOPES] = currentClientAPIScopes GM.Globals[GM.CURRENT_CLIENT_API_SCOPES] = currentClientAPIScopes
return userEmail return userEmail
def chooseSaAPI(api1, api2):
_getSvcAcctData()
if api1 in GM.Globals[GM.SVCACCT_SCOPES]:
return api1
return api2
def buildGAPIServiceObject(api, user, i=0, count=0, displayError=True): def buildGAPIServiceObject(api, user, i=0, count=0, displayError=True):
userEmail = getSaUser(user) userEmail = getSaUser(user)
httpObj = getHttpObj(cache=GM.Globals[GM.CACHE_DIR]) httpObj = getHttpObj(cache=GM.Globals[GM.CACHE_DIR])
@@ -8030,7 +8036,7 @@ class CSVPrintFile():
def getDriveObject(): def getDriveObject():
if not GC.Values[GC.TODRIVE_CLIENTACCESS]: if not GC.Values[GC.TODRIVE_CLIENTACCESS]:
_, drive = buildGAPIServiceObject(API.DRIVETD, self.todrive['user']) _, drive = buildGAPIServiceObject(chooseSaAPI(API.DRIVETD, API.DRIVE3), self.todrive['user'])
if not drive: if not drive:
invalidTodriveUserExit(Ent.USER, Msg.NOT_FOUND) invalidTodriveUserExit(Ent.USER, Msg.NOT_FOUND)
else: else:
@@ -8183,7 +8189,7 @@ class CSVPrintFile():
if result['mimeType'] != MIMETYPE_GA_SPREADSHEET: if result['mimeType'] != MIMETYPE_GA_SPREADSHEET:
invalidTodriveFileIdExit([], f'{Msg.NOT_A} {Ent.Singular(Ent.SPREADSHEET)}', tdfileidLocation) invalidTodriveFileIdExit([], f'{Msg.NOT_A} {Ent.Singular(Ent.SPREADSHEET)}', tdfileidLocation)
if not GC.Values[GC.TODRIVE_CLIENTACCESS]: if not GC.Values[GC.TODRIVE_CLIENTACCESS]:
_, sheet = buildGAPIServiceObject(API.SHEETSTD, self.todrive['user']) _, sheet = buildGAPIServiceObject(chooseSaAPI(API.SHEETSTD, API.SHEETS), self.todrive['user'])
if sheet is None: if sheet is None:
invalidTodriveUserExit(Ent.USER, Msg.NOT_FOUND) invalidTodriveUserExit(Ent.USER, Msg.NOT_FOUND)
else: else:
@@ -8696,7 +8702,7 @@ class CSVPrintFile():
sheetTitle += tdtime.strftime(self.todrive['sheettimeformat']) sheetTitle += tdtime.strftime(self.todrive['sheettimeformat'])
action = Act.Get() action = Act.Get()
if not GC.Values[GC.TODRIVE_CLIENTACCESS]: if not GC.Values[GC.TODRIVE_CLIENTACCESS]:
user, drive = buildGAPIServiceObject(API.DRIVETD, self.todrive['user']) user, drive = buildGAPIServiceObject(chooseSaAPI(API.DRIVETD, API.DRIVE3), self.todrive['user'])
if not drive: if not drive:
closeFile(csvFile) closeFile(csvFile)
return return
@@ -8729,7 +8735,7 @@ class CSVPrintFile():
if result['mimeType'] != MIMETYPE_GA_SPREADSHEET: if result['mimeType'] != MIMETYPE_GA_SPREADSHEET:
todriveCSVErrorExit(entityValueList, f'{Msg.NOT_A} {Ent.Singular(Ent.SPREADSHEET)}') todriveCSVErrorExit(entityValueList, f'{Msg.NOT_A} {Ent.Singular(Ent.SPREADSHEET)}')
if not GC.Values[GC.TODRIVE_CLIENTACCESS]: if not GC.Values[GC.TODRIVE_CLIENTACCESS]:
_, sheet = buildGAPIServiceObject(API.SHEETSTD, user) _, sheet = buildGAPIServiceObject(chooseSaAPI(API.SHEETSTD, API.SHEETS), user)
if sheet is None: if sheet is None:
return return
else: else:
@@ -8877,7 +8883,7 @@ class CSVPrintFile():
(self.todrive['sheetEntity'] or self.todrive['locale'] or self.todrive['timeZone'] or (self.todrive['sheetEntity'] or self.todrive['locale'] or self.todrive['timeZone'] or
self.todrive['sheettitle'] or self.todrive['cellwrap'] or self.todrive['cellnumberformat'])): self.todrive['sheettitle'] or self.todrive['cellwrap'] or self.todrive['cellnumberformat'])):
if not GC.Values[GC.TODRIVE_CLIENTACCESS]: if not GC.Values[GC.TODRIVE_CLIENTACCESS]:
_, sheet = buildGAPIServiceObject(API.SHEETSTD, user) _, sheet = buildGAPIServiceObject(chooseSaAPI(API.SHEETSTD, API.SHEETS), user)
if sheet is None: if sheet is None:
return return
else: else:
@@ -16263,7 +16269,7 @@ def _showCustomerLicenseInfo(customerInfo, FJQC):
while True: while True:
try: try:
result = callGAPI(rep.customerUsageReports(), 'get', result = callGAPI(rep.customerUsageReports(), 'get',
throwReasons=[GAPI.INVALID, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED], throwReasons=[GAPI.INVALID, GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
date=tryDate, customerId=customerInfo['id'], date=tryDate, customerId=customerInfo['id'],
fields='warnings,usageReports', parameters=parameters) fields='warnings,usageReports', parameters=parameters)
usageReports = numUsersAvailable(result) usageReports = numUsersAvailable(result)
@@ -16276,7 +16282,7 @@ def _showCustomerLicenseInfo(customerInfo, FJQC):
if fullData == 0: if fullData == 0:
continue continue
break break
except GAPI.invalid as e: except (GAPI.invalid, GAPI.failedPrecondition) as e:
tryDate = _adjustTryDate(str(e), 0, -1, tryDate) tryDate = _adjustTryDate(str(e), 0, -1, tryDate)
if not tryDate: if not tryDate:
return return
@@ -17052,10 +17058,7 @@ def doPrintShowAdmins():
if assignedTo not in assignedToIdEmailMap: if assignedTo not in assignedToIdEmailMap:
emailTypes = ALL_ASSIGNEE_TYPES if admin.get('assigneeType', '') != 'group' else ['group'] emailTypes = ALL_ASSIGNEE_TYPES if admin.get('assigneeType', '') != 'group' else ['group']
assigneeEmail, assigneeType = convertUIDtoEmailAddressWithType(f'uid:{assignedTo}', cd, sal, emailTypes=emailTypes) assigneeEmail, assigneeType = convertUIDtoEmailAddressWithType(f'uid:{assignedTo}', cd, sal, emailTypes=emailTypes)
if assigneeType in ADMIN_ASSIGNEE_TYPE_TO_ASSIGNEDTO_FIELD_MAP: assignedToField = ADMIN_ASSIGNEE_TYPE_TO_ASSIGNEDTO_FIELD_MAP.get(assigneeType, 'assignedToUnknown')
assignedToField = ADMIN_ASSIGNEE_TYPE_TO_ASSIGNEDTO_FIELD_MAP[assigneeType]
else:
assignedToField = 'assignedToUnknown'
if assignedToField == 'assignedToUnknown': if assignedToField == 'assignedToUnknown':
assigneeEmail = True assigneeEmail = True
assignedToIdEmailMap[assignedTo] = {'assignedToField': assignedToField, 'assigneeEmail': assigneeEmail} assignedToIdEmailMap[assignedTo] = {'assignedToField': assignedToField, 'assigneeEmail': assigneeEmail}
@@ -17084,6 +17087,7 @@ def doPrintShowAdmins():
typesSet = set() typesSet = set()
kwargs = {} kwargs = {}
rolePrivileges = {} rolePrivileges = {}
allGroupRoles = ','.join(sorted(ALL_GROUP_ROLES))
fieldsList = PRINT_ADMIN_FIELDS+['assigneeType'] fieldsList = PRINT_ADMIN_FIELDS+['assigneeType']
assignedToIdEmailMap = {} assignedToIdEmailMap = {}
while Cmd.ArgumentsRemaining(): while Cmd.ArgumentsRemaining():
@@ -17098,7 +17102,6 @@ def doPrintShowAdmins():
pass pass
elif myarg == 'recursive': elif myarg == 'recursive':
recursive = True recursive = True
allGroupRoles = ','.join(sorted(ALL_GROUP_ROLES))
memberOptions = initMemberOptions() memberOptions = initMemberOptions()
memberOptions[MEMBEROPTION_INCLUDEDERIVEDMEMBERSHIP] = True memberOptions[MEMBEROPTION_INCLUDEDERIVEDMEMBERSHIP] = True
memberOptions[MEMBEROPTION_DISPLAYMATCH] = False memberOptions[MEMBEROPTION_DISPLAYMATCH] = False
@@ -17136,7 +17139,7 @@ def doPrintShowAdmins():
return return
except GAPI.notFound as e: except GAPI.notFound as e:
entityActionFailedExit([Ent.ADMIN_ROLE, kwargs['roleId']], str(e)) entityActionFailedExit([Ent.ADMIN_ROLE, kwargs['roleId']], str(e))
except (GAPI.forbidden, GAPI.serviceNotAvailable) as e: except GAPI.serviceNotAvailable as e:
entityActionFailedExit([Ent.ADMINISTRATOR, userKey], str(e)) entityActionFailedExit([Ent.ADMINISTRATOR, userKey], str(e))
except (GAPI.badRequest, GAPI.customerNotFound): except (GAPI.badRequest, GAPI.customerNotFound):
accessErrorExit(cd) accessErrorExit(cd)
@@ -17164,7 +17167,6 @@ def doPrintShowAdmins():
groupMembers[assignedTo] = membersList[:] groupMembers[assignedTo] = membersList[:]
if not _setNamesFromIds(admin, _getPrivileges(admin)): if not _setNamesFromIds(admin, _getPrivileges(admin)):
continue continue
expandedAdmins.append(admin)
if not groupMembers[assignedTo]: if not groupMembers[assignedTo]:
expandedAdmins.append(admin) expandedAdmins.append(admin)
continue continue
@@ -17203,7 +17205,7 @@ def doPrintShowAdmins():
else: else:
for admin in expandedAdmins: for admin in expandedAdmins:
admin.pop('assigneeType', None) admin.pop('assigneeType', None)
admin.pop('assignedToField') admin.pop('assignedToField', None)
if not oneItemPerRow or 'rolePrivileges' not in admin: if not oneItemPerRow or 'rolePrivileges' not in admin:
csvPF.WriteRowTitles(flattenJSON(admin)) csvPF.WriteRowTitles(flattenJSON(admin))
else: else:

View File

@@ -60,6 +60,7 @@ DIRECTORY = 'directory'
DOCS = 'docs' DOCS = 'docs'
DRIVE2 = 'drive2' DRIVE2 = 'drive2'
DRIVE3 = 'drive3' DRIVE3 = 'drive3'
DRIVECD = 'drivecd'
DRIVETD = 'drivetd' DRIVETD = 'drivetd'
DRIVEACTIVITY = 'driveactivity' DRIVEACTIVITY = 'driveactivity'
DRIVELABELS = 'drivelabels' DRIVELABELS = 'drivelabels'
@@ -91,6 +92,7 @@ SERVICEACCOUNTLOOKUP = 'serviceaccountlookup'
SERVICEMANAGEMENT = 'servicemanagement' SERVICEMANAGEMENT = 'servicemanagement'
SERVICEUSAGE = 'serviceusage' SERVICEUSAGE = 'serviceusage'
SHEETS = 'sheets' SHEETS = 'sheets'
SHEETSCD = 'sheetscd'
SHEETSTD = 'sheetstd' SHEETSTD = 'sheetstd'
SITEVERIFICATION = 'siteVerification' SITEVERIFICATION = 'siteVerification'
STORAGE = 'storage' STORAGE = 'storage'
@@ -253,7 +255,8 @@ _INFO = {
DOCS: {'name': 'Docs API', 'version': 'v1', 'v2discovery': True}, DOCS: {'name': 'Docs API', 'version': 'v1', 'v2discovery': True},
DRIVE2: {'name': 'Drive API v2', 'version': 'v2', 'v2discovery': False, 'mappedAPI': 'drive'}, DRIVE2: {'name': 'Drive API v2', 'version': 'v2', 'v2discovery': False, 'mappedAPI': 'drive'},
DRIVE3: {'name': 'Drive API v3', 'version': 'v3', 'v2discovery': False, 'mappedAPI': 'drive'}, DRIVE3: {'name': 'Drive API v3', 'version': 'v3', 'v2discovery': False, 'mappedAPI': 'drive'},
DRIVETD: {'name': 'Drive API v3 - todrive', 'version': 'v3', 'v2discovery': False, 'mappedAPI': 'drive'}, DRIVECD: {'name': 'Drive API v3 - read command data', 'version': 'v3', 'v2discovery': False, 'mappedAPI': 'drive'},
DRIVETD: {'name': 'Drive API v3 - write todrive data', 'version': 'v3', 'v2discovery': False, 'mappedAPI': 'drive'},
DRIVEACTIVITY: {'name': 'Drive Activity API v2', 'version': 'v2', 'v2discovery': True}, DRIVEACTIVITY: {'name': 'Drive Activity API v2', 'version': 'v2', 'v2discovery': True},
DRIVELABELS_ADMIN: {'name': 'Drive Labels API - Admin', 'version': 'v2', 'v2discovery': True, 'mappedAPI': DRIVELABELS}, DRIVELABELS_ADMIN: {'name': 'Drive Labels API - Admin', 'version': 'v2', 'v2discovery': True, 'mappedAPI': DRIVELABELS},
DRIVELABELS_USER: {'name': 'Drive Labels API - User', 'version': 'v2', 'v2discovery': True, 'mappedAPI': DRIVELABELS}, DRIVELABELS_USER: {'name': 'Drive Labels API - User', 'version': 'v2', 'v2discovery': True, 'mappedAPI': DRIVELABELS},
@@ -283,7 +286,8 @@ _INFO = {
SERVICEMANAGEMENT: {'name': 'Service Management API', 'version': 'v1', 'v2discovery': True}, SERVICEMANAGEMENT: {'name': 'Service Management API', 'version': 'v1', 'v2discovery': True},
SERVICEUSAGE: {'name': 'Service Usage API', 'version': 'v1', 'v2discovery': True}, SERVICEUSAGE: {'name': 'Service Usage API', 'version': 'v1', 'v2discovery': True},
SHEETS: {'name': 'Sheets API', 'version': 'v4', 'v2discovery': True}, SHEETS: {'name': 'Sheets API', 'version': 'v4', 'v2discovery': True},
SHEETSTD: {'name': 'Sheets API - todrive', 'version': 'v4', 'v2discovery': True, 'mappedAPI': SHEETS}, SHEETSCD: {'name': 'Sheets API - read command data', 'version': 'v4', 'v2discovery': True, 'mappedAPI': SHEETS},
SHEETSTD: {'name': 'Sheets API - write todrive data', 'version': 'v4', 'v2discovery': True, 'mappedAPI': SHEETS},
SITEVERIFICATION: {'name': 'Site Verification API', 'version': 'v1', 'v2discovery': True}, SITEVERIFICATION: {'name': 'Site Verification API', 'version': 'v1', 'v2discovery': True},
STORAGE: {'name': 'Cloud Storage API', 'version': 'v1', 'v2discovery': True}, STORAGE: {'name': 'Cloud Storage API', 'version': 'v1', 'v2discovery': True},
STORAGEREAD: {'name': 'Cloud Storage API - Read', 'version': 'v1', 'v2discovery': True, 'mappedAPI': STORAGE}, STORAGEREAD: {'name': 'Cloud Storage API - Read', 'version': 'v1', 'v2discovery': True, 'mappedAPI': STORAGE},
@@ -750,9 +754,15 @@ _SVCACCT_SCOPES = [
] ]
_SVCACCT_SPECIAL_SCOPES = [ _SVCACCT_SPECIAL_SCOPES = [
{'name': 'Drive API - todrive', {'name': 'Drive API - read command data',
'api': DRIVECD,
'subscopes': [],
'offByDefault': True,
'scope': DRIVE_SCOPE+'.readonly'},
{'name': 'Drive API - write todrive data',
'api': DRIVETD, 'api': DRIVETD,
'subscopes': [], 'subscopes': [],
'offByDefault': True,
'scope': DRIVE_SCOPE}, 'scope': DRIVE_SCOPE},
{'name': 'Gmail API - Full Access - read only', {'name': 'Gmail API - Full Access - read only',
'api': GMAIL, 'api': GMAIL,
@@ -764,8 +774,14 @@ _SVCACCT_SPECIAL_SCOPES = [
'subscopes': [], 'subscopes': [],
'offByDefault': True, 'offByDefault': True,
'scope': GMAIL_SEND_SCOPE}, 'scope': GMAIL_SEND_SCOPE},
{'name': 'Sheets API - todrive', {'name': 'Sheets API - read command data',
'api': SHEETSCD,
'offByDefault': True,
'subscopes': [],
'scope': 'https://www.googleapis.com/auth/spreadsheets.readonly'},
{'name': 'Sheets API - write todrive data',
'api': SHEETSTD, 'api': SHEETSTD,
'offByDefault': True,
'subscopes': [], 'subscopes': [],
'scope': 'https://www.googleapis.com/auth/spreadsheets'}, 'scope': 'https://www.googleapis.com/auth/spreadsheets'},
] ]

View File

@@ -10,6 +10,11 @@ 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.23.07
Fixed bug in `gam print|show admins` where all admin assignments were not displayed when
`types <AdminAssigneeTypeList>` was not specified, i.e., all assignments should be displayed.
### 7.23.06 ### 7.23.06
Added option `types <AdminAssigneeTypeList>` to `gam print|show admins` that allows filtering Added option `types <AdminAssigneeTypeList>` to `gam print|show admins` that allows filtering

View File

@@ -252,7 +252,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.23.06 - https://github.com/GAM-team/GAM - pyinstaller GAM 7.23.07 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com> GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.7 64-bit final Python 3.13.7 64-bit final
macOS Tahoe 26.0.1 x86_64 macOS Tahoe 26.0.1 x86_64
@@ -990,7 +990,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.22.00 - https://github.com/GAM-team/GAM - pythonsource GAM 7.23.07 - https://github.com/GAM-team/GAM - pythonsource
GAM Team <google-apps-manager@googlegroups.com> GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.7 64-bit final Python 3.13.7 64-bit final
Windows-10-10.0.17134 AMD64 Windows-10-10.0.17134 AMD64

View File

@@ -27,7 +27,7 @@
- [Delete Vault Saved Queries](#delete-vault-saved-queries) - [Delete Vault Saved Queries](#delete-vault-saved-queries)
- [Display Vault Saved Queries](#display-vault-saved-queries) - [Display Vault Saved Queries](#display-vault-saved-queries)
- [Takeout](#takeout) - [Takeout](#takeout)
- [Copy a Takeout Bucket](#copy-a-takeoutbucket) - [Copy a Takeout Bucket](#copy-a-takeout-bucket)
- [Download a Takeout Bucket](#download-a-takeout-bucket) - [Download a Takeout Bucket](#download-a-takeout-bucket)
## API documentation ## API documentation
@@ -848,7 +848,7 @@ gam create vaultquery <MatterItem> [name <String>]
[<JSONData>] [<JSONData>]
[shownames] [shownames]
[showdetails|returnidonly|formatjson] [showdetails|returnidonly|formatjson]
`` ```
If `name <String>` is omitted, the query is named `GAM <corpus> Query - <Time>` If `name <String>` is omitted, the query is named `GAM <corpus> Query - <Time>`
@@ -928,7 +928,7 @@ Select fields to display:
The `shownames` argument controls whether org unit and shared drive names are displayed in queries; additional API calls are required to get the names. The `shownames` argument controls whether org unit and shared drive names are displayed in queries; additional API calls are required to get the names.
# Takeout ## Takeout
Many thanks to Jay for these commands and documentation. Many thanks to Jay for these commands and documentation.
GAM 6.42.00 and newer support copying and downloading Google Cloud Storage (GCS) buckets generated by [organization-wide Takeout](https://support.google.com/a/answer/100458?hl=en). GAM 6.42.00 and newer support copying and downloading Google Cloud Storage (GCS) buckets generated by [organization-wide Takeout](https://support.google.com/a/answer/100458?hl=en).

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.23.06 - https://github.com/GAM-team/GAM - pyinstaller GAM 7.23.07 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com> GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.7 64-bit final Python 3.13.7 64-bit final
macOS Tahoe 26.0.1 x86_64 macOS Tahoe 26.0.1 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.23.06 - https://github.com/GAM-team/GAM - pyinstaller GAM 7.23.07 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com> GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.7 64-bit final Python 3.13.7 64-bit final
macOS Tahoe 26.0.1 x86_64 macOS Tahoe 26.0.1 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.23.06 - https://github.com/GAM-team/GAM - pyinstaller GAM 7.23.07 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com> GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.7 64-bit final Python 3.13.7 64-bit final
macOS Tahoe 26.0.1 x86_64 macOS Tahoe 26.0.1 x86_64