Merge branch 'main' of https://github.com/GAM-team/GAM
Some checks failed
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-apis (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled

This commit is contained in:
Jay Lee
2025-02-26 14:04:41 +00:00
8 changed files with 1489 additions and 107 deletions

View File

@@ -18,7 +18,7 @@ defaults:
working-directory: src working-directory: src
env: env:
SCRATCH_COUNTER: 9 SCRATCH_COUNTER: 11
OPENSSL_CONFIG_OPTS: no-fips --api=3.0.0 OPENSSL_CONFIG_OPTS: no-fips --api=3.0.0
OPENSSL_INSTALL_PATH: ${{ github.workspace }}/bin/ssl OPENSSL_INSTALL_PATH: ${{ github.workspace }}/bin/ssl
OPENSSL_SOURCE_PATH: ${{ github.workspace }}/src/openssl OPENSSL_SOURCE_PATH: ${{ github.workspace }}/src/openssl
@@ -917,7 +917,7 @@ jobs:
$gam calendar $gam_user addevent summary "GHA test event" start +1h end +2h attendee $newgroup hangoutsmeet guestscanmodify true sendupdates all $gam calendar $gam_user addevent summary "GHA test event" start +1h end +2h attendee $newgroup hangoutsmeet guestscanmodify true sendupdates all
$gam calendar $gam_user printevents after -0d $gam calendar $gam_user printevents after -0d
$gam config enable_dasa false save $gam config enable_dasa false save
matterid=uid:$($gam create vaultmatter name "GHA matter $newbase" description "test matter" collaborators $newuser returnidonly) matterid=uid:$($gam create vaultmatter name "GHA matter $newbase" description "test matter" returnidonly)
$gam create vaulthold matter $matterid name "GHA hold $newbase" corpus mail accounts $newuser $gam create vaulthold matter $matterid name "GHA hold $newbase" corpus mail accounts $newuser
$gam print vaultmatters matterstate open $gam print vaultmatters matterstate open
$gam print vaultholds matter $matterid $gam print vaultholds matter $matterid

View File

@@ -3846,6 +3846,7 @@ gam info group|groups <GroupEntity>
[formatjson] [formatjson]
gam print groups [todrive <ToDriveAttribute>*] gam print groups [todrive <ToDriveAttribute>*]
[([domain|domains <DomainNameEntity>] ([member|showownedby <EmailItem>]|[(query <QueryGroup>)|(queries <QueryGroupList>)]))| [([domain|domains <DomainNameEntity>] ([member|showownedby <EmailItem>]|[(query <QueryGroup>)|(queries <QueryGroupList>)]))|
(group|group_ns|group_susp <GroupItem>)|
(select <GroupEntity>)] (select <GroupEntity>)]
[emailmatchpattern [not] <RegularExpression>] [namematchpattern [not] <RegularExpression>] [emailmatchpattern [not] <RegularExpression>] [namematchpattern [not] <RegularExpression>]
[descriptionmatchpattern [not] <RegularExpression>] (matchsetting [not] <GroupAttribute>)* [descriptionmatchpattern [not] <RegularExpression>] (matchsetting [not] <GroupAttribute>)*
@@ -3997,13 +3998,14 @@ gam print cigroups [todrive <ToDriveAttribute>*]
<CIGroupMembersFieldName> ::= <CIGroupMembersFieldName> ::=
createtime createtime
email|useremail|
expiretime| expiretime|
memberkey| memberkey|
name| name|
role| role|
type| type|
updatetime| updatetime
useremail
<CIGroupMembersFieldNameList> ::= "<CIGroupMembersFieldName>(,<CIGroupMembersFieldName>)*" <CIGroupMembersFieldNameList> ::= "<CIGroupMembersFieldName>(,<CIGroupMembersFieldName>)*"
gam <UserTypeEntity> info cimember <GroupEntity> gam <UserTypeEntity> info cimember <GroupEntity>
@@ -4017,16 +4019,19 @@ gam print cigroup-members [todrive <ToDriveAttribute>*]
[types <CIGroupMemberTypeList>] [types <CIGroupMemberTypeList>]
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>] [memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
<CIGroupMembersFieldName>* [fields <CIGroupMembersFieldNameList>] <CIGroupMembersFieldName>* [fields <CIGroupMembersFieldNameList>]
[(recursive [noduplicates])includederivedmembership] [nogroupeemail] [minimal|basic|full]
[(recursive [noduplicates]) | includederivedmembership] [nogroupemail]
[formatjson [quotechar <Character>]] [formatjson [quotechar <Character>]]
gam show cigroup-members gam show cigroup-members
[(cimember|ciowner <UserItem>)|(cigroup <GroupItem>)|(select <GroupEntity>)] [(cimember|ciowner <UserItem>)|(cigroup <GroupItem>)|(select <GroupEntity>)]
[showownedby <UserItem>] [showownedby <UserItem>]
[emailmatchpattern [not] <RegularExpression>] [namematchpattern [not] <RegularExpression>] [emailmatchpattern [not] <RegularExpression>] [namematchpattern [not] <RegularExpression>]
[descriptionmatchpattern [not] <RegularExpression>] [descriptionmatchpattern [not] <RegularExpression>]
[roles <GroupRoleList>] [members] [managers] [owners] [depth <Number>] [roles <GroupRoleList>] [members] [managers] [owners]
[types <CIGroupMemberTypeList>] [types <CIGroupMemberTypeList>]
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>] [memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
[minimal|basic|full]
[(depth <Number>) | includederivedmembership]
# Cloud Identity Devices # Cloud Identity Devices
@@ -4068,6 +4073,7 @@ gam show cigroup-members
releaseversion| releaseversion|
securitypatchtime| securitypatchtime|
serialnumber| serialnumber|
unifieddeviceid|
wifimacaddresses wifimacaddresses
<DeviceFieldNameList> ::= "<DeviceFieldName>(,<DeviceFieldName>)*" <DeviceFieldNameList> ::= "<DeviceFieldName>(,<DeviceFieldName>)*"
@@ -4469,6 +4475,7 @@ gam report <ActivityApplicationName> [todrive <ToDriveAttribute>*]
app_maker| app_maker|
apps_scripts| apps_scripts|
calendar| calendar|
chat|
classroom| classroom|
cros| cros|
device_management| device_management|
@@ -4489,6 +4496,7 @@ gam report customers|customer|domain [todrive <ToDriveAttribute>*]
<UserServiceName> ::= <UserServiceName> ::=
accounts| accounts|
chat|
classroom| classroom|
docs| docs|
drive| drive|
@@ -4959,6 +4967,7 @@ gam create|add permissions <SharedDriveEntityAdmin> <DriveFilePermissionEntity>
<PermissionMatch>* [<PermissionMatchAction>] <PermissionMatch>* [<PermissionMatchAction>]
gam delete permissions <SharedDriveEntityAdmin> <DriveFilePermissionIDEntity> gam delete permissions <SharedDriveEntityAdmin> <DriveFilePermissionIDEntity>
<PermissionMatch>* [<PermissionMatchAction>] <PermissionMatch>* [<PermissionMatchAction>]
[enforceexpansiveaccess [<Boolean>]]
In these commands, you specify an administrator and then indicate that you want domain administrator access with the adminaccess option. In these commands, you specify an administrator and then indicate that you want domain administrator access with the adminaccess option.
@@ -4972,9 +4981,11 @@ gam <UserTypeEntity> create|add drivefileacl <SharedDriveEntityAdmin>
adminaccess adminaccess
gam <UserTypeEntity> update drivefileacl <SharedDriveEntityAdmin> <DriveFilePermissionIDorEmail> gam <UserTypeEntity> update drivefileacl <SharedDriveEntityAdmin> <DriveFilePermissionIDorEmail>
(role <DriveFileACLRole>) [expires|expiration <Time>] [removeexpiration [<Boolean>]] (role <DriveFileACLRole>) [expires|expiration <Time>] [removeexpiration [<Boolean>]]
[enforceexpansiveaccess [<Boolean>]]
[showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])] [showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])]
adminaccess adminaccess
gam <UserTypeEntity> delete drivefileacl <SharedDriveEntityAdmin> <DriveFilePermissionIDorEmail> gam <UserTypeEntity> delete drivefileacl <SharedDriveEntityAdmin> <DriveFilePermissionIDorEmail>
[enforceexpansiveaccess [<Boolean>]]
[showtitles] adminaccess [showtitles] adminaccess
gam <UserTypeEntity> info drivefileacl <SharedDriveEntityAdmin> <DriveFilePermissionIDorEmail> adminaccess gam <UserTypeEntity> info drivefileacl <SharedDriveEntityAdmin> <DriveFilePermissionIDorEmail> adminaccess
[showtitles] [showtitles]
@@ -5000,6 +5011,7 @@ gam <UserTypeEntity> create|add permissions <SharedDriveEntityAdmin> <DriveFileP
<PermissionMatch>* [<PermissionMatchAction>] <PermissionMatch>* [<PermissionMatchAction>]
gam <UserTypeEntity> delete permissions <SharedDriveEntityAdmin> <DriveFilePermissionIDEntity> adminaccess gam <UserTypeEntity> delete permissions <SharedDriveEntityAdmin> <DriveFilePermissionIDEntity> adminaccess
<PermissionMatch>* [<PermissionMatchAction>] <PermissionMatch>* [<PermissionMatchAction>]
[enforceexpansiveaccess [<Boolean>]]
In these commands, the Google administrator named in oauth2.txt is used. In these commands, the Google administrator named in oauth2.txt is used.
@@ -6562,6 +6574,7 @@ gam <UserTypeEntity> copy drivefile <DriveFileEntity>
[sendemailifrequired [<Boolean>]] [sendemailifrequired [<Boolean>]]
[suppressnotselectedmessages [<Boolean>]] [suppressnotselectedmessages [<Boolean>]]
[verifyorganizer [<Boolean>]] [verifyorganizer [<Boolean>]]
[enforceexpansiveaccess [<Boolean>]]
gam <UserTypeEntity> move drivefile <DriveFileEntity> [newfilename <DriveFileName>] gam <UserTypeEntity> move drivefile <DriveFileEntity> [newfilename <DriveFileName>]
[summary [<Boolean>]] [showpermissionmessages [<Boolean>]] [summary [<Boolean>]] [showpermissionmessages [<Boolean>]]
@@ -6585,6 +6598,7 @@ gam <UserTypeEntity> move drivefile <DriveFileEntity> [newfilename <DriveFileNam
[retainsourcefolders [<Boolean>]] [retainsourcefolders [<Boolean>]]
[sendemailifrequired [<Boolean>]] [sendemailifrequired [<Boolean>]]
[verifyorganizer [<Boolean>]] [verifyorganizer [<Boolean>]]
[enforceexpansiveaccess [<Boolean>]]
gam <UserTypeEntity> get document <DriveFileEntity> gam <UserTypeEntity> get document <DriveFileEntity>
[viewmode default|suggestions_inline|preview_suggestions_accepted|preview_without_suggestions] [viewmode default|suggestions_inline|preview_suggestions_accepted|preview_without_suggestions]
@@ -6690,10 +6704,10 @@ gam <UserTypeEntity> create|add drivefileacl <DriveFileEntity> [adminaccess|asad
[showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])] [showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])]
gam <UserTypeEntity> update drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail> gam <UserTypeEntity> update drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail>
(role <DriveFileACLRole>) [expires|expiration <Time>] [removeexpiration [<Boolean>]] (role <DriveFileACLRole>) [expires|expiration <Time>] [removeexpiration [<Boolean>]]
[updatesheetprotectedranges [<Boolean>]] [updatesheetprotectedranges [<Boolean>]] [enforceexpansiveaccess [<Boolean>]]
[showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])] [showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])]
gam <UserTypeEntity> delete drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail> gam <UserTypeEntity> delete drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail>
[updatesheetprotectedranges [<Boolean>]] [updatesheetprotectedranges [<Boolean>]] [enforceexpansiveaccess [<Boolean>]]
[showtitles] [showtitles]
gam <UserTypeEntity> info drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail> gam <UserTypeEntity> info drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail>
[showtitles] [showtitles]
@@ -6817,6 +6831,7 @@ gam <UserTypeEntity> print filerevisions <DriveFileEntity> [todrive <ToDriveAttr
gam <UserTypeEntity> transfer ownership <DriveFileEntity> <UserItem> gam <UserTypeEntity> transfer ownership <DriveFileEntity> <UserItem>
[<DriveFileParentAttribute>] [includetrashed] [norecursion [<Boolean>]] [<DriveFileParentAttribute>] [includetrashed] [norecursion [<Boolean>]]
[enforceexpansiveaccess [<Boolean>]]
(orderby <DriveFileOrderByFieldName> [ascending|descending])* (orderby <DriveFileOrderByFieldName> [ascending|descending])*
[preview] [filepath] [pathdelimiter <Character>] [buildtree] [preview] [filepath] [pathdelimiter <Character>] [buildtree]
[todrive <ToDriveAttribute>*] [todrive <ToDriveAttribute>*]
@@ -6825,6 +6840,7 @@ gam <UserTypeEntity> claim ownership <DriveFileEntity>
[skipids <DriveFileEntity>] [onlyusers|skipusers <UserTypeEntity>] [subdomains <DomainNameEntity>] [skipids <DriveFileEntity>] [onlyusers|skipusers <UserTypeEntity>] [subdomains <DomainNameEntity>]
[restricted [<Boolean>]] [writerscanshare|writerscantshare [<Boolean>]] [restricted [<Boolean>]] [writerscanshare|writerscantshare [<Boolean>]]
[keepuser | (retainrole commenter|reader|writer|editor|fileorganizer|none)] [noretentionmessages] [keepuser | (retainrole commenter|reader|writer|editor|fileorganizer|none)] [noretentionmessages]
[enforceexpansiveaccess [<Boolean>]]
(orderby <DriveFileOrderByFieldName> [ascending|descending])* (orderby <DriveFileOrderByFieldName> [ascending|descending])*
[preview] [filepath] [pathdelimiter <Character>] [buildtree] [preview] [filepath] [pathdelimiter <Character>] [buildtree]
[todrive <ToDriveAttribute>*] [todrive <ToDriveAttribute>*]
@@ -6832,6 +6848,7 @@ gam <UserTypeEntity> claim ownership <DriveFileEntity>
gam <UserTypeEntity> transfer drive <UserItem> [select <DriveFileEntity>] gam <UserTypeEntity> transfer drive <UserItem> [select <DriveFileEntity>]
[(targetfolderid <DriveFolderID>)|(targetfoldername <DriveFolderName>)] [(targetfolderid <DriveFolderID>)|(targetfoldername <DriveFolderName>)]
[targetuserfoldername <DriveFolderName>] [targetuserorphansfoldername <DriveFolderName>] [targetuserfoldername <DriveFolderName>] [targetuserorphansfoldername <DriveFolderName>]
[enforceexpansiveaccess [<Boolean>]]
[mergewithtarget [<Boolean>]] [mergewithtarget [<Boolean>]]
[skipids <DriveFileEntity>] [skipids <DriveFileEntity>]
[keepuser | (retainrole reader|commenter|writer|editor|fileorganizer|none)] [noretentionmessages] [keepuser | (retainrole reader|commenter|writer|editor|fileorganizer|none)] [noretentionmessages]
@@ -7878,7 +7895,15 @@ gam <UserTypeEntity> show lookerstudiopermissions
<MeetSpaceName> ::= spaces/<String> | <String> <MeetSpaceName> ::= spaces/<String> | <String>
<MeetSpaceOptions> ::= <MeetSpaceOptions> ::=
accesstype open|trusted|restricted | accesstype open|trusted|restricted |
entrypointaccess all|creatorapponly entrypointaccess all|creatorapponly |
moderation <Boolean> |
chatrestriction hostsonly|norestriction |
reactionrestriction hostsonly|norestriction |
presentrestriction hostsonly|norestriction |
defaultjoinasviewer <Boolean> |
recording <Boolean> |
transcription <Boolean> |
smartnotes <Boolean>
gam <UserTypeEntity> create meetspace gam <UserTypeEntity> create meetspace
<MeetSpaceOptions>* <MeetSpaceOptions>*

View File

@@ -1,3 +1,96 @@
7.05.04
Updated `gam calendars <CalendarEntity> update events` and `gam <UserTypeEntity> update events`
to handle the following error:
```
ERROR 400: malformedWorkingLocationEvent - A working location event must have a visibility setting of public.
```
7.05.03
Fixed bug in `gam all users print users issuspended false allfields` that caused a trap.
7.05.02
Chat usage reports are now available. Added `chat` to `<CustomerServiceName>` and `<UserServiceName>`
for use in `gam report customer|user`.
* https://workspaceupdates.googleblog.com/2025/02/chat-usage-analytics-updates.html
7.05.01
Updated from `v1beta1` to `v1` for `Cloud Identity - Policy`.
* See: https://workspaceupdates.googleblog.com/2025/02/policy-api-general-availability.html
7.05.00
Enabled support for Limited Access as described here:
* https://workspaceupdates.googleblog.com/2025/02/updating-access-experience-in-google-drive.html
Note that the rollout may take 15 days.
Added option `inheritedpermissionsdisabled [<Boolean>]` to `<DriveFileAttribute>`; this
attribute can be set on folders.
Added `inheritedpermissionsdisabled` to `<DriveFieldName>`.
Added `capabilities.candisableinheritedpermissions` and `capabilities.canenableinheritedpermissions`
to `<DriveCapabilitiesSubfieldName>`.
Added option `enforceexpansiveaccess [<Boolean>]` to 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
gam <UserTypeEntity> transfer drive
```
7.04.05
Added initial support for Meet API v2beta; you must be in the Developer Preview program
for this to be effective.
* https://developers.google.com/meet/api/guides/beta/configuration-beta#auto-artifacts
Added `meet_v2_beta` Boolean variable to `gam.cfg`. When this variable is true,
the following options are added to `<MeetSpaceOptions>` used in `gam <UserTypeEntity> create|update meetspace`.
```
moderation <Boolean> |
chatrestriction hostsonly|norestriction |
reactionrestriction hostsonly|norestriction |
presentrestriction hostsonly|norestriction |
defaultjoinasviewer <Boolean> |
recording <Boolean> |
transcription <Boolean> |
smartnotes <Boolean>
```
This isn't called beta for nothing, I have found problems and reported them.
7.04.04
Updated `gam print group-members|cigroup-members` to include the `email` column
when `fields <MembersFieldNameList>` did not include `email`.
7.04.03
Added option `minimal|basic|full` to `gam print cigroup-members`:
* `minimal` - Fields displayed: group, id, role, email
* `basic` - Fields displayed: group, type, id, role, email
* `full` - Fields displayed: group, type, id, role, email, createTime, updateTime; this is the default
Added option `minimal|basic|full` to `gam show cigroup-members`:
* `minimal` - Fields displayed: role, email
* `basic` - Fields displayed: type, role, email
* `full` - Fields displayed: type, role, email, createTime, updateTime; this is the default
Upgraded `gam print cigroup-members ... recursive` to display sub-group email addresses rather than IDs.
7.04.02 7.04.02
Improved output formatting for the following commands: Improved output formatting for the following commands:

View File

@@ -31,6 +31,7 @@ for pkg in GAM_VER_LIBS:
datas += [('gam/cbcm-v1.1beta1.json', '.')] datas += [('gam/cbcm-v1.1beta1.json', '.')]
datas += [('gam/contactdelegation-v1.json', '.')] datas += [('gam/contactdelegation-v1.json', '.')]
datas += [('gam/datastudio-v1.json', '.')] datas += [('gam/datastudio-v1.json', '.')]
datas += [('gam/meet-v2beta.json', '.')]
datas += [('gam/serviceaccountlookup-v1.json', '.')] datas += [('gam/serviceaccountlookup-v1.json', '.')]
datas += [('cacerts.pem', '.')] datas += [('cacerts.pem', '.')]
hiddenimports = [ hiddenimports = [

View File

@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
""" """
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>' __author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
__version__ = '7.04.02' __version__ = '7.05.04'
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)' __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
#pylint: disable=wrong-import-position #pylint: disable=wrong-import-position
@@ -4710,7 +4710,7 @@ def getAPIService(api, httpObj):
def getService(api, httpObj): def getService(api, httpObj):
### Drive v3beta ### Drive v3beta
mapDriveURL = api == API.DRIVE3 and GC.Values[GC.DRIVE_V3_BETA] # mapDriveURL = api == API.DRIVE3 and GC.Values[GC.DRIVE_V3_BETA]
hasLocalJSON = API.hasLocalJSON(api) hasLocalJSON = API.hasLocalJSON(api)
api, version, v2discovery = API.getVersion(api) api, version, v2discovery = API.getVersion(api)
if api in GM.Globals[GM.CURRENT_API_SERVICES] and version in GM.Globals[GM.CURRENT_API_SERVICES][api]: if api in GM.Globals[GM.CURRENT_API_SERVICES] and version in GM.Globals[GM.CURRENT_API_SERVICES][api]:
@@ -4727,8 +4727,8 @@ def getService(api, httpObj):
GM.Globals[GM.CURRENT_API_SERVICES].setdefault(api, {}) GM.Globals[GM.CURRENT_API_SERVICES].setdefault(api, {})
GM.Globals[GM.CURRENT_API_SERVICES][api][version] = service._rootDesc.copy() GM.Globals[GM.CURRENT_API_SERVICES][api][version] = service._rootDesc.copy()
### Drive v3beta ### Drive v3beta
if mapDriveURL: # if mapDriveURL:
setattr(service, '_baseUrl', getattr(service, '_baseUrl').replace('/v3/', '/v3beta/')) # setattr(service, '_baseUrl', getattr(service, '_baseUrl').replace('/v3/', '/v3beta/'))
if GM.Globals[GM.CACHE_DISCOVERY_ONLY]: if GM.Globals[GM.CACHE_DISCOVERY_ONLY]:
clearServiceCache(service) clearServiceCache(service)
return service return service
@@ -5571,6 +5571,8 @@ def buildGAPIServiceObject(api, user, i=0, count=0, displayError=True):
userEmail = getSaUser(user) userEmail = getSaUser(user)
httpObj = getHttpObj(cache=GM.Globals[GM.CACHE_DIR]) httpObj = getHttpObj(cache=GM.Globals[GM.CACHE_DIR])
service = getService(api, httpObj) service = getService(api, httpObj)
if api == API.MEET_BETA:
api = API.MEET
credentials = getSvcAcctCredentials(api, userEmail) credentials = getSvcAcctCredentials(api, userEmail)
request = transportCreateRequest(httpObj) request = transportCreateRequest(httpObj)
triesLimit = 3 triesLimit = 3
@@ -5985,6 +5987,8 @@ def getCIGroupTransitiveMemberRoleFixType(groupName, tmember):
member['type'] = Ent.TYPE_USER if not tid.endswith('.iam.gserviceaccount.com') else Ent.TYPE_SERVICE_ACCOUNT member['type'] = Ent.TYPE_USER if not tid.endswith('.iam.gserviceaccount.com') else Ent.TYPE_SERVICE_ACCOUNT
elif ttype == 'groups': elif ttype == 'groups':
member['type'] = Ent.TYPE_GROUP member['type'] = Ent.TYPE_GROUP
elif tid.startswith('cbcm-browser.'):
member['type'] = Ent.TYPE_CBCM_BROWSER
else: else:
member['type'] = Ent.TYPE_OTHER member['type'] = Ent.TYPE_OTHER
else: else:
@@ -7326,12 +7330,6 @@ def _getRawFields(requiredField=None):
return rawFields return rawFields
return f'{requiredField},{rawFields}' return f'{requiredField},{rawFields}'
def _addInitialField(fieldsList, initialField):
if isinstance(initialField, list):
fieldsList.extend(initialField)
else:
fieldsList.append(initialField)
def CheckInputRowFilterHeaders(titlesList, rowFilter, rowDropFilter): def CheckInputRowFilterHeaders(titlesList, rowFilter, rowDropFilter):
status = True status = True
for filterVal in rowFilter: for filterVal in rowFilter:
@@ -7746,6 +7744,12 @@ def RowFilterMatch(row, titlesList, rowFilter, rowFilterModeAll, rowDropFilter,
# } # }
# fieldsList is the list of API fields # fieldsList is the list of API fields
def getFieldsList(myarg, fieldsChoiceMap, fieldsList, initialField=None, fieldsArg='fields', onlyFieldsArg=False): def getFieldsList(myarg, fieldsChoiceMap, fieldsList, initialField=None, fieldsArg='fields', onlyFieldsArg=False):
def addInitialField():
if isinstance(initialField, list):
fieldsList.extend(initialField)
else:
fieldsList.append(initialField)
def addMappedFields(mappedFields): def addMappedFields(mappedFields):
if isinstance(mappedFields, list): if isinstance(mappedFields, list):
fieldsList.extend(mappedFields) fieldsList.extend(mappedFields)
@@ -7754,11 +7758,11 @@ def getFieldsList(myarg, fieldsChoiceMap, fieldsList, initialField=None, fieldsA
if not onlyFieldsArg and myarg in fieldsChoiceMap: if not onlyFieldsArg and myarg in fieldsChoiceMap:
if not fieldsList and initialField is not None: if not fieldsList and initialField is not None:
_addInitialField(fieldsList, initialField) addInitialField()
addMappedFields(fieldsChoiceMap[myarg]) addMappedFields(fieldsChoiceMap[myarg])
elif myarg == fieldsArg: elif myarg == fieldsArg:
if not fieldsList and initialField is not None: if not fieldsList and initialField is not None:
_addInitialField(fieldsList, initialField) addInitialField()
for field in _getFieldsList(): for field in _getFieldsList():
if field in fieldsChoiceMap: if field in fieldsChoiceMap:
addMappedFields(fieldsChoiceMap[field]) addMappedFields(fieldsChoiceMap[field])
@@ -7935,14 +7939,21 @@ class CSVPrintFile():
fieldsList.append(fields) fieldsList.append(fields)
self.AddTitles(fields.replace('.', GC.Values[GC.CSV_OUTPUT_SUBFIELD_DELIMITER])) self.AddTitles(fields.replace('.', GC.Values[GC.CSV_OUTPUT_SUBFIELD_DELIMITER]))
def addInitialField(self, initialField, fieldsChoiceMap, fieldsList):
if isinstance(initialField, list):
for field in initialField:
self.AddField(field, fieldsChoiceMap, fieldsList)
else:
self.AddField(initialField, fieldsChoiceMap, fieldsList)
def GetFieldsListTitles(self, fieldName, fieldsChoiceMap, fieldsList, initialField=None): def GetFieldsListTitles(self, fieldName, fieldsChoiceMap, fieldsList, initialField=None):
if fieldName in fieldsChoiceMap: if fieldName in fieldsChoiceMap:
if not fieldsList and initialField is not None: if not fieldsList and initialField is not None:
_addInitialField(fieldsList, initialField) self.addInitialField(initialField, fieldsChoiceMap, fieldsList)
self.AddField(fieldName, fieldsChoiceMap, fieldsList) self.AddField(fieldName, fieldsChoiceMap, fieldsList)
elif fieldName == 'fields': elif fieldName == 'fields':
if not fieldsList and initialField is not None: if not fieldsList and initialField is not None:
_addInitialField(fieldsList, initialField) self.addInitialField(initialField, fieldsChoiceMap, fieldsList)
for field in _getFieldsList(): for field in _getFieldsList():
if field in fieldsChoiceMap: if field in fieldsChoiceMap:
self.AddField(field, fieldsChoiceMap, fieldsList) self.AddField(field, fieldsChoiceMap, fieldsList)
@@ -9835,7 +9846,7 @@ def MultiprocessGAMCommands(items, showCmds):
if GM.Globals[GM.MULTIPROCESS_EXIT_CONDITION] is not None and checkChildProcessRC(result[1]): if GM.Globals[GM.MULTIPROCESS_EXIT_CONDITION] is not None and checkChildProcessRC(result[1]):
GM.Globals[GM.MULTIPROCESS_EXIT_PROCESSING] = True GM.Globals[GM.MULTIPROCESS_EXIT_PROCESSING] = True
def signal_handler(sig, frame): def signal_handler(*_):
nonlocal controlC nonlocal controlC
controlC = True controlC = True
@@ -13102,6 +13113,7 @@ CUSTOMER_REPORT_SERVICES = {
'app_maker', 'app_maker',
'apps_scripts', 'apps_scripts',
'calendar', 'calendar',
'chat',
'classroom', 'classroom',
'cros', 'cros',
'device_management', 'device_management',
@@ -13115,6 +13127,7 @@ CUSTOMER_REPORT_SERVICES = {
USER_REPORT_SERVICES = { USER_REPORT_SERVICES = {
'accounts', 'accounts',
'chat',
'classroom', 'classroom',
'docs', 'docs',
'drive', 'drive',
@@ -17249,7 +17262,7 @@ def checkOrgUnitPathExists(cd, orgUnitPath, i=0, count=0, showError=False):
return (False, orgUnitPath, orgUnitPath) return (False, orgUnitPath, orgUnitPath)
def _batchMoveCrOSesToOrgUnit(cd, orgUnitPath, orgUnitId, i, count, items, quickCrOSMove, fromOrgUnitPath=None): def _batchMoveCrOSesToOrgUnit(cd, orgUnitPath, orgUnitId, i, count, items, quickCrOSMove, fromOrgUnitPath=None):
def _callbackMoveCrOSesToOrgUnit(request_id, response, exception): def _callbackMoveCrOSesToOrgUnit(request_id, _, exception):
ri = request_id.splitlines() ri = request_id.splitlines()
if exception is None: if exception is None:
if not fromOrgUnitPath: if not fromOrgUnitPath:
@@ -17330,7 +17343,7 @@ def _batchMoveCrOSesToOrgUnit(cd, orgUnitPath, orgUnitId, i, count, items, quick
def _batchMoveUsersToOrgUnit(cd, orgUnitPath, i, count, items, fromOrgUnitPath=None): def _batchMoveUsersToOrgUnit(cd, orgUnitPath, i, count, items, fromOrgUnitPath=None):
_MOVE_USER_REASON_TO_MESSAGE_MAP = {GAPI.USER_NOT_FOUND: Msg.DOES_NOT_EXIST, GAPI.DOMAIN_NOT_FOUND: Msg.SERVICE_NOT_APPLICABLE, GAPI.FORBIDDEN: Msg.SERVICE_NOT_APPLICABLE} _MOVE_USER_REASON_TO_MESSAGE_MAP = {GAPI.USER_NOT_FOUND: Msg.DOES_NOT_EXIST, GAPI.DOMAIN_NOT_FOUND: Msg.SERVICE_NOT_APPLICABLE, GAPI.FORBIDDEN: Msg.SERVICE_NOT_APPLICABLE}
def _callbackMoveUsersToOrgUnit(request_id, response, exception): def _callbackMoveUsersToOrgUnit(request_id, _, exception):
ri = request_id.splitlines() ri = request_id.splitlines()
if exception is None: if exception is None:
if not fromOrgUnitPath: if not fromOrgUnitPath:
@@ -27483,6 +27496,8 @@ def printShowChatEvents(users):
csvPF.writeCSVfile('Chat Events') csvPF.writeCSVfile('Chat Events')
def buildMeetServiceObject(api=API.MEET, user=None, i=0, count=0, entityTypeList=None): def buildMeetServiceObject(api=API.MEET, user=None, i=0, count=0, entityTypeList=None):
if GC.Values[GC.MEET_V2_BETA]:
api = API.MEET_BETA
user, meet = buildGAPIServiceObject(api, user, i, count) user, meet = buildGAPIServiceObject(api, user, i, count)
kvList = [Ent.USER, user] kvList = [Ent.USER, user]
if entityTypeList is not None: if entityTypeList is not None:
@@ -27506,7 +27521,10 @@ MEET_SPACE_OPTIONS_MAP = {
'reactionrestriction': 'reactionRestriction', 'reactionrestriction': 'reactionRestriction',
'presentrestriction': 'presentRestriction', 'presentrestriction': 'presentRestriction',
'defaultjoinasviewer': 'defaultJoinAsViewerType', 'defaultjoinasviewer': 'defaultJoinAsViewerType',
'firstjoiner': 'firstJoinerType' 'firstjoiner': 'firstJoinerType',
'autorecording': 'recordingConfig',
'autosmartnotes': 'smartNotesConfig',
'autotranscription': 'transcriptionConfig',
} }
MEET_SPACE_ACCESSTYPE_CHOICES = {'open', 'trusted', 'restricted'} MEET_SPACE_ACCESSTYPE_CHOICES = {'open', 'trusted', 'restricted'}
@@ -27520,9 +27538,15 @@ MEET_SPACE_RESTRICTIONS_CHOICES_MAP = {
'norestriction': 'NO_RESTRICTION' 'norestriction': 'NO_RESTRICTION'
} }
MEET_SPACE_FIRSTJOINERTYPE_CHOICES_MAP = { #MEET_SPACE_FIRSTJOINERTYPE_CHOICES_MAP = {
'hostsonly': 'HOSTS_ONLY', # 'hostsonly': 'HOSTS_ONLY',
'anyone': 'ANYONE' # 'anyone': 'ANYONE'
# }
MEET_SPACE_ARTIFACT_SUB_OPTIONS = {
'recordingConfig': 'autoRecordingGeneration',
'smartNotesConfig': 'autoSmartNotesGeneration',
'transcriptionConfig': 'autoTranscriptionGeneration'
} }
# [accesstype open|trusted|restricted] # [accesstype open|trusted|restricted]
@@ -27533,7 +27557,10 @@ MEET_SPACE_FIRSTJOINERTYPE_CHOICES_MAP = {
# [presentrestriction hostsonly|norestriction] # [presentrestriction hostsonly|norestriction]
# [defaultjoinasviewer <Boolean>] # [defaultjoinasviewer <Boolean>]
# [firstjoiner hostsonly|anyone] # [firstjoiner hostsonly|anyone]
def _getMeetSpaceParameters(myarg, body, updateMask): # [autorecording <Boolean>]
# [autosmartnotes <Boolean>]
# [autotranscription <Boolean>]
def _getMeetSpaceParameters(myarg, body):
option = MEET_SPACE_OPTIONS_MAP.get(myarg, None) option = MEET_SPACE_OPTIONS_MAP.get(myarg, None)
if option is None: if option is None:
return False return False
@@ -27543,15 +27570,17 @@ def _getMeetSpaceParameters(myarg, body, updateMask):
body['config'][option] = getChoice(MEET_SPACE_ENTRYPOINTACCESS_CHOICES_MAP, mapChoice=True) body['config'][option] = getChoice(MEET_SPACE_ENTRYPOINTACCESS_CHOICES_MAP, mapChoice=True)
elif option == 'moderation': elif option == 'moderation':
body['config'][option] = 'ON' if getBoolean() else 'OFF' body['config'][option] = 'ON' if getBoolean() else 'OFF'
elif option in {'chatrestriction', 'reactionrestriction', 'presentrestriction'}: elif option in {'chatRestriction', 'reactionRestriction', 'presentRestriction'}:
body['config'].setdefault('moderationRestictions', {}) body['config'].setdefault('moderationRestrictions', {})
body['config']['moderationRestrictions'][option] = getChoice(MEET_SPACE_RESTRICTIONS_CHOICES_MAP, mapChoice=True) body['config']['moderationRestrictions'][option] = getChoice(MEET_SPACE_RESTRICTIONS_CHOICES_MAP, mapChoice=True)
option = f'moderationRestrictions.{option}'
elif option == 'defaultJoinAsViewerType': elif option == 'defaultJoinAsViewerType':
body['config'][option] = 'ON' if getBoolean() else 'OFF' body['config'][option] = 'ON' if getBoolean() else 'OFF'
elif option == 'firstJoinerType': # elif option == 'firstJoinerType':
body['config'][option] = getChoice(MEET_SPACE_FIRSTJOINERTYPE_CHOICES_MAP, mapChoice=True) # body['config'][option] = getChoice(MEET_SPACE_FIRSTJOINERTYPE_CHOICES_MAP, mapChoice=True)
updateMask.append(f'config.{option}') elif option in {'recordingConfig', 'transcriptionConfig', 'smartNotesConfig'}:
body['config'].setdefault('artifactConfig', {})
body['config']['artifactConfig'].setdefault(option, {})
body['config']['artifactConfig'][option][MEET_SPACE_ARTIFACT_SUB_OPTIONS[option]] = 'ON' if getBoolean() else 'OFF'
return True return True
# gam <UserTypeEntity> create meetspace # gam <UserTypeEntity> create meetspace
@@ -27566,10 +27595,9 @@ def createMeetSpace(users):
# 'firstJoinerType': 'ANYONE', # 'firstJoinerType': 'ANYONE',
}} }}
returnIdOnly = False returnIdOnly = False
updateMask = []
while Cmd.ArgumentsRemaining(): while Cmd.ArgumentsRemaining():
myarg = getArgument() myarg = getArgument()
if _getMeetSpaceParameters(myarg, body, updateMask): if _getMeetSpaceParameters(myarg, body):
pass pass
elif myarg == 'returnidonly': elif myarg == 'returnidonly':
returnIdOnly = True returnIdOnly = True
@@ -27604,12 +27632,11 @@ def updateMeetSpace(users):
FJQC = FormatJSONQuoteChar() FJQC = FormatJSONQuoteChar()
name = None name = None
body = {'config': {}} body = {'config': {}}
updateMask = []
while Cmd.ArgumentsRemaining(): while Cmd.ArgumentsRemaining():
myarg = getArgument() myarg = getArgument()
if (myarg == 'space' or myarg.startswith('spaces/') or myarg.startswith('space/')): if (myarg == 'space' or myarg.startswith('spaces/') or myarg.startswith('space/')):
name = getSpaceName(myarg) name = getSpaceName(myarg)
elif _getMeetSpaceParameters(myarg, body, updateMask): elif _getMeetSpaceParameters(myarg, body):
pass pass
else: else:
FJQC.GetFormatJSON(myarg) FJQC.GetFormatJSON(myarg)
@@ -27624,7 +27651,7 @@ def updateMeetSpace(users):
try: try:
space = callGAPI(meet.spaces(), 'patch', space = callGAPI(meet.spaces(), 'patch',
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED], throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
name=name, updateMask=','.join(updateMask), body=body) name=name, updateMask='', body=body)
if not FJQC.formatJSON: if not FJQC.formatJSON:
entityActionPerformed(kvList, i, count) entityActionPerformed(kvList, i, count)
Ind.Increment() Ind.Increment()
@@ -29230,6 +29257,7 @@ DEVICE_FIELDS_CHOICE_MAP = {
'releaseversion': 'releaseVersion', 'releaseversion': 'releaseVersion',
'securitypatchtime': 'securityPatchTime', 'securitypatchtime': 'securityPatchTime',
'serialnumber': 'serialNumber', 'serialnumber': 'serialNumber',
'unifieddeviceid': 'unifiedDeviceId',
'wifimacaddresses': 'wifiMacAddresses' 'wifimacaddresses': 'wifiMacAddresses'
} }
@@ -32002,7 +32030,7 @@ def doUpdateGroups():
GAPI.INVALID_MEMBER: Msg.INVALID_MEMBER, GAPI.INVALID_MEMBER: Msg.INVALID_MEMBER,
GAPI.CYCLIC_MEMBERSHIPS_NOT_ALLOWED: Msg.WOULD_MAKE_MEMBERSHIP_CYCLE} GAPI.CYCLIC_MEMBERSHIPS_NOT_ALLOWED: Msg.WOULD_MAKE_MEMBERSHIP_CYCLE}
def _callbackAddGroupMembers(request_id, response, exception): def _callbackAddGroupMembers(request_id, _, exception):
ri = request_id.splitlines() ri = request_id.splitlines()
if exception is None: if exception is None:
_showSuccess(ri[RI_ENTITY], ri[RI_ITEM], ri[RI_ROLE], ri[RI_OPTION], int(ri[RI_J]), int(ri[RI_JCOUNT])) _showSuccess(ri[RI_ENTITY], ri[RI_ITEM], ri[RI_ROLE], ri[RI_OPTION], int(ri[RI_J]), int(ri[RI_JCOUNT]))
@@ -32091,7 +32119,7 @@ def doUpdateGroups():
GAPI.CONDITION_NOT_MET: f'{Msg.NOT_A} {Ent.Singular(Ent.MEMBER)}', GAPI.CONDITION_NOT_MET: f'{Msg.NOT_A} {Ent.Singular(Ent.MEMBER)}',
GAPI.INVALID_MEMBER: Msg.DOES_NOT_EXIST} GAPI.INVALID_MEMBER: Msg.DOES_NOT_EXIST}
def _callbackRemoveGroupMembers(request_id, response, exception): def _callbackRemoveGroupMembers(request_id, _, exception):
ri = request_id.splitlines() ri = request_id.splitlines()
if exception is None: if exception is None:
_showSuccess(ri[RI_ENTITY], ri[RI_ITEM], ri[RI_ROLE], DELIVERY_SETTINGS_UNDEFINED, int(ri[RI_J]), int(ri[RI_JCOUNT])) _showSuccess(ri[RI_ENTITY], ri[RI_ITEM], ri[RI_ROLE], DELIVERY_SETTINGS_UNDEFINED, int(ri[RI_J]), int(ri[RI_JCOUNT]))
@@ -32190,7 +32218,7 @@ def doUpdateGroups():
except (GAPI.invalidMember, GAPI.resourceNotFound, GAPI.serviceNotAvailable) as e: except (GAPI.invalidMember, GAPI.resourceNotFound, GAPI.serviceNotAvailable) as e:
_showFailure(group, member, role, str(e), j, jcount) _showFailure(group, member, role, str(e), j, jcount)
def _callbackUpdateGroupMembers(request_id, response, exception): def _callbackUpdateGroupMembers(request_id, _, exception):
ri = request_id.splitlines() ri = request_id.splitlines()
if exception is None: if exception is None:
_showSuccess(ri[RI_ENTITY], ri[RI_ITEM], ri[RI_ROLE], ri[RI_OPTION], int(ri[RI_J]), int(ri[RI_JCOUNT])) _showSuccess(ri[RI_ENTITY], ri[RI_ITEM], ri[RI_ROLE], ri[RI_OPTION], int(ri[RI_J]), int(ri[RI_JCOUNT]))
@@ -33427,6 +33455,7 @@ PRINT_GROUPS_JSON_TITLES = ['email', 'JSON']
# gam print groups [todrive <ToDriveAttribute>*] # gam print groups [todrive <ToDriveAttribute>*]
# [([domain|domains <DomainNameEntity>] ([member|showownedby <EmailItem>]|[(query <QueryGroup>)|(queries <QueryUserList>)]))| # [([domain|domains <DomainNameEntity>] ([member|showownedby <EmailItem>]|[(query <QueryGroup>)|(queries <QueryUserList>)]))|
# (group|group_ns|group_susp <GroupItem>)|
# (select <GroupEntity>)] # (select <GroupEntity>)]
# [emailmatchpattern [not] <RegularExpression>] [namematchpattern [not] <RegularExpression>] # [emailmatchpattern [not] <RegularExpression>] [namematchpattern [not] <RegularExpression>]
# [descriptionmatchpattern [not] <RegularExpression>] (matchsetting [not] <GroupAttribute>)* # [descriptionmatchpattern [not] <RegularExpression>] (matchsetting [not] <GroupAttribute>)*
@@ -33639,6 +33668,12 @@ def doPrintGroups():
pass pass
elif getGroupMatchPatterns(myarg, matchPatterns, False): elif getGroupMatchPatterns(myarg, matchPatterns, False):
pass pass
elif myarg in {'group', 'groupns', 'groupsusp'}:
entitySelection = [getString(Cmd.OB_EMAIL_ADDRESS)]
if myarg == 'groupns':
isSuspended = False
elif myarg == 'groupsusp':
isSuspended = True
elif myarg == 'select': elif myarg == 'select':
entitySelection = getEntityList(Cmd.OB_GROUP_ENTITY) entitySelection = getEntityList(Cmd.OB_GROUP_ENTITY)
elif myarg in SUSPENDED_ARGUMENTS: elif myarg in SUSPENDED_ARGUMENTS:
@@ -33963,6 +33998,8 @@ def infoGroupMembers(entityList, ciGroupsAPI=False):
printKeyValueList(['type', result['type']]) printKeyValueList(['type', result['type']])
for field in ['createTime', 'updateTime']: for field in ['createTime', 'updateTime']:
printKeyValueList([field, formatLocalTime(result[field])]) printKeyValueList([field, formatLocalTime(result[field])])
if 'deliverySetting' in result:
printKeyValueList(['deliverySetting', result['deliverySetting']])
Ind.Decrement() Ind.Decrement()
except (GAPI.groupNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.invalid, GAPI.forbidden) as e: except (GAPI.groupNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.invalid, GAPI.forbidden) as e:
entityActionFailedWarning([entityType, groupKey], str(e), j, jcount) entityActionFailedWarning([entityType, groupKey], str(e), j, jcount)
@@ -34206,7 +34243,7 @@ def doPrintGroupMembers():
pass pass
elif getMemberMatchOptions(myarg, memberOptions): elif getMemberMatchOptions(myarg, memberOptions):
pass pass
elif csvPF.GetFieldsListTitles(myarg, GROUPMEMBERS_FIELDS_CHOICE_MAP, fieldsList): elif csvPF.GetFieldsListTitles(myarg, GROUPMEMBERS_FIELDS_CHOICE_MAP, fieldsList, initialField='email'):
pass pass
elif myarg == 'membernames': elif myarg == 'membernames':
memberOptions[MEMBEROPTION_MEMBERNAMES] = True memberOptions[MEMBEROPTION_MEMBERNAMES] = True
@@ -36125,17 +36162,10 @@ def getCIGroupTransitiveMembers(ci, groupName, membersList, i, count):
return True return True
def getCIGroupMembers(ci, groupName, memberRoles, membersList, membersSet, i, count, def getCIGroupMembers(ci, groupName, memberRoles, membersList, membersSet, i, count,
memberOptions, memberDisplayOptions, level, typesSet, listView='FULL', groupEmail=None): memberOptions, memberDisplayOptions, level, typesSet, groupEmail, kwargs):
if groupEmail: nameToPrint = groupEmail if groupEmail else groupName
nameToPrint = groupEmail
else:
nameToPrint = groupName
printGettingAllEntityItemsForWhom(memberRoles if memberRoles else Ent.ROLE_MANAGER_MEMBER_OWNER, nameToPrint, i, count) printGettingAllEntityItemsForWhom(memberRoles if memberRoles else Ent.ROLE_MANAGER_MEMBER_OWNER, nameToPrint, i, count)
validRoles = _getCIRoleVerification(memberRoles) validRoles = _getCIRoleVerification(memberRoles)
if listView == 'BASIC':
pageSize = GC.Values[GC.MEMBER_MAX_RESULTS_CI_BASIC]
else:
pageSize = GC.Values[GC.MEMBER_MAX_RESULTS_CI_FULL]
if memberOptions[MEMBEROPTION_INCLUDEDERIVEDMEMBERSHIP]: if memberOptions[MEMBEROPTION_INCLUDEDERIVEDMEMBERSHIP]:
groupMembers = [] groupMembers = []
if not getCIGroupTransitiveMembers(ci, groupName, groupMembers, i, count): if not getCIGroupTransitiveMembers(ci, groupName, groupMembers, i, count):
@@ -36149,12 +36179,11 @@ def getCIGroupMembers(ci, groupName, memberRoles, membersList, membersSet, i, co
groupMembers = callGAPIpages(ci.groups().memberships(), 'list', 'memberships', groupMembers = callGAPIpages(ci.groups().memberships(), 'list', 'memberships',
pageMessage=getPageMessageForWhom(), pageMessage=getPageMessageForWhom(),
throwReasons=GAPI.CIGROUP_LIST_THROW_REASONS, retryReasons=GAPI.CIGROUP_RETRY_REASONS, throwReasons=GAPI.CIGROUP_LIST_THROW_REASONS, retryReasons=GAPI.CIGROUP_RETRY_REASONS,
parent=groupName, view=listView, parent=groupName, **kwargs)
fields='nextPageToken,memberships(*)', pageSize=pageSize)
except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis,
GAPI.forbidden, GAPI.badRequest, GAPI.invalid, GAPI.invalidArgument, GAPI.systemError, GAPI.forbidden, GAPI.badRequest, GAPI.invalid, GAPI.invalidArgument, GAPI.systemError,
GAPI.permissionDenied, GAPI.serviceNotAvailable): GAPI.permissionDenied, GAPI.serviceNotAvailable):
entityUnknownWarning(Ent.CLOUD_IDENTITY_GROUP, groupName, i, count) entityUnknownWarning(Ent.CLOUD_IDENTITY_GROUP, nameToPrint, i, count)
return return
checkCategory = memberDisplayOptions['showCategory'] checkCategory = memberDisplayOptions['showCategory']
if not memberOptions[MEMBEROPTION_RECURSIVE]: if not memberOptions[MEMBEROPTION_RECURSIVE]:
@@ -36188,7 +36217,7 @@ def getCIGroupMembers(ci, groupName, memberRoles, membersList, membersSet, i, co
memberName not in membersSet): memberName not in membersSet):
membersSet.add(memberName) membersSet.add(memberName)
member['level'] = level member['level'] = level
member['subgroup'] = groupName member['subgroup'] = nameToPrint
membersList.append(member) membersList.append(member)
else: else:
if memberName not in membersSet: if memberName not in membersSet:
@@ -36197,37 +36226,41 @@ def getCIGroupMembers(ci, groupName, memberRoles, membersList, membersSet, i, co
checkCIMemberMatch(member, memberOptions) and checkCIMemberMatch(member, memberOptions) and
(not checkCategory or _checkCIMemberCategory(member, memberDisplayOptions))): (not checkCategory or _checkCIMemberCategory(member, memberDisplayOptions))):
member['level'] = level member['level'] = level
member['subgroup'] = groupName member['subgroup'] = nameToPrint
membersList.append(member) membersList.append(member)
_, gname = member['name'].rsplit('/', 1) _, gname = member['name'].rsplit('/', 1)
groupMemberList.append(f'groups/{gname}') groupMemberList.append((f'groups/{gname}', memberName))
for member in groupMemberList: for member in groupMemberList:
getCIGroupMembers(ci, member, memberRoles, membersList, membersSet, i, count, getCIGroupMembers(ci, member[0], memberRoles, membersList, membersSet, i, count,
memberOptions, memberDisplayOptions, level+1, typesSet) memberOptions, memberDisplayOptions, level+1, typesSet, member[1], kwargs)
else: else:
for member in groupMembers: for member in groupMembers:
getCIGroupMemberRoleFixType(member) getCIGroupMemberRoleFixType(member)
memberName = member.get('preferredMemberKey', {}).get('id', '')
if member['type'] != Ent.TYPE_GROUP: if member['type'] != Ent.TYPE_GROUP:
if (member['type'] in typesSet and if (member['type'] in typesSet and
checkCIMemberMatch(member, memberOptions) and checkCIMemberMatch(member, memberOptions) and
_checkMemberRole(member, validRoles) and _checkMemberRole(member, validRoles) and
(not checkCategory or _checkCIMemberCategory(member, memberDisplayOptions))): (not checkCategory or _checkCIMemberCategory(member, memberDisplayOptions))):
member['level'] = level member['level'] = level
member['subgroup'] = groupName member['subgroup'] = nameToPrint
membersList.append(member) membersList.append(member)
else: else:
if (member['type'] in typesSet and if (member['type'] in typesSet and
checkCIMemberMatch(member, memberOptions) and checkCIMemberMatch(member, memberOptions) and
(not checkCategory or _checkCIMemberCategory(member, memberDisplayOptions))): (not checkCategory or _checkCIMemberCategory(member, memberDisplayOptions))):
member['level'] = level member['level'] = level
member['subgroup'] = groupName member['subgroup'] = nameToPrint
membersList.append(member) membersList.append(member)
_, gname = member['name'].rsplit('/', 1) _, gname = member['name'].rsplit('/', 1)
getCIGroupMembers(ci, f'groups/{gname}', memberRoles, membersList, membersSet, i, count, getCIGroupMembers(ci, f'groups/{gname}', memberRoles, membersList, membersSet, i, count,
memberOptions, memberDisplayOptions, level+1, typesSet) memberOptions, memberDisplayOptions, level+1, typesSet, memberName, kwargs)
CIGROUPMEMBERS_FIELDS_CHOICE_MAP = { CIGROUPMEMBERS_FIELDS_CHOICE_MAP = {
'createtime': 'createTime', 'createtime': 'createTime',
'delivery': 'deliverySetting',
'deliverysettings': 'deliverySetting',
'email': 'preferredMemberKey',
'expiretime': 'expireTime', 'expiretime': 'expireTime',
'id': 'name', 'id': 'name',
'memberkey': 'preferredMemberKey', 'memberkey': 'preferredMemberKey',
@@ -36248,6 +36281,16 @@ CIGROUPMEMBERS_SORT_FIELDS = [
] ]
CIGROUPMEMBERS_TIME_OBJECTS = {'createTime', 'updateTime', 'expireTime'} CIGROUPMEMBERS_TIME_OBJECTS = {'createTime', 'updateTime', 'expireTime'}
def _getCIListGroupMembersArgs(listView):
if listView == 'full':
return {'view': 'FULL', 'pageSize': GC.Values[GC.MEMBER_MAX_RESULTS_CI_FULL],
'fields': 'nextPageToken,memberships(*)'}
if listView == 'basic':
return {'view': 'FULL', 'pageSize': GC.Values[GC.MEMBER_MAX_RESULTS_CI_FULL],
'fields': 'nextPageToken,memberships(name,preferredMemberKey,roles,type)'}
return {'view': 'BASIC', 'pageSize': GC.Values[GC.MEMBER_MAX_RESULTS_CI_BASIC],
'fields': 'nextPageToken,memberships(*)'}
# gam print cigroup-members [todrive <ToDriveAttribute>*] # gam print cigroup-members [todrive <ToDriveAttribute>*]
# [(cimember|ciowner <UserItem>)|(cigroup <GroupItem>)|(select <GroupEntity>)] # [(cimember|ciowner <UserItem>)|(cigroup <GroupItem>)|(select <GroupEntity>)]
# [showownedby <UserItem>] # [showownedby <UserItem>]
@@ -36257,6 +36300,7 @@ CIGROUPMEMBERS_TIME_OBJECTS = {'createTime', 'updateTime', 'expireTime'}
# [types <CIGroupMemberTypeList>] # [types <CIGroupMemberTypeList>]
# [memberemaildisplaypattern|memberemailskippattern <RegularExpression>] # [memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
# <CIGroupMembersFieldName>* [fields <CIGroupMembersFieldNameList>] # <CIGroupMembersFieldName>* [fields <CIGroupMembersFieldNameList>]
# [minimal|basic|full]
# [(recursive [noduplicates])|includederivedmembership] [nogroupeemail] # [(recursive [noduplicates])|includederivedmembership] [nogroupeemail]
# [formatjson [quotechar <Character>]] # [formatjson [quotechar <Character>]]
def doPrintCIGroupMembers(): def doPrintCIGroupMembers():
@@ -36274,7 +36318,7 @@ def doPrintCIGroupMembers():
rolesSet = set() rolesSet = set()
typesSet = set() typesSet = set()
matchPatterns = {} matchPatterns = {}
listView = 'FULL' listView = 'full'
while Cmd.ArgumentsRemaining(): while Cmd.ArgumentsRemaining():
myarg = getArgument() myarg = getArgument()
if myarg == 'todrive': if myarg == 'todrive':
@@ -36303,7 +36347,7 @@ def doPrintCIGroupMembers():
pass pass
elif getMemberMatchOptions(myarg, memberOptions): elif getMemberMatchOptions(myarg, memberOptions):
pass pass
elif getFieldsList(myarg, CIGROUPMEMBERS_FIELDS_CHOICE_MAP, fieldsList): elif getFieldsList(myarg, CIGROUPMEMBERS_FIELDS_CHOICE_MAP, fieldsList, initialField='preferredMemberKey'):
pass pass
elif myarg == 'noduplicates': elif myarg == 'noduplicates':
memberOptions[MEMBEROPTION_NODUPLICATES] = True memberOptions[MEMBEROPTION_NODUPLICATES] = True
@@ -36315,10 +36359,12 @@ def doPrintCIGroupMembers():
memberOptions[MEMBEROPTION_RECURSIVE] = False memberOptions[MEMBEROPTION_RECURSIVE] = False
elif myarg == 'nogroupemail': elif myarg == 'nogroupemail':
groupColumn = False groupColumn = False
elif myarg == 'basic': elif myarg in {'minimal', 'basic', 'full'}:
listView = 'BASIC' listView = myarg
else: else:
FJQC.GetFormatJSONQuoteChar(myarg, False) FJQC.GetFormatJSONQuoteChar(myarg, False)
if listView == 'minimal' and memberOptions[MEMBEROPTION_RECURSIVE]:
usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format('minimal', 'recursive'))
if not typesSet: if not typesSet:
typesSet = {Ent.TYPE_USER} if memberOptions[MEMBEROPTION_RECURSIVE] else ALL_CIGROUP_MEMBER_TYPES typesSet = {Ent.TYPE_USER} if memberOptions[MEMBEROPTION_RECURSIVE] else ALL_CIGROUP_MEMBER_TYPES
fields = ','.join(set(groupFieldsLists['ci'])) fields = ','.join(set(groupFieldsLists['ci']))
@@ -36345,6 +36391,7 @@ def doPrintCIGroupMembers():
if showOwnedBy: if showOwnedBy:
getRolesSet.add(Ent.ROLE_OWNER) getRolesSet.add(Ent.ROLE_OWNER)
getRoles = ','.join(sorted(getRolesSet)) getRoles = ','.join(sorted(getRolesSet))
kwargs = _getCIListGroupMembersArgs(listView)
level = 0 level = 0
i = 0 i = 0
count = len(entityList) count = len(entityList)
@@ -36371,7 +36418,7 @@ def doPrintCIGroupMembers():
membersList = [] membersList = []
membersSet = set() membersSet = set()
getCIGroupMembers(ci, groupEntity['name'], getRoles, membersList, membersSet, i, count, getCIGroupMembers(ci, groupEntity['name'], getRoles, membersList, membersSet, i, count,
memberOptions, memberDisplayOptions, level, typesSet, listView, groupEmail) memberOptions, memberDisplayOptions, level, typesSet, groupEmail, kwargs)
if showOwnedBy and not checkCIGroupShowOwnedBy(showOwnedBy, membersList): if showOwnedBy and not checkCIGroupShowOwnedBy(showOwnedBy, membersList):
continue continue
for member in membersList: for member in membersList:
@@ -36389,6 +36436,8 @@ def doPrintCIGroupMembers():
row['subgroup'] = member['subgroup'] row['subgroup'] = member['subgroup']
if memberDisplayOptions['showCategory']: if memberDisplayOptions['showCategory']:
row['category'] = member['category'] row['category'] = member['category']
if listView == 'minimal':
dmember.pop('type', None)
mapCIGroupMemberFieldNames(dmember) mapCIGroupMemberFieldNames(dmember)
if not FJQC.formatJSON: if not FJQC.formatJSON:
csvPF.WriteRowTitles(flattenJSON(dmember, flattened=row, timeObjects=CIGROUPMEMBERS_TIME_OBJECTS)) csvPF.WriteRowTitles(flattenJSON(dmember, flattened=row, timeObjects=CIGROUPMEMBERS_TIME_OBJECTS))
@@ -36418,17 +36467,19 @@ def doPrintCIGroupMembers():
# [showownedby <UserItem>] # [showownedby <UserItem>]
# [emailmatchpattern [not] <RegularExpression>] [namematchpattern [not] <RegularExpression>] # [emailmatchpattern [not] <RegularExpression>] [namematchpattern [not] <RegularExpression>]
# [descriptionmatchpattern [not] <RegularExpression>] # [descriptionmatchpattern [not] <RegularExpression>]
# [roles <GroupRoleList>] [members] [managers] [owners] [depth <Number>] # [roles <GroupRoleList>] [members] [managers] [owners]
# [internal] [internaldomains <DomainList>] [external] # [internal] [internaldomains <DomainList>] [external]
# [types <CIGroupMemberTypeList>] # [types <CIGroupMemberTypeList>]
# [memberemaildisplaypattern|memberemailskippattern <RegularExpression>] # [memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
# [includederivedmembership] # [minimal|basic|full]
# [(depth <Number>) | includederivedmembership]
def doShowCIGroupMembers(): def doShowCIGroupMembers():
def _roleOrder(key): def _roleOrder(key):
return {Ent.ROLE_OWNER: 0, Ent.ROLE_MANAGER: 1, Ent.ROLE_MEMBER: 2}.get(key, 3) return {Ent.ROLE_OWNER: 0, Ent.ROLE_MANAGER: 1, Ent.ROLE_MEMBER: 2}.get(key, 3)
def _typeOrder(key): def _typeOrder(key):
return {Ent.TYPE_CUSTOMER: 0, Ent.TYPE_USER: 1, Ent.TYPE_GROUP: 2, Ent.TYPE_EXTERNAL: 3}.get(key, 4) return {Ent.TYPE_CUSTOMER: 0, Ent.TYPE_USER: 1, Ent.TYPE_GROUP: 2,
Ent.TYPE_CBCM_BROWSER: 3, Ent.TYPE_OTHER: 4, Ent.TYPE_EXTERNAL: 5}.get(key, 6)
def _showGroup(groupName, groupEmail, depth): def _showGroup(groupName, groupEmail, depth):
if includeDerivedMembership: if includeDerivedMembership:
@@ -36439,8 +36490,7 @@ def doShowCIGroupMembers():
try: try:
membersList = callGAPIpages(ci.groups().memberships(), 'list', 'memberships', membersList = callGAPIpages(ci.groups().memberships(), 'list', 'memberships',
throwReasons=GAPI.CIGROUP_LIST_THROW_REASONS, retryReasons=GAPI.CIGROUP_RETRY_REASONS, throwReasons=GAPI.CIGROUP_LIST_THROW_REASONS, retryReasons=GAPI.CIGROUP_RETRY_REASONS,
parent=groupName, view='FULL', parent=groupName, **kwargs)
fields='nextPageToken,memberships(*)', pageSize=GC.Values[GC.MEMBER_MAX_RESULTS])
for member in membersList: for member in membersList:
getCIGroupMemberRoleFixType(member) getCIGroupMemberRoleFixType(member)
except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis,
@@ -36461,7 +36511,10 @@ def doShowCIGroupMembers():
if (_checkMemberRole(member, rolesSet) and if (_checkMemberRole(member, rolesSet) and
member['type'] in typesSet and member['type'] in typesSet and
checkCIMemberMatch(member, memberOptions)): checkCIMemberMatch(member, memberOptions)):
memberDetails = f'{member.get("role", Ent.ROLE_MEMBER)}, {member["type"]}, {member["preferredMemberKey"]["id"]}' if listView != 'minimal':
memberDetails = f'{member.get("role", Ent.ROLE_MEMBER)}, {member["type"]}, {member["preferredMemberKey"]["id"]}'
else:
memberDetails = f'{member.get("role", Ent.ROLE_MEMBER)}, {member["preferredMemberKey"]["id"]}'
if checkCategory: if checkCategory:
memberDetails += f', {member["category"]}' memberDetails += f', {member["category"]}'
for field in ['createTime', 'updateTime', 'expireTime']: for field in ['createTime', 'updateTime', 'expireTime']:
@@ -36486,6 +36539,7 @@ def doShowCIGroupMembers():
matchPatterns = {} matchPatterns = {}
maxdepth = -1 maxdepth = -1
includeDerivedMembership = False includeDerivedMembership = False
listView = 'full'
while Cmd.ArgumentsRemaining(): while Cmd.ArgumentsRemaining():
myarg = getArgument() myarg = getArgument()
if myarg == 'showownedby': if myarg == 'showownedby':
@@ -36516,6 +36570,8 @@ def doShowCIGroupMembers():
maxdepth = getInteger(minVal=-1) maxdepth = getInteger(minVal=-1)
elif myarg == 'includederivedmembership': elif myarg == 'includederivedmembership':
includeDerivedMembership = True includeDerivedMembership = True
elif myarg in {'minimal', 'basic', 'full'}:
listView = myarg
else: else:
unknownArgumentExit() unknownArgumentExit()
if not rolesSet: if not rolesSet:
@@ -36525,6 +36581,7 @@ def doShowCIGroupMembers():
checkCategory = memberDisplayOptions['showCategory'] checkCategory = memberDisplayOptions['showCategory']
fields = ','.join(set(groupFieldsLists['ci'])) fields = ','.join(set(groupFieldsLists['ci']))
entityList = getCIGroupMembersEntityList(ci, entityList, query, subTitle, matchPatterns, groupFieldsLists['ci'], None) entityList = getCIGroupMembersEntityList(ci, entityList, query, subTitle, matchPatterns, groupFieldsLists['ci'], None)
kwargs = _getCIListGroupMembersArgs(listView)
i = 0 i = 0
count = len(entityList) count = len(entityList)
for group in entityList: for group in entityList:
@@ -39001,7 +39058,8 @@ def _updateCalendarEvents(origUser, user, origCal, calIds, count, calendarEventE
event = callGAPI(cal.events(), 'patch', event = callGAPI(cal.events(), 'patch',
throwReasons=GAPI.CALENDAR_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.DELETED, GAPI.FORBIDDEN, throwReasons=GAPI.CALENDAR_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.DELETED, GAPI.FORBIDDEN,
GAPI.INVALID, GAPI.REQUIRED, GAPI.TIME_RANGE_EMPTY, GAPI.EVENT_DURATION_EXCEEDS_LIMIT, GAPI.INVALID, GAPI.REQUIRED, GAPI.TIME_RANGE_EMPTY, GAPI.EVENT_DURATION_EXCEEDS_LIMIT,
GAPI.REQUIRED_ACCESS_LEVEL, GAPI.CANNOT_CHANGE_ORGANIZER_OF_INSTANCE], GAPI.REQUIRED_ACCESS_LEVEL, GAPI.CANNOT_CHANGE_ORGANIZER_OF_INSTANCE,
GAPI.MALFORMED_WORKING_LOCATION_EVENT],
calendarId=calId, eventId=eventId, conferenceDataVersion=1, sendUpdates=parameters['sendUpdates'], supportsAttachments=True, calendarId=calId, eventId=eventId, conferenceDataVersion=1, sendUpdates=parameters['sendUpdates'], supportsAttachments=True,
body=body, fields=pfields) body=body, fields=pfields)
if parameters['csvPF'] is None: if parameters['csvPF'] is None:
@@ -39016,7 +39074,7 @@ def _updateCalendarEvents(origUser, user, origCal, calIds, count, calendarEventE
break break
entityActionFailedWarning([Ent.CALENDAR, calId, Ent.EVENT, eventId], str(e), j, jcount) entityActionFailedWarning([Ent.CALENDAR, calId, Ent.EVENT, eventId], str(e), j, jcount)
except (GAPI.forbidden, GAPI.invalid, GAPI.required, GAPI.timeRangeEmpty, GAPI.eventDurationExceedsLimit, except (GAPI.forbidden, GAPI.invalid, GAPI.required, GAPI.timeRangeEmpty, GAPI.eventDurationExceedsLimit,
GAPI.requiredAccessLevel, GAPI.cannotChangeOrganizerOfInstance) as e: GAPI.requiredAccessLevel, GAPI.cannotChangeOrganizerOfInstance, GAPI.malformedWorkingLocationEvent) as e:
entityActionFailedWarning([Ent.CALENDAR, calId, Ent.EVENT, eventId], str(e), j, jcount) entityActionFailedWarning([Ent.CALENDAR, calId, Ent.EVENT, eventId], str(e), j, jcount)
except GAPI.notACalendarUser: except GAPI.notACalendarUser:
userCalServiceNotEnabledWarning(calId, i, count) userCalServiceNotEnabledWarning(calId, i, count)
@@ -42304,7 +42362,7 @@ def doPrintVaultCounts():
# gam [<UserTypeEntity>] print siteacls <SiteEntity> [todrive <ToDriveAttribute>*] # gam [<UserTypeEntity>] print siteacls <SiteEntity> [todrive <ToDriveAttribute>*]
# gam [<UserTypeEntity>] print siteactivity <SiteEntity> [todrive <ToDriveAttribute>*] # gam [<UserTypeEntity>] print siteactivity <SiteEntity> [todrive <ToDriveAttribute>*]
# [startindex <Number>] [maxresults <Number>] [updated_min <Date>] [updated_max <Date>] # [startindex <Number>] [maxresults <Number>] [updated_min <Date>] [updated_max <Date>]
def deprecatedUserSites(users): def deprecatedUserSites(_):
deprecatedCommandExit() deprecatedCommandExit()
def deprecatedDomainSites(): def deprecatedDomainSites():
@@ -43626,7 +43684,7 @@ def waitForMailbox(entityList):
Ind.Decrement() Ind.Decrement()
def getUserLicenses(lic, user, skus): def getUserLicenses(lic, user, skus):
def _callbackGetLicense(request_id, response, exception): def _callbackGetLicense(_, response, exception):
if exception is None: if exception is None:
if response and 'skuId' in response: if response and 'skuId' in response:
licenses.append(response['skuId']) licenses.append(response['skuId'])
@@ -44739,7 +44797,7 @@ def doPrintUsers(entityList=None):
return return
sortRows = True sortRows = True
# If no individual fields were specified (allfields, basic, full) or individual fields other than primaryEmail were specified, look up each user # If no individual fields were specified (allfields, basic, full) or individual fields other than primaryEmail were specified, look up each user
if isSuspended is not None: if isSuspended is not None and fieldsList:
fieldsList.append('suspended') fieldsList.append('suspended')
if projectionSet or len(set(fieldsList)) > 1 or showValidColumn: if projectionSet or len(set(fieldsList)) > 1 or showValidColumn:
jcount = len(entityList) jcount = len(entityList)
@@ -48132,7 +48190,7 @@ def _batchAddItemsToCourse(croom, courseId, i, count, addParticipants, role):
_ADD_PART_REASON_TO_MESSAGE_MAP = {GAPI.NOT_FOUND: Msg.DOES_NOT_EXIST, _ADD_PART_REASON_TO_MESSAGE_MAP = {GAPI.NOT_FOUND: Msg.DOES_NOT_EXIST,
GAPI.ALREADY_EXISTS: Msg.DUPLICATE, GAPI.ALREADY_EXISTS: Msg.DUPLICATE,
GAPI.FAILED_PRECONDITION: Msg.NOT_ALLOWED} GAPI.FAILED_PRECONDITION: Msg.NOT_ALLOWED}
def _callbackAddItemsToCourse(request_id, response, exception): def _callbackAddItemsToCourse(request_id, _, exception):
ri = request_id.splitlines() ri = request_id.splitlines()
if exception is None: if exception is None:
entityActionPerformed([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], int(ri[RI_J]), int(ri[RI_JCOUNT])) entityActionPerformed([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], int(ri[RI_J]), int(ri[RI_JCOUNT]))
@@ -48212,7 +48270,7 @@ def _batchRemoveItemsFromCourse(croom, courseId, i, count, removeParticipants, r
_REMOVE_PART_REASON_TO_MESSAGE_MAP = {GAPI.NOT_FOUND: Msg.DOES_NOT_EXIST, _REMOVE_PART_REASON_TO_MESSAGE_MAP = {GAPI.NOT_FOUND: Msg.DOES_NOT_EXIST,
GAPI.FORBIDDEN: Msg.FORBIDDEN, GAPI.FORBIDDEN: Msg.FORBIDDEN,
GAPI.PERMISSION_DENIED: Msg.PERMISSION_DENIED} GAPI.PERMISSION_DENIED: Msg.PERMISSION_DENIED}
def _callbackRemoveItemsFromCourse(request_id, response, exception): def _callbackRemoveItemsFromCourse(request_id, _, exception):
ri = request_id.splitlines() ri = request_id.splitlines()
if exception is None: if exception is None:
entityActionPerformed([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], int(ri[RI_J]), int(ri[RI_JCOUNT])) entityActionPerformed([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], int(ri[RI_J]), int(ri[RI_JCOUNT]))
@@ -48424,7 +48482,7 @@ def doCourseRemoveItems(courseIdList, getEntityListArg):
# gam courses <CourseEntity> clear teachers|students # gam courses <CourseEntity> clear teachers|students
# gam course <CourseID> clear teacher|student # gam course <CourseID> clear teacher|student
def doCourseClearParticipants(courseIdList, getEntityListArg): def doCourseClearParticipants(courseIdList, _):
croom = buildGAPIObject(API.CLASSROOM) croom = buildGAPIObject(API.CLASSROOM)
role = getChoice(CLEAR_SYNC_PARTICIPANT_TYPES_MAP, mapChoice=True) role = getChoice(CLEAR_SYNC_PARTICIPANT_TYPES_MAP, mapChoice=True)
checkForExtraneousArguments() checkForExtraneousArguments()
@@ -48440,7 +48498,7 @@ def doCourseClearParticipants(courseIdList, getEntityListArg):
# gam course <CourseID> sync students [addonly|removeonly] <UserTypeEntity> # gam course <CourseID> sync students [addonly|removeonly] <UserTypeEntity>
# gam courses <CourseEntity> sync teachers [addonly|removeonly] [makefirstteacherowner] <UserTypeEntity> # gam courses <CourseEntity> sync teachers [addonly|removeonly] [makefirstteacherowner] <UserTypeEntity>
# gam course <CourseID> sync teachers [addonly|removeonly] [makefirstteacherowner] <UserTypeEntity> # gam course <CourseID> sync teachers [addonly|removeonly] [makefirstteacherowner] <UserTypeEntity>
def doCourseSyncParticipants(courseIdList, getEntityListArg): def doCourseSyncParticipants(courseIdList, _):
croom = buildGAPIObject(API.CLASSROOM) croom = buildGAPIObject(API.CLASSROOM)
role = getChoice(CLEAR_SYNC_PARTICIPANT_TYPES_MAP, mapChoice=True) role = getChoice(CLEAR_SYNC_PARTICIPANT_TYPES_MAP, mapChoice=True)
if role == Ent.TEACHER: if role == Ent.TEACHER:
@@ -58176,6 +58234,7 @@ def initCopyMoveOptions(copyCmd):
'showPermissionMessages': False, 'showPermissionMessages': False,
'sendEmailIfRequired': False, 'sendEmailIfRequired': False,
'useDomainAdminAccess': False, 'useDomainAdminAccess': False,
'enforceExpansiveAccess': False,
'copiedShortcutsPointToCopiedFiles': True, 'copiedShortcutsPointToCopiedFiles': True,
'createShortcutsForNonmovableFiles': False, 'createShortcutsForNonmovableFiles': False,
'duplicateFiles': DUPLICATE_FILE_OVERWRITE_OLDER, 'duplicateFiles': DUPLICATE_FILE_OVERWRITE_OLDER,
@@ -58274,6 +58333,8 @@ def getCopyMoveOptions(myarg, copyMoveOptions):
elif myarg == 'mappermissionsdomain': elif myarg == 'mappermissionsdomain':
oldDomain = getString(Cmd.OB_DOMAIN_NAME).lower() oldDomain = getString(Cmd.OB_DOMAIN_NAME).lower()
copyMoveOptions['mapPermissionsDomains'][oldDomain] = getString(Cmd.OB_DOMAIN_NAME).lower() copyMoveOptions['mapPermissionsDomains'][oldDomain] = getString(Cmd.OB_DOMAIN_NAME).lower()
elif myarg == 'enforceexpansiveaccess':
copyMoveOptions['enforceExpansiveAccess'] = getBoolean()
else: else:
# Move arguments # Move arguments
if not copyMoveOptions['copyCmd']: if not copyMoveOptions['copyCmd']:
@@ -58545,6 +58606,9 @@ def _copyPermissions(drive, user, i, count, j, jcount,
updateTargetPerms[permissionId].update(updatePerm) updateTargetPerms[permissionId].update(updatePerm)
updateTargetPerms[permissionId]['updates'] = updatePerm updateTargetPerms[permissionId]['updates'] = updatePerm
copySourcePerms.pop(permissionId) copySourcePerms.pop(permissionId)
deleteUpdateKwargs = {'useDomainAdminAccess': copyMoveOptions['useDomainAdminAccess']}
if entityType != Ent.SHAREDDRIVE:
deleteUpdateKwargs['enforceExpansiveAccess'] = copyMoveOptions['enforceExpansiveAccess']
Ind.Increment() Ind.Increment()
action = Act.Get() action = Act.Get()
Act.Set(Act.COPY) Act.Set(Act.COPY)
@@ -58563,8 +58627,9 @@ def _copyPermissions(drive, user, i, count, j, jcount,
callGAPI(drive.permissions(), 'create', callGAPI(drive.permissions(), 'create',
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_CREATE_ACL_THROW_REASONS, throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_CREATE_ACL_THROW_REASONS,
# retryReasons=[GAPI.INVALID_SHARING_REQUEST], # retryReasons=[GAPI.INVALID_SHARING_REQUEST],
useDomainAdminAccess=copyMoveOptions['useDomainAdminAccess'],
fileId=newFileId, sendNotificationEmail=sendNotificationEmail, emailMessage=None, fileId=newFileId, sendNotificationEmail=sendNotificationEmail, emailMessage=None,
body=permission, fields='', useDomainAdminAccess=copyMoveOptions['useDomainAdminAccess'], supportsAllDrives=True) body=permission, fields='', supportsAllDrives=True)
if copyMoveOptions['showPermissionMessages']: if copyMoveOptions['showPermissionMessages']:
entityActionPerformed(kvList, k, kcount) entityActionPerformed(kvList, k, kcount)
break break
@@ -58602,7 +58667,8 @@ def _copyPermissions(drive, user, i, count, j, jcount,
try: try:
callGAPI(drive.permissions(), 'delete', 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+[GAPI.FILE_NEVER_WRITABLE],
fileId=newFileId, permissionId=permissionId, useDomainAdminAccess=copyMoveOptions['useDomainAdminAccess'], supportsAllDrives=True) **deleteUpdateKwargs,
fileId=newFileId, permissionId=permissionId, supportsAllDrives=True)
if copyMoveOptions['showPermissionMessages']: if copyMoveOptions['showPermissionMessages']:
entityActionPerformed(kvList, k, kcount) entityActionPerformed(kvList, k, kcount)
except (GAPI.notFound, GAPI.permissionNotFound, except (GAPI.notFound, GAPI.permissionNotFound,
@@ -58627,8 +58693,9 @@ def _copyPermissions(drive, user, i, count, j, jcount,
callGAPI(drive.permissions(), 'update', callGAPI(drive.permissions(), 'update',
bailOnInternalError=True, bailOnInternalError=True,
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_UPDATE_ACL_THROW_REASONS+[GAPI.FILE_NEVER_WRITABLE], throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_UPDATE_ACL_THROW_REASONS+[GAPI.FILE_NEVER_WRITABLE],
fileId=newFileId, permissionId=permissionId, removeExpiration=removeExpiration, removeExpiration=removeExpiration,
body=permission['updates'], useDomainAdminAccess=copyMoveOptions['useDomainAdminAccess'], supportsAllDrives=True) **deleteUpdateKwargs,
fileId=newFileId, permissionId=permissionId, body=permission['updates'], supportsAllDrives=True)
if copyMoveOptions['showPermissionMessages']: if copyMoveOptions['showPermissionMessages']:
entityActionPerformed(kvList, k, kcount) entityActionPerformed(kvList, k, kcount)
except (GAPI.notFound, GAPI.permissionNotFound, except (GAPI.notFound, GAPI.permissionNotFound,
@@ -58902,6 +58969,7 @@ copyReturnItemMap = {
# [sendemailifrequired [<Boolean>]] # [sendemailifrequired [<Boolean>]]
# [suppressnotselectedmessages [<Boolean>]] # [suppressnotselectedmessages [<Boolean>]]
# [verifyorganizer [<Boolean>]] # [verifyorganizer [<Boolean>]]
# [enforceexpansiveaccess [<Boolean>]]
def copyDriveFile(users): def copyDriveFile(users):
def _writeCSVData(user, oldName, oldId, newName, newId, mimeType): def _writeCSVData(user, oldName, oldId, newName, newId, mimeType):
row = {'User': user, fileNameTitle: oldName, 'id': oldId, row = {'User': user, fileNameTitle: oldName, 'id': oldId,
@@ -59629,7 +59697,9 @@ def _updateMoveFilePermissions(drive, user, i, count,
try: try:
callGAPI(drive.permissions(), 'delete', 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+[GAPI.FILE_NEVER_WRITABLE],
fileId=fileId, permissionId=permissionId, useDomainAdminAccess=copyMoveOptions['useDomainAdminAccess'], supportsAllDrives=True) useDomainAdminAccess=copyMoveOptions['useDomainAdminAccess'],
enforceExpansiveAccess=copyMoveOptions['enforceExpansiveAccess'],
fileId=fileId, permissionId=permissionId, supportsAllDrives=True)
if copyMoveOptions['showPermissionMessages']: if copyMoveOptions['showPermissionMessages']:
entityActionPerformed(kvList, k, kcount) entityActionPerformed(kvList, k, kcount)
except (GAPI.notFound, GAPI.permissionNotFound, except (GAPI.notFound, GAPI.permissionNotFound,
@@ -59717,6 +59787,7 @@ def _updateMoveFilePermissions(drive, user, i, count,
# [retainsourcefolders [<Boolean>]] # [retainsourcefolders [<Boolean>]]
# [sendemailifrequired [<Boolean>]] # [sendemailifrequired [<Boolean>]]
# [verifyorganizer [<Boolean>]] # [verifyorganizer [<Boolean>]]
# [enforceexpansiveaccess [<Boolean>]]
def moveDriveFile(users): def moveDriveFile(users):
def _cloneFolderMove(drive, user, i, count, j, jcount, def _cloneFolderMove(drive, user, i, count, j, jcount,
source, targetChildren, newFolderName, newParentId, newParentName, mergeParentModifiedTime, source, targetChildren, newFolderName, newParentId, newParentName, mergeParentModifiedTime,
@@ -60060,9 +60131,8 @@ def moveDriveFile(users):
parentBody = {} parentBody = {}
parentParms = initDriveFileAttributes() parentParms = initDriveFileAttributes()
copyMoveOptions = initCopyMoveOptions(False) copyMoveOptions = initCopyMoveOptions(False)
newParentsSpecified = False newParentsSpecified = updateFilePermissions = False
movedFiles = {} movedFiles = {}
updateFilePermissions = False
verifyOrganizer = True verifyOrganizer = True
while Cmd.ArgumentsRemaining(): while Cmd.ArgumentsRemaining():
myarg = getArgument() myarg = getArgument()
@@ -60951,6 +61021,7 @@ TRANSFER_DRIVEFILE_ACL_ROLES_MAP = {
# [nonowner_retainrole reader|commenter|writer|editor|fileorganizer|current|none] # [nonowner_retainrole reader|commenter|writer|editor|fileorganizer|current|none]
# [nonowner_targetrole reader|commenter|writer|editor|fileorganizer|current|none|source] # [nonowner_targetrole reader|commenter|writer|editor|fileorganizer|current|none|source]
# (orderby <DriveFileOrderByFieldName> [ascending|descending])* # (orderby <DriveFileOrderByFieldName> [ascending|descending])*
# [enforceexpansiveaccess [<Boolean>]]
# [preview] [todrive <ToDriveAttribute>*] # [preview] [todrive <ToDriveAttribute>*]
def transferDrive(users): def transferDrive(users):
@@ -61137,6 +61208,7 @@ def transferDrive(users):
callGAPI(sourceDrive.permissions(), 'update', callGAPI(sourceDrive.permissions(), 'update',
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.BAD_REQUEST, GAPI.INVALID_OWNERSHIP_TRANSFER, throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.BAD_REQUEST, GAPI.INVALID_OWNERSHIP_TRANSFER,
GAPI.PERMISSION_NOT_FOUND, GAPI.SHARING_RATE_LIMIT_EXCEEDED], GAPI.PERMISSION_NOT_FOUND, GAPI.SHARING_RATE_LIMIT_EXCEEDED],
enforceExpansiveAccess=enforceExpansiveAccess,
fileId=childFileId, permissionId=targetPermissionId, fileId=childFileId, permissionId=targetPermissionId,
transferOwnership=True, body={'role': 'owner'}, fields='') transferOwnership=True, body={'role': 'owner'}, fields='')
if removeSourceParents: if removeSourceParents:
@@ -61325,6 +61397,7 @@ def transferDrive(users):
if ownerRetainRoleBody['role'] != 'writer': if ownerRetainRoleBody['role'] != 'writer':
callGAPI(targetDrive.permissions(), 'update', callGAPI(targetDrive.permissions(), 'update',
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.PERMISSION_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.SHARING_RATE_LIMIT_EXCEEDED],
enforceExpansiveAccess=enforceExpansiveAccess,
fileId=childFileId, permissionId=sourcePermissionId, body=ownerRetainRoleBody, fields='') fileId=childFileId, permissionId=sourcePermissionId, body=ownerRetainRoleBody, fields='')
else: else:
callGAPI(targetDrive.permissions(), 'delete', callGAPI(targetDrive.permissions(), 'delete',
@@ -61374,6 +61447,7 @@ def transferDrive(users):
if nonOwnerRetainRoleBody['role'] != 'current': if nonOwnerRetainRoleBody['role'] != 'current':
callGAPI(ownerDrive.permissions(), 'update', callGAPI(ownerDrive.permissions(), 'update',
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.PERMISSION_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.SHARING_RATE_LIMIT_EXCEEDED],
enforceExpansiveAccess=enforceExpansiveAccess,
fileId=childFileId, permissionId=sourcePermissionId, body=sourceUpdateRole, fields='') fileId=childFileId, permissionId=sourcePermissionId, body=sourceUpdateRole, fields='')
else: else:
try: try:
@@ -61534,7 +61608,7 @@ def transferDrive(users):
targetUserFolderPattern = '#user# old files' targetUserFolderPattern = '#user# old files'
targetUserOrphansFolderPattern = '#user# orphaned files' targetUserOrphansFolderPattern = '#user# orphaned files'
targetIds = [None, None] targetIds = [None, None]
createShortcutsForNonmovableFiles = False createShortcutsForNonmovableFiles = enforceExpansiveAccess = False
mergeWithTarget = False mergeWithTarget = False
thirdPartyOwners = {} thirdPartyOwners = {}
skipFileIdEntity = initDriveFileEntity() skipFileIdEntity = initDriveFileEntity()
@@ -61552,6 +61626,8 @@ def transferDrive(users):
nonOwnerRetainRoleBody['role'] = 'current' nonOwnerRetainRoleBody['role'] = 'current'
elif myarg == 'nonownertargetrole': elif myarg == 'nonownertargetrole':
nonOwnerTargetRoleBody['role'] = getChoice(TRANSFER_DRIVEFILE_ACL_ROLES_MAP, mapChoice=True) nonOwnerTargetRoleBody['role'] = getChoice(TRANSFER_DRIVEFILE_ACL_ROLES_MAP, mapChoice=True)
elif myarg == 'enforceexpansiveaccess':
enforceExpansiveAccess = getBoolean()
elif myarg == 'noretentionmessages': elif myarg == 'noretentionmessages':
showRetentionMessages = False showRetentionMessages = False
elif myarg == 'orderby': elif myarg == 'orderby':
@@ -61789,6 +61865,7 @@ def getPermissionIdForEmail(user, i, count, email):
# [<DriveFileParentAttribute>] [includetrashed] [norecursion [<Boolean>]] # [<DriveFileParentAttribute>] [includetrashed] [norecursion [<Boolean>]]
# (orderby <DriveFileOrderByFieldName> [ascending|descending])* # (orderby <DriveFileOrderByFieldName> [ascending|descending])*
# [preview] [filepath] [pathdelimiter <Character>] [buildtree] # [preview] [filepath] [pathdelimiter <Character>] [buildtree]
# [enforceexpansiveaccess [<Boolean>]]
# [todrive <ToDriveAttribute>*] # [todrive <ToDriveAttribute>*]
def transferOwnership(users): def transferOwnership(users):
def _identifyFilesToTransfer(fileEntry): def _identifyFilesToTransfer(fileEntry):
@@ -61837,7 +61914,7 @@ def transferOwnership(users):
body = {} body = {}
newOwner = getEmailAddress() newOwner = getEmailAddress()
OBY = OrderBy(DRIVEFILE_ORDERBY_CHOICE_MAP) OBY = OrderBy(DRIVEFILE_ORDERBY_CHOICE_MAP)
changeParents = filepath = includeTrashed = noRecursion = False changeParents = enforceExpansiveAccess = filepath = includeTrashed = noRecursion = False
pathDelimiter = '/' pathDelimiter = '/'
csvPF = fileTree = None csvPF = fileTree = None
addParents = '' addParents = ''
@@ -61864,6 +61941,8 @@ def transferOwnership(users):
csvPF.GetTodriveParameters() csvPF.GetTodriveParameters()
elif getDriveFileParentAttribute(myarg, parentParms): elif getDriveFileParentAttribute(myarg, parentParms):
changeParents = True changeParents = True
elif myarg == 'enforceexpansiveaccess':
enforceExpansiveAccess = getBoolean()
else: else:
unknownArgumentExit() unknownArgumentExit()
Act.Set(Act.TRANSFER_OWNERSHIP) Act.Set(Act.TRANSFER_OWNERSHIP)
@@ -61981,6 +62060,7 @@ def transferOwnership(users):
Act.Set(action) Act.Set(action)
callGAPI(drive.permissions(), 'update', callGAPI(drive.permissions(), 'update',
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND], throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND],
enforceExpansiveAccess=enforceExpansiveAccess,
fileId=xferFileId, permissionId=permissionId, transferOwnership=True, body=body, fields='') fileId=xferFileId, permissionId=permissionId, transferOwnership=True, body=body, fields='')
entityModifierNewValueItemValueListActionPerformed(kvList, Act.MODIFIER_TO, None, [Ent.USER, newOwner], k, kcount) entityModifierNewValueItemValueListActionPerformed(kvList, Act.MODIFIER_TO, None, [Ent.USER, newOwner], k, kcount)
else: else:
@@ -62002,6 +62082,7 @@ def transferOwnership(users):
fileId=xferFileId, sendNotificationEmail=False, body=bodyAdd, fields='') fileId=xferFileId, sendNotificationEmail=False, body=bodyAdd, fields='')
callGAPI(drive.permissions(), 'update', callGAPI(drive.permissions(), 'update',
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND], throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND],
enforceExpansiveAccess=enforceExpansiveAccess,
fileId=xferFileId, permissionId=permissionId, transferOwnership=True, body=body, fields='') fileId=xferFileId, permissionId=permissionId, transferOwnership=True, body=body, fields='')
entityModifierNewValueItemValueListActionPerformed(kvList, Act.MODIFIER_TO, None, [Ent.USER, newOwner], k, kcount) entityModifierNewValueItemValueListActionPerformed(kvList, Act.MODIFIER_TO, None, [Ent.USER, newOwner], k, kcount)
except GAPI.invalidSharingRequest as e: except GAPI.invalidSharingRequest as e:
@@ -62074,6 +62155,7 @@ def transferOwnership(users):
# [keepuser | (retainrole reader|commenter|writer|editor|none)] [noretentionmessages] # [keepuser | (retainrole reader|commenter|writer|editor|none)] [noretentionmessages]
# (orderby <DriveFileOrderByFieldName> [ascending|descending])* # (orderby <DriveFileOrderByFieldName> [ascending|descending])*
# [preview] [filepath] [pathdelimiter <Character>] [buildtree] # [preview] [filepath] [pathdelimiter <Character>] [buildtree]
# [enforceexpansiveaccess [<Boolean>]]
# [todrive <ToDriveAttribute>*] # [todrive <ToDriveAttribute>*]
def claimOwnership(users): def claimOwnership(users):
def _identifyFilesToClaim(fileEntry): def _identifyFilesToClaim(fileEntry):
@@ -62134,6 +62216,7 @@ def claimOwnership(users):
if sourceRetainRoleBody['role'] != 'writer': if sourceRetainRoleBody['role'] != 'writer':
callGAPI(sourceDrive.permissions(), 'update', callGAPI(sourceDrive.permissions(), 'update',
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND, GAPI.BAD_REQUEST], throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND, GAPI.BAD_REQUEST],
enforceExpansiveAccess=enforceExpansiveAccess,
fileId=ofileId, permissionId=oldOwnerPermissionId, body=sourceRetainRoleBody, fields='') fileId=ofileId, permissionId=oldOwnerPermissionId, body=sourceRetainRoleBody, fields='')
else: else:
callGAPI(sourceDrive.permissions(), 'delete', callGAPI(sourceDrive.permissions(), 'delete',
@@ -62157,7 +62240,7 @@ def claimOwnership(users):
onlyOwners = set() onlyOwners = set()
skipOwners = set() skipOwners = set()
subdomains = [] subdomains = []
filepath = includeTrashed = False enforceExpansiveAccess = filepath = includeTrashed = False
pathDelimiter = '/' pathDelimiter = '/'
addParents = '' addParents = ''
parentBody = {} parentBody = {}
@@ -62192,6 +62275,8 @@ def claimOwnership(users):
includeTrashed = True includeTrashed = True
elif myarg == 'orderby': elif myarg == 'orderby':
OBY.GetChoice() OBY.GetChoice()
elif myarg == 'enforceexpansiveaccess':
enforceExpansiveAccess = getBoolean()
elif myarg == 'restricted': elif myarg == 'restricted':
bodyShare['copyRequiresWriterPermission'] = getBoolean() bodyShare['copyRequiresWriterPermission'] = getBoolean()
elif myarg == 'writerscanshare': elif myarg == 'writerscanshare':
@@ -62362,6 +62447,7 @@ def claimOwnership(users):
Act.Set(action) Act.Set(action)
callGAPI(sourceDrive.permissions(), 'update', callGAPI(sourceDrive.permissions(), 'update',
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND], throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND],
enforceExpansiveAccess=enforceExpansiveAccess,
fileId=xferFileId, permissionId=permissionId, transferOwnership=True, body=body, fields='') fileId=xferFileId, permissionId=permissionId, transferOwnership=True, body=body, fields='')
kvList = [Ent.USER, user, entityType, fileDesc] kvList = [Ent.USER, user, entityType, fileDesc]
entityModifierNewValueItemValueListActionPerformed(kvList, Act.MODIFIER_FROM, None, [Ent.USER, oldOwner], l, lcount) entityModifierNewValueItemValueListActionPerformed(kvList, Act.MODIFIER_FROM, None, [Ent.USER, oldOwner], l, lcount)
@@ -62386,6 +62472,7 @@ def claimOwnership(users):
fileId=xferFileId, sendNotificationEmail=False, body=bodyAdd, fields='') fileId=xferFileId, sendNotificationEmail=False, body=bodyAdd, fields='')
callGAPI(sourceDrive.permissions(), 'update', callGAPI(sourceDrive.permissions(), 'update',
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND], throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.PERMISSION_NOT_FOUND],
enforceExpansiveAccess=enforceExpansiveAccess,
fileId=xferFileId, permissionId=permissionId, transferOwnership=True, body=body, fields='') fileId=xferFileId, permissionId=permissionId, transferOwnership=True, body=body, fields='')
entityModifierNewValueItemValueListActionPerformed(kvList, Act.MODIFIER_FROM, None, [Ent.USER, oldOwner], l, lcount) entityModifierNewValueItemValueListActionPerformed(kvList, Act.MODIFIER_FROM, None, [Ent.USER, oldOwner], l, lcount)
_processRetainedRole(user, i, count, oldOwner, entityType, xferFileId, fileDesc, l, lcount) _processRetainedRole(user, i, count, oldOwner, entityType, xferFileId, fileDesc, l, lcount)
@@ -62922,11 +63009,12 @@ def doCreateDriveFileACL():
# gam [<UserTypeEntity>] update drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail> [asadmin] # gam [<UserTypeEntity>] update drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail> [asadmin]
# (role <DriveFileACLRole>) [expiration <Time>] [removeexpiration [<Boolean>]] # (role <DriveFileACLRole>) [expiration <Time>] [removeexpiration [<Boolean>]]
# [updatesheetprotectedranges [<Boolean>]] # [updatesheetprotectedranges [<Boolean>]] [enforceexpansiveaccess [<Boolean>]]
# [showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])] # [showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])]
def updateDriveFileACLs(users, useDomainAdminAccess=False): def updateDriveFileACLs(users, useDomainAdminAccess=False):
fileIdEntity = getDriveFileEntity() fileIdEntity = getDriveFileEntity()
isEmail, permissionId = getPermissionId() isEmail, permissionId = getPermissionId()
enforceExpansiveAccess = None
removeExpiration = showTitles = updateSheetProtectedRanges = False removeExpiration = showTitles = updateSheetProtectedRanges = False
showDetails = True showDetails = True
csvPF = None csvPF = None
@@ -62945,6 +63033,8 @@ def updateDriveFileACLs(users, useDomainAdminAccess=False):
showTitles = True showTitles = True
elif myarg == 'updatesheetprotectedranges': elif myarg == 'updatesheetprotectedranges':
updateSheetProtectedRanges = getBoolean() updateSheetProtectedRanges = getBoolean()
elif myarg == 'enforceexpansiveaccess':
enforceExpansiveAccess = getBoolean()
elif myarg == 'nodetails': elif myarg == 'nodetails':
showDetails = False showDetails = False
elif myarg == 'csv': elif myarg == 'csv':
@@ -62962,6 +63052,9 @@ def updateDriveFileACLs(users, useDomainAdminAccess=False):
_checkFileIdEntityDomainAccess(fileIdEntity, useDomainAdminAccess) _checkFileIdEntityDomainAccess(fileIdEntity, useDomainAdminAccess)
if 'role' not in body: if 'role' not in body:
missingArgumentExit(f'role {formatChoiceList(DRIVEFILE_ACL_ROLES_MAP)}') missingArgumentExit(f'role {formatChoiceList(DRIVEFILE_ACL_ROLES_MAP)}')
updateKwargs = {'useDomainAdminAccess': useDomainAdminAccess}
if enforceExpansiveAccess is not None:
updateKwargs['enforceExpansiveAccess'] = enforceExpansiveAccess
printKeys, timeObjects = _getDriveFileACLPrintKeysTimeObjects() printKeys, timeObjects = _getDriveFileACLPrintKeysTimeObjects()
if csvPF and showTitles: if csvPF and showTitles:
csvPF.AddTitles(fileNameTitle) csvPF.AddTitles(fileNameTitle)
@@ -62999,7 +63092,7 @@ def updateDriveFileACLs(users, useDomainAdminAccess=False):
permission = callGAPI(drive.permissions(), 'update', permission = callGAPI(drive.permissions(), 'update',
bailOnInternalError=True, bailOnInternalError=True,
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_UPDATE_ACL_THROW_REASONS+[GAPI.FILE_NEVER_WRITABLE], throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_UPDATE_ACL_THROW_REASONS+[GAPI.FILE_NEVER_WRITABLE],
useDomainAdminAccess=useDomainAdminAccess, **updateKwargs,
fileId=fileId, permissionId=permissionId, removeExpiration=removeExpiration, fileId=fileId, permissionId=permissionId, removeExpiration=removeExpiration,
transferOwnership=body.get('role', '') == 'owner', body=body, fields='*', supportsAllDrives=True) transferOwnership=body.get('role', '') == 'owner', body=body, fields='*', supportsAllDrives=True)
if updateSheetProtectedRanges and mimeType == MIMETYPE_GA_SPREADSHEET: if updateSheetProtectedRanges and mimeType == MIMETYPE_GA_SPREADSHEET:
@@ -63095,7 +63188,7 @@ def createDriveFilePermissions(users, useDomainAdminAccess=False):
except ValueError: except ValueError:
return None return None
def _callbackCreatePermission(request_id, response, exception): def _callbackCreatePermission(request_id, _, exception):
ri = request_id.splitlines() ri = request_id.splitlines()
if int(ri[RI_J]) == 1: if int(ri[RI_J]) == 1:
entityPerformActionNumItems([Ent.DRIVE_FILE_OR_FOLDER_ID, ri[RI_ENTITY]], int(ri[RI_JCOUNT]), Ent.PERMITTEE, int(ri[RI_I]), int(ri[RI_COUNT])) entityPerformActionNumItems([Ent.DRIVE_FILE_OR_FOLDER_ID, ri[RI_ENTITY]], int(ri[RI_JCOUNT]), Ent.PERMITTEE, int(ri[RI_I]), int(ri[RI_COUNT]))
@@ -63243,11 +63336,12 @@ def doCreatePermissions():
createDriveFilePermissions([_getAdminEmail()], True) createDriveFilePermissions([_getAdminEmail()], True)
# gam [<UserTypeEntity>] delete drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail> [asadmin] # gam [<UserTypeEntity>] delete drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail> [asadmin]
# [updatesheetprotectedranges [<Boolean>]] # [updatesheetprotectedranges [<Boolean>]] [enforceexpansiveaccess [<Boolean>]]
# [showtitles] # [showtitles]
def deleteDriveFileACLs(users, useDomainAdminAccess=False): def deleteDriveFileACLs(users, useDomainAdminAccess=False):
fileIdEntity = getDriveFileEntity() fileIdEntity = getDriveFileEntity()
isEmail, permissionId = getPermissionId() isEmail, permissionId = getPermissionId()
enforceExpansiveAccess = None
showTitles = updateSheetProtectedRanges = False showTitles = updateSheetProtectedRanges = False
while Cmd.ArgumentsRemaining(): while Cmd.ArgumentsRemaining():
myarg = getArgument() myarg = getArgument()
@@ -63255,11 +63349,16 @@ def deleteDriveFileACLs(users, useDomainAdminAccess=False):
showTitles = getBoolean() showTitles = getBoolean()
elif myarg == 'updatesheetprotectedranges': elif myarg == 'updatesheetprotectedranges':
updateSheetProtectedRanges = getBoolean() updateSheetProtectedRanges = getBoolean()
elif myarg == 'enforceexpansiveaccess':
enforceExpansiveAccess = getBoolean()
elif myarg in ADMIN_ACCESS_OPTIONS: elif myarg in ADMIN_ACCESS_OPTIONS:
useDomainAdminAccess = True useDomainAdminAccess = True
else: else:
unknownArgumentExit() unknownArgumentExit()
_checkFileIdEntityDomainAccess(fileIdEntity, useDomainAdminAccess) _checkFileIdEntityDomainAccess(fileIdEntity, useDomainAdminAccess)
deleteKwargs = {'useDomainAdminAccess': useDomainAdminAccess}
if enforceExpansiveAccess is not None:
deleteKwargs['enforceExpansiveAccess'] = enforceExpansiveAccess
i, count, users = getEntityArgument(users) i, count, users = getEntityArgument(users)
for user in users: for user in users:
i += 1 i += 1
@@ -63292,7 +63391,8 @@ def deleteDriveFileACLs(users, useDomainAdminAccess=False):
break break
callGAPI(drive.permissions(), 'delete', 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+[GAPI.FILE_NEVER_WRITABLE],
useDomainAdminAccess=useDomainAdminAccess, fileId=fileId, permissionId=permissionId, supportsAllDrives=True) **deleteKwargs,
fileId=fileId, permissionId=permissionId, supportsAllDrives=True)
entityActionPerformed([Ent.USER, user, entityType, fileName, Ent.PERMISSION_ID, permissionId], j, jcount) entityActionPerformed([Ent.USER, user, entityType, fileName, Ent.PERMISSION_ID, permissionId], j, jcount)
if updateSheetProtectedRanges and mimeType == MIMETYPE_GA_SPREADSHEET: if updateSheetProtectedRanges and mimeType == MIMETYPE_GA_SPREADSHEET:
_updateSheetProtectedRangesACLchange(sheet, user, i, count, j, jcount, fileId, fileName, False, permission) _updateSheetProtectedRangesACLchange(sheet, user, i, count, j, jcount, fileId, fileName, False, permission)
@@ -63314,6 +63414,7 @@ def doDeleteDriveFileACLs():
# gam [<UserTypeEntity>] delete permissions <DriveFileEntity> <DriveFilePermissionIDEntity> [asadmin] # gam [<UserTypeEntity>] delete permissions <DriveFileEntity> <DriveFilePermissionIDEntity> [asadmin]
# <PermissionMatch>* [<PermissionMatchAction>] # <PermissionMatch>* [<PermissionMatchAction>]
# [enforceexpansiveaccess [<Boolean>]]
def deletePermissions(users, useDomainAdminAccess=False): def deletePermissions(users, useDomainAdminAccess=False):
def convertJSONPermissions(jsonPermissions): def convertJSONPermissions(jsonPermissions):
permissionIds = [] permissionIds = []
@@ -63323,7 +63424,7 @@ def deletePermissions(users, useDomainAdminAccess=False):
permissionIds.append(permission['id']) permissionIds.append(permission['id'])
return permissionIds return permissionIds
def _callbackDeletePermissionId(request_id, response, exception): def _callbackDeletePermissionId(request_id, _, exception):
ri = request_id.splitlines() ri = request_id.splitlines()
if int(ri[RI_J]) == 1: if int(ri[RI_J]) == 1:
entityPerformActionNumItems([Ent.DRIVE_FILE_OR_FOLDER_ID, ri[RI_ENTITY]], int(ri[RI_JCOUNT]), Ent.PERMISSION_ID, int(ri[RI_I]), int(ri[RI_COUNT])) entityPerformActionNumItems([Ent.DRIVE_FILE_OR_FOLDER_ID, ri[RI_ENTITY]], int(ri[RI_JCOUNT]), Ent.PERMISSION_ID, int(ri[RI_I]), int(ri[RI_COUNT]))
@@ -63348,7 +63449,8 @@ def deletePermissions(users, useDomainAdminAccess=False):
callGAPI(drive.permissions(), 'delete', callGAPI(drive.permissions(), 'delete',
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_DELETE_ACL_THROW_REASONS, throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_DELETE_ACL_THROW_REASONS,
retryReasons=[GAPI.SERVICE_LIMIT], retryReasons=[GAPI.SERVICE_LIMIT],
useDomainAdminAccess=useDomainAdminAccess, fileId=ri[RI_ENTITY], permissionId=ri[RI_ITEM], supportsAllDrives=True) useDomainAdminAccess=useDomainAdminAccess, enforceExpansiveAccess=enforceExpansiveAccess,
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])) 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, except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError,
GAPI.badRequest, GAPI.cannotRemoveOwner, GAPI.cannotModifyInheritedTeamDrivePermission, GAPI.badRequest, GAPI.cannotRemoveOwner, GAPI.cannotModifyInheritedTeamDrivePermission,
@@ -63368,12 +63470,15 @@ def deletePermissions(users, useDomainAdminAccess=False):
jsonData = getJSON([]) jsonData = getJSON([])
PM = PermissionMatch() PM = PermissionMatch()
PM.SetDefaultMatch(False, {'role': 'owner'}) PM.SetDefaultMatch(False, {'role': 'owner'})
enforceExpansiveAccess = False
while Cmd.ArgumentsRemaining(): while Cmd.ArgumentsRemaining():
myarg = getArgument() myarg = getArgument()
if myarg in ADMIN_ACCESS_OPTIONS: if myarg in ADMIN_ACCESS_OPTIONS:
useDomainAdminAccess = True useDomainAdminAccess = True
elif PM and PM.ProcessArgument(myarg): elif PM and PM.ProcessArgument(myarg):
pass pass
elif myarg == 'enforceexpansiveaccess':
enforceExpansiveAccess = getBoolean()
else: else:
unknownArgumentExit() unknownArgumentExit()
_checkFileIdEntityDomainAccess(fileIdEntity, useDomainAdminAccess) _checkFileIdEntityDomainAccess(fileIdEntity, useDomainAdminAccess)
@@ -68604,7 +68709,7 @@ def deleteLabels(users, labelEntity):
http_status, reason, message = checkGAPIError(exception) http_status, reason, message = checkGAPIError(exception)
entityActionFailedWarning([Ent.USER, ri[RI_ENTITY], Ent.LABEL, labelIdToNameMap[ri[RI_ITEM]]], formatHTTPError(http_status, reason, message), int(ri[RI_J]), int(ri[RI_JCOUNT])) entityActionFailedWarning([Ent.USER, ri[RI_ENTITY], Ent.LABEL, labelIdToNameMap[ri[RI_ITEM]]], formatHTTPError(http_status, reason, message), int(ri[RI_J]), int(ri[RI_JCOUNT]))
def _callbackDeleteLabel(request_id, response, exception): def _callbackDeleteLabel(request_id, _, exception):
ri = request_id.splitlines() ri = request_id.splitlines()
if exception is None: if exception is None:
entityActionPerformed([Ent.USER, ri[RI_ENTITY], Ent.LABEL, labelIdToNameMap[ri[RI_ITEM]]], int(ri[RI_J]), int(ri[RI_JCOUNT])) entityActionPerformed([Ent.USER, ri[RI_ENTITY], Ent.LABEL, labelIdToNameMap[ri[RI_ITEM]]], int(ri[RI_J]), int(ri[RI_JCOUNT]))
@@ -69205,7 +69310,7 @@ def _processMessagesThreads(users, entityType):
GAPI.INVALID_MESSAGE_ID: Msg.INVALID_MESSAGE_ID, GAPI.INVALID_MESSAGE_ID: Msg.INVALID_MESSAGE_ID,
GAPI.FAILED_PRECONDITION: Msg.FAILED_PRECONDITION} GAPI.FAILED_PRECONDITION: Msg.FAILED_PRECONDITION}
def _callbackProcessMessage(request_id, response, exception): def _callbackProcessMessage(request_id, _, exception):
ri = request_id.splitlines() ri = request_id.splitlines()
if exception is None: if exception is None:
if not csvPF: if not csvPF:

View File

@@ -75,6 +75,7 @@ KEEP = 'keep'
LICENSING = 'licensing' LICENSING = 'licensing'
LOOKERSTUDIO = 'datastudio' LOOKERSTUDIO = 'datastudio'
MEET = 'meet' MEET = 'meet'
MEET_BETA = 'meetbeta'
OAUTH2 = 'oauth2' OAUTH2 = 'oauth2'
ORGPOLICY = 'orgpolicy' ORGPOLICY = 'orgpolicy'
PEOPLE = 'people' PEOPLE = 'people'
@@ -226,7 +227,7 @@ _INFO = {
CLOUDIDENTITY_INBOUND_SSO: {'name': 'Cloud Identity Inbound SSO API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'}, CLOUDIDENTITY_INBOUND_SSO: {'name': 'Cloud Identity Inbound SSO API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
CLOUDIDENTITY_ORGUNITS: {'name': 'Cloud Identity OrgUnits API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'}, CLOUDIDENTITY_ORGUNITS: {'name': 'Cloud Identity OrgUnits API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
CLOUDIDENTITY_ORGUNITS_BETA: {'name': 'Cloud Identity OrgUnits API', 'version': 'v1beta1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'}, CLOUDIDENTITY_ORGUNITS_BETA: {'name': 'Cloud Identity OrgUnits API', 'version': 'v1beta1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
CLOUDIDENTITY_POLICY: {'name': 'Cloud Identity Policy API', 'version': 'v1beta1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'}, CLOUDIDENTITY_POLICY: {'name': 'Cloud Identity Policy API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
CLOUDIDENTITY_USERINVITATIONS: {'name': 'Cloud Identity User Invitations API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'}, CLOUDIDENTITY_USERINVITATIONS: {'name': 'Cloud Identity User Invitations API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
CLOUDRESOURCEMANAGER: {'name': 'Cloud Resource Manager API v3', 'version': 'v3', 'v2discovery': True}, CLOUDRESOURCEMANAGER: {'name': 'Cloud Resource Manager API v3', 'version': 'v3', 'v2discovery': True},
CONTACTS: {'name': 'Contacts API', 'version': 'v3', 'v2discovery': False}, CONTACTS: {'name': 'Contacts API', 'version': 'v3', 'v2discovery': False},
@@ -251,6 +252,7 @@ _INFO = {
LICENSING: {'name': 'License Manager API', 'version': 'v1', 'v2discovery': True}, LICENSING: {'name': 'License Manager API', 'version': 'v1', 'v2discovery': True},
LOOKERSTUDIO: {'name': 'Looker Studio API', 'version': 'v1', 'v2discovery': True, 'localjson': True}, LOOKERSTUDIO: {'name': 'Looker Studio API', 'version': 'v1', 'v2discovery': True, 'localjson': True},
MEET: {'name': 'Meet API', 'version': 'v2', 'v2discovery': True}, MEET: {'name': 'Meet API', 'version': 'v2', 'v2discovery': True},
MEET_BETA: {'name': 'Meet API', 'version': 'v2beta', 'v2discovery': True, 'localjson': True, 'mappedAPI': MEET},
OAUTH2: {'name': 'OAuth2 API', 'version': 'v2', 'v2discovery': False}, OAUTH2: {'name': 'OAuth2 API', 'version': 'v2', 'v2discovery': False},
ORGPOLICY: {'name': 'Organization Policy API', 'version': 'v2', 'v2discovery': True}, ORGPOLICY: {'name': 'Organization Policy API', 'version': 'v2', 'v2discovery': True},
PEOPLE: {'name': 'People API', 'version': 'v1', 'v2discovery': True}, PEOPLE: {'name': 'People API', 'version': 'v1', 'v2discovery': True},

View File

@@ -177,10 +177,12 @@ INTER_BATCH_WAIT = 'inter_batch_wait'
LICENSE_MAX_RESULTS = 'license_max_results' LICENSE_MAX_RESULTS = 'license_max_results'
# License SKUs to process # License SKUs to process
LICENSE_SKUS = 'license_skus' LICENSE_SKUS = 'license_skus'
# Use Meet V2 beta
MEET_V2_BETA = 'meet_v2_beta'
# When retrieving lists of Google Group members from API, how many should be retrieved in each chunk # When retrieving lists of Google Group members from API, how many should be retrieved in each chunk
MEMBER_MAX_RESULTS = 'member_max_results' MEMBER_MAX_RESULTS = 'member_max_results'
# CI API Group members max page size when view=BASIC # CI API Group members max page size when view=BASIC
MEMBER_MAX_RESULTS_CI_BASIC = 'member.max_results_ci_basic' MEMBER_MAX_RESULTS_CI_BASIC = 'member_max_results_ci_basic'
# CI API Group members max page size when view=FULL # CI API Group members max page size when view=FULL
MEMBER_MAX_RESULTS_CI_FULL = 'member_max_results_ci_full' MEMBER_MAX_RESULTS_CI_FULL = 'member_max_results_ci_full'
# When deleting or modifying Gmail messages, how many should be processed in each batch # When deleting or modifying Gmail messages, how many should be processed in each batch
@@ -388,6 +390,7 @@ Defaults = {
INTER_BATCH_WAIT: '0', INTER_BATCH_WAIT: '0',
LICENSE_MAX_RESULTS: '100', LICENSE_MAX_RESULTS: '100',
LICENSE_SKUS: '', LICENSE_SKUS: '',
MEET_V2_BETA: FALSE,
MEMBER_MAX_RESULTS: '200', MEMBER_MAX_RESULTS: '200',
MEMBER_MAX_RESULTS_CI_BASIC: '1000', MEMBER_MAX_RESULTS_CI_BASIC: '1000',
MEMBER_MAX_RESULTS_CI_FULL: '500', MEMBER_MAX_RESULTS_CI_FULL: '500',
@@ -555,6 +558,7 @@ VAR_INFO = {
INTER_BATCH_WAIT: {VAR_TYPE: TYPE_FLOAT, VAR_LIMITS: (0.0, 60.0)}, INTER_BATCH_WAIT: {VAR_TYPE: TYPE_FLOAT, VAR_LIMITS: (0.0, 60.0)},
LICENSE_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (10, 1000)}, LICENSE_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (10, 1000)},
LICENSE_SKUS: {VAR_TYPE: TYPE_STRING, VAR_LIMITS: (0, None)}, LICENSE_SKUS: {VAR_TYPE: TYPE_STRING, VAR_LIMITS: (0, None)},
MEET_V2_BETA: {VAR_TYPE: TYPE_BOOLEAN},
MEMBER_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 200)}, MEMBER_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 200)},
MEMBER_MAX_RESULTS_CI_BASIC: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 1000)}, MEMBER_MAX_RESULTS_CI_BASIC: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 1000)},
MEMBER_MAX_RESULTS_CI_FULL: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 500)}, MEMBER_MAX_RESULTS_CI_FULL: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 500)},

1152
src/gam/meet-v2beta.json Normal file

File diff suppressed because it is too large Load Diff