mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-10 17:21:36 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
226781766b | ||
|
|
434e30d57c | ||
|
|
2ab059926b |
@@ -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
|
||||
|
||||
Fixed bug in `gam print|show admins` where all admin assignments were not displayed when
|
||||
|
||||
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
|
||||
"""
|
||||
|
||||
__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)'
|
||||
|
||||
#pylint: disable=wrong-import-position
|
||||
@@ -3049,9 +3049,10 @@ def getGDocData(gformat):
|
||||
mimeType = GDOC_FORMAT_MIME_TYPES[gformat]
|
||||
user = getEmailAddress()
|
||||
fileIdEntity = getDriveFileEntity(queryShortcutsOK=False)
|
||||
user, drive, jcount = _validateUserGetFileIDs(user, 0, 0, fileIdEntity)
|
||||
_, drive = buildGAPIServiceObject(chooseSaAPI(API.DRIVECD, API.DRIVE3), user)
|
||||
if not drive:
|
||||
sys.exit(GM.Globals[GM.SYSEXITRC])
|
||||
_, _, jcount = _validateUserGetFileIDs(user, 0, 0, fileIdEntity, drive=drive)
|
||||
if jcount == 0:
|
||||
getGDocSheetDataFailedExit([Ent.USER, user], Msg.NO_ENTITIES_FOUND.format(Ent.Singular(Ent.DRIVE_FILE)))
|
||||
if jcount > 1:
|
||||
@@ -3105,14 +3106,15 @@ def getGSheetData():
|
||||
user = getEmailAddress()
|
||||
fileIdEntity = getDriveFileEntity(queryShortcutsOK=False)
|
||||
sheetEntity = getSheetEntity(False)
|
||||
user, drive, jcount = _validateUserGetFileIDs(user, 0, 0, fileIdEntity)
|
||||
user, drive = buildGAPIServiceObject(chooseSaAPI(API.DRIVECD, API.DRIVE3), user)
|
||||
if not drive:
|
||||
sys.exit(GM.Globals[GM.SYSEXITRC])
|
||||
_, _, jcount = _validateUserGetFileIDs(user, 0, 0, fileIdEntity, drive=drive)
|
||||
if jcount == 0:
|
||||
getGDocSheetDataFailedExit([Ent.USER, user], Msg.NO_ENTITIES_FOUND.format(Ent.Singular(Ent.DRIVE_FILE)))
|
||||
if jcount > 1:
|
||||
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:
|
||||
sys.exit(GM.Globals[GM.SYSEXITRC])
|
||||
fileId = fileIdEntity['list'][0]
|
||||
@@ -4801,8 +4803,6 @@ def defaultSvcAcctScopes():
|
||||
saScopes[scope['api']].extend(scope['scope'])
|
||||
saScopes[API.DRIVEACTIVITY].append(API.DRIVE_SCOPE)
|
||||
saScopes[API.DRIVE2] = saScopes[API.DRIVE3]
|
||||
saScopes[API.DRIVETD] = saScopes[API.DRIVE3]
|
||||
saScopes[API.SHEETSTD] = saScopes[API.SHEETS]
|
||||
return saScopes
|
||||
|
||||
def _getSvcAcctData():
|
||||
@@ -5609,6 +5609,12 @@ def getSaUser(user):
|
||||
GM.Globals[GM.CURRENT_CLIENT_API_SCOPES] = currentClientAPIScopes
|
||||
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):
|
||||
userEmail = getSaUser(user)
|
||||
httpObj = getHttpObj(cache=GM.Globals[GM.CACHE_DIR])
|
||||
@@ -8030,7 +8036,7 @@ class CSVPrintFile():
|
||||
|
||||
def getDriveObject():
|
||||
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:
|
||||
invalidTodriveUserExit(Ent.USER, Msg.NOT_FOUND)
|
||||
else:
|
||||
@@ -8183,7 +8189,7 @@ class CSVPrintFile():
|
||||
if result['mimeType'] != MIMETYPE_GA_SPREADSHEET:
|
||||
invalidTodriveFileIdExit([], f'{Msg.NOT_A} {Ent.Singular(Ent.SPREADSHEET)}', tdfileidLocation)
|
||||
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:
|
||||
invalidTodriveUserExit(Ent.USER, Msg.NOT_FOUND)
|
||||
else:
|
||||
@@ -8696,7 +8702,7 @@ class CSVPrintFile():
|
||||
sheetTitle += tdtime.strftime(self.todrive['sheettimeformat'])
|
||||
action = Act.Get()
|
||||
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:
|
||||
closeFile(csvFile)
|
||||
return
|
||||
@@ -8729,7 +8735,7 @@ class CSVPrintFile():
|
||||
if result['mimeType'] != MIMETYPE_GA_SPREADSHEET:
|
||||
todriveCSVErrorExit(entityValueList, f'{Msg.NOT_A} {Ent.Singular(Ent.SPREADSHEET)}')
|
||||
if not GC.Values[GC.TODRIVE_CLIENTACCESS]:
|
||||
_, sheet = buildGAPIServiceObject(API.SHEETSTD, user)
|
||||
_, sheet = buildGAPIServiceObject(chooseSaAPI(API.SHEETSTD, API.SHEETS), user)
|
||||
if sheet is None:
|
||||
return
|
||||
else:
|
||||
@@ -8877,7 +8883,7 @@ class CSVPrintFile():
|
||||
(self.todrive['sheetEntity'] or self.todrive['locale'] or self.todrive['timeZone'] or
|
||||
self.todrive['sheettitle'] or self.todrive['cellwrap'] or self.todrive['cellnumberformat'])):
|
||||
if not GC.Values[GC.TODRIVE_CLIENTACCESS]:
|
||||
_, sheet = buildGAPIServiceObject(API.SHEETSTD, user)
|
||||
_, sheet = buildGAPIServiceObject(chooseSaAPI(API.SHEETSTD, API.SHEETS), user)
|
||||
if sheet is None:
|
||||
return
|
||||
else:
|
||||
@@ -16263,7 +16269,7 @@ def _showCustomerLicenseInfo(customerInfo, FJQC):
|
||||
while True:
|
||||
try:
|
||||
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'],
|
||||
fields='warnings,usageReports', parameters=parameters)
|
||||
usageReports = numUsersAvailable(result)
|
||||
@@ -16276,7 +16282,7 @@ def _showCustomerLicenseInfo(customerInfo, FJQC):
|
||||
if fullData == 0:
|
||||
continue
|
||||
break
|
||||
except GAPI.invalid as e:
|
||||
except (GAPI.invalid, GAPI.failedPrecondition) as e:
|
||||
tryDate = _adjustTryDate(str(e), 0, -1, tryDate)
|
||||
if not tryDate:
|
||||
return
|
||||
@@ -17052,10 +17058,7 @@ def doPrintShowAdmins():
|
||||
if assignedTo not in assignedToIdEmailMap:
|
||||
emailTypes = ALL_ASSIGNEE_TYPES if admin.get('assigneeType', '') != 'group' else ['group']
|
||||
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[assigneeType]
|
||||
else:
|
||||
assignedToField = 'assignedToUnknown'
|
||||
assignedToField = ADMIN_ASSIGNEE_TYPE_TO_ASSIGNEDTO_FIELD_MAP.get(assigneeType, 'assignedToUnknown')
|
||||
if assignedToField == 'assignedToUnknown':
|
||||
assigneeEmail = True
|
||||
assignedToIdEmailMap[assignedTo] = {'assignedToField': assignedToField, 'assigneeEmail': assigneeEmail}
|
||||
@@ -17084,6 +17087,7 @@ def doPrintShowAdmins():
|
||||
typesSet = set()
|
||||
kwargs = {}
|
||||
rolePrivileges = {}
|
||||
allGroupRoles = ','.join(sorted(ALL_GROUP_ROLES))
|
||||
fieldsList = PRINT_ADMIN_FIELDS+['assigneeType']
|
||||
assignedToIdEmailMap = {}
|
||||
while Cmd.ArgumentsRemaining():
|
||||
@@ -17098,7 +17102,6 @@ def doPrintShowAdmins():
|
||||
pass
|
||||
elif myarg == 'recursive':
|
||||
recursive = True
|
||||
allGroupRoles = ','.join(sorted(ALL_GROUP_ROLES))
|
||||
memberOptions = initMemberOptions()
|
||||
memberOptions[MEMBEROPTION_INCLUDEDERIVEDMEMBERSHIP] = True
|
||||
memberOptions[MEMBEROPTION_DISPLAYMATCH] = False
|
||||
@@ -17136,7 +17139,7 @@ def doPrintShowAdmins():
|
||||
return
|
||||
except GAPI.notFound as 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))
|
||||
except (GAPI.badRequest, GAPI.customerNotFound):
|
||||
accessErrorExit(cd)
|
||||
@@ -17164,7 +17167,6 @@ def doPrintShowAdmins():
|
||||
groupMembers[assignedTo] = membersList[:]
|
||||
if not _setNamesFromIds(admin, _getPrivileges(admin)):
|
||||
continue
|
||||
expandedAdmins.append(admin)
|
||||
if not groupMembers[assignedTo]:
|
||||
expandedAdmins.append(admin)
|
||||
continue
|
||||
@@ -17203,7 +17205,7 @@ def doPrintShowAdmins():
|
||||
else:
|
||||
for admin in expandedAdmins:
|
||||
admin.pop('assigneeType', None)
|
||||
admin.pop('assignedToField')
|
||||
admin.pop('assignedToField', None)
|
||||
if not oneItemPerRow or 'rolePrivileges' not in admin:
|
||||
csvPF.WriteRowTitles(flattenJSON(admin))
|
||||
else:
|
||||
|
||||
@@ -60,6 +60,7 @@ DIRECTORY = 'directory'
|
||||
DOCS = 'docs'
|
||||
DRIVE2 = 'drive2'
|
||||
DRIVE3 = 'drive3'
|
||||
DRIVECD = 'drivecd'
|
||||
DRIVETD = 'drivetd'
|
||||
DRIVEACTIVITY = 'driveactivity'
|
||||
DRIVELABELS = 'drivelabels'
|
||||
@@ -91,6 +92,7 @@ SERVICEACCOUNTLOOKUP = 'serviceaccountlookup'
|
||||
SERVICEMANAGEMENT = 'servicemanagement'
|
||||
SERVICEUSAGE = 'serviceusage'
|
||||
SHEETS = 'sheets'
|
||||
SHEETSCD = 'sheetscd'
|
||||
SHEETSTD = 'sheetstd'
|
||||
SITEVERIFICATION = 'siteVerification'
|
||||
STORAGE = 'storage'
|
||||
@@ -253,7 +255,8 @@ _INFO = {
|
||||
DOCS: {'name': 'Docs API', 'version': 'v1', 'v2discovery': True},
|
||||
DRIVE2: {'name': 'Drive API v2', 'version': 'v2', '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},
|
||||
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},
|
||||
@@ -283,7 +286,8 @@ _INFO = {
|
||||
SERVICEMANAGEMENT: {'name': 'Service Management API', 'version': 'v1', 'v2discovery': True},
|
||||
SERVICEUSAGE: {'name': 'Service Usage API', 'version': 'v1', '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},
|
||||
STORAGE: {'name': 'Cloud Storage API', 'version': 'v1', 'v2discovery': True},
|
||||
STORAGEREAD: {'name': 'Cloud Storage API - Read', 'version': 'v1', 'v2discovery': True, 'mappedAPI': STORAGE},
|
||||
@@ -750,9 +754,15 @@ _SVCACCT_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,
|
||||
'subscopes': [],
|
||||
'offByDefault': True,
|
||||
'scope': DRIVE_SCOPE},
|
||||
{'name': 'Gmail API - Full Access - read only',
|
||||
'api': GMAIL,
|
||||
@@ -764,8 +774,14 @@ _SVCACCT_SPECIAL_SCOPES = [
|
||||
'subscopes': [],
|
||||
'offByDefault': True,
|
||||
'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,
|
||||
'offByDefault': True,
|
||||
'subscopes': [],
|
||||
'scope': 'https://www.googleapis.com/auth/spreadsheets'},
|
||||
]
|
||||
|
||||
@@ -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
|
||||
|
||||
### 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
|
||||
|
||||
Added option `types <AdminAssigneeTypeList>` to `gam print|show admins` that allows filtering
|
||||
|
||||
@@ -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$ gam version
|
||||
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>
|
||||
Python 3.13.7 64-bit final
|
||||
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:\>gam version
|
||||
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>
|
||||
Python 3.13.7 64-bit final
|
||||
Windows-10-10.0.17134 AMD64
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
- [Delete Vault Saved Queries](#delete-vault-saved-queries)
|
||||
- [Display Vault Saved Queries](#display-vault-saved-queries)
|
||||
- [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)
|
||||
|
||||
## API documentation
|
||||
@@ -848,7 +848,7 @@ gam create vaultquery <MatterItem> [name <String>]
|
||||
[<JSONData>]
|
||||
[shownames]
|
||||
[showdetails|returnidonly|formatjson]
|
||||
``
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
# Takeout
|
||||
## Takeout
|
||||
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).
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Print the current version of Gam with details
|
||||
```
|
||||
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>
|
||||
Python 3.13.7 64-bit final
|
||||
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
|
||||
```
|
||||
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>
|
||||
Python 3.13.7 64-bit final
|
||||
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
|
||||
```
|
||||
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>
|
||||
Python 3.13.7 64-bit final
|
||||
macOS Tahoe 26.0.1 x86_64
|
||||
|
||||
Reference in New Issue
Block a user