mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-18 13:11:37 +00:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93ace6dacd | ||
|
|
117c239cc8 | ||
|
|
ce4a867802 | ||
|
|
d5ccb2a2c4 | ||
|
|
3a921f39dc | ||
|
|
63b0d9ae5f | ||
|
|
56bdca9d41 | ||
|
|
8018783aed | ||
|
|
4642868969 | ||
|
|
1ea3c29ba2 | ||
|
|
18b83204a7 | ||
|
|
1d1dc90a49 | ||
|
|
6b6b29ca3c | ||
|
|
94232d5135 | ||
|
|
de83607be3 | ||
|
|
462e39ca13 | ||
|
|
12be449aa6 | ||
|
|
259f0dd6f8 | ||
|
|
0f9b3467a4 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -935,6 +935,8 @@ jobs:
|
||||
run_gam csv ./resources.csv gam delete resource ~resourceId
|
||||
run_gam config csv_output_row_filter "buildingId:regex:^gha_test_${JID}_" redirect csv ./buildings.csv print buildings
|
||||
run_gam csv ./buildings.csv gam delete building ~buildingId
|
||||
run_gam config csv_output_row_filter "displayName:regex:^El\ Goog\ gha_test_${JID}_" redirect csv ./ssoprofiles.csv print inboundssoprofiles
|
||||
run_gam csv ./ssoprofiles.csv gam delete inboundssoprofile "id:~~name~~"
|
||||
|
||||
echo "Creating OrgUnit ${newou}"
|
||||
run_gam create ou "${newou}"
|
||||
|
||||
@@ -260,6 +260,7 @@ If an item contains spaces, it should be surrounded by ".
|
||||
4tb | drive4tb | googledrivestorage4tb | Google-Drive-storage-4TB |
|
||||
8tb | drive8tb | googledrivestorage8tb | Google-Drive-storage-8TB |
|
||||
16tb | drive16tb | googledrivestorage16tb | Google-Drive-storage-16TB |
|
||||
aiexpandedaccess | 1010470009 | AI Expanded Access |
|
||||
aimeetingsandmessaging | 1010470007 | AI Meetings and Messaging |
|
||||
aisecurity | 1010470006 | AI Security |
|
||||
appsheetcore | 1010380001 | AppSheet Core |
|
||||
@@ -278,7 +279,7 @@ If an item contains spaces, it should be surrounded by ".
|
||||
gaiproedu | geminiedu | 1010470004 | Google AI Pro for Education |
|
||||
geminibiz | 1010470003 | Gemini Business |
|
||||
geminiedupremium| 1010470005 | Gemini Education Premium |
|
||||
geminient| duetai | 1010470001 | Gemini Enterprise |
|
||||
geminient| duetai | 1010470001 | Gemini Enterprise - Legacy |
|
||||
geminiultra | 1010470008 | Google AI Ultra for Business |
|
||||
gsuitebasic | gafb | gafw | basic | Google-Apps-For-Business |
|
||||
gsuitebusiness | gau | gsb | unlimited | Google-Apps-Unlimited |
|
||||
@@ -3890,6 +3891,7 @@ gam create|add group <EmailAddress>
|
||||
[copyfrom <GroupItem>] <GroupAttribute>*
|
||||
[verifynotinvitable]
|
||||
gam update group|groups <GroupEntity> [email <EmailAddress>]
|
||||
[updateprimaryemail <RESearchPattern> <RESubstitution>]
|
||||
[copyfrom <GroupItem>] <GroupAttribute>*
|
||||
[security|makesecuritygroup]
|
||||
[admincreated <Boolean>]
|
||||
@@ -4117,6 +4119,7 @@ gam create cigroup <EmailAddress>
|
||||
[security|makesecuritygroup] [locked]
|
||||
[dynamic <QueryDynamicGroup>]
|
||||
gam update cigroup <GroupEntity> [copyfrom <GroupItem>] <GroupAttribute>
|
||||
[updateprimaryemail <RESearchPattern> <RESubstitution>]
|
||||
[security|makesecuritygroup|
|
||||
dynamicsecurity|makedynamicsecuritygroup|
|
||||
lockedsecurity|makelockedsecuritygroup]
|
||||
@@ -5208,7 +5211,6 @@ gam create|add permissions <SharedDriveEntityAdmin> <DriveFilePermissionEntity>
|
||||
<PermissionMatch>* [<PermissionMatchAction>]
|
||||
gam delete permissions <SharedDriveEntityAdmin> <DriveFilePermissionIDEntity>
|
||||
<PermissionMatch>* [<PermissionMatchAction>]
|
||||
[enforceexpansiveaccess [<Boolean>]]
|
||||
|
||||
In these commands, you specify an administrator and then indicate that you want domain administrator access with the adminaccess option.
|
||||
|
||||
@@ -5222,11 +5224,9 @@ gam <UserTypeEntity> create|add drivefileacl <SharedDriveEntityAdmin>
|
||||
adminaccess
|
||||
gam <UserTypeEntity> update drivefileacl <SharedDriveEntityAdmin> <DriveFilePermissionIDorEmail>
|
||||
(role <DriveFileACLRole>) [expires|expiration <Time>] [removeexpiration [<Boolean>]]
|
||||
[enforceexpansiveaccess [<Boolean>]]
|
||||
[showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])]
|
||||
adminaccess
|
||||
gam <UserTypeEntity> delete drivefileacl <SharedDriveEntityAdmin> <DriveFilePermissionIDorEmail>
|
||||
[enforceexpansiveaccess [<Boolean>]]
|
||||
[showtitles] adminaccess
|
||||
gam <UserTypeEntity> info drivefileacl <SharedDriveEntityAdmin> <DriveFilePermissionIDorEmail> adminaccess
|
||||
[showtitles]
|
||||
@@ -5252,7 +5252,6 @@ gam <UserTypeEntity> create|add permissions <SharedDriveEntityAdmin> <DriveFileP
|
||||
<PermissionMatch>* [<PermissionMatchAction>]
|
||||
gam <UserTypeEntity> delete permissions <SharedDriveEntityAdmin> <DriveFilePermissionIDEntity> adminaccess
|
||||
<PermissionMatch>* [<PermissionMatchAction>]
|
||||
[enforceexpansiveaccess [<Boolean>]]
|
||||
|
||||
In these commands, the Google administrator named in oauth2.txt is used.
|
||||
|
||||
@@ -6531,7 +6530,8 @@ gam <UserTypeEntity> create chatspace
|
||||
[description <String>] [guidelines <String>]
|
||||
[history <Boolean>]
|
||||
[<ChatContent>]
|
||||
[formatjson|returnidonly]
|
||||
[(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]] (addcsvdata <FieldName> <String>)*) | formatjson | returnidonly]
|
||||
|
||||
gam <UserTypeEntity> update chatspace <ChatSpace>
|
||||
[restricted|(audience <String>)]|
|
||||
([displayname <String>]
|
||||
@@ -6971,7 +6971,6 @@ gam <UserTypeEntity> copy drivefile <DriveFileEntity>
|
||||
[sendemailifrequired [<Boolean>]]
|
||||
[suppressnotselectedmessages [<Boolean>]]
|
||||
[verifyorganizer [<Boolean>]]
|
||||
[enforceexpansiveaccess [<Boolean>]]
|
||||
|
||||
gam <UserTypeEntity> move drivefile <DriveFileEntity> [newfilename <DriveFileName>]
|
||||
[summary [<Boolean>]] [showpermissionmessages [<Boolean>]]
|
||||
@@ -6996,7 +6995,6 @@ gam <UserTypeEntity> move drivefile <DriveFileEntity> [newfilename <DriveFileNam
|
||||
[retainsourcefolders [<Boolean>]]
|
||||
[sendemailifrequired [<Boolean>]]
|
||||
[verifyorganizer [<Boolean>]]
|
||||
[enforceexpansiveaccess [<Boolean>]]
|
||||
|
||||
gam <UserTypeEntity> get document <DriveFileEntity>
|
||||
[viewmode default|suggestions_inline|preview_suggestions_accepted|preview_without_suggestions]
|
||||
@@ -7103,10 +7101,10 @@ gam <UserTypeEntity> create|add drivefileacl <DriveFileEntity> [adminaccess|asad
|
||||
[showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])]
|
||||
gam <UserTypeEntity> update drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail>
|
||||
(role <DriveFileACLRole>) [expires|expiration <Time>] [removeexpiration [<Boolean>]]
|
||||
[updatesheetprotectedranges [<Boolean>]] [enforceexpansiveaccess [<Boolean>]]
|
||||
[updatesheetprotectedranges [<Boolean>]]
|
||||
[showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])]
|
||||
gam <UserTypeEntity> delete drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail>
|
||||
[updatesheetprotectedranges [<Boolean>]] [enforceexpansiveaccess [<Boolean>]]
|
||||
[updatesheetprotectedranges [<Boolean>]]
|
||||
[showtitles]
|
||||
gam <UserTypeEntity> info drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail>
|
||||
[showtitles]
|
||||
@@ -7230,7 +7228,6 @@ gam <UserTypeEntity> print filerevisions <DriveFileEntity> [todrive <ToDriveAttr
|
||||
|
||||
gam <UserTypeEntity> transfer ownership <DriveFileEntity> <UserItem>
|
||||
[<DriveFileParentAttribute>] [includetrashed] [norecursion [<Boolean>]]
|
||||
[enforceexpansiveaccess [<Boolean>]]
|
||||
(orderby <DriveFileOrderByFieldName> [ascending|descending])*
|
||||
[preview] [filepath] [pathdelimiter <Character>] [buildtree]
|
||||
[todrive <ToDriveAttribute>*]
|
||||
@@ -7239,7 +7236,6 @@ gam <UserTypeEntity> claim ownership <DriveFileEntity>
|
||||
[skipids <DriveFileEntity>] [onlyusers|skipusers <UserTypeEntity>] [subdomains <DomainNameEntity>]
|
||||
[restricted [<Boolean>]] [writerscanshare|writerscantshare [<Boolean>]]
|
||||
[keepuser | (retainrole commenter|reader|writer|editor|fileorganizer|none)] [noretentionmessages]
|
||||
[enforceexpansiveaccess [<Boolean>]]
|
||||
(orderby <DriveFileOrderByFieldName> [ascending|descending])*
|
||||
[preview] [filepath] [pathdelimiter <Character>] [buildtree]
|
||||
[todrive <ToDriveAttribute>*]
|
||||
@@ -7247,7 +7243,6 @@ gam <UserTypeEntity> claim ownership <DriveFileEntity>
|
||||
gam <UserTypeEntity> transfer drive <UserItem> [select <DriveFileEntity>]
|
||||
[(targetfolderid <DriveFolderID>)|(targetfoldername <DriveFolderName>)]
|
||||
[targetuserfoldername <DriveFolderName>] [targetuserorphansfoldername <DriveFolderName>]
|
||||
[enforceexpansiveaccess [<Boolean>]]
|
||||
[mergewithtarget [<Boolean>]]
|
||||
[skipids <DriveFileEntity>]
|
||||
[keepuser | (retainrole reader|commenter|writer|editor|fileorganizer|none)] [noretentionmessages]
|
||||
|
||||
@@ -1,6 +1,58 @@
|
||||
7.39.04
|
||||
|
||||
Added `updateprimaryemail <RegularExpression> <EmailReplacement>` option to
|
||||
`gam update group <GroupEntity>` and `gam update cigroup <GroupEntity>` to allow modifying
|
||||
the group's current primary email address.
|
||||
For example, to change the domain of a set of groups from the current domain.com to newdomain.com:
|
||||
```
|
||||
gam update group csvfile Groups.csv:email updateprimaryemail "^(.+)@domain.com$" "\1@newdomain.com"
|
||||
```
|
||||
|
||||
7.39.03
|
||||
|
||||
Added the following options to `gam <UserTypeEntity> create chatspace` that can be used to capture
|
||||
space details when creating chat spaces in bulk.
|
||||
```
|
||||
csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]] (addcsvdata <FieldName> <String>)*
|
||||
```
|
||||
|
||||
See: https://github.com/GAM-team/GAM/wiki/Users-Chat#bulk-build-chat-spaces
|
||||
|
||||
7.39.02
|
||||
|
||||
Fixed progress messages for `gam <UserTypeEntity> print filelist` when permissions were being
|
||||
displayed/matched for Shared Drives.
|
||||
|
||||
7.39.01
|
||||
|
||||
Updated `gam <UserTypeEntity> transfer drive <UserItem>` to handle the following error:
|
||||
```
|
||||
ERROR: 403: cannotDeletePermission - The authenticated user cannot delete the permission.
|
||||
```
|
||||
|
||||
7.39.00
|
||||
|
||||
Deleted variable `enforce_expansive_access` from `gam.cfg` and removed option `enforceexpansiveaccess`
|
||||
from the following commands as expansive access is now always enforced by Google on My Drives.
|
||||
```
|
||||
gam <UserTypeEntity> delete permissions
|
||||
gam <UserTypeEntity> delete drivefileacl
|
||||
gam <UserTypeEntity> update drivefileacl
|
||||
gam <UserTypeEntity> copy drivefile
|
||||
gam <UserTypeEntity> move drivefile
|
||||
gam <UserTypeEntity> transfer ownership
|
||||
gam <UserTypeEntity> claim ownership
|
||||
```
|
||||
|
||||
7.38.02
|
||||
|
||||
Added license SKU `1010470009` for `AI Expanded Access`; abbreviation `aiexpandedaccess`.
|
||||
|
||||
Renamed license SKU `1010470001` from `Gemini Enterprise` to `Gemini Enterprise - Legacy`.
|
||||
|
||||
7.38.01
|
||||
|
||||
Added `root` as a synonnym for '/' in command line arguments that specify an OU.
|
||||
Added `root` as a synonym for '/' in command line arguments that specify an OU.
|
||||
This is to avoid issues where a stand-alone `/` on the command line may be mis-interpreted
|
||||
by the command line interpreter as a reference to the file system root.
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
|
||||
"""
|
||||
|
||||
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
|
||||
__version__ = '7.38.01'
|
||||
__version__ = '7.39.04'
|
||||
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
||||
|
||||
# pylint: disable=wrong-import-position
|
||||
@@ -27627,11 +27627,26 @@ CHAT_SPACE_MIN_MAX_MEMBERS = {
|
||||
# [members <UserTypeEntity>]
|
||||
# [displayname <String>]
|
||||
# [description <String>] [guidelines|rules <String>]
|
||||
# [history <Boolean>]
|
||||
# [<ChatContent>]
|
||||
# [formatjson|returnidonly]
|
||||
# [(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]] (addcsvdata <FieldName> <String>)*) | formatjson | returnidonly]
|
||||
def createChatSpace(users):
|
||||
FJQC = FormatJSONQuoteChar()
|
||||
def _writeSpaceDetails(space, resp=None):
|
||||
baserow = {'User': user, 'name': space['name']}
|
||||
if resp:
|
||||
baserow['message.name'] = resp['name']
|
||||
if addCSVData:
|
||||
baserow.update(addCSVData)
|
||||
row = flattenJSON(space, flattened=baserow.copy(), timeObjects=CHAT_TIME_OBJECTS)
|
||||
if not FJQC.formatJSON:
|
||||
csvPF.WriteRowTitles(row)
|
||||
else:
|
||||
row = baserow.copy()
|
||||
row['JSON'] = json.dumps(cleanJSON(space, timeObjects=CHAT_TIME_OBJECTS), ensure_ascii=False, sort_keys=True)
|
||||
csvPF.WriteRowNoFilter(row)
|
||||
|
||||
csvPF = None
|
||||
FJQC = FormatJSONQuoteChar(csvPF)
|
||||
addCSVData = {}
|
||||
body = {'space': {'spaceType': CHAT_SPACE_TYPE_MAP['space'], 'displayName': ''}, 'requestId': str(uuid.uuid4())}
|
||||
members = []
|
||||
tbody = {}
|
||||
@@ -27649,10 +27664,17 @@ def createChatSpace(users):
|
||||
_, members = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS)
|
||||
elif myarg == 'returnidonly':
|
||||
returnIdOnly = True
|
||||
elif myarg == 'csv':
|
||||
csvPF = CSVPrintFile(['User', 'name'])
|
||||
FJQC = FormatJSONQuoteChar(csvPF)
|
||||
elif csvPF and myarg == 'todrive':
|
||||
csvPF.GetTodriveParameters()
|
||||
elif csvPF and myarg == 'addcsvdata':
|
||||
getAddCSVData(addCSVData)
|
||||
elif myarg in SORF_TEXT_ARGUMENTS:
|
||||
tbody['text'] = getStringOrFile(myarg, minLen=0, unescapeCRLF=True)[0]
|
||||
else:
|
||||
FJQC.GetFormatJSON(myarg)
|
||||
FJQC.GetFormatJSONQuoteChar(myarg)
|
||||
spaceType = body['space']['spaceType']
|
||||
jcount = len(members)
|
||||
if (jcount < CHAT_SPACE_MIN_MAX_MEMBERS[spaceType]['min'] or
|
||||
@@ -27681,6 +27703,15 @@ def createChatSpace(users):
|
||||
body['space']['singleUserBotDm'] = False
|
||||
if tbody:
|
||||
trimChatMessageIfRequired(tbody)
|
||||
if csvPF:
|
||||
if tbody:
|
||||
csvPF.AddTitle('message.name')
|
||||
if addCSVData:
|
||||
csvPF.AddTitles(sorted(addCSVData.keys()))
|
||||
if FJQC.formatJSON:
|
||||
csvPF.SetJSONTitles(csvPF.titlesList)
|
||||
csvPF.AddJSONTitle('JSON')
|
||||
csvPF.SetSortAllTitles()
|
||||
i, count, users = getEntityArgument(users)
|
||||
for user in users:
|
||||
i += 1
|
||||
@@ -27692,15 +27723,17 @@ def createChatSpace(users):
|
||||
space = callGAPI(chat.spaces(), 'setup',
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.FAILED_PRECONDITION],
|
||||
body=body)
|
||||
if not returnIdOnly:
|
||||
if returnIdOnly:
|
||||
writeStdout(f'{space["name"]}\n')
|
||||
elif not csvPF:
|
||||
kvList[-1] = space['name']
|
||||
if not FJQC.formatJSON:
|
||||
entityActionPerformed(kvList, i, count)
|
||||
Ind.Increment()
|
||||
_showChatItem(space, Ent.CHAT_SPACE, FJQC)
|
||||
Ind.Decrement()
|
||||
else:
|
||||
writeStdout(f'{space["name"]}\n')
|
||||
elif not tbody:
|
||||
_writeSpaceDetails(space, None)
|
||||
except (GAPI.notFound, GAPI.invalidArgument, GAPI.permissionDenied) as e:
|
||||
exitIfChatNotConfigured(chat, kvList, str(e), i, count)
|
||||
continue
|
||||
@@ -27712,18 +27745,29 @@ def createChatSpace(users):
|
||||
_, chat, kvList = buildChatServiceObject(API.CHAT_MESSAGES, user, i, count,
|
||||
[Ent.CHAT_SPACE, body['space'].get('displayName', parent)])
|
||||
if not chat:
|
||||
if csvPF:
|
||||
_writeSpaceDetails(space, None)
|
||||
continue
|
||||
try:
|
||||
resp = callGAPI(chat.spaces().messages(), 'create',
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
|
||||
parent=parent, requestId=str(uuid.uuid4()), body=tbody)
|
||||
if not returnIdOnly:
|
||||
kvList.extend([Ent.CHAT_MESSAGE, resp['name']])
|
||||
entityActionPerformed(kvList, i, count)
|
||||
else:
|
||||
parent=parent, requestId=str(uuid.uuid4()), body=tbody, fields='name')
|
||||
if returnIdOnly:
|
||||
writeStdout(f'{resp["name"]}\n')
|
||||
elif not csvPF:
|
||||
if not FJQC.formatJSON:
|
||||
kvList.extend([Ent.CHAT_MESSAGE, resp['name']])
|
||||
entityActionPerformed(kvList, i, count)
|
||||
else:
|
||||
printLine(json.dumps(cleanJSON(resp), ensure_ascii=False, sort_keys=True))
|
||||
else:
|
||||
_writeSpaceDetails(space, resp)
|
||||
except (GAPI.notFound, GAPI.invalidArgument, GAPI.permissionDenied) as e:
|
||||
exitIfChatNotConfigured(chat, kvList, str(e), i, count)
|
||||
if csvPF:
|
||||
_writeSpaceDetails(space, None)
|
||||
if csvPF:
|
||||
csvPF.writeCSVfile('Chat Spaces')
|
||||
|
||||
CHAT_UPDATE_SPACE_TYPE_MAP = {
|
||||
'space': 'SPACE',
|
||||
@@ -34058,6 +34102,7 @@ UPDATE_GROUP_SUBCMDS = ['add', 'create', 'delete', 'remove', 'clear', 'sync', 'u
|
||||
GROUP_PREVIEW_TITLES = ['group', 'email', 'role', 'action', 'message']
|
||||
|
||||
# gam update groups <GroupEntity> [email <EmailAddress>]
|
||||
# [updateprimaryemail <RESEarchPattern> <RESubstitution>]
|
||||
# [copyfrom <GroupItem>] <GroupAttribute>*
|
||||
# [security|makesecuritygroup]
|
||||
# [admincreated <Boolean>]
|
||||
@@ -34487,10 +34532,13 @@ def doUpdateGroups():
|
||||
gs_body = {}
|
||||
ci_body = {}
|
||||
verifyNotInvitable = False
|
||||
updatePrimaryEmail = {}
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if myarg == 'email':
|
||||
body['email'] = getEmailAddress(noUid=True)
|
||||
elif myarg == 'updateprimaryemail':
|
||||
updatePrimaryEmail = getREPatternSubstitution(re.IGNORECASE)
|
||||
elif myarg == 'admincreated':
|
||||
body['adminCreated'] = getBoolean()
|
||||
elif myarg == 'getbeforeupdate':
|
||||
@@ -34506,15 +34554,8 @@ def doUpdateGroups():
|
||||
verifyNotInvitable = True
|
||||
else:
|
||||
getGroupAttrValue(myarg, gs_body)
|
||||
if 'email' in body and verifyNotInvitable:
|
||||
isInvitableUser, _ = _getIsInvitableUser(None, body['email'])
|
||||
if isInvitableUser:
|
||||
entityActionNotPerformedWarning([Ent.GROUP, body['email']], Msg.EMAIL_ADDRESS_IS_UNMANAGED_ACCOUNT)
|
||||
return
|
||||
if ci_body:
|
||||
ci = buildGAPIObject(API.CLOUDIDENTITY_GROUPS)
|
||||
if 'email' in body:
|
||||
ci_body['groupKey'] = {'id': body.pop('email')}
|
||||
if gs_body:
|
||||
gs = buildGAPIObject(API.GROUPSSETTINGS)
|
||||
gs_body = getSettingsFromGroup(cd, ','.join(entityList), gs, gs_body)
|
||||
@@ -34527,7 +34568,7 @@ def doUpdateGroups():
|
||||
settings = gs_body
|
||||
elif not ci_body:
|
||||
return
|
||||
elif not body and not ci_body:
|
||||
elif not body and not ci_body and not updatePrimaryEmail:
|
||||
return
|
||||
Act.Set(Act.UPDATE)
|
||||
i = 0
|
||||
@@ -34535,6 +34576,22 @@ def doUpdateGroups():
|
||||
for group in entityList:
|
||||
i += 1
|
||||
ci, _, group = convertGroupCloudIDToEmail(ci, group, i, count)
|
||||
if updatePrimaryEmail:
|
||||
if updatePrimaryEmail[0].search(group) is not None:
|
||||
body['email'] = re.sub(updatePrimaryEmail[0], updatePrimaryEmail[1], group)
|
||||
else:
|
||||
body.pop('email', None)
|
||||
if not body:
|
||||
entityActionNotPerformedWarning([Ent.GROUP, group], Msg.PRIMARY_EMAIL_DID_NOT_MATCH_PATTERN.format(updatePrimaryEmail[0].pattern), i, count)
|
||||
continue
|
||||
if 'email' in body and verifyNotInvitable:
|
||||
isInvitableUser, _ = _getIsInvitableUser(None, body['email'])
|
||||
if isInvitableUser:
|
||||
entityActionNotPerformedWarning([Ent.GROUP, body['email']], Msg.EMAIL_ADDRESS_IS_UNMANAGED_ACCOUNT)
|
||||
continue
|
||||
if ci_body and 'email' in body:
|
||||
ci_body['groupKey'] = {'id': body.pop('email')}
|
||||
origGroup = group
|
||||
if gs_body and not GroupIsAbuseOrPostmaster(group):
|
||||
try:
|
||||
if group.find('@') == -1: # group settings API won't take uid so we make sure cd API is used so that we can grab real email.
|
||||
@@ -34549,12 +34606,12 @@ def doUpdateGroups():
|
||||
if not checkReplyToCustom(group, settings, i, count):
|
||||
continue
|
||||
except GAPI.notFound:
|
||||
entityActionFailedWarning([entityType, group], Msg.DOES_NOT_EXIST, i, count)
|
||||
entityActionFailedWarning([entityType, origGroup], Msg.DOES_NOT_EXIST, i, count)
|
||||
continue
|
||||
except (GAPI.groupNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden,
|
||||
GAPI.backendError, GAPI.invalid, GAPI.invalidInput, GAPI.badRequest, GAPI.permissionDenied,
|
||||
GAPI.systemError, GAPI.serviceLimit, GAPI.serviceNotAvailable, GAPI.authError) as e:
|
||||
entityActionFailedWarning([entityType, group], str(e), i, count)
|
||||
entityActionFailedWarning([entityType, origGroup], str(e), i, count)
|
||||
continue
|
||||
if body:
|
||||
try:
|
||||
@@ -34563,7 +34620,7 @@ def doUpdateGroups():
|
||||
groupKey=group, body=body, fields='email')['email']
|
||||
except (GAPI.groupNotFound, GAPI.domainNotFound, GAPI.backendError, GAPI.badRequest, GAPI.invalid, GAPI.invalidInput,
|
||||
GAPI.systemError, GAPI.permissionDenied, GAPI.failedPrecondition, GAPI.forbidden) as e:
|
||||
entityActionFailedWarning([entityType, group], str(e), i, count)
|
||||
entityActionFailedWarning([entityType, origGroup], str(e), i, count)
|
||||
continue
|
||||
if gs_body and not GroupIsAbuseOrPostmaster(group):
|
||||
try:
|
||||
@@ -34572,15 +34629,15 @@ def doUpdateGroups():
|
||||
throwReasons=GAPI.GROUP_SETTINGS_THROW_REASONS, retryReasons=GAPI.GROUP_SETTINGS_RETRY_REASONS,
|
||||
groupUniqueId=mapGroupEmailForSettings(group), body=settings, fields='')
|
||||
except GAPI.notFound:
|
||||
entityActionFailedWarning([entityType, group], Msg.DOES_NOT_EXIST, i, count)
|
||||
entityActionFailedWarning([entityType, origGroup], Msg.DOES_NOT_EXIST, i, count)
|
||||
continue
|
||||
except (GAPI.groupNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden, GAPI.backendError,
|
||||
GAPI.invalid, GAPI.invalidArgument, GAPI.invalidAttributeValue, GAPI.invalidInput, GAPI.badRequest, GAPI.permissionDenied,
|
||||
GAPI.systemError, GAPI.serviceLimit, GAPI.serviceNotAvailable, GAPI.authError) as e:
|
||||
entityActionFailedWarning([entityType, group], str(e), i, count)
|
||||
entityActionFailedWarning([entityType, origGroup], str(e), i, count)
|
||||
continue
|
||||
except GAPI.required:
|
||||
entityActionFailedWarning([entityType, group], Msg.INVALID_JSON_SETTING, i, count)
|
||||
entityActionFailedWarning([entityType, origGroup], Msg.INVALID_JSON_SETTING, i, count)
|
||||
continue
|
||||
if ci_body:
|
||||
_, name, groupEmail = convertGroupEmailToCloudID(ci, group, i, count)
|
||||
@@ -34595,7 +34652,7 @@ def doUpdateGroups():
|
||||
GAPI.systemError, GAPI.permissionDenied, GAPI.failedPrecondition, GAPI.serviceNotAvailable) as e:
|
||||
entityActionFailedWarning([Ent.CLOUD_IDENTITY_GROUP, groupEmail], str(e), i, count)
|
||||
continue
|
||||
entityActionPerformed([entityType, group], i, count)
|
||||
entityActionPerformed([entityType, origGroup], i, count)
|
||||
elif CL_subCommand in {'create', 'add'}:
|
||||
baseRole, groupMemberType = _getRoleGroupMemberType()
|
||||
isSuspended, isArchived = _getOptionalIsSuspendedIsArchived()
|
||||
@@ -36993,6 +37050,7 @@ def doCreateCIGroup():
|
||||
doCreateGroup(ciGroupsAPI=True)
|
||||
|
||||
# gam update cigroups <GroupEntity> [email <EmailAddress>]
|
||||
# [updateprimaryemail <RESEarchPattern> <RESubstitution>]
|
||||
# [copyfrom <GroupItem>] <GroupAttribute>*
|
||||
# [security|makesecuritygroup|dynamicsecurity|makedynamicsecuritygroup]
|
||||
# [dynamic <QueryDynamicGroup>]
|
||||
@@ -37181,10 +37239,13 @@ def doUpdateCIGroups():
|
||||
gs_body = {}
|
||||
ci_body = {}
|
||||
se_body = {}
|
||||
updatePrimaryEmail = {}
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if myarg == 'email':
|
||||
ci_body['groupKey'] = {'id': getEmailAddress(noUid=True)}
|
||||
elif myarg == 'updateprimaryemail':
|
||||
updatePrimaryEmail = getREPatternSubstitution(re.IGNORECASE)
|
||||
elif myarg == 'getbeforeupdate':
|
||||
getBeforeUpdate = True
|
||||
elif myarg == 'dynamic':
|
||||
@@ -37229,7 +37290,7 @@ def doUpdateCIGroups():
|
||||
settings = gs_body
|
||||
elif not ci_body:
|
||||
return
|
||||
elif not ci_body and not se_body and lockGroup is None:
|
||||
elif not ci_body and not se_body and not updatePrimaryEmail and lockGroup is None:
|
||||
return
|
||||
Act.Set(Act.UPDATE)
|
||||
i = 0
|
||||
@@ -37237,6 +37298,14 @@ def doUpdateCIGroups():
|
||||
for group in entityList:
|
||||
i += 1
|
||||
ci, _, group = convertGroupCloudIDToEmail(ci, group, i, count)
|
||||
if updatePrimaryEmail:
|
||||
if updatePrimaryEmail[0].search(group) is not None:
|
||||
ci_body['groupKey'] = {'id': re.sub(updatePrimaryEmail[0], updatePrimaryEmail[1], group)}
|
||||
else:
|
||||
ci_body.pop('groupKey', None)
|
||||
if not ci_body:
|
||||
entityActionNotPerformedWarning([Ent.GROUP, group], Msg.PRIMARY_EMAIL_DID_NOT_MATCH_PATTERN.format(updatePrimaryEmail[0].pattern), i, count)
|
||||
continue
|
||||
if gs_body and not GroupIsAbuseOrPostmaster(group):
|
||||
try:
|
||||
if group.find('@') == -1: # group settings API won't take uid so we make sure cd API is used so that we can grab real email.
|
||||
@@ -59337,7 +59406,7 @@ def printFileList(users):
|
||||
csvPF.WriteRowTitlesJSONNoFilter(row)
|
||||
|
||||
def _printFileInfo(drive, user, f_file, cleanFileName):
|
||||
nonlocal getSharedDriveACLsCount, getSharedDriveACLsCountMsg
|
||||
nonlocal getSharedDriveACLsCount
|
||||
driveId = f_file.get('driveId')
|
||||
checkSharedDrivePermissions = getPermissionsForSharedDrives and driveId and 'permissions' not in f_file
|
||||
if (f_file.get('noDisplay', False) or
|
||||
@@ -59354,7 +59423,7 @@ def printFileList(users):
|
||||
if not incrementalPrint:
|
||||
getSharedDriveACLsCount += 1
|
||||
if getSharedDriveACLsCount % 100 == 0:
|
||||
writeStderr(f'{Msg.GOT} {getSharedDriveACLsCount} {getSharedDriveACLsCountMsg}')
|
||||
writeStderr(f'{Msg.GOT} {getSharedDriveACLsCount} {Ent.Plural(Ent.DRIVE_FILE_OR_FOLDER_ACL)} {Msg.FOR} {gettingEntity}\n')
|
||||
try:
|
||||
f_file['permissions'] = callGAPIpages(drive.permissions(), 'list', 'permissions',
|
||||
throwReasons=GAPI.DRIVE3_GET_ACL_REASONS,
|
||||
@@ -59530,7 +59599,7 @@ def printFileList(users):
|
||||
simpleLists = ['permissionIds', 'spaces']
|
||||
skipObjects = set()
|
||||
fileIdEntity = {}
|
||||
getSharedDriveACLsCountMsg = selectSubQuery = ''
|
||||
selectSubQuery = ''
|
||||
delimiter = GC.Values[GC.CSV_OUTPUT_FIELD_DELIMITER]
|
||||
DLP = DriveListParameters({'allowChoose': True, 'allowCorpora': True, 'allowQuery': True, 'mimeTypeInQuery': False})
|
||||
DFF = DriveFileFields()
|
||||
@@ -59613,7 +59682,6 @@ def printFileList(users):
|
||||
elif myarg == 'showshareddrivepermissions':
|
||||
getPermissionsForSharedDrives = True
|
||||
permissionsFields = f'nextPageToken,permissions({",".join(DRIVEFILE_BASIC_PERMISSION_FIELDS)})'
|
||||
getSharedDriveACLsCountMsg = f'{Ent.Plural(Ent.DRIVE_FILE_OR_FOLDER_ACL)} {Msg.FOR} {Ent.Plural(Ent.SHAREDDRIVE)}\n'
|
||||
elif myarg == 'pmfilter':
|
||||
pmselect = False
|
||||
elif myarg == 'oneitemperrow':
|
||||
@@ -62364,7 +62432,6 @@ def initCopyMoveOptions(copyCmd):
|
||||
'showPermissionMessages': False,
|
||||
'sendEmailIfRequired': False,
|
||||
'useDomainAdminAccess': False,
|
||||
'enforceExpansiveAccess': GC.Values[GC.ENFORCE_EXPANSIVE_ACCESS],
|
||||
'copiedShortcutsPointToCopiedFiles': True,
|
||||
'createShortcutsForNonmovableFiles': False,
|
||||
'duplicateFiles': DUPLICATE_FILE_OVERWRITE_OLDER,
|
||||
@@ -62491,8 +62558,6 @@ def getCopyMoveOptions(myarg, copyMoveOptions):
|
||||
elif myarg == 'mappermissionsdomain':
|
||||
oldDomain = getString(Cmd.OB_DOMAIN_NAME).lower()
|
||||
copyMoveOptions['mapPermissionsDomains'][oldDomain] = getString(Cmd.OB_DOMAIN_NAME).lower()
|
||||
elif myarg == 'enforceexpansiveaccess':
|
||||
copyMoveOptions['enforceExpansiveAccess'] = getBoolean()
|
||||
else:
|
||||
# Move arguments
|
||||
if not copyMoveOptions['copyCmd']:
|
||||
@@ -62778,8 +62843,6 @@ def _copyPermissions(drive, user, i, count, j, jcount,
|
||||
updateTargetPerms[permissionId]['updates'] = updatePerm
|
||||
copySourcePerms.pop(permissionId)
|
||||
deleteUpdateKwargs = {'useDomainAdminAccess': copyMoveOptions['useDomainAdminAccess']}
|
||||
if entityType != Ent.SHAREDDRIVE:
|
||||
deleteUpdateKwargs['enforceExpansiveAccess'] = copyMoveOptions['enforceExpansiveAccess']
|
||||
action = Act.Get()
|
||||
Act.Set(Act.COPY)
|
||||
kcount = len(copySourcePerms)
|
||||
@@ -62837,16 +62900,16 @@ def _copyPermissions(drive, user, i, count, j, jcount,
|
||||
kvList = permissionKVList(user, entityType, newFileTitle, targetPerms[permissionId])
|
||||
try:
|
||||
callGAPI(drive.permissions(), 'delete',
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_DELETE_ACL_THROW_REASONS+[GAPI.FILE_NEVER_WRITABLE],
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_DELETE_ACL_THROW_REASONS,
|
||||
**deleteUpdateKwargs,
|
||||
fileId=newFileId, permissionId=permissionId, supportsAllDrives=True)
|
||||
if copyMoveOptions['showPermissionMessages']:
|
||||
entityActionPerformed(kvList, k, kcount)
|
||||
except (GAPI.notFound, GAPI.permissionNotFound,
|
||||
GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError,
|
||||
GAPI.fileNeverWritable, GAPI.badRequest, GAPI.cannotRemoveOwner,
|
||||
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError, GAPI.invalid,
|
||||
GAPI.badRequest, GAPI.notFound, GAPI.permissionNotFound, GAPI.cannotRemoveOwner,
|
||||
GAPI.cannotModifyInheritedTeamDrivePermission, GAPI.cannotModifyInheritedPermission,
|
||||
GAPI.insufficientAdministratorPrivileges, GAPI.sharingRateLimitExceeded, GAPI.cannotDeletePermission) as e:
|
||||
GAPI.insufficientAdministratorPrivileges, GAPI.sharingRateLimitExceeded, GAPI.cannotDeletePermission,
|
||||
GAPI.fileNeverWritable) as e:
|
||||
entityActionFailedWarning(kvList, str(e), k, kcount)
|
||||
except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
|
||||
userDriveServiceNotEnabledWarning(user, str(e), i, count)
|
||||
@@ -63151,7 +63214,6 @@ copyReturnItemMap = {
|
||||
# [sendemailifrequired [<Boolean>]]
|
||||
# [suppressnotselectedmessages [<Boolean>]]
|
||||
# [verifyorganizer [<Boolean>]]
|
||||
# [enforceexpansiveaccess [<Boolean>]]
|
||||
def copyDriveFile(users):
|
||||
def _writeCSVData(user, oldName, oldId, newName, newId, mimeType):
|
||||
row = {'User': user, 'name': oldName, 'id': oldId,
|
||||
@@ -63915,17 +63977,16 @@ def _updateMoveFilePermissions(drive, user, i, count,
|
||||
kvList = permissionKVList(user, entityType, fileTitle, permission)
|
||||
try:
|
||||
callGAPI(drive.permissions(), 'delete',
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_DELETE_ACL_THROW_REASONS+[GAPI.FILE_NEVER_WRITABLE],
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_DELETE_ACL_THROW_REASONS,
|
||||
useDomainAdminAccess=copyMoveOptions['useDomainAdminAccess'],
|
||||
enforceExpansiveAccess=copyMoveOptions['enforceExpansiveAccess'],
|
||||
fileId=fileId, permissionId=permissionId, supportsAllDrives=True)
|
||||
if copyMoveOptions['showPermissionMessages']:
|
||||
entityActionPerformed(kvList, k, kcount)
|
||||
except (GAPI.notFound, GAPI.permissionNotFound,
|
||||
GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError,
|
||||
GAPI.fileNeverWritable, GAPI.badRequest, GAPI.cannotRemoveOwner,
|
||||
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError, GAPI.invalid,
|
||||
GAPI.badRequest, GAPI.notFound, GAPI.permissionNotFound, GAPI.cannotRemoveOwner,
|
||||
GAPI.cannotModifyInheritedTeamDrivePermission, GAPI.cannotModifyInheritedPermission,
|
||||
GAPI.insufficientAdministratorPrivileges, GAPI.sharingRateLimitExceeded, GAPI.cannotDeletePermission) as e:
|
||||
GAPI.insufficientAdministratorPrivileges, GAPI.sharingRateLimitExceeded, GAPI.cannotDeletePermission,
|
||||
GAPI.fileNeverWritable) as e:
|
||||
entityActionFailedWarning(kvList, str(e), k, kcount)
|
||||
except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
|
||||
userDriveServiceNotEnabledWarning(user, str(e), i, count)
|
||||
@@ -64037,7 +64098,6 @@ def _recursiveUpdateMovePermissions(drive, user, i, count,
|
||||
# [retainsourcefolders [<Boolean>]]
|
||||
# [sendemailifrequired [<Boolean>]]
|
||||
# [verifyorganizer [<Boolean>]]
|
||||
# [enforceexpansiveaccess [<Boolean>]]
|
||||
def moveDriveFile(users):
|
||||
def _cloneFolderMove(drive, user, i, count, j, jcount,
|
||||
source, targetChildren, newFolderName, newParentId, newParentName, mergeParentModifiedTime,
|
||||
@@ -65284,7 +65344,6 @@ TRANSFER_DRIVEFILE_ACL_ROLES_MAP = {
|
||||
# [nonowner_retainrole reader|commenter|writer|editor|fileorganizer|current|none]
|
||||
# [nonowner_targetrole reader|commenter|writer|editor|fileorganizer|current|none|source]
|
||||
# (orderby <DriveFileOrderByFieldName> [ascending|descending])*
|
||||
# [enforceexpansiveaccess [<Boolean>]]
|
||||
# [preview] [todrive <ToDriveAttribute>*]
|
||||
def transferDrive(users):
|
||||
|
||||
@@ -65471,7 +65530,6 @@ def transferDrive(users):
|
||||
callGAPI(sourceDrive.permissions(), 'update',
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.BAD_REQUEST, GAPI.INVALID_OWNERSHIP_TRANSFER,
|
||||
GAPI.PERMISSION_NOT_FOUND, GAPI.SHARING_RATE_LIMIT_EXCEEDED],
|
||||
enforceExpansiveAccess=enforceExpansiveAccess,
|
||||
fileId=childFileId, permissionId=targetPermissionId,
|
||||
transferOwnership=True, body={'role': 'owner'}, fields='')
|
||||
if removeSourceParents:
|
||||
@@ -65660,16 +65718,18 @@ def transferDrive(users):
|
||||
if ownerRetainRoleBody['role'] != 'writer':
|
||||
callGAPI(targetDrive.permissions(), 'update',
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.SHARING_RATE_LIMIT_EXCEEDED],
|
||||
enforceExpansiveAccess=enforceExpansiveAccess,
|
||||
fileId=childFileId, permissionId=sourcePermissionId, body=ownerRetainRoleBody, fields='')
|
||||
else:
|
||||
callGAPI(targetDrive.permissions(), 'delete',
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.SHARING_RATE_LIMIT_EXCEEDED, GAPI.CANNOT_REMOVE_OWNER],
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_DELETE_ACL_THROW_REASONS,
|
||||
fileId=childFileId, permissionId=sourcePermissionId)
|
||||
if showRetentionMessages:
|
||||
entityActionPerformed([Ent.USER, sourceUser, childFileType, childFileName, Ent.ROLE, ownerRetainRoleBody['role']], j, jcount)
|
||||
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError,
|
||||
GAPI.badRequest, GAPI.sharingRateLimitExceeded, GAPI.cannotRemoveOwner, GAPI.cannotDeletePermission) as e:
|
||||
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError, GAPI.invalid,
|
||||
GAPI.badRequest, GAPI.notFound, GAPI.cannotRemoveOwner,
|
||||
GAPI.cannotModifyInheritedTeamDrivePermission, GAPI.cannotModifyInheritedPermission,
|
||||
GAPI.insufficientAdministratorPrivileges, GAPI.sharingRateLimitExceeded, GAPI.cannotDeletePermission,
|
||||
GAPI.fileNeverWritable) as e:
|
||||
entityActionFailedWarning([Ent.USER, sourceUser, childFileType, childFileName], str(e), j, jcount)
|
||||
except GAPI.permissionNotFound:
|
||||
entityDoesNotHaveItemWarning([Ent.USER, sourceUser, childFileType, childFileName, Ent.PERMISSION_ID, sourcePermissionId], j, jcount)
|
||||
@@ -65710,19 +65770,21 @@ def transferDrive(users):
|
||||
if nonOwnerRetainRoleBody['role'] != 'current':
|
||||
callGAPI(ownerDrive.permissions(), 'update',
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.SHARING_RATE_LIMIT_EXCEEDED],
|
||||
enforceExpansiveAccess=enforceExpansiveAccess,
|
||||
fileId=childFileId, permissionId=sourcePermissionId, body=sourceUpdateRole, fields='')
|
||||
else:
|
||||
try:
|
||||
callGAPI(ownerDrive.permissions(), 'delete',
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.SHARING_RATE_LIMIT_EXCEEDED, GAPI.CANNOT_REMOVE_OWNER],
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_DELETE_ACL_THROW_REASONS,
|
||||
fileId=childFileId, permissionId=sourcePermissionId)
|
||||
except GAPI.permissionNotFound:
|
||||
pass
|
||||
if showRetentionMessages:
|
||||
entityActionPerformed([Ent.USER, sourceUser, childFileType, childFileName, Ent.ROLE, sourceUpdateRole['role']], j, jcount)
|
||||
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError,
|
||||
GAPI.badRequest, GAPI.sharingRateLimitExceeded, GAPI.cannotRemoveOwner, GAPI.cannotDeletePermission) as e:
|
||||
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError, GAPI.invalid,
|
||||
GAPI.badRequest, GAPI.notFound, GAPI.cannotRemoveOwner,
|
||||
GAPI.cannotModifyInheritedTeamDrivePermission, GAPI.cannotModifyInheritedPermission,
|
||||
GAPI.insufficientAdministratorPrivileges, GAPI.sharingRateLimitExceeded, GAPI.cannotDeletePermission,
|
||||
GAPI.fileNeverWritable) as e:
|
||||
entityActionFailedWarning([Ent.USER, ownerUser, childFileType, childFileName], str(e), j, jcount)
|
||||
except GAPI.permissionNotFound:
|
||||
entityDoesNotHaveItemWarning([Ent.USER, ownerUser, childFileType, childFileName, Ent.PERMISSION_ID, sourcePermissionId], j, jcount)
|
||||
@@ -65739,14 +65801,17 @@ def transferDrive(users):
|
||||
else:
|
||||
try:
|
||||
callGAPI(ownerDrive.permissions(), 'delete',
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.SHARING_RATE_LIMIT_EXCEEDED],
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_DELETE_ACL_THROW_REASONS,
|
||||
fileId=childFileId, permissionId=targetPermissionId)
|
||||
except GAPI.permissionNotFound:
|
||||
pass
|
||||
if showRetentionMessages:
|
||||
entityActionPerformed([Ent.USER, targetUser, childFileType, childFileName, Ent.ROLE, targetInsertBody['role']], j, jcount)
|
||||
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError,
|
||||
GAPI.badRequest, GAPI.sharingRateLimitExceeded, GAPI.cannotDeletePermission) as e:
|
||||
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError, GAPI.invalid,
|
||||
GAPI.badRequest, GAPI.notFound, GAPI.permissionNotFound, GAPI.cannotRemoveOwner,
|
||||
GAPI.cannotModifyInheritedTeamDrivePermission, GAPI.cannotModifyInheritedPermission,
|
||||
GAPI.insufficientAdministratorPrivileges, GAPI.sharingRateLimitExceeded, GAPI.cannotDeletePermission,
|
||||
GAPI.fileNeverWritable) as e:
|
||||
entityActionFailedWarning([Ent.USER, ownerUser, childFileType, childFileName], str(e), j, jcount)
|
||||
except GAPI.invalidSharingRequest as e:
|
||||
entityActionFailedWarning([Ent.USER, ownerUser, childFileType, childFileName], Ent.TypeNameMessage(Ent.PERMISSION_ID, targetPermissionId, str(e)), j, jcount)
|
||||
@@ -65845,7 +65910,7 @@ def transferDrive(users):
|
||||
return
|
||||
if fileEntry['info']['name'] != MY_DRIVE:
|
||||
filesTransferred.add(fileId)
|
||||
if not atSelectTop or not mergeWithTarget:
|
||||
if not atSelectTop or not mergeWithTarget:
|
||||
_manageRoleRetention(fileEntry, i, count, j, jcount, atSelectTop)
|
||||
kcount = len(fileEntry['children'])
|
||||
if kcount == 0:
|
||||
@@ -65872,7 +65937,6 @@ def transferDrive(users):
|
||||
targetUserOrphansFolderPattern = '#user# orphaned files'
|
||||
targetIds = [None, None]
|
||||
createShortcutsForNonmovableFiles = False
|
||||
enforceExpansiveAccess = GC.Values[GC.ENFORCE_EXPANSIVE_ACCESS]
|
||||
mergeWithTarget = False
|
||||
thirdPartyOwners = {}
|
||||
skipFileIdEntity = initDriveFileEntity()
|
||||
@@ -65890,8 +65954,6 @@ def transferDrive(users):
|
||||
nonOwnerRetainRoleBody['role'] = 'current'
|
||||
elif myarg == 'nonownertargetrole':
|
||||
nonOwnerTargetRoleBody['role'] = getChoice(TRANSFER_DRIVEFILE_ACL_ROLES_MAP, mapChoice=True)
|
||||
elif myarg == 'enforceexpansiveaccess':
|
||||
enforceExpansiveAccess = getBoolean()
|
||||
elif myarg == 'noretentionmessages':
|
||||
showRetentionMessages = False
|
||||
elif myarg == 'orderby':
|
||||
@@ -66129,7 +66191,6 @@ def getPermissionIdForEmail(user, i, count, email):
|
||||
# [<DriveFileParentAttribute>] [includetrashed] [norecursion [<Boolean>]]
|
||||
# (orderby <DriveFileOrderByFieldName> [ascending|descending])*
|
||||
# [preview] [filepath] [pathdelimiter <Character>] [buildtree]
|
||||
# [enforceexpansiveaccess [<Boolean>]]
|
||||
# [todrive <ToDriveAttribute>*]
|
||||
def transferOwnership(users):
|
||||
def _identifyFilesToTransfer(fileEntry):
|
||||
@@ -66179,7 +66240,6 @@ def transferOwnership(users):
|
||||
newOwner = getEmailAddress()
|
||||
OBY = OrderBy(DRIVEFILE_ORDERBY_CHOICE_MAP)
|
||||
changeParents = filepath = includeTrashed = noRecursion = False
|
||||
enforceExpansiveAccess = GC.Values[GC.ENFORCE_EXPANSIVE_ACCESS]
|
||||
pathDelimiter = '/'
|
||||
csvPF = fileTree = None
|
||||
addParents = ''
|
||||
@@ -66206,8 +66266,6 @@ def transferOwnership(users):
|
||||
csvPF.GetTodriveParameters()
|
||||
elif getDriveFileParentAttribute(myarg, parentParms):
|
||||
changeParents = True
|
||||
elif myarg == 'enforceexpansiveaccess':
|
||||
enforceExpansiveAccess = getBoolean()
|
||||
else:
|
||||
unknownArgumentExit()
|
||||
Act.Set(Act.TRANSFER_OWNERSHIP)
|
||||
@@ -66325,7 +66383,6 @@ def transferOwnership(users):
|
||||
Act.Set(action)
|
||||
callGAPI(drive.permissions(), 'update',
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND],
|
||||
enforceExpansiveAccess=enforceExpansiveAccess,
|
||||
fileId=xferFileId, permissionId=permissionId, transferOwnership=True, body=body, fields='')
|
||||
entityModifierNewValueItemValueListActionPerformed(kvList, Act.MODIFIER_TO, None, [Ent.USER, newOwner], k, kcount)
|
||||
else:
|
||||
@@ -66347,7 +66404,6 @@ def transferOwnership(users):
|
||||
fileId=xferFileId, sendNotificationEmail=False, body=bodyAdd, fields='')
|
||||
callGAPI(drive.permissions(), 'update',
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND],
|
||||
enforceExpansiveAccess=enforceExpansiveAccess,
|
||||
fileId=xferFileId, permissionId=permissionId, transferOwnership=True, body=body, fields='')
|
||||
entityModifierNewValueItemValueListActionPerformed(kvList, Act.MODIFIER_TO, None, [Ent.USER, newOwner], k, kcount)
|
||||
except GAPI.invalidSharingRequest as e:
|
||||
@@ -66420,7 +66476,6 @@ def transferOwnership(users):
|
||||
# [keepuser | (retainrole reader|commenter|writer|editor|none)] [noretentionmessages]
|
||||
# (orderby <DriveFileOrderByFieldName> [ascending|descending])*
|
||||
# [preview] [filepath] [pathdelimiter <Character>] [buildtree]
|
||||
# [enforceexpansiveaccess [<Boolean>]]
|
||||
# [todrive <ToDriveAttribute>*]
|
||||
def claimOwnership(users):
|
||||
def _identifyFilesToClaim(fileEntry):
|
||||
@@ -66481,18 +66536,21 @@ def claimOwnership(users):
|
||||
if sourceRetainRoleBody['role'] != 'writer':
|
||||
callGAPI(sourceDrive.permissions(), 'update',
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND, GAPI.BAD_REQUEST],
|
||||
enforceExpansiveAccess=enforceExpansiveAccess,
|
||||
fileId=ofileId, permissionId=oldOwnerPermissionId, body=sourceRetainRoleBody, fields='')
|
||||
else:
|
||||
callGAPI(sourceDrive.permissions(), 'delete',
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND, GAPI.BAD_REQUEST],
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_DELETE_ACL_THROW_REASONS,
|
||||
fileId=ofileId, permissionId=oldOwnerPermissionId)
|
||||
if showRetentionMessages:
|
||||
entityActionPerformed([Ent.USER, oldOwner, entityType, fileDesc, Ent.ROLE, sourceRetainRoleBody['role']], l, lcount)
|
||||
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError, GAPI.invalid,
|
||||
GAPI.badRequest, GAPI.notFound, GAPI.cannotRemoveOwner,
|
||||
GAPI.cannotModifyInheritedTeamDrivePermission, GAPI.cannotModifyInheritedPermission,
|
||||
GAPI.insufficientAdministratorPrivileges, GAPI.sharingRateLimitExceeded, GAPI.cannotDeletePermission,
|
||||
GAPI.fileNeverWritable) as e:
|
||||
entityActionFailedWarning([Ent.USER, oldOwner, entityType, fileDesc], str(e), l, lcount)
|
||||
except GAPI.permissionNotFound:
|
||||
entityDoesNotHaveItemWarning([Ent.USER, oldOwner, entityType, fileDesc, Ent.PERMISSION_ID, oldOwnerPermissionId], l, lcount)
|
||||
except (GAPI.badRequest, GAPI.insufficientFilePermissions, GAPI.cannotDeletePermission) as e:
|
||||
entityActionFailedWarning([Ent.USER, oldOwner, entityType, fileDesc], str(e), l, lcount)
|
||||
except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
|
||||
userDriveServiceNotEnabledWarning(user, str(e), i, count)
|
||||
Act.Set(Act.CLAIM_OWNERSHIP)
|
||||
@@ -66506,7 +66564,6 @@ def claimOwnership(users):
|
||||
skipOwners = set()
|
||||
subdomains = []
|
||||
filepath = includeTrashed = False
|
||||
enforceExpansiveAccess = GC.Values[GC.ENFORCE_EXPANSIVE_ACCESS]
|
||||
pathDelimiter = '/'
|
||||
addParents = ''
|
||||
parentBody = {}
|
||||
@@ -66541,8 +66598,6 @@ def claimOwnership(users):
|
||||
includeTrashed = True
|
||||
elif myarg == 'orderby':
|
||||
OBY.GetChoice()
|
||||
elif myarg == 'enforceexpansiveaccess':
|
||||
enforceExpansiveAccess = getBoolean()
|
||||
elif myarg == 'restricted':
|
||||
bodyShare['copyRequiresWriterPermission'] = getBoolean()
|
||||
elif myarg == 'writerscanshare':
|
||||
@@ -66713,7 +66768,6 @@ def claimOwnership(users):
|
||||
Act.Set(action)
|
||||
callGAPI(sourceDrive.permissions(), 'update',
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND],
|
||||
enforceExpansiveAccess=enforceExpansiveAccess,
|
||||
fileId=xferFileId, permissionId=permissionId, transferOwnership=True, body=body, fields='')
|
||||
kvList = [Ent.USER, user, entityType, fileDesc]
|
||||
entityModifierNewValueItemValueListActionPerformed(kvList, Act.MODIFIER_FROM, None, [Ent.USER, oldOwner], l, lcount)
|
||||
@@ -66738,7 +66792,6 @@ def claimOwnership(users):
|
||||
fileId=xferFileId, sendNotificationEmail=False, body=bodyAdd, fields='')
|
||||
callGAPI(sourceDrive.permissions(), 'update',
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND],
|
||||
enforceExpansiveAccess=enforceExpansiveAccess,
|
||||
fileId=xferFileId, permissionId=permissionId, transferOwnership=True, body=body, fields='')
|
||||
entityModifierNewValueItemValueListActionPerformed(kvList, Act.MODIFIER_FROM, None, [Ent.USER, oldOwner], l, lcount)
|
||||
_processRetainedRole(user, i, count, oldOwner, entityType, xferFileId, fileDesc, l, lcount)
|
||||
@@ -67291,7 +67344,7 @@ def doCreateDriveFileACL():
|
||||
|
||||
# gam [<UserTypeEntity>] update drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail> [asadmin]
|
||||
# (role <DriveFileACLRole>) [expiration <Time>] [removeexpiration [<Boolean>]]
|
||||
# [updatesheetprotectedranges [<Boolean>]] [enforceexpansiveaccess [<Boolean>]]
|
||||
# [updatesheetprotectedranges [<Boolean>]]
|
||||
# [showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])]
|
||||
def updateDriveFileACLs(users, useDomainAdminAccess=False):
|
||||
def _showResult(permission, showAction):
|
||||
@@ -67319,7 +67372,6 @@ def updateDriveFileACLs(users, useDomainAdminAccess=False):
|
||||
|
||||
fileIdEntity = getDriveFileEntity()
|
||||
isEmail, permissionId = getPermissionId()
|
||||
enforceExpansiveAccess = GC.Values[GC.ENFORCE_EXPANSIVE_ACCESS]
|
||||
removeExpiration = showTitles = updateSheetProtectedRanges = False
|
||||
showDetails = True
|
||||
csvPF = None
|
||||
@@ -67337,8 +67389,6 @@ def updateDriveFileACLs(users, useDomainAdminAccess=False):
|
||||
showTitles = True
|
||||
elif myarg == 'updatesheetprotectedranges':
|
||||
updateSheetProtectedRanges = getBoolean()
|
||||
elif myarg == 'enforceexpansiveaccess':
|
||||
enforceExpansiveAccess = getBoolean()
|
||||
elif myarg == 'nodetails':
|
||||
showDetails = False
|
||||
elif myarg == 'csv':
|
||||
@@ -67393,7 +67443,7 @@ def updateDriveFileACLs(users, useDomainAdminAccess=False):
|
||||
permission = callGAPI(drive.permissions(), 'update',
|
||||
bailOnInternalError=True,
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_UPDATE_ACL_THROW_REASONS+[GAPI.FILE_NEVER_WRITABLE],
|
||||
useDomainAdminAccess=useDomainAdminAccess, enforceExpansiveAccess=enforceExpansiveAccess,
|
||||
useDomainAdminAccess=useDomainAdminAccess,
|
||||
fileId=fileId, permissionId=permissionId, removeExpiration=removeExpiration,
|
||||
transferOwnership=body.get('role', '') == 'owner', body=body, fields='*', supportsAllDrives=True)
|
||||
_showResult(permission, True)
|
||||
@@ -67622,12 +67672,11 @@ def doCreatePermissions():
|
||||
createDriveFilePermissions([_getAdminEmail()], True)
|
||||
|
||||
# gam [<UserTypeEntity>] delete drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail> [asadmin]
|
||||
# [updatesheetprotectedranges [<Boolean>]] [enforceexpansiveaccess [<Boolean>]]
|
||||
# [updatesheetprotectedranges [<Boolean>]]
|
||||
# [showtitles]
|
||||
def deleteDriveFileACLs(users, useDomainAdminAccess=False):
|
||||
fileIdEntity = getDriveFileEntity()
|
||||
isEmail, permissionId = getPermissionId()
|
||||
enforceExpansiveAccess = GC.Values[GC.ENFORCE_EXPANSIVE_ACCESS]
|
||||
showTitles = updateSheetProtectedRanges = False
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
@@ -67635,8 +67684,6 @@ def deleteDriveFileACLs(users, useDomainAdminAccess=False):
|
||||
showTitles = getBoolean()
|
||||
elif myarg == 'updatesheetprotectedranges':
|
||||
updateSheetProtectedRanges = getBoolean()
|
||||
elif myarg == 'enforceexpansiveaccess':
|
||||
enforceExpansiveAccess = getBoolean()
|
||||
elif myarg in ADMIN_ACCESS_OPTIONS:
|
||||
useDomainAdminAccess = True
|
||||
else:
|
||||
@@ -67673,16 +67720,17 @@ def deleteDriveFileACLs(users, useDomainAdminAccess=False):
|
||||
if not sheet:
|
||||
break
|
||||
callGAPI(drive.permissions(), 'delete',
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_DELETE_ACL_THROW_REASONS+[GAPI.FILE_NEVER_WRITABLE],
|
||||
useDomainAdminAccess=useDomainAdminAccess, enforceExpansiveAccess=enforceExpansiveAccess,
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_DELETE_ACL_THROW_REASONS,
|
||||
useDomainAdminAccess=useDomainAdminAccess,
|
||||
fileId=fileId, permissionId=permissionId, supportsAllDrives=True)
|
||||
entityActionPerformed([Ent.USER, user, entityType, fileName, Ent.PERMISSION_ID, permissionId], j, jcount)
|
||||
if updateSheetProtectedRanges and mimeType == MIMETYPE_GA_SPREADSHEET:
|
||||
_updateSheetProtectedRangesACLchange(sheet, user, i, count, j, jcount, fileId, fileName, False, permission)
|
||||
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError,
|
||||
GAPI.fileNeverWritable, GAPI.badRequest, GAPI.cannotRemoveOwner,
|
||||
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError, GAPI.invalid,
|
||||
GAPI.badRequest, GAPI.cannotRemoveOwner,
|
||||
GAPI.cannotModifyInheritedTeamDrivePermission, GAPI.cannotModifyInheritedPermission,
|
||||
GAPI.insufficientAdministratorPrivileges, GAPI.sharingRateLimitExceeded, GAPI.cannotDeletePermission) as e:
|
||||
GAPI.insufficientAdministratorPrivileges, GAPI.sharingRateLimitExceeded, GAPI.cannotDeletePermission,
|
||||
GAPI.fileNeverWritable) as e:
|
||||
entityActionFailedWarning([Ent.USER, user, entityType, fileName], str(e), j, jcount)
|
||||
except GAPI.notFound as e:
|
||||
entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE, fileName], str(e), j, jcount)
|
||||
@@ -67698,7 +67746,6 @@ def doDeleteDriveFileACLs():
|
||||
|
||||
# gam [<UserTypeEntity>] delete permissions <DriveFileEntity> <DriveFilePermissionIDEntity> [asadmin]
|
||||
# <PermissionMatch>* [<PermissionMatchAction>]
|
||||
# [enforceexpansiveaccess [<Boolean>]]
|
||||
def deletePermissions(users, useDomainAdminAccess=False):
|
||||
def convertJSONPermissions(jsonPermissions):
|
||||
permissionIds = []
|
||||
@@ -67733,13 +67780,14 @@ def deletePermissions(users, useDomainAdminAccess=False):
|
||||
callGAPI(drive.permissions(), 'delete',
|
||||
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_DELETE_ACL_THROW_REASONS,
|
||||
retryReasons=[GAPI.SERVICE_LIMIT],
|
||||
useDomainAdminAccess=useDomainAdminAccess, enforceExpansiveAccess=enforceExpansiveAccess,
|
||||
useDomainAdminAccess=useDomainAdminAccess,
|
||||
fileId=ri[RI_ENTITY], permissionId=ri[RI_ITEM], supportsAllDrives=True)
|
||||
entityActionPerformed([Ent.DRIVE_FILE_OR_FOLDER_ID, ri[RI_ENTITY], Ent.PERMISSION_ID, ri[RI_ITEM]], int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError,
|
||||
GAPI.badRequest, GAPI.cannotRemoveOwner,
|
||||
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError, GAPI.invalid,
|
||||
GAPI.badRequest, GAPI.notFound, GAPI.permissionNotFound, GAPI.cannotRemoveOwner,
|
||||
GAPI.cannotModifyInheritedTeamDrivePermission, GAPI.cannotModifyInheritedPermission,
|
||||
GAPI.insufficientAdministratorPrivileges, GAPI.sharingRateLimitExceeded, GAPI.permissionNotFound, GAPI.cannotDeletePermission,
|
||||
GAPI.insufficientAdministratorPrivileges, GAPI.sharingRateLimitExceeded, GAPI.cannotDeletePermission,
|
||||
GAPI.fileNeverWritable,
|
||||
GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
|
||||
entityActionFailedWarning([Ent.DRIVE_FILE_OR_FOLDER_ID, ri[RI_ENTITY], Ent.PERMISSION_ID, ri[RI_ITEM]], str(e), int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||
if int(ri[RI_J]) == int(ri[RI_JCOUNT]):
|
||||
@@ -67755,15 +67803,12 @@ def deletePermissions(users, useDomainAdminAccess=False):
|
||||
jsonData = getJSON([])
|
||||
PM = PermissionMatch()
|
||||
PM.SetDefaultMatch(False, {'role': 'owner'})
|
||||
enforceExpansiveAccess = GC.Values[GC.ENFORCE_EXPANSIVE_ACCESS]
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if myarg in ADMIN_ACCESS_OPTIONS:
|
||||
useDomainAdminAccess = True
|
||||
elif PM and PM.ProcessArgument(myarg):
|
||||
pass
|
||||
elif myarg == 'enforceexpansiveaccess':
|
||||
enforceExpansiveAccess = getBoolean()
|
||||
else:
|
||||
unknownArgumentExit()
|
||||
_checkFileIdEntityDomainAccess(fileIdEntity, useDomainAdminAccess)
|
||||
|
||||
@@ -171,8 +171,6 @@ EMAIL_BATCH_SIZE = 'email_batch_size'
|
||||
ENABLE_DASA = 'enable_dasa'
|
||||
# Enable Cloud Session Reauthentication by borrowing a RAPT token from gcloud command
|
||||
ENABLE_GCLOUD_REAUTH = 'enable_gcloud_reauth'
|
||||
# Value for enforceExpansiveAccess for commands that delete or update drive file ACLs/permissions.
|
||||
ENFORCE_EXPANSIVE_ACCESS = 'enforce_expansive_access'
|
||||
# When retrieving lists of calendar events from API, how many should be retrieved in each chunk
|
||||
EVENT_MAX_RESULTS = 'event_max_results'
|
||||
# Path to extra_args.txt
|
||||
@@ -398,7 +396,6 @@ Defaults = {
|
||||
DEVICE_MAX_RESULTS: '200',
|
||||
DOMAIN: '',
|
||||
DRIVE_DIR: '',
|
||||
ENFORCE_EXPANSIVE_ACCESS: TRUE,
|
||||
DRIVE_MAX_RESULTS: '1000',
|
||||
EMAIL_BATCH_SIZE: '50',
|
||||
ENABLE_DASA: FALSE,
|
||||
@@ -573,7 +570,6 @@ VAR_INFO = {
|
||||
DEVICE_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 200)},
|
||||
DOMAIN: {VAR_TYPE: TYPE_STRING, VAR_ENVVAR: 'GA_DOMAIN', VAR_LIMITS: (0, None)},
|
||||
DRIVE_DIR: {VAR_TYPE: TYPE_DIRECTORY, VAR_ENVVAR: 'GAMDRIVEDIR'},
|
||||
ENFORCE_EXPANSIVE_ACCESS: {VAR_TYPE: TYPE_BOOLEAN},
|
||||
DRIVE_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 1000)},
|
||||
EMAIL_BATCH_SIZE: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 100)},
|
||||
ENABLE_DASA: {VAR_TYPE: TYPE_BOOLEAN, VAR_SIGFILE: 'enabledasa.txt', VAR_SFFT: (FALSE, TRUE)},
|
||||
|
||||
@@ -257,10 +257,10 @@ DRIVE3_UPDATE_ACL_THROW_REASONS = [BAD_REQUEST, INVALID_OWNERSHIP_TRANSFER, CANN
|
||||
CANNOT_UPDATE_PERMISSION,
|
||||
CANNOT_MODIFY_INHERITED_TEAMDRIVE_PERMISSION, CANNOT_MODIFY_INHERITED_PERMISSION,
|
||||
FIELD_NOT_WRITABLE, PERMISSION_NOT_FOUND]
|
||||
DRIVE3_DELETE_ACL_THROW_REASONS = [BAD_REQUEST, CANNOT_REMOVE_OWNER,
|
||||
DRIVE3_DELETE_ACL_THROW_REASONS = [BAD_REQUEST, NOT_FOUND, PERMISSION_NOT_FOUND, CANNOT_REMOVE_OWNER,
|
||||
CANNOT_MODIFY_INHERITED_TEAMDRIVE_PERMISSION, CANNOT_MODIFY_INHERITED_PERMISSION,
|
||||
INSUFFICIENT_ADMINISTRATOR_PRIVILEGES, SHARING_RATE_LIMIT_EXCEEDED,
|
||||
NOT_FOUND, PERMISSION_NOT_FOUND, CANNOT_DELETE_PERMISSION]
|
||||
CANNOT_DELETE_PERMISSION, FILE_NEVER_WRITABLE]
|
||||
DRIVE3_MODIFY_LABEL_THROW_REASONS = DRIVE_USER_THROW_REASONS+[FILE_NOT_FOUND, NOT_FOUND, FORBIDDEN, INTERNAL_ERROR,
|
||||
FILE_NEVER_WRITABLE, APPLY_LABEL_FORBIDDEN,
|
||||
INSUFFICIENT_ADMINISTRATOR_PRIVILEGES, INSUFFICIENT_FILE_PERMISSIONS,
|
||||
|
||||
@@ -94,7 +94,7 @@ _SKUS = {
|
||||
'1010430001': {
|
||||
'product': '101043', 'aliases': ['gwas', 'plusstorage'], 'displayName': 'Google Workspace Additional Storage'},
|
||||
'1010470001': {
|
||||
'product': '101047', 'aliases': ['geminient', 'duetai'], 'displayName': 'Gemini Enterprise'},
|
||||
'product': '101047', 'aliases': ['geminient', 'duetai'], 'displayName': 'Gemini Enterprise - Legacy'},
|
||||
'1010470002': {
|
||||
'product': '101047', 'aliases': ['gwlabs', 'workspacelabs'], 'displayName': 'Google Workspace Labs'},
|
||||
'1010470003': {
|
||||
@@ -109,6 +109,8 @@ _SKUS = {
|
||||
'product': '101047', 'aliases': ['aimeetingsandmessaging'], 'displayName': 'AI Meetings and Messaging'},
|
||||
'1010470008': {
|
||||
'product': '101047', 'aliases': ['geminiultra'], 'displayName': 'Google AI Ultra for Business'},
|
||||
'1010470009': {
|
||||
'product': '101047', 'aliases': ['aiexpandedaccess'], 'displayName': 'AI Expanded Access'},
|
||||
'1010490001': {
|
||||
'product': '101049', 'aliases': ['eeu'], 'displayName': 'Endpoint Education Upgrade'},
|
||||
'1010500001': {
|
||||
|
||||
@@ -10,6 +10,54 @@ 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.39.03
|
||||
|
||||
Added the following options to `gam <UserTypeEntity> create chatspace` that can be used to capture
|
||||
space details when creating chat spaces in bulk.
|
||||
```
|
||||
csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]] (addcsvdata <FieldName> <String>)*
|
||||
```
|
||||
|
||||
See: https://github.com/GAM-team/GAM/wiki/Users-Chat#bulk-build-chat-spaces
|
||||
|
||||
### 7.39.02
|
||||
|
||||
Fixed progress messages for `gam <UserTypeEntity> print filelist` when permissions were being
|
||||
displayed/matched for Shared Drives.
|
||||
|
||||
### 7.39.01
|
||||
|
||||
Updated `gam <UserTypeEntity> transfer drive <UserItem>` to handle the following error:
|
||||
```
|
||||
ERROR: 403: cannotDeletePermission - The authenticated user cannot delete the permission.
|
||||
```
|
||||
|
||||
### 7.39.00
|
||||
|
||||
Deleted variable `enforce_expansive_access` from `gam.cfg` and removed option `enforceexpansiveaccess`
|
||||
from the following commands as expansive access is now always enforced by Google on My Drives.
|
||||
```
|
||||
gam <UserTypeEntity> delete permissions
|
||||
gam <UserTypeEntity> delete drivefileacl
|
||||
gam <UserTypeEntity> update drivefileacl
|
||||
gam <UserTypeEntity> copy drivefile
|
||||
gam <UserTypeEntity> move drivefile
|
||||
gam <UserTypeEntity> transfer ownership
|
||||
gam <UserTypeEntity> claim ownership
|
||||
```
|
||||
|
||||
### 7.38.02
|
||||
|
||||
Added license SKU `1010470009` for `AI Expanded Access`; abbreviation `aiexpandedaccess`.
|
||||
|
||||
Renamed license SKU `1010470001` from `Gemini Enterprise` to `Gemini Enterprise - Legacy`.
|
||||
|
||||
### 7.38.01
|
||||
|
||||
Added `root` as a synonym for '/' in command line arguments that specify an OU.
|
||||
This is to avoid issues where a stand-alone `/` on the command line may be mis-interpreted
|
||||
by the command line interpreter as a reference to the file system root.
|
||||
|
||||
### 7.38.00
|
||||
|
||||
Added variable `gcp_org_id` to `gam.cfg` that is used by the following commands;
|
||||
@@ -23,14 +71,14 @@ gam print|show tokens gcpdetails
|
||||
```
|
||||
You can get and set the `gam.cfg/gcp_org_id` value with these commands:
|
||||
```
|
||||
$ gam info gcporgid
|
||||
$ gam info gcporgid
|
||||
organizations/906207637890
|
||||
$ gam config gcp_org_id organizations/906207637890 save
|
||||
```
|
||||
|
||||
You can get and set the `gam.cfg/customer_id` value with these commands:
|
||||
```
|
||||
$ gam info customerid
|
||||
$ gam info customerid
|
||||
C78abc9de
|
||||
$ gam config customer_id C78abc9de save
|
||||
```
|
||||
|
||||
@@ -251,7 +251,7 @@ writes the credentials into the file oauth2.txt.
|
||||
```
|
||||
gamteam@server:/Users/gamteam$ rm -f /Users/gamteam/GAMConfig/oauth2.txt
|
||||
gamteam@server:/Users/gamteam$ gam version
|
||||
GAM 7.38.00 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.39.03 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
macOS Tahoe 26.3.1 arm64
|
||||
@@ -1034,7 +1034,7 @@ writes the credentials into the file oauth2.txt.
|
||||
```
|
||||
C:\>del C:\GAMConfig\oauth2.txt
|
||||
C:\>gam version
|
||||
GAM 7.38.00 - https://github.com/GAM-team/GAM - pythonsource
|
||||
GAM 7.39.03 - https://github.com/GAM-team/GAM - pythonsource
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
Windows 11 10.0.26200 AMD64
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
|
||||
| License Name | License SKU | Abbreviation |
|
||||
|--------------|-------------|---------------|
|
||||
| AI Expanded Access | 1010470009 | aiexpandedaccess |
|
||||
| AI Meetings and Messaging | 1010470007 | aimeetingsandmessaging |
|
||||
| AI Security | 1010470006 | aisecurity |
|
||||
| AppSheet Core | 1010380001 | appsheetcore |
|
||||
@@ -61,7 +62,7 @@
|
||||
| G Suite Lite | Google-Apps-Lite | gsuitelite |
|
||||
| Gemini Business | 1010470003 | geminibiz
|
||||
| Gemini Education Premium | 1010470005 | geminiedupremium |
|
||||
| Gemini Enterprise | 1010470001 | geminient | duetai |
|
||||
| Gemini Enterprise - Legacy | 1010470001 | geminient | duetai |
|
||||
| Google AI Pro for Education | 1010470004 | gaiproedu |
|
||||
| Google AI Ultra for Business | 1010470008 | geminiultra |
|
||||
| Google Apps Message Security | Google-Apps-For-Postini | postini |
|
||||
@@ -152,6 +153,7 @@
|
||||
4tb | drive4tb | googledrivestorage4tb | Google-Drive-storage-4TB |
|
||||
8tb | drive8tb | googledrivestorage8tb | Google-Drive-storage-8TB |
|
||||
16tb | drive16tb | googledrivestorage16tb | Google-Drive-storage-16TB |
|
||||
aiexpandedaccess | 1010470009 | AI Expanded Access |
|
||||
aimeetingsandmessaging | 1010470007 | AI Meetings and Messaging |
|
||||
aisecurity | 1010470006 | AI Security |
|
||||
appsheetcore | 1010380001 | AppSheet Core |
|
||||
@@ -170,7 +172,7 @@
|
||||
gaiproedu | geminiedu | 1010470004 | Google AI Pro for Education |
|
||||
geminibiz | 1010470003 | Gemini Business |
|
||||
geminiedupremium| 1010470005 | Gemini Education Premium |
|
||||
geminient| duetai | 1010470001 | Gemini Enterprise |
|
||||
geminient| duetai | 1010470001 | Gemini Enterprise - Legacy|
|
||||
geminiultra | 1010470008 | Google AI Ultra for Business |
|
||||
gsuitebasic | gafb | gafw | basic | Google-Apps-For-Business |
|
||||
gsuitebusiness | gau | gsb | unlimited | Google-Apps-Unlimited |
|
||||
|
||||
@@ -44,6 +44,7 @@ Thanks to Duncan Isaksen-Loxton for a script to help manage multiple domains.
|
||||
4tb | drive4tb | googledrivestorage4tb | Google-Drive-storage-4TB |
|
||||
8tb | drive8tb | googledrivestorage8tb | Google-Drive-storage-8TB |
|
||||
16tb | drive16tb | googledrivestorage16tb | Google-Drive-storage-16TB |
|
||||
aiexpandedaccess | 1010470009 | AI Expanded Access |
|
||||
aimeetingsandmessaging | 1010470007 | AI Meetings and Messaging |
|
||||
aisecurity | 1010470006 | AI Security |
|
||||
appsheetcore | 1010380001 | AppSheet Core |
|
||||
@@ -61,7 +62,7 @@ Thanks to Duncan Isaksen-Loxton for a script to help manage multiple domains.
|
||||
geminibiz | 1010470003 | Gemini Business |
|
||||
geminiedu | 1010470004 | Gemini Education |
|
||||
geminiedupremium| 1010470005 | Gemini Education Premium |
|
||||
geminient| duetai | 1010470001 | Gemini Enterprise |
|
||||
geminient| duetai | 1010470001 | Gemini Enterprise - Legacy |
|
||||
gsuitebasic | gafb | gafw | basic | Google-Apps-For-Business |
|
||||
gsuitebusiness | gau | gsb | unlimited | Google-Apps-Unlimited |
|
||||
gsuitebusinessarchived | gsbau | businessarchived | 1010340002 | Google Workspace Business - Archived User |
|
||||
|
||||
@@ -211,16 +211,14 @@ gam <UserTypeEntity> create chatspace
|
||||
[members <UserTypeEntity>]
|
||||
[displayname <String>]
|
||||
[description <String>] [guidelines <String>]
|
||||
[history <Boolean>]
|
||||
[<ChatContent>]
|
||||
[formatjson|returnidonly]
|
||||
```
|
||||
For `type space`, the following apply:
|
||||
* `members <UserTypeEntity>` - Optional, can not specify more that 20 users
|
||||
* `members <UserTypeEntity>` - Optional, can not specify more than 20 users
|
||||
* `displayname <String>` - Required
|
||||
* `description <String>` - Optional
|
||||
* `guidelines <String>` - Optional
|
||||
* `history <Boolean>` - Optional
|
||||
* `announcement|collaboration` - Initial permission settings; default is `collaboration`
|
||||
|
||||
For `type groupchat`, the following apply:
|
||||
@@ -228,23 +226,60 @@ For `type groupchat`, the following apply:
|
||||
* `displayname <String>` - Ignored
|
||||
* `description <String>` - Optional
|
||||
* `guidelines <String>` - Optional
|
||||
* `history <Boolean>` - Optional
|
||||
|
||||
For `type directmessage`, the following apply:
|
||||
* `members <UserTypeEntity>` - Required, must specify 1 user
|
||||
* `displayname <String>` - Ignored
|
||||
* `description <String>` - Ignored
|
||||
* `guidelines <String>` - Ignored
|
||||
* `history <Boolean>` - Optional
|
||||
|
||||
By default, Gam displays the information about the created chatspace as an indented list of keys and values.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
* `returnidonly` - Display the chatspace name only
|
||||
|
||||
Alternately, you can display the information about the created chatspace as columns of fields.
|
||||
* `csv [todrive <ToDriveAttribute>*]` - Write Chat Space information to a CSV file.
|
||||
* `addcsvdata <FieldName> <String>` - Add additional columns of data from the command line to the output
|
||||
|
||||
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
|
||||
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
|
||||
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.
|
||||
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
|
||||
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
|
||||
|
||||
Use the `<ChatContent>` option to send an initial message to the created chatspace.
|
||||
|
||||
By default, details about the chatmessage are displayed.
|
||||
* `formatjson` - Display the chat message name in JSON format.
|
||||
* `returnidonly` - Display the chatmessage name only
|
||||
* `csv` - The column `message.name` is added the CSV file output
|
||||
|
||||
### Bulk build chat spaces
|
||||
You want to create Chat Spaces for use by users that don't currently have Chat enabled;
|
||||
all commands will be run by a super admin.
|
||||
|
||||
Make a CSV file NewSpaces.csv with columns: displayName,manager,members
|
||||
```
|
||||
displayName,manager,members
|
||||
Chat 123,user1@domain.com,user1@domain.com user2@domain.com user3@domain.com
|
||||
Chat 456,user4@domain.com,user4@domain.com user5@domain.com user6@domain.com
|
||||
```
|
||||
The manager column specifies the member that will be updated to be a manager.
|
||||
|
||||
Create the spaces
|
||||
```
|
||||
gam redirect csv ./NewSpaceDetails.csv multiprocess csv NewSpaces.csv gam user admin@domain.com create chatspace type space collaboration displayname "~displayName" members "~members" csv addcsvdata manager "~manager"
|
||||
```
|
||||
|
||||
Update the specified member from ROLE_MEMBER to ROLE_MANAGER
|
||||
```
|
||||
gam redirect stdout ./UpdateMemberToManager.txt multiprocess redirect stderr stdout csv NewSpaceDetails.csv gam user admin@domain.com update chatmember "~name" role manager user "~manager"
|
||||
```
|
||||
|
||||
Delete the super admin from the space
|
||||
```
|
||||
gam redirect stdout ./DeleteAdmin.txt multiprocess redirect stderr stdout csv NewSpaceDetails.csv gam user admin@domain.com delete chatmember "~name" user admin@domain.com
|
||||
```
|
||||
|
||||
### Update a user's chat space
|
||||
```
|
||||
|
||||
@@ -140,7 +140,6 @@ gam <UserTypeEntity> copy drivefile <DriveFileEntity>
|
||||
(mappermissionsdomain <DomainName> <DomainName>)*
|
||||
[sendemailifrequired [<Boolean>]]
|
||||
[verifyorganizer [<Boolean>]]
|
||||
[enforceexpansiveaccess [<Boolean>]]
|
||||
```
|
||||
The files/folders specified by `<DriveFileEntity>` are referred to as `source`, `target` refers to where those files are being copied.
|
||||
The files/folders specified by `<DriveFileEntity>` are referred to as `top`; when a folder is being copied recursively, the files/folders that it contains are referred as `sub`.
|
||||
@@ -590,7 +589,6 @@ gam <UserTypeEntity> move drivefile <DriveFileEntity> [newfilename <DriveFileNam
|
||||
[retainsourcefolders [<Boolean>]]
|
||||
[sendemailifrequired [<Boolean>]]
|
||||
[verifyorganizer [<Boolean>]]
|
||||
[enforceexpansiveaccess [<Boolean>]]
|
||||
```
|
||||
The files/folders specified by `<DriveFileEntity>` are referred to as `source`, `target` refers to where those files are being moved.
|
||||
The files/folders specified by `<DriveFileEntity>` are referred to as `top`; when a folder is being moved, the files/folders that it contains are referred as `sub`.
|
||||
|
||||
@@ -61,7 +61,6 @@ Use [Users - Drive - Transfer](Users-Drive-Transfer) for more complex ownership
|
||||
```
|
||||
gam <UserTypeEntity> transfer ownership <DriveFileEntity> <UserItem>
|
||||
[<DriveFileParentAttribute>] [includetrashed] [norecursion [<Boolean>]]
|
||||
[enforceexpansiveaccess [<Boolean>]]
|
||||
(orderby <DriveOrderByFieldName> [ascending|descending])*
|
||||
[preview] [filepath] [pathdelimiter <Character>] [buildtree] [todrive <ToDriveAttribute>*]
|
||||
```
|
||||
@@ -101,7 +100,6 @@ gam <UserTypeEntity> claim ownership <DriveFileEntity>
|
||||
[skipids <DriveFileEntity>] [onlyusers|skipusers <UserTypeEntity>] [subdomains <DomainNameEntity>]
|
||||
[restricted [<Boolean>]] [writerscanshare|writerscantshare [<Boolean>]]
|
||||
[keepuser | (retainrole reader|commenter|writer|editor|none)] [noretentionmessages]
|
||||
[enforceexpansiveaccess [<Boolean>]]
|
||||
(orderby <DriveOrderByFieldName> [ascending|descending])*
|
||||
[preview] [filepath] [pathdelimiter <Character>] [buildtree] [todrive <ToDriveAttribute>*]
|
||||
```
|
||||
|
||||
@@ -220,7 +220,7 @@ By default, when an ACL is created, GAM outputs details of the ACL as indented k
|
||||
```
|
||||
gam <UserTypeEntity> update drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail>
|
||||
(role <DriveFileACLRole>) [expiration <Time>] [removeexpiration [<Boolean>]]
|
||||
[updatesheetprotectedranges [<Boolean>]] [enforceexpansiveaccess [<Boolean>]]
|
||||
[updatesheetprotectedranges [<Boolean>]]
|
||||
[showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])]
|
||||
```
|
||||
There is no change of parents when a new user is updated to be a file's owner.
|
||||
@@ -236,10 +236,7 @@ The option `updatesheetprotectedranges` only applies to items in `<DriveFileEnti
|
||||
* ACLs with role reader or commenter will be removed from existing protected ranges
|
||||
* ACLs with role writer or higher will be added to existing protected ranges
|
||||
|
||||
`enforceexpansiveaccess` defaults to the value of `gam.cfg/enforce_expansive_access` that controls
|
||||
the ability to update inherited ACLs.
|
||||
* False - Inherited ACLs can be updated
|
||||
* True = Inherited ACLs can not be updated
|
||||
Inherited ACLs can not be updated.
|
||||
|
||||
By default, the file ID is displayed in the output; to see the file name, use the `showtitles`
|
||||
option; this requires an additional API call per file.
|
||||
@@ -251,7 +248,7 @@ By default, when an ACL is updated, GAM outputs details of the ACL as indented k
|
||||
### Delete
|
||||
```
|
||||
gam <UserTypeEntity> delete|del drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail>
|
||||
[updatesheetprotectedranges [<Boolean>]] [enforceexpansiveaccess [<Boolean>]]
|
||||
[updatesheetprotectedranges [<Boolean>]]
|
||||
[showtitles]
|
||||
```
|
||||
The option `updatesheetprotectedranges` only applies to items in `<DriveFileEntity>` that are Google Sheets.
|
||||
@@ -261,10 +258,7 @@ The option `updatesheetprotectedranges` only applies to items in `<DriveFileEnti
|
||||
* Sheet Protected Ranges are updated to reflect the deleted ACL; additional API calls are required.
|
||||
* ACLs with any role will be removed from existing protected ranges
|
||||
|
||||
`enforceexpansiveaccess` defaults to the value of `gam.cfg/enforce_expansive_access` that controls
|
||||
the ability to delete inherited ACLs.
|
||||
* False - Inherited ACLs can be deleted
|
||||
* True = Inherited ACLs can not be deleted
|
||||
Inherited ACLs can not be deleted.
|
||||
|
||||
By default, the file ID is displayed in the output; to see the file name, use the `showtitles`
|
||||
option; this requires an additional API call per file.
|
||||
@@ -306,12 +300,8 @@ When adding permissions from JSON data, permissions with `deleted` true are neve
|
||||
```
|
||||
gam <UserTypeEntity> delete permissions <DriveFileEntity> <DriveFilePermissionIDEntity>
|
||||
<PermissionMatch>* [<PermissionMatchAction>]
|
||||
[enforceexpansiveaccess [<Boolean>]]
|
||||
```
|
||||
`enforceexpansiveaccess` defaults to the value of `gam.cfg/enforce_expansive_access` that controls
|
||||
the ability to delete inherited ACLs.
|
||||
* False - Inherited ACLs can be deleted
|
||||
* True = Inherited ACLs can not be deleted
|
||||
Inherited ACLs can not be deleted.
|
||||
|
||||
When deleting permissions from JSON data, permissions with role `owner` true are never processed.
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@ gam <UserTypeEntity> transfer drive <UserItem> [select <DriveFileEntity>]
|
||||
[noretentionmessages]
|
||||
[nonowner_retainrole reader|commenter|writer|editor|contentmanager|fileorganizer|current|none]
|
||||
[nonowner_targetrole reader|commenter|writer|editor|contentmanager|fileorganizer|current|none|source]
|
||||
[enforceexpansiveaccess [<Boolean>]]
|
||||
(orderby <DriveFileOrderByFieldName> [ascending|descending])*
|
||||
[preview] [todrive <ToDriveAttribute>*]
|
||||
```
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Print the current version of Gam with details
|
||||
```
|
||||
gam version
|
||||
GAM 7.38.00 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.39.03 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
macOS Tahoe 26.3.1 arm64
|
||||
@@ -15,7 +15,7 @@ Time: 2026-02-15T07:51:00-08:00
|
||||
Print the current version of Gam with details and time offset information
|
||||
```
|
||||
gam version timeoffset
|
||||
GAM 7.38.00 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.39.03 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
macOS Tahoe 26.3.1 arm64
|
||||
@@ -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.38.00 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.39.03 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
macOS Tahoe 26.3.1 arm64
|
||||
@@ -68,7 +68,7 @@ MacOS High Sierra 10.13.6 x86_64
|
||||
Path: /Users/gamteam/bin/gam7
|
||||
Version Check:
|
||||
Current: 5.35.08
|
||||
Latest: 7.38.00
|
||||
Latest: 7.39.03
|
||||
echo $?
|
||||
1
|
||||
```
|
||||
@@ -76,7 +76,7 @@ echo $?
|
||||
Print the current version number without details
|
||||
```
|
||||
gam version simple
|
||||
7.38.00
|
||||
7.39.03
|
||||
```
|
||||
In Linux/MacOS you can do:
|
||||
```
|
||||
@@ -86,7 +86,7 @@ echo $VER
|
||||
Print the current version of Gam and address of this Wiki
|
||||
```
|
||||
gam help
|
||||
GAM 7.38.00 - https://github.com/GAM-team/GAM
|
||||
GAM 7.39.03 - https://github.com/GAM-team/GAM
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
macOS Tahoe 26.3.1 arm64
|
||||
|
||||
@@ -355,17 +355,6 @@ enable_dasa
|
||||
admin_email, customer_id and domain must be set when enable_dasa is True,
|
||||
customer_id may not be set to my_customer
|
||||
Signal file: OldGamPath/enabledasa.txt
|
||||
enforce_expansive_access
|
||||
The default value for option `enforceexpansiveaccess` in all commands that delete or update
|
||||
drive file ACLs/permissions.
|
||||
gam <UserTypeEntity> delete permissions
|
||||
gam <UserTypeEntity> delete drivefileacl
|
||||
gam <UserTypeEntity> update drivefileacl
|
||||
gam <UserTypeEntity> copy drivefile
|
||||
gam <UserTypeEntity> move drivefile
|
||||
gam <UserTypeEntity> transfer ownership
|
||||
gam <UserTypeEntity> claim ownership
|
||||
Default: True
|
||||
event_max_results
|
||||
When retrieving lists of Calendar events from API,
|
||||
how many should be retrieved in each API call
|
||||
@@ -1023,7 +1012,6 @@ drive_max_results = 1000
|
||||
email_batch_size = 50
|
||||
enable_dasa = false
|
||||
enable_gcloud_reauth = false
|
||||
enforce_expansive_access = true
|
||||
event_max_results = 250
|
||||
extra_args = ''
|
||||
gmail_cse_incert_dir = ''
|
||||
|
||||
Reference in New Issue
Block a user