Files
GoogleDriveManagement/src/gam/cmd/drive/fileinfo.py

1071 lines
49 KiB
Python

"""File counts, comments, paths, disk usage, share counts, tree printing.
Part of the drive sub-package, extracted from drive.py."""
"""GAM Google Drive file, permission, shared drive, and label management."""
import re
import sys
from gamlib import glaction
from gamlib import glapi as API
from gamlib import glcfg as GC
from gamlib import glclargs
from gamlib import glentity
from gamlib import glgapi as GAPI
from gamlib import glglobals as GM
from gamlib import glindent
from gamlib import glmsgs as Msg
Act = glaction.GamAction()
Ent = glentity.GamEntity()
Ind = glindent.GamIndent()
Cmd = glclargs.GamCLArgs()
APPLICATION_VND_GOOGLE_APPS = 'application/vnd.google-apps.'
MIMETYPE_GA_DOCUMENT = f'{APPLICATION_VND_GOOGLE_APPS}document'
MIMETYPE_GA_DRAWING = f'{APPLICATION_VND_GOOGLE_APPS}drawing'
MIMETYPE_GA_FILE = f'{APPLICATION_VND_GOOGLE_APPS}file'
MIMETYPE_GA_FOLDER = f'{APPLICATION_VND_GOOGLE_APPS}folder'
MIMETYPE_GA_FORM = f'{APPLICATION_VND_GOOGLE_APPS}form'
MIMETYPE_GA_FUSIONTABLE = f'{APPLICATION_VND_GOOGLE_APPS}fusiontable'
MIMETYPE_GA_JAM = f'{APPLICATION_VND_GOOGLE_APPS}jam'
MIMETYPE_GA_MAP = f'{APPLICATION_VND_GOOGLE_APPS}map'
MIMETYPE_GA_PRESENTATION = f'{APPLICATION_VND_GOOGLE_APPS}presentation'
MIMETYPE_GA_SCRIPT = f'{APPLICATION_VND_GOOGLE_APPS}script'
MIMETYPE_GA_SCRIPT_JSON = f'{APPLICATION_VND_GOOGLE_APPS}script+json'
MIMETYPE_GA_SHORTCUT = f'{APPLICATION_VND_GOOGLE_APPS}shortcut'
MIMETYPE_GA_3P_SHORTCUT = f'{APPLICATION_VND_GOOGLE_APPS}drive-sdk'
MIMETYPE_GA_SITE = f'{APPLICATION_VND_GOOGLE_APPS}site'
MIMETYPE_GA_SPREADSHEET = f'{APPLICATION_VND_GOOGLE_APPS}spreadsheet'
ME_IN_OWNERS = "'me' in owners"
ME_IN_OWNERS_AND = ME_IN_OWNERS + " and "
NOT_ME_IN_OWNERS = "not " + ME_IN_OWNERS
NOT_ME_IN_OWNERS_AND = NOT_ME_IN_OWNERS + " and "
WITH_ANY_FILE_NAME = "name = '{0}'"
WITH_MY_FILE_NAME = ME_IN_OWNERS_AND + WITH_ANY_FILE_NAME
WITH_OTHER_FILE_NAME = NOT_ME_IN_OWNERS_AND + WITH_ANY_FILE_NAME
ROOT = 'root'
ORPHANS = 'Orphans'
SHARED_WITHME = 'SharedWithMe'
SHARED_DRIVES = 'SharedDrives'
def _getMain():
return sys.modules['gam']
from gam.cmd.drive.core import (
MimeTypeCheck, _getSharedDriveNameFromId, _simpleFileIdEntityList,
_validateUserGetFileIDs, _validateUserSharedDrive,
cleanFileIDsList, getDriveFileEntity, getSharedDriveEntity, initDriveFileEntity,
)
from gam.cmd.drive.filepaths import DRIVEFILE_ORDERBY_CHOICE_MAP, _setGetCheckFilePermissions
from gam.cmd.drive.filetree import (
DriveListParameters,
FILECOUNT_SUMMARY_CHOICE_MAP, FILECOUNT_SUMMARY_NONE,
FILECOUNT_SUMMARY_ONLY, FILECOUNT_SUMMARY_USER,
OWNED_BY_ME_FIELDS_TITLES, SHOW_OWNED_BY_CHOICE_MAP,
SIZE_FIELD_CHOICE_MAP, _getGettingEntity,
extendFileTree, extendFileTreeParents, initFileTree,
)
from gam.cmd.drive.filelist import (
_checkUpdateLastModifiction, _getLastModificationPath,
_initLastModification, _showLastModification, _updateLastModificationRow,
)
def __getattr__(name):
"""Fall back to gam module for any undefined names."""
main = _getMain()
try:
return getattr(main, name)
except AttributeError:
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
SHARED_DRIVE_MAX_FILES_FOLDERS = 500000
TEAM_DRIVE = 'Drive'
MY_DRIVE = 'My Drive'
def printShowFileCounts(users):
def _setSelectionFields():
if DLP.showOwnedBy is not None:
fieldsList.extend(OWNED_BY_ME_FIELDS_TITLES)
if (showSize or showSizeUnits) or (DLP.minimumFileSize is not None) or (DLP.maximumFileSize is not None):
fieldsList.append(sizeField)
if showLastModification:
fieldsList.extend(['id,name,modifiedTime,lastModifyingUser(me, displayName, emailAddress),parents'])
if DLP.filenameMatchPattern:
fieldsList.append('name')
if DLP.excludeTrashed:
fieldsList.append('trashed')
if DLP.PM.permissionMatches:
fieldsList.extend(['id', 'permissions'])
if DLP.onlySharedDrives or getPermissionsForSharedDrives:
fieldsList.append('driveId')
def showMimeTypeInfo(user, mimeTypeInfo, sharedDriveId, sharedDriveName, lastModification, i, count):
if summary != FILECOUNT_SUMMARY_NONE:
if count != 0:
for mimeType, mtinfo in mimeTypeInfo.items():
summaryMimeTypeInfo.setdefault(mimeType, {'count': 0, 'size': 0})
summaryMimeTypeInfo[mimeType]['count'] += mtinfo['count']
summaryMimeTypeInfo[mimeType]['size'] += mtinfo['size']
if summary == FILECOUNT_SUMMARY_ONLY:
return
countTotal = sizeTotal = 0
for mtinfo in mimeTypeInfo.values():
countTotal += mtinfo['count']
sizeTotal += mtinfo['size']
if not csvPF:
if sharedDriveId:
kvList = [Ent.USER, user, Ent.SHAREDDRIVE, f'{sharedDriveName} ({sharedDriveId})']
else:
kvList = [Ent.USER, user]
dataList = [Ent.Choose(Ent.DRIVE_FILE_OR_FOLDER, countTotal), countTotal]
if showSize:
dataList.extend(['Size', sizeTotal])
if showSizeUnits:
dataList.extend(['SizeUnits', _getMain().formatFileSize(sizeTotal)])
if sharedDriveId:
dataList.extend(['Item cap', f"{countTotal/SHARED_DRIVE_MAX_FILES_FOLDERS:.2%}"])
_getMain().printEntityKVList(kvList, dataList, i, count)
Ind.Increment()
if showLastModification:
_showLastModification(lastModification)
for mimeType, mtinfo in sorted(mimeTypeInfo.items()):
if not showMimeTypeSize:
_getMain().printKeyValueList([mimeType, mtinfo['count']])
else:
_getMain().printKeyValueList([mimeType, f"{mtinfo['count']}, {mtinfo['size']}"])
Ind.Decrement()
else:
if sharedDriveId:
row = {'User': user, 'id': sharedDriveId, 'name': sharedDriveName, 'Total': countTotal, 'Item cap': f"{countTotal/SHARED_DRIVE_MAX_FILES_FOLDERS:.2%}"}
else:
row = {'User': user, 'Total': countTotal}
if showSize:
row['Size'] = sizeTotal
if showSizeUnits:
row['SizeUnits'] = _getMain().formatFileSize(sizeTotal)
if showLastModification:
_updateLastModificationRow(row, lastModification)
if addCSVData:
row.update(addCSVData)
for mimeType, mtinfo in sorted(mimeTypeInfo.items()):
row[f'{mimeType}'] = mtinfo['count']
if showMimeTypeSize:
row[f'{mimeType}:Size'] = mtinfo['size']
csvPF.WriteRowTitles(row)
csvPF = _getMain().CSVPrintFile() if Act.csvFormat() else None
if csvPF:
csvPF.SetZeroBlankMimeTypeCounts(True)
fieldsList = ['mimeType']
DLP = DriveListParameters({'allowChoose': False, 'allowCorpora': True, 'allowQuery': True, 'mimeTypeInQuery': True})
pathDelimiter = '/'
sharedDriveId = sharedDriveName = ''
continueOnInvalidQuery = showSize = showSizeUnits = showLastModification = showMimeTypeSize = False
sizeField = 'quotaBytesUsed'
summary = FILECOUNT_SUMMARY_NONE
summaryUser = FILECOUNT_SUMMARY_USER
summaryMimeTypeInfo = {}
fileIdEntity = {}
addCSVData = {}
summaryLastModification = _initLastModification()
while Cmd.ArgumentsRemaining():
myarg = _getMain().getArgument()
if csvPF and myarg == 'todrive':
csvPF.GetTodriveParameters()
elif DLP.ProcessArgument(myarg, fileIdEntity):
pass
elif myarg == 'select':
if fileIdEntity:
_getMain().usageErrorExit(Msg.CAN_NOT_BE_SPECIFIED_MORE_THAN_ONCE.format('select'))
fileIdEntity = getSharedDriveEntity()
elif myarg == 'showsize':
showSize = True
elif myarg == 'showsizeunits':
showSizeUnits = True
elif myarg == 'showmimetypesize':
showMimeTypeSize = showSize = True
elif myarg == 'sizefield':
sizeField = _getMain().getChoice(SIZE_FIELD_CHOICE_MAP, mapChoice=True)
elif myarg == 'showlastmodification':
showLastModification = True
elif myarg == 'summary':
summary = _getMain().getChoice(FILECOUNT_SUMMARY_CHOICE_MAP, mapChoice=True)
elif myarg == 'summaryuser':
summaryUser = _getMain().getString(Cmd.OB_STRING)
elif myarg == 'pathdelimiter':
pathDelimiter = _getMain().getCharacter()
elif csvPF and myarg == 'addcsvdata':
_getMain().getAddCSVData(addCSVData)
elif myarg == 'continueoninvalidquery':
continueOnInvalidQuery = _getMain().getBoolean()
else:
_getMain().unknownArgumentExit()
if not fileIdEntity:
fileIdEntity = DLP.GetFileIdEntity()
if not fileIdEntity.get('shareddrive'):
btkwargs = DLP.kwargs
else:
btkwargs = fileIdEntity['shareddrive']
fieldsList.append('driveId')
DLP.Finalize(fileIdEntity)
if DLP.PM.permissionMatches:
getPermissionDetailsForMyDrive = DLP.PM.checkDetails
getPermissionsForSharedDrives = True
permissionsFields = f'nextPageToken,permissions({",".join(DLP.PM.permissionFields)})'
else:
getPermissionDetailsForMyDrive = getPermissionsForSharedDrives = False
_setSelectionFields()
if csvPF:
sortTitles = ['User', 'id', 'name', 'Total', 'Item cap'] if fileIdEntity.get('shareddrive') else ['User', 'Total']
if showSizeUnits:
sortTitles.insert(sortTitles.index('Total')+1, 'SizeUnits')
if showSize:
sortTitles.insert(sortTitles.index('Total')+1, 'Size')
if showLastModification:
sortTitles.extend(['lastModifiedFileId', 'lastModifiedFileName',
'lastModifiedFileMimeType', 'lastModifiedFilePath',
'lastModifyingUser', 'lastModifiedTime'])
if addCSVData:
sortTitles.extend(sorted(addCSVData.keys()))
csvPF.SetTitles(sortTitles)
csvPF.SetSortAllTitles()
pagesFields = _getMain().getItemFieldsFromFieldsList('files', fieldsList)
i, count, users = _getMain().getEntityArgument(users)
for user in users:
i += 1
user, drive = _validateUserSharedDrive(user, i, count, fileIdEntity)
if not drive:
continue
sharedDriveId = fileIdEntity.get('shareddrive', {}).get('driveId', '')
sharedDriveName = _getSharedDriveNameFromId(drive, sharedDriveId) if sharedDriveId else ''
mimeTypeInfo = {}
userLastModification = _initLastModification()
gettingEntity = _getGettingEntity(user, fileIdEntity)
_getMain().printGettingAllEntityItemsForWhom(Ent.DRIVE_FILE_OR_FOLDER, gettingEntity, i, count, query=DLP.fileIdEntity['query'])
try:
feed = _getMain().yieldGAPIpages(drive.files(), 'list', 'files',
pageMessage=_getMain().getPageMessageForWhom(),
throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.INVALID_QUERY, GAPI.INVALID,
GAPI.BAD_REQUEST, GAPI.FILE_NOT_FOUND,
GAPI.NOT_FOUND, GAPI.TEAMDRIVE_MEMBERSHIP_REQUIRED],
retryReasons=[GAPI.UNKNOWN_ERROR],
q=DLP.fileIdEntity['query'],
fields=pagesFields, pageSize=GC.Values[GC.DRIVE_MAX_RESULTS], **btkwargs)
for files in feed:
for f_file in files:
driveId = f_file.get('driveId')
getCheckFilePermissions = _setGetCheckFilePermissions(f_file, getPermissionDetailsForMyDrive, getPermissionsForSharedDrives,
driveId, DLP)
if (not DLP.CheckShowOwnedBy(f_file) or
not DLP.CheckShowSharedByMe(f_file) or
not DLP.CheckExcludeTrashed(f_file) or
not DLP.CheckFileSize(f_file, sizeField) or
not DLP.CheckFilenameMatch(f_file) or
(not getCheckFilePermissions and not DLP.CheckFilePermissionMatches(f_file)) or
(DLP.onlySharedDrives and not driveId)):
continue
if getCheckFilePermissions:
try:
f_file['permissions'] = _getMain().callGAPIpages(drive.permissions(), 'list', 'permissions',
throwReasons=GAPI.DRIVE3_GET_ACL_REASONS+[GAPI.BAD_REQUEST],
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
fileId=f_file['id'], fields=permissionsFields, supportsAllDrives=True)
if not DLP.CheckFilePermissionMatches(f_file):
continue
for permission in f_file['permissions']:
permission.pop('teamDrivePermissionDetails', None)
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError,
GAPI.insufficientAdministratorPrivileges, GAPI.insufficientFilePermissions,
GAPI.unknownError, GAPI.invalid, GAPI.badRequest,
GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy):
continue
mimeTypeInfo.setdefault(f_file['mimeType'], {'count': 0, 'size': 0})
mimeTypeInfo[f_file['mimeType']]['count'] += 1
mimeTypeInfo[f_file['mimeType']]['size'] += int(f_file.get(sizeField, '0'))
if showLastModification:
_checkUpdateLastModifiction(f_file, userLastModification)
_getLastModificationPath(drive, userLastModification, pathDelimiter)
showMimeTypeInfo(user, mimeTypeInfo, sharedDriveId, sharedDriveName, userLastModification, i, count)
if showLastModification and userLastModification['lastModifiedTime'] > summaryLastModification['lastModifiedTime']:
summaryLastModification = userLastModification.copy()
except (GAPI.invalidQuery, GAPI.invalid, GAPI.badRequest):
_getMain().entityActionFailedWarning([Ent.USER, user, Ent.DRIVE_FILE_OR_FOLDER, None], _getMain().invalidQuery(DLP.fileIdEntity['query']), i, count)
if not continueOnInvalidQuery:
break
continue
except GAPI.fileNotFound:
_getMain().printGotEntityItemsForWhom(0)
except (GAPI.notFound, GAPI.teamDriveMembershipRequired) as e:
_getMain().entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE_ID, sharedDriveId], str(e), i, count)
except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
_getMain().userDriveServiceNotEnabledWarning(user, str(e), i, count)
continue
if summary != FILECOUNT_SUMMARY_NONE:
showMimeTypeInfo(summaryUser, summaryMimeTypeInfo,
'' if count > 1 else sharedDriveId,
'' if count > 1 else sharedDriveName,
summaryLastModification, 0, 0)
if csvPF:
csvPF.writeCSVfile('Drive File Counts')
# gam <UserTypeEntity> print drivelastmodification [todrive <ToDriveAttribute>*]
# [select <SharedDriveEntity>]
# [pathdelimiter <Character>]
# (addcsvdata <FieldName> <String>)*
# gam <UserTypeEntity> show drivelastmodification
# [select <SharedDriveEntity>]
# [pathdelimiter <Character>]
def printShowDrivelastModifications(users):
def showLastModificationInfo(user, sharedDriveId, sharedDriveName, lastModification, i, count):
if not csvPF:
if sharedDriveId:
kvList = [Ent.USER, user, Ent.SHAREDDRIVE, f'{sharedDriveName} ({sharedDriveId})']
else:
kvList = [Ent.USER, user]
_getMain().printEntity(kvList, i, count)
Ind.Increment()
_showLastModification(lastModification)
Ind.Decrement()
else:
if sharedDriveId:
row = {'User': user, 'id': sharedDriveId, 'name': sharedDriveName}
else:
row = {'User': user}
_updateLastModificationRow(row, lastModification)
if addCSVData:
row.update(addCSVData)
csvPF.WriteRowTitles(row)
csvPF = _getMain().CSVPrintFile() if Act.csvFormat() else None
fieldsList = ['id', 'driveId', 'name', 'mimeType', 'lastModifyingUser', 'modifiedTime', 'parents']
DLP = DriveListParameters({'allowChoose': False, 'allowCorpora': False, 'allowQuery': False, 'mimeTypeInQuery': True})
pathDelimiter = '/'
sharedDriveId = sharedDriveName = ''
fileIdEntity = {}
addCSVData = {}
while Cmd.ArgumentsRemaining():
myarg = _getMain().getArgument()
if csvPF and myarg == 'todrive':
csvPF.GetTodriveParameters()
elif myarg == 'select':
if fileIdEntity:
_getMain().usageErrorExit(Msg.CAN_NOT_BE_SPECIFIED_MORE_THAN_ONCE.format('select'))
fileIdEntity = getSharedDriveEntity()
elif myarg == 'pathdelimiter':
pathDelimiter = _getMain().getCharacter()
elif csvPF and myarg == 'addcsvdata':
_getMain().getAddCSVData(addCSVData)
else:
_getMain().unknownArgumentExit()
if not fileIdEntity:
fileIdEntity = DLP.GetFileIdEntity()
if not fileIdEntity.get('shareddrive'):
btkwargs = DLP.kwargs
else:
btkwargs = fileIdEntity['shareddrive']
fieldsList.append('driveId')
DLP.Finalize(fileIdEntity)
if csvPF:
sortTitles = ['User', 'id', 'name'] if fileIdEntity.get('shareddrive') else ['User']
if addCSVData:
sortTitles.extend(sorted(addCSVData.keys()))
sortTitles.extend(['lastModifiedFileId', 'lastModifiedFileName',
'lastModifiedFileMimeType', 'lastModifiedFilePath',
'lastModifyingUser', 'lastModifiedTime'])
csvPF.SetTitles(sortTitles)
csvPF.SetSortAllTitles()
pagesFields = _getMain().getItemFieldsFromFieldsList('files', fieldsList)
i, count, users = _getMain().getEntityArgument(users)
for user in users:
i += 1
user, drive = _validateUserSharedDrive(user, i, count, fileIdEntity)
if not drive:
continue
sharedDriveId = fileIdEntity.get('shareddrive', {}).get('driveId', '')
sharedDriveName = _getSharedDriveNameFromId(drive, sharedDriveId) if sharedDriveId else ''
userLastModification = _initLastModification()
gettingEntity = _getGettingEntity(user, fileIdEntity)
_getMain().printGettingAllEntityItemsForWhom(Ent.DRIVE_FILE_OR_FOLDER, gettingEntity, i, count)
try:
feed = _getMain().yieldGAPIpages(drive.files(), 'list', 'files',
pageMessage=_getMain().getPageMessageForWhom(),
throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.INVALID, GAPI.BAD_REQUEST, GAPI.FILE_NOT_FOUND,
GAPI.NOT_FOUND, GAPI.TEAMDRIVE_MEMBERSHIP_REQUIRED],
retryReasons=[GAPI.UNKNOWN_ERROR],
fields=pagesFields, pageSize=GC.Values[GC.DRIVE_MAX_RESULTS], **btkwargs)
for files in feed:
for f_file in files:
_checkUpdateLastModifiction(f_file, userLastModification)
_getLastModificationPath(drive, userLastModification, pathDelimiter)
showLastModificationInfo(user, sharedDriveId, sharedDriveName, userLastModification, i, count)
except (GAPI.invalid, GAPI.badRequest) as e:
_getMain().entityActionFailedWarning([Ent.USER, user, Ent.DRIVE_FILE_OR_FOLDER, None], str(e), i, count)
continue
except GAPI.fileNotFound:
_getMain().printGotEntityItemsForWhom(0)
except (GAPI.notFound, GAPI.teamDriveMembershipRequired) as e:
_getMain().entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE_ID, sharedDriveId], str(e), i, count)
except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
_getMain().userDriveServiceNotEnabledWarning(user, str(e), i, count)
continue
if csvPF:
csvPF.writeCSVfile('Drive File Last Modification')
DISKUSAGE_SHOW_CHOICES = {'all', 'summary', 'summaryandtrash'}
# gam <UserTypeEntity> print diskusage <DriveFileEntity> [todrive <ToDriveAttribute>*]
# [anyowner|(showownedby any|me|others)]
# [sizefield quotabytesused|size]
# [pathdelimiter <Character>] [excludetrashed] [stripcrsfromname]
# (addcsvdata <FieldName> <String>)*
# [noprogress] [show all|summary|summaryandtrash]
def printDiskUsage(users):
def _getChildDriveFolderInfo(drive, fileEntry, user, i, count, depth):
fileEntry['depth'] = depth
q = _getMain().WITH_PARENTS.format(fileEntry['id'])
try:
children = _getMain().callGAPIpages(drive.files(), 'list', 'files',
throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.INVALID_QUERY, GAPI.INVALID],
retryReasons=[GAPI.UNKNOWN_ERROR],
q=q, orderBy=orderBy, fields=pagesFields,
pageSize=GC.Values[GC.DRIVE_MAX_RESULTS], supportsAllDrives=True, includeItemsFromAllDrives=True)
except (GAPI.invalidQuery, GAPI.invalid):
_getMain().entityActionFailedWarning([Ent.USER, user, Ent.DRIVE_FOLDER, None], _getMain().invalidQuery(q), i, count)
return
except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
_getMain().userDriveServiceNotEnabledWarning(user, str(e), i, count)
return
Ind.Increment()
if showProgress:
_getMain().entityActionPerformed([Ent.USER, user, Ent.DRIVE_FOLDER, fileEntry['path']])
for childEntryInfo in children:
trashed = childEntryInfo['trashed']
if trashed and excludeTrashed:
continue
mimeType = childEntryInfo.pop('mimeType')
if mimeType == MIMETYPE_GA_FOLDER:
fileEntry['directFolderCount'] += 1
fileEntry['totalFolderCount'] += 1
if trashed:
trashFolder['totalFolderCount'] += 1
if childEntryInfo['explicitlyTrashed']:
trashFolder['directFolderCount'] += 1
childEntryInfo['User'] = user
if includeOwner:
owners = childEntryInfo.pop('owners', [])
if owners:
childEntryInfo['Owner'] = owners[0].get('emailAddress', 'Unknown')
childEntryInfo.update(zeroFolderInfo)
if stripCRsFromName:
childEntryInfo['name'] = _stripControlCharsFromName(childEntryInfo['name'])
childEntryInfo['path'] = fileEntry['path']+pathDelimiter+childEntryInfo['name']
childEntryInfo.pop(sizeField, None)
foldersList.append(childEntryInfo)
_getChildDriveFolderInfo(drive, childEntryInfo, user, i, count, depth+1)
fileEntry['totalFileCount'] += childEntryInfo['totalFileCount']
fileEntry['totalFileSize'] += childEntryInfo['totalFileSize']
fileEntry['totalFolderCount'] += childEntryInfo['totalFolderCount']
elif mimeType != MIMETYPE_GA_SHORTCUT:
if includeOwner and showOwnedBy is not None and childEntryInfo['ownedByMe'] != showOwnedBy:
continue
fsize = int(childEntryInfo.get(sizeField, '0'))
fileEntry['directFileCount'] += 1
fileEntry['directFileSize'] += fsize
fileEntry['totalFileCount'] += 1
fileEntry['totalFileSize'] += fsize
if trashed:
trashFolder['totalFileCount'] += 1
trashFolder['totalFileSize'] += fsize
if childEntryInfo['explicitlyTrashed']:
trashFolder['directFileCount'] += 1
trashFolder['directFileSize'] += fsize
Ind.Decrement()
csvPF = _getMain().CSVPrintFile(['User', 'Owner', 'id', 'name', 'ownedByMe', 'trashed', 'explicitlyTrashed',
'directFileCount', 'directFileSize', 'directFolderCount',
'totalFileCount', 'totalFileSize', 'totalFolderCount', 'depth', 'path'])
excludeTrashed = stripCRsFromName = False
includeOwner = True
orderBy = 'folder,name'
zeroFolderInfo = {'directFileCount': 0, 'directFileSize': 0, 'directFolderCount': 0,
'totalFileCount': 0, 'totalFileSize': 0, 'totalFolderCount': 0}
sizeField = 'quotaBytesUsed'
showOwnedBy = showProgress = True
pathDelimiter = '/'
fileIdEntity = getDriveFileEntity()
addCSVData = {}
showResults = 'all'
while Cmd.ArgumentsRemaining():
myarg = _getMain().getArgument()
if myarg == 'todrive':
csvPF.GetTodriveParameters()
elif myarg == 'anyowner':
showOwnedBy = None
elif myarg == 'showownedby':
showOwnedBy = _getMain().getChoice(SHOW_OWNED_BY_CHOICE_MAP, mapChoice=True)
elif myarg == 'sizefield':
sizeField = _getMain().getChoice(SIZE_FIELD_CHOICE_MAP, mapChoice=True)
elif myarg == 'pathdelimiter':
pathDelimiter = _getMain().getCharacter()
elif myarg == 'excludetrashed':
excludeTrashed = True
elif myarg == 'stripcrsfromname':
stripCRsFromName = True
elif myarg == 'addcsvdata':
_getMain().getAddCSVData(addCSVData)
elif myarg == 'show':
showResults = _getMain().getChoice(DISKUSAGE_SHOW_CHOICES)
elif myarg == 'noprogress':
showProgress = False
else:
_getMain().unknownArgumentExit()
if addCSVData:
csvPF.AddTitles(sorted(addCSVData.keys()))
fieldsList = ['id', 'name', 'mimeType', sizeField, 'trashed', 'explicitlyTrashed', 'owners(emailAddress)', 'ownedByMe']
pagesFields = _getMain().getItemFieldsFromFieldsList('files', fieldsList)
topFieldsList = fieldsList[:]
topFieldsList.extend(['driveId', 'parents'])
topFields = _getMain().getFieldsFromFieldsList(topFieldsList)
i, count, users = _getMain().getEntityArgument(users)
i = 0
for user in users:
i += 1
origUser = user
user, drive, jcount = _validateUserGetFileIDs(origUser, i, count, fileIdEntity, entityType=Ent.DRIVE_DISK_USAGE)
if jcount == 0:
continue
j = 0
for fileId in fileIdEntity['list']:
j += 1
foldersList = []
trashFolder = {'User': user, 'id': 'Trash', 'name': 'Trash', 'path': 'Trash'}
trashFolder.update(zeroFolderInfo)
try:
topFolder = _getMain().callGAPI(drive.files(), 'get',
throwReasons=GAPI.DRIVE_GET_THROW_REASONS,
fileId=fileId, fields=topFields, supportsAllDrives=True)
if stripCRsFromName:
topFolder['name'] = _stripControlCharsFromName(topFolder['name'])
mimeType = topFolder.pop('mimeType')
if mimeType != MIMETYPE_GA_FOLDER:
entityValueList = [Ent.USER, user, _getMain()._getEntityMimeType(topFolder), topFolder['name']]
_getMain().entityActionNotPerformedWarning(entityValueList, Msg.INVALID_MIMETYPE.format(mimeType, MIMETYPE_GA_FOLDER), i, count)
continue
if topFolder['trashed']:
if excludeTrashed:
entityValueList = [Ent.USER, user, Ent.DRIVE_FOLDER, topFolder['name']]
_getMain().entityActionNotPerformedWarning(entityValueList, Msg.IN_TRASH_AND_EXCLUDE_TRASHED, i, count)
continue
trashFolder['totalFolderCount'] += 1
if topFolder['explicitlyTrashed']:
trashFolder['directFolderCount'] += 1
driveId = topFolder.pop('driveId', None)
if driveId:
includeOwner = False
csvPF.RemoveTitles(['Owner', 'ownedByMe'])
if topFolder['name'] == TEAM_DRIVE and not topFolder.get('parents'):
topFolder['name'] = _getSharedDriveNameFromId(drive, driveId)
topFolder['path'] = f'{SHARED_DRIVES}{pathDelimiter}{topFolder["name"]}'
else:
topFolder['path'] = topFolder['name']
topFolder.pop('ownedByMe', None)
elif topFolder['name'] == MY_DRIVE and not topFolder.get('parents'):
topFolder['path'] = _getMain().MY_DRIVE
else:
topFolder['path'] = topFolder['name']
topFolder['User'] = user
if includeOwner:
owners = topFolder.pop('owners', [])
if owners:
topFolder['Owner'] = owners[0].get('emailAddress', 'Unknown')
trashFolder['Owner'] = topFolder['Owner']
topFolder.pop('parents', None)
topFolder.update(zeroFolderInfo)
topFolder.pop(sizeField, None)
foldersList.append(topFolder)
_getChildDriveFolderInfo(drive, topFolder, user, i, count, -1)
except GAPI.fileNotFound:
_getMain().entityActionFailedWarning([Ent.USER, user, Ent.DRIVE_FOLDER, fileId], Msg.NOT_FOUND, j, jcount)
continue
except (GAPI.notFound, GAPI.teamDriveMembershipRequired) as e:
_getMain().entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE_ID, fileIdEntity['shareddrive']['driveId']], str(e), j, jcount)
continue
except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
_getMain().userDriveServiceNotEnabledWarning(user, str(e), i, count)
break
if showResults == 'all':
for folder in foldersList:
if addCSVData:
folder.update(addCSVData)
csvPF.WriteRow(folder)
else:
folder = foldersList[0]
if addCSVData:
folder.update(addCSVData)
csvPF.WriteRow(folder)
if showResults != 'summary' and not excludeTrashed:
trashFolder['trashed'] = trashFolder['totalFileCount']+trashFolder['totalFolderCount'] > 0
trashFolder['explicitlyTrashed'] = trashFolder['directFileCount']+trashFolder['directFolderCount'] > 0
if addCSVData:
trashFolder.update(addCSVData)
trashFolder['depth'] = -1
csvPF.WriteRow(trashFolder)
csvPF.writeCSVfile('Drive Disk Usage')
FILESHARECOUNTS_OWNER = 'Owner'
FILESHARECOUNTS_TOTAL = 'Total'
FILESHARECOUNTS_SHARED = 'Shared'
FILESHARECOUNTS_SHARED_EXTERNAL = 'Shared External'
FILESHARECOUNTS_SHARED_INTERNAL = 'Shared Internal'
FILESHARECOUNTS_ZEROCOUNTS = {
FILESHARECOUNTS_TOTAL: 0,
FILESHARECOUNTS_SHARED: 0,
FILESHARECOUNTS_SHARED_EXTERNAL: 0,
FILESHARECOUNTS_SHARED_INTERNAL: 0,
'anyone': 0, 'anyoneWithLink': 0,
'externalDomain': 0, 'externalDomainWithLink': 0,
'internalDomain': 0, 'internalDomainWithLink': 0,
'externalGroup': 0, 'internalGroup': 0,
'externalUser': 0, 'internalUser': 0,
'deletedGroup': 0, 'deletedUser': 0,
}
FILESHARECOUNTS_CATEGORIES = {
'anyone': {False: 'anyone', True: 'anyoneWithLink'},
'domain': {False: {False: 'externalDomain', True: 'externalDomainWithLink'}, True: {False: 'internalDomain', True: 'internalDomainWithLink'}},
'group': {False: 'externalGroup', True: 'internalGroup'},
'user': {False: 'externalUser', True: 'internalUser'},
'deleted': {'group': 'deletedGroup', 'user': 'deletedUser'},
}
# gam <UserTypeEntity> print filesharecounts [todrive <ToDriveAttribute>*]
# [excludetrashed]
# [internaldomains all|primary|<DomainNameList>]
# [summary none|only|plus] [summaryuser <String>]
# gam <UserTypeEntity> show filesharecounts
# [excludetrashed]
# [internaldomains all|primary|<DomainNameList>]
# [summary none|only|plus] [summaryuser <String>]
def printShowFileShareCounts(users):
def incrementCounter(counter):
if not counterSet[counter]:
userShareCounts[counter] += 1
counterSet[counter] = True
def showShareCounts(user, shareCounts, i, count):
if summary != FILECOUNT_SUMMARY_NONE:
if count != 0:
for field, shareCount in shareCounts.items():
summaryShareCounts[field] += shareCount
if summary == FILECOUNT_SUMMARY_ONLY:
return
if not csvPF:
_getMain().printEntity([Ent.USER, user, Ent.DRIVE_FILE_OR_FOLDER, shareCounts[FILESHARECOUNTS_TOTAL]], i, count)
Ind.Increment()
for field, shareCount in shareCounts.items():
_getMain().printKeyValueList([field, shareCount])
Ind.Decrement()
else:
row = {FILESHARECOUNTS_OWNER: user}
row.update(shareCounts)
csvPF.WriteRow(row)
cd = _getMain().buildGAPIObject(API.DIRECTORY)
csvPF = _getMain().CSVPrintFile([FILESHARECOUNTS_OWNER]+list(FILESHARECOUNTS_ZEROCOUNTS.keys())) if Act.csvFormat() else None
query = ME_IN_OWNERS
summary = FILECOUNT_SUMMARY_NONE
summaryUser = FILECOUNT_SUMMARY_USER
fileIdEntity = {}
internalDomains = 'all'
while Cmd.ArgumentsRemaining():
myarg = _getMain().getArgument()
if csvPF and myarg == 'todrive':
csvPF.GetTodriveParameters()
elif myarg == 'excludetrashed':
query += ' and trashed=false'
elif myarg == 'internaldomains':
internalDomains = _getMain().getString(Cmd.OB_DOMAIN_NAME_LIST).replace(',', ' ').lower()
elif myarg == 'summary':
summary = _getMain().getChoice(FILECOUNT_SUMMARY_CHOICE_MAP, mapChoice=True)
elif myarg == 'summaryuser':
summaryUser = _getMain().getString(Cmd.OB_STRING)
else:
_getMain().unknownArgumentExit()
internalDomains = _getMain().finalizeInternalDomains(cd, internalDomains)
summaryShareCounts = FILESHARECOUNTS_ZEROCOUNTS.copy()
i, count, users = _getMain().getEntityArgument(users)
for user in users:
i += 1
user, drive = _validateUserSharedDrive(user, i, count, fileIdEntity)
if not drive:
continue
userShareCounts = FILESHARECOUNTS_ZEROCOUNTS.copy()
gettingEntity = _getGettingEntity(user, fileIdEntity)
_getMain().printGettingAllEntityItemsForWhom(Ent.DRIVE_FILE_OR_FOLDER, gettingEntity, i, count, query=query)
try:
feed = _getMain().yieldGAPIpages(drive.files(), 'list', 'files',
pageMessage=_getMain().getPageMessageForWhom(),
throwReasons=GAPI.DRIVE_USER_THROW_REASONS,
retryReasons=[GAPI.UNKNOWN_ERROR],
q=query, fields='nextPageToken,files(permissions(type,role,emailAddress,domain,allowFileDiscovery,deleted))',
pageSize=GC.Values[GC.DRIVE_MAX_RESULTS])
for files in feed:
for f_file in files:
counterSet = {FILESHARECOUNTS_TOTAL: False, FILESHARECOUNTS_SHARED: False,
FILESHARECOUNTS_SHARED_EXTERNAL: False, FILESHARECOUNTS_SHARED_INTERNAL: False}
for permission in f_file['permissions']:
if permission['role'] == 'owner':
incrementCounter(FILESHARECOUNTS_TOTAL)
else:
incrementCounter(FILESHARECOUNTS_SHARED)
ptype = permission['type']
if ptype == 'anyone':
incrementCounter(FILESHARECOUNTS_SHARED_EXTERNAL)
userShareCounts[FILESHARECOUNTS_CATEGORIES[ptype][not permission['allowFileDiscovery']]] += 1
else:
domain = permission.get('domain', '')
if not domain and ptype in ['user', 'group']:
if permission.get('deleted', False):
userShareCounts[FILESHARECOUNTS_CATEGORIES['deleted'][ptype]] += 1
continue
emailAddress = permission['emailAddress']
domain = emailAddress[emailAddress.find('@')+1:]
internal = domain in internalDomains
incrementCounter([FILESHARECOUNTS_SHARED_EXTERNAL, FILESHARECOUNTS_SHARED_INTERNAL][internal])
if ptype == 'domain':
userShareCounts[FILESHARECOUNTS_CATEGORIES[ptype][internal][not permission['allowFileDiscovery']]] +=1
else: # group, user
userShareCounts[FILESHARECOUNTS_CATEGORIES[ptype][internal]] += 1
showShareCounts(user, userShareCounts, i, count)
except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
_getMain().userDriveServiceNotEnabledWarning(user, str(e), i, count)
continue
if summary != FILECOUNT_SUMMARY_NONE:
showShareCounts(summaryUser, summaryShareCounts, 0, 0)
if csvPF:
csvPF.writeCSVfile('Drive File Share Counts')
FILETREE_FIELDS_CHOICE_MAP = {
'explicitlytrashed': 'explicitlyTrashed',
'filesize': 'size',
'id': 'id',
'mime': 'mimeType',
'mimetype': 'mimeType',
'owners': 'owners',
'parents': 'parents',
'size': 'size',
'trashed': 'trashed',
'webviewlink': 'webViewLink',
}
FILETREE_FIELDS_PRINT_ORDER = ['id', 'parents', 'owners', 'mimeType', 'size', 'explicitlyTrashed', 'trashed', 'webViewLink']
# gam <UserTypeEntity> print filetree [todrive <ToDriveAttribute>*]
# [select <DriveFileEntity> [selectsubquery <QueryDriveFile>] [depth <Number>]]
# [anyowner|(showownedby any|me|others)]
# [showmimetype [not] <MimeTypeList>] [showmimetype category <MimeTypeNameList>]
# [sizefield quotabytesused|size] [minimumfilesize <Integer>] [maximumfilesize <Integer>]
# [filenamematchpattern <REMatchPattern>]
# <PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
# [excludetrashed]
# [fields <FileTreeFieldNameList>]
# (orderby <DriveFileOrderByFieldName> [ascending|descending])* [delimiter <Character>]
# [noindent] [stripcrsfromname]
# gam <UserTypeEntity> show filetree
# [select <DriveFileEntity> [selectsubquery <QueryDriveFile>] [depth <Number>]]
# [anyowner|(showownedby any|me|others)]
# [showmimetype [not] <MimeTypeList>] [showmimetype category <MimeTypeNameList>]
# [sizefield quotabytesused|size] [minimumfilesize <Integer>] [maximumfilesize <Integer>]
# [filenamematchpattern <REMatchPattern>]
# <PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
# [excludetrashed]
# [fields <FileTreeFieldNameList>]
# (orderby <DriveFileOrderByFieldName> [ascending|descending])* [delimiter <Character>]
# [stripcrsfromname]
def printShowFileTree(users):
def _showFileInfo(fileEntry, depth, j=0, jcount=0):
if not DLP.CheckExcludeTrashed(fileEntry):
return
if stripCRsFromName:
fileEntry['name'] = _stripControlCharsFromName(fileEntry['name'])
if not csvPF:
fileInfoList = []
for field in FILETREE_FIELDS_PRINT_ORDER:
if showFields[field]:
if field == 'parents':
parents = fileEntry.get(field, [])
fileInfoList.extend([field, f'{len(parents)} [{delimiter.join(parents)}]'])
elif field == 'owners':
owners = [owner['emailAddress'] for owner in fileEntry.get(field, [])]
if owners:
fileInfoList.extend([field, delimiter.join(owners)])
elif field in {'explicitlyTrashed', 'trashed'}:
trashed = fileEntry.get(field, False)
if trashed:
fileInfoList.extend([field, trashed])
elif field == 'size':
fileInfoList.extend([field, fileEntry.get(sizeField, 0)])
else:
fileInfoList.extend([field, fileEntry.get(field, '')])
if fileInfoList:
_getMain().printKeyValueListWithCount([fileEntry['name'], formatKeyValueList('(', fileInfoList, ')')], j, jcount)
else:
_getMain().printKeyValueList([fileEntry['name']])
else:
userInfo['index'] += 1
row = userInfo.copy()
row['depth'] = depth
row['name'] = ('' if noindent else Ind.SpacesSub1())+fileEntry['name']
for field in FILETREE_FIELDS_PRINT_ORDER:
if showFields[field]:
if field == 'parents':
row[field] = delimiter.join(fileEntry.get(field, []))
elif field == 'owners':
row[field] = delimiter.join([owner['emailAddress'] for owner in fileEntry.get(field, [])])
elif field == 'size':
row['size'] = fileEntry.get(sizeField, 0)
else:
row[field] = fileEntry.get(field, '')
csvPF.WriteRow(row)
def _showDriveFolderContents(fileEntry, depth):
for childId in fileEntry['children']:
childEntry = fileTree.get(childId)
if childEntry:
if not DLP.CheckExcludeTrashed(childEntry['info']):
continue
if (DLP.CheckMimeType(childEntry['info']) and
DLP.CheckFileSize(childEntry['info'], sizeField) and
DLP.CheckFilenameMatch(childEntry['info']) and
DLP.CheckFilePermissionMatches(childEntry['info'])):
_showFileInfo(childEntry['info'], depth)
if childEntry['info']['mimeType'] == MIMETYPE_GA_FOLDER and (maxdepth == -1 or depth < maxdepth):
Ind.Increment()
_showDriveFolderContents(childEntry, depth+1)
Ind.Decrement()
def _showChildDriveFolderContents(drive, fileEntry, user, i, count, depth):
if not DLP.CheckExcludeTrashed(fileEntry):
return
q = _getMain().WITH_PARENTS.format(fileEntry['id'])
if selectSubQuery:
q += ' and ('+selectSubQuery+')'
try:
children = _getMain().callGAPIpages(drive.files(), 'list', 'files',
throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.INVALID_QUERY, GAPI.INVALID],
retryReasons=[GAPI.UNKNOWN_ERROR],
q=q, orderBy=OBY.orderBy, fields=pagesFields,
pageSize=GC.Values[GC.DRIVE_MAX_RESULTS], supportsAllDrives=True, includeItemsFromAllDrives=True)
except (GAPI.invalidQuery, GAPI.invalid):
_getMain().entityActionFailedWarning([Ent.USER, user, Ent.DRIVE_FILE, None], _getMain().invalidQuery(selectSubQuery), i, count)
return
except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
_getMain().userDriveServiceNotEnabledWarning(user, str(e), i, count)
return
for childEntryInfo in children:
if not DLP.CheckExcludeTrashed(childEntryInfo):
continue
if (DLP.CheckShowOwnedBy(childEntryInfo) and
DLP.CheckMimeType(childEntryInfo) and
DLP.CheckFileSize(childEntryInfo, sizeField) and
DLP.CheckFilenameMatch(childEntryInfo) and
DLP.CheckFilePermissionMatches(childEntryInfo)):
_showFileInfo(childEntryInfo, depth)
if childEntryInfo['mimeType'] == MIMETYPE_GA_FOLDER and (maxdepth == -1 or depth < maxdepth):
Ind.Increment()
_showChildDriveFolderContents(drive, childEntryInfo, user, i, count, depth+1)
Ind.Decrement()
csvPF = _getMain().CSVPrintFile(['User', 'index', 'depth', 'name']) if Act.csvFormat() else None
maxdepth = -1
fileIdEntity = {}
selectSubQuery = ''
sizeField = 'quotaBytesUsed'
showFields = {}
for mappedField in FILETREE_FIELDS_CHOICE_MAP.values():
showFields[mappedField] = False
buildTree = noindent = stripCRsFromName = False
delimiter = GC.Values[GC.CSV_OUTPUT_FIELD_DELIMITER]
OBY = _getMain().OrderBy(DRIVEFILE_ORDERBY_CHOICE_MAP)
DLP = DriveListParameters({'allowChoose': False, 'allowCorpora': False, 'allowQuery': False, 'mimeTypeInQuery': False})
while Cmd.ArgumentsRemaining():
myarg = _getMain().getArgument()
if csvPF and myarg == 'todrive':
csvPF.GetTodriveParameters()
elif DLP.ProcessArgument(myarg, fileIdEntity):
pass
elif myarg == 'select':
if fileIdEntity:
_getMain().usageErrorExit(Msg.CAN_NOT_BE_SPECIFIED_MORE_THAN_ONCE.format('select'))
fileIdEntity = getDriveFileEntity(DLP=DLP)
elif myarg == 'selectsubquery':
selectSubQuery = _getMain().getString(Cmd.OB_QUERY, minLen=0)
elif myarg == 'orderby':
OBY.GetChoice()
elif myarg == 'depth':
maxdepth = _getMain().getInteger(minVal=-1)
elif myarg == 'sizefield':
sizeField = _getMain().getChoice(SIZE_FIELD_CHOICE_MAP, mapChoice=True)
elif myarg == 'fields':
for field in _getMain()._getFieldsList():
if field in FILETREE_FIELDS_CHOICE_MAP:
showFields[FILETREE_FIELDS_CHOICE_MAP[field]] = True
if csvPF:
csvPF.AddTitle(FILETREE_FIELDS_CHOICE_MAP[field])
else:
_getMain().invalidChoiceExit(field, FILETREE_FIELDS_CHOICE_MAP, True)
elif myarg == 'delimiter':
delimiter = _getMain().getCharacter()
elif csvPF and myarg == 'noindent':
noindent = True
elif myarg == 'stripcrsfromname':
stripCRsFromName = True
else:
_getMain().unknownArgumentExit()
fieldsList = ['driveId', 'id', 'name', 'parents', 'mimeType', 'ownedByMe', 'owners(emailAddress)',
'shared', sizeField, 'explicitlyTrashed', 'trashed', 'webViewLink']
buildTree = (not fileIdEntity
or (not fileIdEntity['dict']
and not fileIdEntity['query']
and not fileIdEntity['shareddrivefilequery']
and _simpleFileIdEntityList(fileIdEntity['list'])))
if buildTree:
if not fileIdEntity:
fileIdEntity = initDriveFileEntity()
DLP.GetFileIdEntity()
if not fileIdEntity.get('shareddrive'):
btkwargs = DLP.kwargs
btkwargs['q'] = DLP.fileIdEntity['query']
cleanFileIDsList(fileIdEntity, [ROOT, ORPHANS])
else:
btkwargs = fileIdEntity['shareddrive']
DLP.Finalize(fileIdEntity)
elif not fileIdEntity:
fileIdEntity = initDriveFileEntity()
if DLP.PM.permissionMatches:
fieldsList.append('permissions')
fields = _getMain().getFieldsFromFieldsList(fieldsList)
pagesFields = _getMain().getItemFieldsFromFieldsList('files', fieldsList)
shareddriveFields = []
i, count, users = _getMain().getEntityArgument(users)
for user in users:
i += 1
origUser = user
user, drive = _validateUserSharedDrive(user, i, count, fileIdEntity)
if not drive:
continue
if buildTree:
fileTree, status = initFileTree(drive, fileIdEntity.get('shareddrive'), DLP, shareddriveFields, True, user, i, count)
if not status:
continue
gettingEntity = _getGettingEntity(user, fileIdEntity)
_getMain().printGettingAllEntityItemsForWhom(Ent.DRIVE_FILE_OR_FOLDER, gettingEntity, i, count, query=DLP.fileIdEntity['query'])
try:
feed = _getMain().yieldGAPIpages(drive.files(), 'list', 'files',
pageMessage=_getMain().getPageMessageForWhom(),
throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.TEAMDRIVE_MEMBERSHIP_REQUIRED],
retryReasons=[GAPI.UNKNOWN_ERROR],
orderBy=OBY.orderBy,
fields=pagesFields, pageSize=GC.Values[GC.DRIVE_MAX_RESULTS], **btkwargs)
for files in feed:
extendFileTree(fileTree, files, DLP, stripCRsFromName)
extendFileTreeParents(drive, fileTree, fields)
DLP.GetLocationFileIdsFromTree(fileTree, fileIdEntity)
except (GAPI.notFound, GAPI.teamDriveMembershipRequired) as e:
_getMain().entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE_ID, fileIdEntity['shareddrive']['driveId']], str(e), i, count)
continue
except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
_getMain().userDriveServiceNotEnabledWarning(user, str(e), i, count)
continue
else:
fileTree = {}
user, drive, jcount = _validateUserGetFileIDs(origUser, i, count, fileIdEntity, drive=drive, entityType=Ent.DRIVE_FILE_OR_FOLDER)
if jcount == 0:
continue
if csvPF:
userInfo = {'User': user, 'index': 0, 'depth': 0, 'name': ''}
j = 0
Ind.Increment()
for fileId in fileIdEntity['list']:
j += 1
fileEntry = fileTree.get(fileId)
if fileEntry:
fileEntryInfo = fileEntry['info']
else:
try:
fileEntryInfo = _getMain().callGAPI(drive.files(), 'get',
throwReasons=GAPI.DRIVE_GET_THROW_REASONS,
fileId=fileId, fields=fields, supportsAllDrives=True)
if (fileEntryInfo['mimeType'] == MIMETYPE_GA_FOLDER and fileEntryInfo.get('driveId') and
fileEntryInfo['name'] == TEAM_DRIVE and not fileEntryInfo.get('parents', [])):
fileEntryInfo['name'] = f"{SHARED_DRIVES}/{_getSharedDriveNameFromId(drive, fileId)}"
if stripCRsFromName:
fileEntryInfo['name'] = _stripControlCharsFromName(fileEntryInfo['name'])
if buildTree:
fileTree[fileId] = {'info': fileEntryInfo}
except GAPI.fileNotFound:
_getMain().entityActionFailedWarning([Ent.USER, user, Ent.DRIVE_FILE_OR_FOLDER, fileId], Msg.NOT_FOUND, j, jcount)
continue
except (GAPI.notFound, GAPI.teamDriveMembershipRequired) as e:
_getMain().entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE_ID, fileIdEntity['shareddrive']['driveId']], str(e), j, jcount)
continue
except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
_getMain().userDriveServiceNotEnabledWarning(user, str(e), i, count)
break
_showFileInfo(fileEntryInfo, -1, j, jcount)
Ind.Increment()
if buildTree:
_showDriveFolderContents(fileEntry, 0)
else:
_showChildDriveFolderContents(drive, fileEntryInfo, user, i, count, 0)
Ind.Decrement()
Ind.Decrement()
if csvPF:
csvPF.writeCSVfile('Drive File Tree')
def getCreationModificationTimes(path_to_file):
"""
Try to get the date that a file was created, falling back to when it was
last modified if that isn't possible.
See http://stackoverflow.com/a/39501288/1709587 for explanation.
"""
mtime = os.path.getmtime(path_to_file)
if platform.system() == 'Windows':
ctime = os.path.getctime(path_to_file)
else:
stat = os.stat(path_to_file)
try:
ctime = stat.st_birthtime
except AttributeError:
# We're probably on Linux. No easy way to get creation dates here,
# so we'll settle for when its content was last modified.
ctime = stat.st_mtime
return (_getMain().formatLocalSecondsTimestamp(ctime), _getMain().formatLocalSecondsTimestamp(mtime))
def writeReturnIdLink(returnIdLink, mimeType, result):
if returnIdLink != 'editLink':
_getMain().writeStdout(f'{result[returnIdLink]}\n')
return
if mimeType is None:
_getMain().writeStdout(f'{result["webViewLink"]}\n')
return
for mt in MICROSOFT_FORMATS_LIST:
if mimeType == mt['mime']:
if mt['ext'][1] == 'd':
_getMain().writeStdout(f'https://docs.google.com/document/d/{result["id"]}/edit\n')
return
if mt['ext'][1] == 'x':
_getMain().writeStdout(f'https://docs.google.com/spreadsheets/d/{result["id"]}/edit\n')
return
if mt['ext'][1] == 'p':
_getMain().writeStdout(f'https://docs.google.com/presentation/d/{result["id"]}/edit\n')
return
_getMain().writeStdout(f'https://drive.google.com/file/d/{result["id"]}/edit\n')