Compare commits

..

15 Commits

Author SHA1 Message Date
Ross Scroggs
2afc28e017 Updated from v1beta1 to v1 for Cloud Identity - Policy.
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-21 07:22:17 -08:00
Ross Scroggs
90a2d385d6 Force rebuild
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-20 20:24:42 -08:00
Jay Lee
f123fe197f actions: remove collab to see if it fixes Vault API 2025-02-20 17:20:27 -05:00
Ross Scroggs
8503aabefe Enabled support for Limited Access
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-19 19:07:03 -08:00
Ross Scroggs
80933755c4 Enabled support for Limited Access 2025-02-19 18:59:37 -08:00
Ross Scroggs
03148a6ae8 Added initial support for Meet API v2beta
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-18 14:25:35 -08:00
Ross Scroggs
96acd40692 Increment scratch_counter to flush out bug
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-18 12:23:11 -08:00
Ross Scroggs
3004da5ad7 Create meet-v2beta.json 2025-02-18 10:47:03 -08:00
Ross Scroggs
bd699e2b31 Added initial support for Meet API v2beta 2025-02-18 10:40:44 -08:00
Ross Scroggs
0d9e35d013 Updated gam print group-members|cigroup-members to include the email column when fields <MembersFieldNameList> did not include email.
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
2025-02-16 10:35:35 -08:00
Ross Scroggs
af43db44ed Added option minimal|basic|full to gam print|show cigroup-members
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-15 11:11:42 -08:00
Jay Lee
8e3f30e901 display group email instead of unique name
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
2025-02-14 13:47:10 +00:00
Jay Lee
cccbddcf45 use larger ci.members.list() page sizes 2025-02-14 13:32:40 +00:00
Ross Scroggs
a70bbf08ed Improved output formatting for people objects
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-13 19:58:07 -08:00
Jay Lee
57e1625246 remove Sites API library
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-13 16:21:19 +00:00
10 changed files with 1501 additions and 623 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>)*"
@@ -4959,6 +4965,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 +4979,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 +5009,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 +6572,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 +6596,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 +6702,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 +6829,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 +6838,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 +6846,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 +7893,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,90 @@
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
Improved output formatting for the following commands:
```
gam info peoplecontact
gam show peoplecontacts
gam info peopleprofile
gam show peopleprofile
gam <UserTypeEntity> info contacts
gam <UserTypeEntity> show contacts
gam <UserTypeEntity> show peopleprofile
```
7.04.01 7.04.01
Fixed bug where multiple `querytime<String>` values in a query were not properly processed; Fixed bug where multiple `querytime<String>` values in a query were not properly processed;

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.01' __version__ = '7.05.01'
__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
@@ -5981,6 +5983,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:
@@ -7322,12 +7326,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:
@@ -7742,6 +7740,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)
@@ -7750,11 +7754,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])
@@ -7931,14 +7935,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)
@@ -9831,7 +9842,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
@@ -17245,7 +17256,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:
@@ -17326,7 +17337,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:
@@ -21864,12 +21875,29 @@ def _printPerson(entityTypeName, user, person, csvPF, FJQC, parameters):
'JSON': json.dumps(cleanJSON(person), 'JSON': json.dumps(cleanJSON(person),
ensure_ascii=False, sort_keys=True)}) ensure_ascii=False, sort_keys=True)})
PEOPLE_CONTACT_OBJECT_KEYS = {
'addresses': 'type',
'calendarUrls': 'type',
'emailAddresses': 'type',
'events': 'type',
'externalIds': 'type',
'genders': 'value',
'imClients': 'type',
'locations': 'type',
'miscKeywords': 'type',
'nicknames': 'type',
'organizations': 'type',
'relations': 'type',
'urls': 'type',
'userDefined': 'key',
}
def _showPerson(userEntityType, user, entityType, person, i, count, FJQC, parameters): def _showPerson(userEntityType, user, entityType, person, i, count, FJQC, parameters):
_processPersonMetadata(person, parameters) _processPersonMetadata(person, parameters)
if not FJQC.formatJSON: if not FJQC.formatJSON:
printEntity([userEntityType, user, entityType, person['resourceName']], i, count) printEntity([userEntityType, user, entityType, person['resourceName']], i, count)
Ind.Increment() Ind.Increment()
showJSON(None, person) showJSON(None, person, dictObjectsKey=PEOPLE_CONTACT_OBJECT_KEYS)
Ind.Decrement() Ind.Decrement()
else: else:
printLine(json.dumps(cleanJSON(person), ensure_ascii=False, sort_keys=True)) printLine(json.dumps(cleanJSON(person), ensure_ascii=False, sort_keys=True))
@@ -27462,6 +27490,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:
@@ -27485,7 +27515,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'}
@@ -27499,9 +27532,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]
@@ -27512,7 +27551,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
@@ -27522,15 +27564,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
@@ -27545,10 +27589,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
@@ -27583,12 +27626,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)
@@ -27603,7 +27645,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()
@@ -29209,6 +29251,7 @@ DEVICE_FIELDS_CHOICE_MAP = {
'releaseversion': 'releaseVersion', 'releaseversion': 'releaseVersion',
'securitypatchtime': 'securityPatchTime', 'securitypatchtime': 'securityPatchTime',
'serialnumber': 'serialNumber', 'serialnumber': 'serialNumber',
'unifieddeviceid': 'unifiedDeviceId',
'wifimacaddresses': 'wifiMacAddresses' 'wifimacaddresses': 'wifiMacAddresses'
} }
@@ -31981,7 +32024,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]))
@@ -32070,7 +32113,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]))
@@ -32169,7 +32212,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]))
@@ -33406,6 +33449,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>)*
@@ -33618,6 +33662,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:
@@ -33942,6 +33992,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)
@@ -34185,7 +34237,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
@@ -36104,8 +36156,9 @@ 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): memberOptions, memberDisplayOptions, level, typesSet, groupEmail, kwargs):
printGettingAllEntityItemsForWhom(memberRoles if memberRoles else Ent.ROLE_MANAGER_MEMBER_OWNER, groupName, i, count) nameToPrint = groupEmail if groupEmail else groupName
printGettingAllEntityItemsForWhom(memberRoles if memberRoles else Ent.ROLE_MANAGER_MEMBER_OWNER, nameToPrint, i, count)
validRoles = _getCIRoleVerification(memberRoles) validRoles = _getCIRoleVerification(memberRoles)
if memberOptions[MEMBEROPTION_INCLUDEDERIVEDMEMBERSHIP]: if memberOptions[MEMBEROPTION_INCLUDEDERIVEDMEMBERSHIP]:
groupMembers = [] groupMembers = []
@@ -36120,12 +36173,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='FULL', parent=groupName, **kwargs)
fields='nextPageToken,memberships(*)', pageSize=GC.Values[GC.MEMBER_MAX_RESULTS])
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]:
@@ -36159,7 +36211,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:
@@ -36168,37 +36220,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',
@@ -36219,6 +36275,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>]
@@ -36228,6 +36294,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():
@@ -36245,6 +36312,7 @@ def doPrintCIGroupMembers():
rolesSet = set() rolesSet = set()
typesSet = set() typesSet = set()
matchPatterns = {} matchPatterns = {}
listView = 'full'
while Cmd.ArgumentsRemaining(): while Cmd.ArgumentsRemaining():
myarg = getArgument() myarg = getArgument()
if myarg == 'todrive': if myarg == 'todrive':
@@ -36273,7 +36341,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
@@ -36285,8 +36353,12 @@ def doPrintCIGroupMembers():
memberOptions[MEMBEROPTION_RECURSIVE] = False memberOptions[MEMBEROPTION_RECURSIVE] = False
elif myarg == 'nogroupemail': elif myarg == 'nogroupemail':
groupColumn = False groupColumn = False
elif myarg in {'minimal', 'basic', 'full'}:
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']))
@@ -36313,6 +36385,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)
@@ -36339,7 +36412,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) 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:
@@ -36357,6 +36430,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))
@@ -36386,17 +36461,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:
@@ -36407,8 +36484,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,
@@ -36429,7 +36505,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)):
if listView != 'minimal':
memberDetails = f'{member.get("role", Ent.ROLE_MEMBER)}, {member["type"]}, {member["preferredMemberKey"]["id"]}' 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']:
@@ -36454,6 +36533,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':
@@ -36484,6 +36564,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:
@@ -36493,6 +36575,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:
@@ -42272,7 +42355,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():
@@ -43594,7 +43677,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'])
@@ -48100,7 +48183,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]))
@@ -48180,7 +48263,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]))
@@ -48392,7 +48475,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()
@@ -48408,7 +48491,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:
@@ -58144,6 +58227,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,
@@ -58242,6 +58326,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']:
@@ -58513,6 +58599,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)
@@ -58531,8 +58620,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
@@ -58570,7 +58660,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,
@@ -58595,8 +58686,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,
@@ -58870,6 +58962,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,
@@ -59597,7 +59690,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,
@@ -59685,6 +59780,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,
@@ -60028,9 +60124,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()
@@ -60919,6 +61014,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):
@@ -61105,6 +61201,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:
@@ -61293,6 +61390,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',
@@ -61342,6 +61440,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:
@@ -61502,7 +61601,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()
@@ -61520,6 +61619,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':
@@ -61757,6 +61858,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):
@@ -61805,7 +61907,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 = ''
@@ -61832,6 +61934,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)
@@ -61949,6 +62053,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:
@@ -61970,6 +62075,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:
@@ -62042,6 +62148,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):
@@ -62102,6 +62209,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',
@@ -62125,7 +62233,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 = {}
@@ -62160,6 +62268,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':
@@ -62330,6 +62440,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)
@@ -62354,6 +62465,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)
@@ -62890,11 +63002,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
@@ -62913,6 +63026,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':
@@ -62930,6 +63045,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)
@@ -62967,7 +63085,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:
@@ -63063,7 +63181,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]))
@@ -63211,11 +63329,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()
@@ -63223,11 +63342,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
@@ -63260,7 +63384,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)
@@ -63282,6 +63407,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 = []
@@ -63291,7 +63417,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]))
@@ -63316,7 +63442,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,
@@ -63336,12 +63463,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)
@@ -68572,7 +68702,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]))
@@ -69173,7 +69303,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,8 +177,14 @@ 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
MEMBER_MAX_RESULTS_CI_BASIC = 'member_max_results_ci_basic'
# CI API Group members max page size when view=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
MESSAGE_BATCH_SIZE = 'message_batch_size' MESSAGE_BATCH_SIZE = 'message_batch_size'
# When retrieving lists of Gmail messages from API, how many should be retrieved in each chunk # When retrieving lists of Gmail messages from API, how many should be retrieved in each chunk
@@ -384,7 +390,10 @@ 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_FULL: '500',
MESSAGE_BATCH_SIZE: '50', MESSAGE_BATCH_SIZE: '50',
MESSAGE_MAX_RESULTS: '500', MESSAGE_MAX_RESULTS: '500',
MOBILE_MAX_RESULTS: '100', MOBILE_MAX_RESULTS: '100',
@@ -549,7 +558,10 @@ 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_FULL: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 500)},
MESSAGE_BATCH_SIZE: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 1000)}, MESSAGE_BATCH_SIZE: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 1000)},
MESSAGE_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 10000)}, MESSAGE_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 10000)},
MOBILE_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 100)}, MOBILE_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 100)},

View File

@@ -1,283 +0,0 @@
#!/usr/bin/env python
#
# Copyright 2009 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Data model classes for parsing and generating XML for the Sites Data API."""
import atom
import gdata
# XML Namespaces used in Google Sites entities.
SITES_NAMESPACE = 'http://schemas.google.com/sites/2008'
SITES_TEMPLATE = '{http://schemas.google.com/sites/2008}%s'
SPREADSHEETS_NAMESPACE = 'http://schemas.google.com/spreadsheets/2006'
SPREADSHEETS_TEMPLATE = '{http://schemas.google.com/spreadsheets/2006}%s'
GACL_NAMESPACE = 'http://schemas.google.com/acl/2007'
GACL_TEMPLATE = '{http://schemas.google.com/acl/2007}%s'
DC_TERMS_TEMPLATE = '{http://purl.org/dc/terms}%s'
THR_TERMS_TEMPLATE = '{http://purl.org/syndication/thread/1.0}%s'
XHTML_NAMESPACE = 'http://www.w3.org/1999/xhtml'
XHTML_TEMPLATE = '{http://www.w3.org/1999/xhtml}%s'
SITES_INVITE_LINK_REL = SITES_NAMESPACE + '#invite'
SITES_PARENT_LINK_REL = SITES_NAMESPACE + '#parent'
SITES_REVISION_LINK_REL = SITES_NAMESPACE + '#revision'
SITES_SOURCE_LINK_REL = SITES_NAMESPACE + '#source'
SITES_TEMPLATE_LINK_REL = SITES_NAMESPACE + '#template'
ALTERNATE_REL = 'alternate'
WEB_ADDRESS_MAPPING_REL = 'webAddressMapping'
SITES_KIND_SCHEME = 'http://schemas.google.com/g/2005#kind'
ANNOUNCEMENT_KIND_TERM = SITES_NAMESPACE + '#announcement'
ANNOUNCEMENT_PAGE_KIND_TERM = SITES_NAMESPACE + '#announcementspage'
ATTACHMENT_KIND_TERM = SITES_NAMESPACE + '#attachment'
COMMENT_KIND_TERM = SITES_NAMESPACE + '#comment'
FILECABINET_KIND_TERM = SITES_NAMESPACE + '#filecabinet'
LISTITEM_KIND_TERM = SITES_NAMESPACE + '#listitem'
LISTPAGE_KIND_TERM = SITES_NAMESPACE + '#listpage'
WEBPAGE_KIND_TERM = SITES_NAMESPACE + '#webpage'
WEBATTACHMENT_KIND_TERM = SITES_NAMESPACE + '#webattachment'
FOLDER_KIND_TERM = SITES_NAMESPACE + '#folder'
TAG_KIND_TERM = SITES_NAMESPACE + '#tag'
SUPPORT_KINDS = [
'announcement', 'announcementspage', 'attachment', 'comment', 'filecabinet',
'listitem', 'listpage', 'webpage', 'webattachment', 'tag'
]
class GDataBase(atom.AtomBase):
"""The Google Sites intermediate class from atom.AtomBase."""
_namespace = gdata.GDATA_NAMESPACE
_children = atom.AtomBase._children.copy()
_attributes = atom.AtomBase._attributes.copy()
def __init__(self, text=None):
atom.AtomBase.__init__(self, text=text)
class SitesBase(GDataBase):
_namespace = SITES_NAMESPACE
class SiteName(SitesBase):
"""Google Sites <sites:siteName>."""
_tag = 'siteName'
class Theme(SitesBase):
"""Google Sites <sites:theme>."""
_tag = 'theme'
class SiteEntry(gdata.BatchEntry):
"""Google Sites Site Feed Entry."""
_tag = 'entry'
_namespace = atom.ATOM_NAMESPACE
_children = gdata.BatchEntry._children.copy()
_children['{%s}siteName' % SITES_NAMESPACE] = ('siteName', SiteName)
_children['{%s}theme' % SITES_NAMESPACE] = ('theme', Theme)
_attributes = gdata.BatchEntry._attributes.copy()
_attributes['{%s}etag' % gdata.GDATA_NAMESPACE] = 'etag'
def __init__(self, siteName=None, title=None, summary=None, theme=None, sourceSite=None, category=None, etag=None):
gdata.BatchEntry.__init__(self, category=category)
self.siteName = siteName
self.title = title
self.summary = summary
self.theme = theme
if sourceSite is not None:
sourceLink = atom.Link(href=sourceSite, rel=SITES_SOURCE_LINK_REL, link_type='application/atom+xml')
self.link.append(sourceLink)
self.etag = etag
def find_alternate_link(self):
for link in self.link:
if link.rel == ALTERNATE_REL and link.href:
return link.href
return None
FindAlternateLink = find_alternate_link
def find_source_link(self):
for link in self.link:
if link.rel == SITES_SOURCE_LINK_REL and link.href:
return link.href
return None
FindSourceLink = find_source_link
def find_webaddress_mappings(self):
mappingLinks = []
for link in self.link:
if link.rel == WEB_ADDRESS_MAPPING_REL and link.href:
mappingLinks.append(link.href)
return mappingLinks
FindWebAddressMappings = find_webaddress_mappings
def SiteEntryFromString(xml_string):
return atom.CreateClassFromXMLString(SiteEntry, xml_string)
class SiteFeed(gdata.BatchFeed, gdata.LinkFinder):
"""A Google Sites feed flavor of an Atom Feed."""
_tag = 'feed'
_namespace = atom.ATOM_NAMESPACE
_children = gdata.BatchFeed._children.copy()
_children['{%s}entry' % atom.ATOM_NAMESPACE] = ('entry', [SiteEntry])
def __init__(self):
gdata.BatchFeed.__init__(self)
def SiteFeedFromString(xml_string):
return atom.CreateClassFromXMLString(SiteFeed, xml_string)
class AclBase(GDataBase):
_namespace = GACL_NAMESPACE
class AclRole(AclBase):
"""Describes the role of an entry in an access control list."""
_tag = 'role'
_children = AclBase._children.copy()
_attributes = AclBase._attributes.copy()
_attributes['value'] = 'value'
def __init__(self, value=None):
AclBase.__init__(self)
self.value = value
class AclAdditionalRole(AclBase):
"""Describes an additionalRole element."""
_tag = 'additionalRole'
_children = AclBase._children.copy()
_attributes = AclBase._attributes.copy()
_attributes['value'] = 'value'
def __init__(self, value=None):
AclBase.__init__(self)
self.value = value
class AclScope(AclBase):
"""Describes the scope of an entry in an access control list."""
_tag = 'scope'
_children = AclBase._children.copy()
_attributes = AclBase._attributes.copy()
_attributes['type'] = 'type'
_attributes['value'] = 'value'
def __init__(self, stype=None, value=None):
AclBase.__init__(self)
self.type = stype
self.value = value
class AclWithKey(AclBase):
"""Describes a key that can be used to access a document."""
_tag = 'withKey'
_children = AclBase._children.copy()
_children['{%s}role' % GACL_NAMESPACE] = ('role', AclRole)
_children['{%s}additionalRole' % GACL_NAMESPACE] = ('additionalRole', AclAdditionalRole)
_attributes = AclBase._attributes.copy()
_attributes['key'] = 'key'
def __init__(self, key=None, role=None, additionalRole=None):
AclBase.__init__(self)
self.key = key
self.role = role
self.additionalRole = additionalRole
class AclEntry(gdata.BatchEntry):
"""Describes an entry in a feed of an access control list (ACL)."""
_tag = 'entry'
_namespace = atom.ATOM_NAMESPACE
_children = gdata.BatchEntry._children.copy()
_children['{%s}role' % GACL_NAMESPACE] = ('role', AclRole)
_children['{%s}additionalRole' % GACL_NAMESPACE] = ('additionalRole', AclAdditionalRole)
_children['{%s}scope' % GACL_NAMESPACE] = ('scope', AclScope)
_children['{%s}withKey' % GACL_NAMESPACE] = ('withKey', AclWithKey)
_attributes = gdata.BatchEntry._attributes.copy()
_attributes['{%s}etag' % gdata.GDATA_NAMESPACE] = 'etag'
def __init__(self, role=None, additionalRole=None, scope=None, withKey=None, etag=None):
gdata.BatchEntry.__init__(self)
self.role = role
self.additionalRole = additionalRole
self.scope = scope
self.withKey = withKey
self.etag = etag
def find_invite_link(self):
for link in self.link:
if link.rel == SITES_INVITE_LINK_REL and link.href:
return link.href
return None
FindInviteLink = find_invite_link
def AclEntryFromString(xml_string):
return atom.CreateClassFromXMLString(AclEntry, xml_string)
class AclFeed(gdata.BatchFeed, gdata.LinkFinder):
"""Describes a feed of an access control list (ACL)."""
_tag = 'feed'
_namespace = atom.ATOM_NAMESPACE
_children = gdata.BatchFeed._children.copy()
_children['{%s}entry' % atom.ATOM_NAMESPACE] = ('entry', [AclEntry])
def __init__(self):
gdata.BatchFeed.__init__(self)
def AclFeedFromString(xml_string):
return atom.CreateClassFromXMLString(AclFeed, xml_string)
class ActivityEntry(gdata.BatchEntry):
"""Describes an entry in a feed of site activity (changes)."""
_tag = 'entry'
_namespace = atom.ATOM_NAMESPACE
_children = gdata.BatchEntry._children.copy()
_attributes = gdata.BatchEntry._attributes.copy()
def __init__(self):
gdata.BatchEntry.__init__(self)
def __find_category_scheme(self, scheme):
for category in self.category:
if category.scheme == scheme:
return category
return None
def kind(self):
kind = self.__find_category_scheme(SITES_KIND_SCHEME)
if kind is not None:
return kind.term[len(SITES_NAMESPACE) + 1:]
else:
return None
Kind = kind
def ActivityEntryFromString(xml_string):
return atom.CreateClassFromXMLString(ActivityEntry, xml_string)
class ActivityFeed(gdata.BatchFeed, gdata.LinkFinder):
"""Describes a feed of site activity (changes)."""
_tag = 'feed'
_namespace = atom.ATOM_NAMESPACE
_children = gdata.BatchFeed._children.copy()
_children['{%s}entry' % atom.ATOM_NAMESPACE] = ('entry', [ActivityEntry])
def __init__(self):
gdata.BatchFeed.__init__(self)
def ActivityFeedFromString(xml_string):
return atom.CreateClassFromXMLString(ActivityFeed, xml_string)

View File

@@ -1,246 +0,0 @@
#!/usr/bin/python
#
# Copyright 2009 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""SitesService extends the GDataService for Google Sites API calls."""
import gdata.apps
import gdata.apps.service
import gdata.service
# Feed URI templates
CONTENT_FEED_TEMPLATE = '/feeds/content/%s/%s/'
REVISION_FEED_TEMPLATE = '/feeds/revision/%s/%s/'
ACTIVITY_FEED_TEMPLATE = '/feeds/activity/%s/%s/'
ACTIVITY_ENTRY_TEMPLATE = '/feeds/activity/%s/%s/%s'
SITE_FEED_TEMPLATE = '/feeds/site/%s/'
ACL_FEED_TEMPLATE = '/feeds/acl/site/%s/%s'
ACL_ENTRY_TEMPLATE = '/feeds/acl/site/%s/%s/%s'
class SitesService(gdata.service.GDataService):
"""Client extension for the Google Sites API service."""
def __init__(self,
source=None, server='sites.google.com', additional_headers=None,
**kwargs):
"""Constructs a new client for the Sites API.
Args:
site: string (optional) Name (webspace) of the Google Site
domain: string (optional) Domain of the (Google Apps hosted) Site.
If no domain is given, the Site is assumed to be a consumer Google
Site, in which case the value 'site' is used.
source: string (optional) The name of the user's application.
server: string (optional) The name of the server to which a connection
will be opened. Default value: 'sites..google.com'.
**kwargs: The other parameters to pass to gdata.service.GDataService
constructor.
"""
if additional_headers == None:
additional_headers = {}
additional_headers['GData-Version'] = '1.4'
gdata.service.GDataService.__init__(self,
source=source, server=server, additional_headers=additional_headers,
**kwargs)
self.ssl = True
self.port = 443
def make_site_feed_uri(self, domain=None, site=None):
if not domain:
domain = 'site'
if not site:
return SITE_FEED_TEMPLATE % domain
return (SITE_FEED_TEMPLATE % domain) + site
MakeSiteFeedUri = make_site_feed_uri
def get_site_feed(self, uri=None, domain=None, site=None,
extra_headers=None, url_params=None, escape_params=True):
uri = uri or self.make_site_feed_uri(domain=domain, site=site)
try:
return self.Get(uri,
url_params=url_params, extra_headers=extra_headers, escape_params=escape_params,
converter=gdata.apps.sites.SiteFeedFromString)
except gdata.service.RequestError as e:
raise gdata.apps.service.AppsForYourDomainException(e.args[0])
GetSiteFeed = get_site_feed
def create_site(self, siteentry=None, uri=None, domain=None, site=None,
extra_headers=None, url_params=None, escape_params=True):
if uri is None:
uri = self.make_site_feed_uri(domain=domain, site=site)
try:
return self.Post(siteentry, uri,
url_params=url_params, extra_headers=extra_headers, escape_params=escape_params,
converter=gdata.apps.sites.SiteEntryFromString)
except gdata.service.RequestError as e:
raise gdata.apps.service.AppsForYourDomainException(e.args[0])
CreateSite = create_site
def get_site(self, uri=None, domain=None, site=None,
extra_headers=None, url_params=None, escape_params=True):
uri = uri or self.make_site_feed_uri(domain=domain, site=site)
try:
return self.Get(uri,
url_params=url_params, extra_headers=extra_headers, escape_params=escape_params,
converter=gdata.apps.sites.SiteEntryFromString)
except gdata.service.RequestError as e:
raise gdata.apps.service.AppsForYourDomainException(e.args[0])
GetSite = get_site
def update_site(self, siteentry=None, uri=None, domain=None, site=None,
extra_headers=None, url_params=None, escape_params=True):
uri = uri or self.make_site_feed_uri(domain=domain, site=site)
try:
return self.Put(siteentry, uri,
url_params=url_params, extra_headers=extra_headers, escape_params=escape_params,
converter=gdata.apps.sites.SiteEntryFromString)
except gdata.service.RequestError as e:
raise gdata.apps.service.AppsForYourDomainException(e.args[0])
UpdateSite = update_site
def make_acl_feed_uri(self, domain=None, site=None):
return ACL_FEED_TEMPLATE % (domain, site)
MakeAclFeedUri = make_acl_feed_uri
def get_acl_feed(self, uri=None, domain=None, site=None,
extra_headers=None, url_params=None, escape_params=True):
uri = uri or self.make_acl_feed_uri(domain=domain, site=site)
try:
return self.Get(uri,
url_params=url_params, extra_headers=extra_headers, escape_params=escape_params,
converter=gdata.apps.sites.AclFeedFromString)
except gdata.service.RequestError as e:
raise gdata.apps.service.AppsForYourDomainException(e.args[0])
GetAclFeed = get_acl_feed
def make_acl_entry_uri(self, domain=None, site=None, ruleId=None):
return ACL_ENTRY_TEMPLATE % (domain, site, ruleId)
MakeAclEntryUri = make_acl_entry_uri
def create_acl_entry(self, aclentry=None, uri=None, domain=None, site=None,
extra_headers=None, url_params=None, escape_params=True):
uri = uri or self.make_acl_feed_uri(domain=domain, site=site)
try:
return self.Post(aclentry, uri,
url_params=url_params, extra_headers=extra_headers, escape_params=escape_params,
converter=gdata.apps.sites.AclEntryFromString)
except gdata.service.RequestError as e:
raise gdata.apps.service.AppsForYourDomainException(e.args[0])
CreateAclEntry = create_acl_entry
def get_acl_entry(self, uri=None, domain=None, site=None, ruleId=None,
extra_headers=None, url_params=None, escape_params=True):
uri = uri or self.make_acl_entry_uri(domain=domain, site=site, ruleId=ruleId)
try:
return self.Get(uri,
url_params=url_params, extra_headers=extra_headers, escape_params=escape_params,
converter=gdata.apps.sites.AclEntryFromString)
except gdata.service.RequestError as e:
raise gdata.apps.service.AppsForYourDomainException(e.args[0])
GetAclEntry = get_acl_entry
def update_acl_entry(self, aclentry=None, uri=None, domain=None, site=None, ruleId=None,
extra_headers=None, url_params=None, escape_params=True):
uri = uri or self.make_acl_entry_uri(domain=domain, site=site, ruleId=ruleId)
try:
return self.Put(aclentry, uri,
url_params=url_params, extra_headers=extra_headers, escape_params=escape_params,
converter=gdata.apps.sites.AclEntryFromString)
except gdata.service.RequestError as e:
raise gdata.apps.service.AppsForYourDomainException(e.args[0])
UpdateAclEntry = update_acl_entry
def delete_acl_entry(self, uri=None, domain=None, site=None, ruleId=None,
extra_headers=None, url_params=None, escape_params=True):
uri = uri or self.make_acl_entry_uri(domain=domain, site=site, ruleId=ruleId)
try:
return self.Delete(uri,
url_params=url_params, escape_params=escape_params, extra_headers=extra_headers)
except gdata.service.RequestError as e:
raise gdata.apps.service.AppsForYourDomainException(e.args[0])
DeleteAclEntry = delete_acl_entry
def make_activity_feed_uri(self, domain=None, site=None):
return ACTIVITY_FEED_TEMPLATE % (domain, site)
MakeActivityFeedUri = make_activity_feed_uri
def get_activity_feed(self, uri=None, domain=None, site=None,
extra_headers=None, url_params=None, escape_params=True):
uri = uri or self.make_activity_feed_uri(domain=domain, site=site)
try:
return self.Get(uri,
url_params=url_params, extra_headers=extra_headers, escape_params=escape_params,
converter=gdata.apps.sites.ActivityFeedFromString)
except gdata.service.RequestError as e:
raise gdata.apps.service.AppsForYourDomainException(e.args[0])
GetActivityFeed = get_activity_feed
def make_activity_entry_uri(self, domain=None, site=None, activityId=None):
return ACTIVITY_ENTRY_TEMPLATE % (domain, site, activityId)
MakeActivityEntryUri = make_activity_entry_uri
def get_activity_entry(self, uri=None, domain=None, site=None, activityId=None,
extra_headers=None, url_params=None, escape_params=True):
uri = uri or self.make_activity_entry_uri(domain=domain, site=site, activityId=activityId)
try:
return self.Get(uri,
url_params=url_params, extra_headers=extra_headers, escape_params=escape_params,
converter=gdata.apps.sites.ActivityEntryFromString)
except gdata.service.RequestError as e:
raise gdata.apps.service.AppsForYourDomainException(e.args[0])
GetActivityEntry = get_activity_entry
class SitesQuery(gdata.service.Query):
def make_site_feed_uri(self, domain=None, site=None):
if not domain:
domain = 'site'
if not site:
return SITE_FEED_TEMPLATE % domain
return (SITE_FEED_TEMPLATE % domain) + site
def __init__(self, feed=None, domain=None, site=None, params=None):
self.feed = feed or self.make_site_feed_uri(domain=domain, site=site)
gdata.service.Query.__init__(self, feed=self.feed, params=params)

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

File diff suppressed because it is too large Load Diff