Compare commits

..

19 Commits

Author SHA1 Message Date
Ross Scroggs
54eb666bc5 Merge branch 'main' of https://github.com/GAM-team/GAM
Some checks failed
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-apis (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
2025-01-23 15:26:09 -08:00
Ross Scroggs
f6ea570888 Two updates
Updated `gam report <ActivityApplicationName>` to display `id:<actor.profileId>` in the `emailAddress` column
when `actor.email` is empty. This typically occurs when the actor is not in your workspace.

Updated `gam <UserTypeEntity> copy drivefile` to ignore ACLs referencing deleted user/groups.
2025-01-23 15:26:01 -08:00
Jay Lee
5d3fbed497 actions: scratch to test win signing 2025-01-23 11:19:10 -05:00
Ross Scroggs
e7b3b1453a Added option bydate to gam report <ActivityApplicationName> ... countsonly #1740
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-01-22 16:16:15 -08:00
Jay Lee
c31beeddfa actions: use ubuntu-24.04 instead of ubuntu-latest
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-01-20 17:01:45 -05:00
Ross Scroggs
bad376ea82 Add resource options to event commands
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-01-18 10:52:21 -08:00
Jay Lee
6af38e24af actions: disable python 3.9 testing
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
We currently only have 13 JID accounts available for testing but after Linux arm64 changes needed 14 runners.

I'm disabling Python 3.9 tests for now since it's the oldest and due for deprecation in October.

If there's any concerns we can re-enable and disable something else or else Jay can rebuild the auth files to add a 14th JID Google account and credentials (not hard but cumbersome and time consuming).
2025-01-16 14:35:46 -05:00
Jay Lee
a4eff89658 actions: install scons for staticx (needed for arm64) 2025-01-16 13:46:27 -05:00
Jay Lee
91db5e5c45 actions: apt install on GH hosted arm builds also 2025-01-16 12:27:28 -05:00
Jay Lee
67390a9863 actions: GH hosted arm runners, rebuild cache 2025-01-16 12:22:17 -05:00
Jay Lee
6c24636833 actions: scratch again 2025-01-16 09:47:26 -05:00
Jay Lee
776bc969de actions: scratch to kick off a build
Some checks failed
Build and test GAM / build (Win64, build, 9, VC-WIN64A, windows-2022) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 3, linux-aarch64, [self-hosted linux arm64]) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 5, linux-aarch64, [self-hosted linux arm64], yes) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 7, darwin64-arm64, macos-14) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 8, 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, 4, linux-x86_64, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 6, darwin64-x86_64, macos-13) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 10, ubuntu-24.04, 3.9) (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-01-14 16:45:32 -05:00
Ross Scroggs
7008d8c311 Fixed bug in gam print|show chromepolicies that caused a trap
Some checks are pending
Build and test GAM / build (Win64, build, 9, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, [self-hosted linux arm64]) (push) Waiting to run
Build and test GAM / build (aarch64, build, 5, linux-aarch64, [self-hosted linux arm64], yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 7, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, 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, 4, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 6, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 10, ubuntu-24.04, 3.9) (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-01-13 11:54:17 -08:00
Ross Scroggs
a54870f91d Updated gam delete|update chromepolicy
Some checks failed
Build and test GAM / build (Win64, build, 9, VC-WIN64A, windows-2022) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 3, linux-aarch64, [self-hosted linux arm64]) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 5, linux-aarch64, [self-hosted linux arm64], yes) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 7, darwin64-arm64, macos-14) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 8, 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, 4, linux-x86_64, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 6, darwin64-x86_64, macos-13) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 10, ubuntu-24.04, 3.9) (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-01-06 16:45:00 -08:00
Ross Scroggs
782d57b02e Added option <JSONData> to gam <UserTypeEntity> create|update form
Some checks failed
Build and test GAM / build (Win64, build, 9, VC-WIN64A, windows-2022) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 3, linux-aarch64, [self-hosted linux arm64]) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 5, linux-aarch64, [self-hosted linux arm64], yes) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 7, darwin64-arm64, macos-14) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 8, 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, 4, linux-x86_64, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 6, darwin64-x86_64, macos-13) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 10, ubuntu-24.04, 3.9) (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-01-04 10:30:52 -08:00
Ross Scroggs
0c6825fa12 Updated gam [<UserTypeEntity>] show shareddriveacls ... formatjson
Some checks failed
Build and test GAM / build (Win64, build, 9, VC-WIN64A, windows-2022) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 3, linux-aarch64, [self-hosted linux arm64]) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 5, linux-aarch64, [self-hosted linux arm64], yes) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 7, darwin64-arm64, macos-14) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 8, 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, 4, linux-x86_64, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 6, darwin64-x86_64, macos-13) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 10, ubuntu-24.04, 3.9) (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
2024-12-27 19:27:04 -08:00
Ross Scroggs
6a82343668 Update gam-install.sh
Some checks are pending
Build and test GAM / build (Win64, build, 9, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, [self-hosted linux arm64]) (push) Waiting to run
Build and test GAM / build (aarch64, build, 5, linux-aarch64, [self-hosted linux arm64], yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 7, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, 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, 4, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 6, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 10, ubuntu-24.04, 3.9) (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
2024-12-27 12:21:43 -08:00
Ross Scroggs
47ec93140e Updated code to eliminate trap caused by bug introduced in 7.02.00
Some checks failed
Build and test GAM / build (Win64, build, 9, VC-WIN64A, windows-2022) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 3, linux-aarch64, [self-hosted linux arm64]) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 5, linux-aarch64, [self-hosted linux arm64], yes) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 7, darwin64-arm64, macos-14) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 8, 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, 4, linux-x86_64, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 6, darwin64-x86_64, macos-13) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 10, ubuntu-24.04, 3.9) (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
2024-12-26 08:36:25 -08:00
Ross Scroggs
d0d5ac74da Fix issue #1732
Some checks failed
Build and test GAM / build (Win64, build, 9, VC-WIN64A, windows-2022) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 3, linux-aarch64, [self-hosted linux arm64]) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 5, linux-aarch64, [self-hosted linux arm64], yes) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 7, darwin64-arm64, macos-14) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 8, 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, 4, linux-x86_64, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 6, darwin64-x86_64, macos-13) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 10, ubuntu-24.04, 3.9) (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
2024-12-23 12:24:30 -08:00
6 changed files with 310 additions and 154 deletions

View File

@@ -17,7 +17,7 @@ defaults:
working-directory: src working-directory: src
env: env:
SCRATCH_COUNTER: 4 SCRATCH_COUNTER: 7
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
@@ -41,48 +41,57 @@ jobs:
goal: build goal: build
arch: x86_64 arch: x86_64
openssl_archs: linux-x86_64 openssl_archs: linux-x86_64
- os: [self-hosted, linux, arm64] - os: ubuntu-24.04-arm
jid: 3 jid: 3
goal: build goal: build
arch: aarch64 arch: aarch64
openssl_archs: linux-aarch64 openssl_archs: linux-aarch64
- os: ubuntu-22.04 - os: ubuntu-22.04-arm
jid: 4 jid: 4
goal: build goal: build
arch: aarch64
openssl_archs: linux-aarch64
- os: ubuntu-22.04
jid: 5
goal: build
arch: x86_64 arch: x86_64
openssl_archs: linux-x86_64 openssl_archs: linux-x86_64
staticx: yes staticx: yes
- os: [self-hosted, linux, arm64] - os: ubuntu-22.04-arm
jid: 5 jid: 6
goal: build goal: build
arch: aarch64 arch: aarch64
openssl_archs: linux-aarch64 openssl_archs: linux-aarch64
staticx: yes staticx: yes
- os: macos-13 - os: macos-13
jid: 6 jid: 7
goal: build goal: build
arch: x86_64 arch: x86_64
openssl_archs: darwin64-x86_64 openssl_archs: darwin64-x86_64
- os: macos-14 - os: macos-14
jid: 7
goal: build
arch: aarch64
openssl_archs: darwin64-arm64
- os: macos-15
jid: 8 jid: 8
goal: build goal: build
arch: aarch64 arch: aarch64
openssl_archs: darwin64-arm64 openssl_archs: darwin64-arm64
- os: windows-2022 - os: macos-15
jid: 9 jid: 9
goal: build goal: build
arch: aarch64
openssl_archs: darwin64-arm64
- os: windows-2022
jid: 10
goal: build
arch: Win64 arch: Win64
openssl_archs: VC-WIN64A openssl_archs: VC-WIN64A
- os: ubuntu-24.04 # disable 3.9 test for now since it's oldest and due
goal: test # for removal in Oct 2025. We only have 13 jid accounts
python: "3.9" # so we need this one off but can re-enable at some point
jid: 10 # if we feel the need.
arch: x86_64 #- os: ubuntu-24.04
# goal: test
# python: "3.9"
# jid: 11
# arch: x86_64
- os: ubuntu-24.04 - os: ubuntu-24.04
goal: test goal: test
python: "3.10" python: "3.10"
@@ -120,7 +129,7 @@ jobs:
with: with:
path: | path: |
cache.tar.xz cache.tar.xz
key: gam-${{ matrix.jid }}-20241203 key: gam-${{ matrix.jid }}-20250116
- name: Untar Cache archive - name: Untar Cache archive
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true' if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
@@ -187,7 +196,7 @@ jobs:
echo "gampath=${gampath}" >> $GITHUB_ENV echo "gampath=${gampath}" >> $GITHUB_ENV
- name: Install necessary Github-hosted Linux packages - name: Install necessary Github-hosted Linux packages
if: runner.os == 'Linux' && runner.arch == 'X64' if: runner.os == 'Linux'
run: | run: |
echo "RUNNING: apt update..." echo "RUNNING: apt update..."
sudo apt-get -qq --yes update sudo apt-get -qq --yes update
@@ -548,7 +557,6 @@ jobs:
# https://github.com/pyinstaller/pyinstaller/issues/7102 # https://github.com/pyinstaller/pyinstaller/issues/7102
export PATH="$(dirname ${PYTHON}):/usr/bin" export PATH="$(dirname ${PYTHON}):/usr/bin"
fi fi
#if ([ "${staticx}" != "yes" ] && [ "$RUNNER_OS" != "Windows" ]); then
if [[ "$staticx" != "yes" ]]; then if [[ "$staticx" != "yes" ]]; then
export PYINSTALLER_BUILD_ONEDIR=yes export PYINSTALLER_BUILD_ONEDIR=yes
fi fi
@@ -594,6 +602,9 @@ jobs:
- name: Install StaticX - name: Install StaticX
if: matrix.staticx == 'yes' if: matrix.staticx == 'yes'
run: | run: |
sudo apt-get -qq --yes update
# arm64 needs to build a wheel and needs scons to build
sudo apt-get -qq --yes install scons
"${PYTHON}" -m pip install --upgrade patchelf-wrapper "${PYTHON}" -m pip install --upgrade patchelf-wrapper
"${PYTHON}" -m pip install --upgrade staticx "${PYTHON}" -m pip install --upgrade staticx
@@ -994,7 +1005,7 @@ jobs:
merge: merge:
if: (github.event_name == 'push' || github.event_name == 'schedule') if: (github.event_name == 'push' || github.event_name == 'schedule')
runs-on: ubuntu-latest runs-on: ubuntu-24.04
needs: build needs: build
permissions: permissions:
contents: write contents: write
@@ -1008,7 +1019,7 @@ jobs:
publish: publish:
if: github.event_name == 'push' if: github.event_name == 'push'
runs-on: ubuntu-latest runs-on: ubuntu-24.04
needs: merge needs: merge
permissions: permissions:
contents: write contents: write

View File

@@ -1677,6 +1677,7 @@ gam calendar <CalendarEntity> printacl [todrive <ToDriveAttribute>*]
(range <Date> <Date>)| (range <Date> <Date>)|
(recurrence <RRULE, EXRULE, RDATE and EXDATE line>)| (recurrence <RRULE, EXRULE, RDATE and EXDATE line>)|
(reminder <Number> email|popup))| (reminder <Number> email|popup))|
(resource <ResourceID>)|
(selectattendees [<AttendeeAttendance>] [<AttendeeStatus>] <UserTypeEntity>)| (selectattendees [<AttendeeAttendance>] [<AttendeeStatus>] <UserTypeEntity>)|
(sequence <Integer>)| (sequence <Integer>)|
(sharedproperty <PropertyKey> <PropertyValue>)| (sharedproperty <PropertyKey> <PropertyValue>)|
@@ -1707,8 +1708,10 @@ The following attributes are equivalent:
clearattendees| clearattendees|
clearhangoutsmeet| clearhangoutsmeet|
(clearprivateproperty <PropertyKey>)| (clearprivateproperty <PropertyKey>)|
clearresources|
(clearsharedproperty <PropertyKey>)| (clearsharedproperty <PropertyKey>)|
(removeattendee <EmailAddress>)| (removeattendee <EmailAddress>)|
(removeresource <ResourceID>)|
(replacedescription <RegularExpression> <String>)| (replacedescription <RegularExpression> <String>)|
(selectremoveattendees <UserTypeEntity>) (selectremoveattendees <UserTypeEntity>)
@@ -4448,7 +4451,7 @@ gam report <ActivityApplicationName> [todrive <ToDriveAttribute>*]
[event|events <EventNameList>] [ip <String>] [event|events <EventNameList>] [ip <String>]
[groupidfilter <String>] [groupidfilter <String>]
[maxactivities <Number>] [maxevents <Number>] [maxresults <Number>] [maxactivities <Number>] [maxevents <Number>] [maxresults <Number>]
[countsonly [summary] [eventrowfilter]] [countsonly [bydate|summary] [eventrowfilter]]
(addcsvdata <FieldName> <String>)* [shownoactivities] (addcsvdata <FieldName> <String>)* [shownoactivities]
<CustomerServiceName> ::= <CustomerServiceName> ::=
@@ -7352,11 +7355,11 @@ gam <UserTypeEntity> print filters [labelidsonly] [todrive <ToDriveAttribute>*]
# Users - Forms # Users - Forms
gam <UserTypeEntity> create form gam <UserTypeEntity> create form
title <String> [description <String>] [isquiz [<Boolean>] title <String> [description <String>] [isquiz [<Boolean>]] [<JSONData>]
[drivefilename <DriveFileName>] [<DriveFileParentAttribute>] [drivefilename <DriveFileName>] [<DriveFileParentAttribute>]
[(csv [todrive <ToDriveAttribute>*]) | returnidonly] [(csv [todrive <ToDriveAttribute>*]) | returnidonly]
gam <UserTypeEntity> update form <DriveFileEntity> gam <UserTypeEntity> update form <DriveFileEntity>
[title <String>] [description <String>] [isquiz [<Boolean>] [title <String>] [description <String>] [isquiz [<Boolean>]] [<JSONData>]
gam <UserTypeEntity> print forms <DriveFileEntity> [todrive <ToDriveAttribute>*] gam <UserTypeEntity> print forms <DriveFileEntity> [todrive <ToDriveAttribute>*]
(addcsvdata <FieldName> <String>)* (addcsvdata <FieldName> <String>)*

View File

@@ -1,3 +1,60 @@
7.02.11
Updated `gam report <ActivityApplicationName>` to display `id:<actor.profileId>` in the `emailAddress` column
when `actor.email` is empty. This typically occurs when the actor is not in your workspace.
Updated `gam <UserTypeEntity> copy drivefile` to ignore ACLs referencing deleted user/groups.
7.02.10
Added option `bydate` to `gam report <ActivityApplicationName> ... countsonly` that provides an additional display option.
* `countsonly` - Display a row per user across all dates with all event counts on one row
* `countsonly bydate` - Display a row per user per date for all dates with any events with all events counts on the row
* `countsonly summary` - Display a row per event with counts for each event summarized across users and dates
7.02.09
Added option `clearresources` to `<EventUpdateAttribute>` for use in `gam <UserTypeEntity> update events`
that allows clearing all resources from a user's calendar events. For example, to clear all resources from a user's future events:
```
gam user user@domain.com update events primary matchfield attendeespattern @resource.calendar.google.com after now clearresources
```
Added option `resource <ResourceID>` to `<EventAttribute>` for use in `gam <UserTypeEntity> create|update events`
that adds a resource to an event.
Added option `removeresource <ResourceID>` to `<EventUpdateAttribute>` for use in `gam <UserTypeEntity> update events`
that removes a resource from an event.
7.02.08
Fixed bug in `gam print|show chromepolicies` that caused a trap when neither
`ou|orgunit <OrgUnitItem>` nor `group <GroupItem>` was specified.
7.02.07
Updated `gam delete|update chromepolicy` to display the `<AppID>` or `<PrinterID>` (if specified)
in the command status messages.
7.02.06
Added option `<JSONData>` to `gam <UserTypeEntity> create|update form` that allows for
creation/modification of all fields in a form. `<JSONData>` is a list of form update requests.
* See: https://developers.google.com/forms/api/reference/rest/v1/forms/batchUpdate
7.02.05
Updated `gam [<UserTypeEntity>] show shareddriveacls ... formatjson` to not display this line
which interferes with the JSON output.
```
User: user@domain.com, Show N Shared Drives
```
7.02.04
Updated code to eliminate trap caused by bug introduced in 7.02.00 that occurs when an invalid domain or OU is specified.
7.02.03 7.02.03
Added option `archive` to `gam <UserTypeEntity> update license <NewSKUID> from <OldSKUID>` that causes GAM Added option `archive` to `gam <UserTypeEntity> update license <NewSKUID> from <OldSKUID>` that causes GAM

View File

@@ -323,6 +323,8 @@ echo_yellow "Downloading ${download_url} to $temp_archive_dir ($check_type)..."
(cd "$temp_archive_dir" && curl -O -L -s "${curl_opts[@]}" "$download_url") (cd "$temp_archive_dir" && curl -O -L -s "${curl_opts[@]}" "$download_url")
mkdir -p "$target_dir" mkdir -p "$target_dir"
echo_yellow "Deleting contents of $target_dir/gam7/lib"
rm -frv "$target_dir/gam7/lib"
echo_yellow "Extracting archive to $target_dir" echo_yellow "Extracting archive to $target_dir"
if [[ "$name" =~ tar.xz|tar.gz|tar ]]; then if [[ "$name" =~ tar.xz|tar.gz|tar ]]; then
@@ -379,7 +381,7 @@ while true; do
;; ;;
[Nn]*) [Nn]*)
# config_cmd="config no_browser true" # config_cmd="config no_browser true"
touch "$target_dir/gam/nobrowser.txt" > /dev/null 2>&1 touch "$target_dir/gam7/nobrowser.txt" > /dev/null 2>&1
break break
;; ;;
*) *)

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.02.03' __version__ = '7.02.11'
__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
@@ -628,7 +628,7 @@ def formatKeyValueList(prefixStr, kvList, suffixStr):
msg += suffixStr msg += suffixStr
return msg return msg
# Something's wrong with CustomerID # Something's wrong with CustomerID??
def accessErrorMessage(cd, errMsg=None): def accessErrorMessage(cd, errMsg=None):
if cd is None: if cd is None:
cd = buildGAPIObject(API.DIRECTORY) cd = buildGAPIObject(API.DIRECTORY)
@@ -652,10 +652,12 @@ def accessErrorMessage(cd, errMsg=None):
Ent.DOMAIN, GC.Values[GC.DOMAIN], Ent.DOMAIN, GC.Values[GC.DOMAIN],
Ent.USER, GM.Globals[GM.ADMIN]])+[Msg.ACCESS_FORBIDDEN], Ent.USER, GM.Globals[GM.ADMIN]])+[Msg.ACCESS_FORBIDDEN],
'') '')
return formatKeyValueList('', if errMsg:
[Ent.Singular(Ent.CUSTOMER_ID), GC.Values[GC.CUSTOMER_ID], return formatKeyValueList('',
errMsg], [Ent.Singular(Ent.CUSTOMER_ID), GC.Values[GC.CUSTOMER_ID],
'') errMsg],
'')
return None
def accessErrorExit(cd, errMsg=None): def accessErrorExit(cd, errMsg=None):
systemErrorExit(INVALID_DOMAIN_RC, accessErrorMessage(cd or buildGAPIObject(API.DIRECTORY), errMsg)) systemErrorExit(INVALID_DOMAIN_RC, accessErrorMessage(cd or buildGAPIObject(API.DIRECTORY), errMsg))
@@ -13088,13 +13090,13 @@ def _checkDataRequiredServices(result, tryDate, dataRequiredServices, parameterS
# 0: Backup to earlier date # 0: Backup to earlier date
# 1: Data available # 1: Data available
oneDay = datetime.timedelta(days=1) oneDay = datetime.timedelta(days=1)
warnings = result.get('warnings', []) dataWarnings = result.get('warnings', [])
usageReports = result.get('usageReports', []) usageReports = result.get('usageReports', [])
# move to day before if we don't have at least one usageReport with parameters # move to day before if we don't have at least one usageReport with parameters
if not usageReports or not usageReports[0].get('parameters', []): if not usageReports or not usageReports[0].get('parameters', []):
tryDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT)-oneDay tryDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT)-oneDay
return (0, tryDateTime.strftime(YYYYMMDD_FORMAT), None) return (0, tryDateTime.strftime(YYYYMMDD_FORMAT), None)
for warning in warnings: for warning in dataWarnings:
if warning['code'] == 'PARTIAL_DATA_AVAILABLE': if warning['code'] == 'PARTIAL_DATA_AVAILABLE':
for app in warning['data']: for app in warning['data']:
if app['key'] == 'application' and app['value'] != 'docs' and app['value'] in dataRequiredServices: if app['key'] == 'application' and app['value'] != 'docs' and app['value'] in dataRequiredServices:
@@ -13519,7 +13521,7 @@ REPORT_ACTIVITIES_TIME_OBJECTS = {'time'}
# [event|events <EventNameList>] [ip <String>] # [event|events <EventNameList>] [ip <String>]
# [groupidfilter <String>] # [groupidfilter <String>]
# [maxactivities <Number>] [maxevents <Number>] [maxresults <Number>] # [maxactivities <Number>] [maxevents <Number>] [maxresults <Number>]
# [countsonly [summary] [eventrowfilter]] # [countsonly [bydate|summary] [eventrowfilter]]
# (addcsvdata <FieldName> <String>)* [shownoactivities] # (addcsvdata <FieldName> <String>)* [shownoactivities]
# gam report users|user [todrive <ToDriveAttribute>*] # gam report users|user [todrive <ToDriveAttribute>*]
# [(user all|<UserItem>)|(orgunit|org|ou <OrgUnitPath> [showorgunit])|(select <UserTypeEntity>)] # [(user all|<UserItem>)|(orgunit|org|ou <OrgUnitPath> [showorgunit])|(select <UserTypeEntity>)]
@@ -13792,8 +13794,8 @@ def doReport():
filterTimes = {} filterTimes = {}
maxActivities = maxEvents = 0 maxActivities = maxEvents = 0
maxResults = 1000 maxResults = 1000
aggregateByDate = aggregateByUser = convertMbToGb = countsOnly = eventRowFilter = exitUserLoop = \ aggregateByDate = aggregateByUser = convertMbToGb = countsOnly = countsByDate = countsSummary = \
noAuthorizedApps = normalizeUsers = select = summary = userCustomerRange = False eventRowFilter = exitUserLoop = noAuthorizedApps = normalizeUsers = select = userCustomerRange = False
limitDateChanges = -1 limitDateChanges = -1
allVerifyUser = userKey = 'all' allVerifyUser = userKey = 'all'
cd = orgUnit = orgUnitId = None cd = orgUnit = orgUnitId = None
@@ -13891,8 +13893,10 @@ def doReport():
actorIpAddress = getString(Cmd.OB_STRING) actorIpAddress = getString(Cmd.OB_STRING)
elif activityReports and myarg == 'countsonly': elif activityReports and myarg == 'countsonly':
countsOnly = True countsOnly = True
elif activityReports and myarg == 'bydate':
countsByDate = True
elif activityReports and myarg == 'summary': elif activityReports and myarg == 'summary':
summary = True countsSummary = True
elif activityReports and myarg == 'eventrowfilter': elif activityReports and myarg == 'eventrowfilter':
eventRowFilter = True eventRowFilter = True
elif activityReports and myarg == 'groupidfilter': elif activityReports and myarg == 'groupidfilter':
@@ -13926,6 +13930,8 @@ def doReport():
unknownArgumentExit() unknownArgumentExit()
if aggregateByDate and aggregateByUser: if aggregateByDate and aggregateByUser:
usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format('aggregateByDate', 'aggregateByUser')) usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format('aggregateByDate', 'aggregateByUser'))
if countsOnly and countsByDate and countsSummary:
usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format('bydate', 'summary'))
parameters = ','.join(parameters) if parameters else None parameters = ','.join(parameters) if parameters else None
if usageReports and not includeServices: if usageReports and not includeServices:
includeServices = set(fullDataServices) includeServices = set(fullDataServices)
@@ -14142,8 +14148,12 @@ def doReport():
pageMessage = getPageMessage() pageMessage = getPageMessage()
users = [normalizeEmailAddressOrUID(userKey)] users = [normalizeEmailAddressOrUID(userKey)]
orgUnitId = None orgUnitId = None
zeroEventCounts = {}
if not eventNames: if not eventNames:
eventNames.append(None) eventNames.append(None)
else:
for eventName in eventNames:
zeroEventCounts[eventName] = 0
i = 0 i = 0
count = len(users) count = len(users)
for user in users: for user in users:
@@ -14175,9 +14185,22 @@ def doReport():
accessErrorExit(None) accessErrorExit(None)
for activity in feed: for activity in feed:
events = activity.pop('events') events = activity.pop('events')
actor = activity['actor'].get('email', activity['actor'].get('key', UNKNOWN)) actor = activity['actor'].get('email')
if not actor:
actor = 'id:'+activity['actor'].get('profileId', UNKNOWN)
if showOrgUnit: if showOrgUnit:
activity['actor']['orgUnitPath'] = userOrgUnits.get(actor, UNKNOWN) activity['actor']['orgUnitPath'] = userOrgUnits.get(actor, UNKNOWN)
if countsOnly and countsByDate:
eventTime = activity.get('id', {}).get('time', UNKNOWN)
if eventTime != UNKNOWN:
try:
eventTime, _ = iso8601.parse_date(eventTime)
except (iso8601.ParseError, OverflowError):
eventTime = UNKNOWN
if eventTime != UNKNOWN:
eventDate = eventTime.strftime(YYYYMMDD_FORMAT)
else:
eventDate = UNKNOWN
if not countsOnly or eventRowFilter: if not countsOnly or eventRowFilter:
activity_row = flattenJSON(activity, timeObjects=REPORT_ACTIVITIES_TIME_OBJECTS) activity_row = flattenJSON(activity, timeObjects=REPORT_ACTIVITIES_TIME_OBJECTS)
purge_parameters = True purge_parameters = True
@@ -14228,18 +14251,32 @@ def doReport():
if numEvents >= maxEvents > 0: if numEvents >= maxEvents > 0:
break break
elif csvPF.CheckRowTitles(row): elif csvPF.CheckRowTitles(row):
if not summary: eventName = event['name']
if not countsSummary:
eventCounts.setdefault(actor, {}) eventCounts.setdefault(actor, {})
eventCounts[actor].setdefault(event['name'], 0) if not countsByDate:
eventCounts[actor][event['name']] += 1 eventCounts[actor].setdefault(eventName, 0)
eventCounts[actor][eventName] += 1
else:
eventCounts[actor].setdefault(eventDate, {})
eventCounts[actor][eventDate].setdefault(eventName, 0)
eventCounts[actor][eventDate][eventName] += 1
else: else:
eventCounts.setdefault(event['name'], 0) eventCounts.setdefault(eventName, 0)
eventCounts[event['name']] += 1 eventCounts[eventName] += 1
elif not summary: elif not countsSummary:
eventCounts.setdefault(actor, {}) eventCounts.setdefault(actor, {})
for event in events: if not countsByDate:
eventCounts[actor].setdefault(event['name'], 0) for event in events:
eventCounts[actor][event['name']] += 1 eventName = event['name']
eventCounts[actor].setdefault(eventName, 0)
eventCounts[actor][eventName] += 1
else:
for event in events:
eventName = event['name']
eventCounts[actor].setdefault(eventDate, {})
eventCounts[actor][eventDate].setdefault(eventName, 0)
eventCounts[actor][eventDate][eventName] += 1
else: else:
for event in events: for event in events:
eventCounts.setdefault(event['name'], 0) eventCounts.setdefault(event['name'], 0)
@@ -14254,31 +14291,46 @@ def doReport():
else: else:
if eventRowFilter: if eventRowFilter:
csvPF.SetRowFilter([], GC.Values[GC.CSV_OUTPUT_ROW_FILTER_MODE]) csvPF.SetRowFilter([], GC.Values[GC.CSV_OUTPUT_ROW_FILTER_MODE])
if not summary: if not countsSummary:
csvPF.SetTitles('emailAddress') titles = ['emailAddress']
if countsOnly and countsByDate:
titles.append('date')
csvPF.SetTitles(titles)
csvPF.SetSortTitles(titles)
if addCSVData: if addCSVData:
csvPF.AddTitles(sorted(addCSVData.keys())) csvPF.AddTitles(sorted(addCSVData.keys()))
if eventCounts: if eventCounts:
for actor, events in iter(eventCounts.items()): if not countsByDate:
row = {'emailAddress': actor} for actor, events in iter(eventCounts.items()):
for event, count in iter(events.items()): row = {'emailAddress': actor}
row[event] = count row.update(zeroEventCounts)
if addCSVData: for event, count in iter(events.items()):
row.update(addCSVData) row[event] = count
csvPF.WriteRowTitles(row) if addCSVData:
row.update(addCSVData)
csvPF.WriteRowTitles(row)
else:
for actor, eventDates in iter(eventCounts.items()):
for eventDate, events in iter(eventDates.items()):
row = {'emailAddress': actor, 'date': eventDate}
row.update(zeroEventCounts)
for event, count in iter(events.items()):
row[event] = count
if addCSVData:
row.update(addCSVData)
csvPF.WriteRowTitles(row)
elif showNoActivities: elif showNoActivities:
row = {'emailAddress': 'NoActivities'} row = {'emailAddress': 'NoActivities'}
if addCSVData: if addCSVData:
row.update(addCSVData) row.update(addCSVData)
csvPF.WriteRow(row) csvPF.WriteRow(row)
csvPF.SetSortTitles(['emailAddress'])
else: else:
csvPF.SetTitles(['event', 'count']) csvPF.SetTitles(['event', 'count'])
if addCSVData: if addCSVData:
csvPF.AddTitles(sorted(addCSVData.keys())) csvPF.AddTitles(sorted(addCSVData.keys()))
if eventCounts: if eventCounts:
for event in sorted(eventCounts): for event, count in sorted(iter(eventCounts.items())):
row = {'event': event, 'count': eventCounts[event]} row = {'event': event, 'count': count}
if addCSVData: if addCSVData:
row.update(addCSVData) row.update(addCSVData)
csvPF.WriteRow(row) csvPF.WriteRow(row)
@@ -23169,8 +23221,8 @@ def printShowContactDelegates(users):
continue continue
jcount = len(delegates) jcount = len(delegates)
if not csvPF: if not csvPF:
entityPerformActionNumItems([Ent.USER, user], jcount, Ent.CONTACT_DELEGATE, i, count)
if not csvStyle: if not csvStyle:
entityPerformActionNumItems([Ent.USER, user], jcount, Ent.CONTACT_DELEGATE, i, count)
Ind.Increment() Ind.Increment()
j = 0 j = 0
for delegate in delegates: for delegate in delegates:
@@ -27892,14 +27944,28 @@ def _getPolicyGroupTarget(cd, cp, myarg, orgUnit):
targetResource = f"groups/{convertEmailAddressToUID(targetName, cd, emailType='group')}" targetResource = f"groups/{convertEmailAddressToUID(targetName, cd, emailType='group')}"
return (targetName, targetName, targetResource, Ent.GROUP, cp.customers().policies().groups()) return (targetName, targetName, targetResource, Ent.GROUP, cp.customers().policies().groups())
def checkPolicyArgs(targetResource, printer_id, app_id):
if not targetResource:
missingArgumentExit('ou|org|orgunit|group')
if printer_id and app_id:
usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format('printerid', 'appid'))
def setPolicyKVList(baseList, printer_id, app_id):
kvList = baseList[:]
if app_id:
kvList.extend([Ent.APP_ID, app_id])
elif printer_id:
kvList.extend([Ent.PRINTER_ID, printer_id])
return kvList
def updatePolicyRequests(body, targetResource, printer_id, app_id): def updatePolicyRequests(body, targetResource, printer_id, app_id):
for request in body['requests']: for request in body['requests']:
request.setdefault('policyTargetKey', {}) request.setdefault('policyTargetKey', {})
request['policyTargetKey']['targetResource'] = targetResource request['policyTargetKey']['targetResource'] = targetResource
if printer_id: if app_id:
request['policyTargetKey']['additionalTargetKeys'] = {'printer_id': printer_id}
elif app_id:
request['policyTargetKey']['additionalTargetKeys'] = {'app_id': app_id} request['policyTargetKey']['additionalTargetKeys'] = {'app_id': app_id}
elif printer_id:
request['policyTargetKey']['additionalTargetKeys'] = {'printer_id': printer_id}
# gam delete chromepolicy # gam delete chromepolicy
# (<SchemaName> [<JSONData>])+ # (<SchemaName> [<JSONData>])+
@@ -27935,15 +28001,14 @@ def doDeleteChromePolicy():
body['requests'][-1].setdefault('policyTargetKey', {}) body['requests'][-1].setdefault('policyTargetKey', {})
for atk in jsonData['additionalTargetKeys']: for atk in jsonData['additionalTargetKeys']:
body['requests'][-1]['policyTargetKey']['additionalTargetKeys'] = {atk['name']: atk['value']} body['requests'][-1]['policyTargetKey']['additionalTargetKeys'] = {atk['name']: atk['value']}
if not targetResource: checkPolicyArgs(targetResource, printer_id, app_id)
missingArgumentExit('ou|org|orgunit|group')
count = len(body['requests']) count = len(body['requests'])
if count != 1: if count != 1:
entityPerformActionNumItems([entityType, targetName], count, Ent.CHROME_POLICY) entityPerformActionNumItems([entityType, targetName], count, Ent.CHROME_POLICY)
if count == 0: if count == 0:
return return
kvList = setPolicyKVList([entityType, targetName, Ent.CHROME_POLICY, ','.join(schemaNameList)], printer_id, app_id)
updatePolicyRequests(body, targetResource, printer_id, app_id) updatePolicyRequests(body, targetResource, printer_id, app_id)
kvList = [entityType, targetName, Ent.CHROME_POLICY, ','.join(schemaNameList)]
try: try:
callGAPI(service, function, callGAPI(service, function,
throwReasons=[GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED, throwReasons=[GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED,
@@ -28189,12 +28254,11 @@ def doUpdateChromePolicy():
invalidArgumentExit(Msg.CHROME_TARGET_VERSION_FORMAT) invalidArgumentExit(Msg.CHROME_TARGET_VERSION_FORMAT)
body['requests'][-1]['policyValue']['value'][casedField] = value body['requests'][-1]['policyValue']['value'][casedField] = value
body['requests'][-1]['updateMask'] += f'{casedField},' body['requests'][-1]['updateMask'] += f'{casedField},'
if not targetResource: checkPolicyArgs(targetResource, printer_id, app_id)
missingArgumentExit('ou|org|orgunit|group')
count = len(body['requests']) count = len(body['requests'])
if count > 0 and not body['requests'][-1]['updateMask']: if count > 0 and not body['requests'][-1]['updateMask']:
body['requests'].pop() body['requests'].pop()
kvList = [entityType, targetName, Ent.CHROME_POLICY, ','.join(schemaNameList)] kvList = setPolicyKVList([entityType, targetName, Ent.CHROME_POLICY, ','.join(schemaNameList)], printer_id, app_id)
if count != 1: if count != 1:
entityPerformActionNumItems(kvList, count, Ent.CHROME_POLICY) entityPerformActionNumItems(kvList, count, Ent.CHROME_POLICY)
if count == 0: if count == 0:
@@ -28236,10 +28300,10 @@ CHROME_POLICY_SHOW_CHOICE_MAP = {
def doPrintShowChromePolicies(): def doPrintShowChromePolicies():
def normalizedPolicy(policy): def normalizedPolicy(policy):
norm = {'name': policy['value']['policySchema']} norm = {'name': policy['value']['policySchema']}
if printerId: if app_id:
norm['printerId'] = printerId norm['appId'] = app_id
elif appId: elif printer_id:
norm['appId'] = appId norm['printerId'] = printer_id
if entityType == Ent.ORGANIZATIONAL_UNIT: if entityType == Ent.ORGANIZATIONAL_UNIT:
orgUnitId = policy.get('targetKey', {}).get('targetResource') orgUnitId = policy.get('targetKey', {}).get('targetResource')
norm['orgUnitPath'] = convertOrgUnitIDtoPath(cd, orgUnitId) if orgUnitId else UNKNOWN norm['orgUnitPath'] = convertOrgUnitIDtoPath(cd, orgUnitId) if orgUnitId else UNKNOWN
@@ -28335,7 +28399,7 @@ def doPrintShowChromePolicies():
if csvPF: if csvPF:
csvPF.SetNoEscapeChar(True) csvPF.SetNoEscapeChar(True)
FJQC = FormatJSONQuoteChar(csvPF) FJQC = FormatJSONQuoteChar(csvPF)
appId = groupEmail = orgUnit = printerId = None app_id = groupEmail = orgUnit = printer_id = targetResource = None
showPolicies = CHROME_POLICY_SHOW_ALL showPolicies = CHROME_POLICY_SHOW_ALL
psFilters = [] psFilters = []
while Cmd.ArgumentsRemaining(): while Cmd.ArgumentsRemaining():
@@ -28346,10 +28410,10 @@ def doPrintShowChromePolicies():
orgUnit, targetName, targetResource, entityType, _ = _getPolicyOrgUnitTarget(cd, cp, myarg, groupEmail) orgUnit, targetName, targetResource, entityType, _ = _getPolicyOrgUnitTarget(cd, cp, myarg, groupEmail)
elif myarg == 'group': elif myarg == 'group':
groupEmail, targetName, targetResource, entityType, _ = _getPolicyGroupTarget(cd, cp, myarg, orgUnit) groupEmail, targetName, targetResource, entityType, _ = _getPolicyGroupTarget(cd, cp, myarg, orgUnit)
elif (not printerId and not appId) and myarg == 'printerid': elif myarg == 'printerid':
printerId = getString(Cmd.OB_PRINTER_ID) printer_id = getString(Cmd.OB_PRINTER_ID)
elif (not printerId and not appId) and myarg == 'appid': elif myarg == 'appid':
appId = getString(Cmd.OB_APP_ID) app_id = getString(Cmd.OB_APP_ID)
elif myarg == 'filter': elif myarg == 'filter':
for psFilter in getString(Cmd.OB_STRING).replace(',', ' ').split(): for psFilter in getString(Cmd.OB_STRING).replace(',', ' ').split():
psFilters.append(psFilter) psFilters.append(psFilter)
@@ -28363,20 +28427,19 @@ def doPrintShowChromePolicies():
showPolicies = getChoice(CHROME_POLICY_SHOW_CHOICE_MAP, mapChoice=True) showPolicies = getChoice(CHROME_POLICY_SHOW_CHOICE_MAP, mapChoice=True)
else: else:
FJQC.GetFormatJSONQuoteChar(myarg, False) FJQC.GetFormatJSONQuoteChar(myarg, False)
if not targetResource: checkPolicyArgs(targetResource, printer_id, app_id)
missingArgumentExit('ou|org|orgunit|group')
body = {'policyTargetKey': {'targetResource': targetResource}} body = {'policyTargetKey': {'targetResource': targetResource}}
if printerId: if app_id:
body['policyTargetKey']['additionalTargetKeys'] = {'printer_id': printerId} body['policyTargetKey']['additionalTargetKeys'] = {'app_id': app_id}
if not psFilters:
psFilters = ['chrome.printers.*']
elif appId:
body['policyTargetKey']['additionalTargetKeys'] = {'app_id': appId}
if not psFilters: if not psFilters:
psFilters = ['chrome.users.apps.*', psFilters = ['chrome.users.apps.*',
'chrome.devices.kiosk.apps.*', 'chrome.devices.kiosk.apps.*',
'chrome.devices.managedguest.apps.*', 'chrome.devices.managedguest.apps.*',
] ]
elif printer_id:
body['policyTargetKey']['additionalTargetKeys'] = {'printer_id': printer_id}
if not psFilters:
psFilters = ['chrome.printers.*']
elif not psFilters: elif not psFilters:
if entityType == Ent.ORGANIZATIONAL_UNIT: if entityType == Ent.ORGANIZATIONAL_UNIT:
psFilters = ['chrome.users.*', psFilters = ['chrome.users.*',
@@ -28410,10 +28473,10 @@ def doPrintShowChromePolicies():
csvPF.AddTitles(['group']) csvPF.AddTitles(['group'])
csvPF.SetSortAllTitles() csvPF.SetSortAllTitles()
if not FJQC.formatJSON: if not FJQC.formatJSON:
if printerId: if app_id:
csvPF.AddSortTitles(['printerId'])
elif appId:
csvPF.AddSortTitles(['appId']) csvPF.AddSortTitles(['appId'])
elif printer_id:
csvPF.AddSortTitles(['printerId'])
else: else:
csvPF.SetJSONTitles(csvPF.titlesList+['JSON']) csvPF.SetJSONTitles(csvPF.titlesList+['JSON'])
policies = [] policies = []
@@ -28440,11 +28503,7 @@ def doPrintShowChromePolicies():
if not csvPF: if not csvPF:
jcount = len(policies) jcount = len(policies)
if not FJQC.formatJSON: if not FJQC.formatJSON:
kvList = [entityType, targetName] kvList = setPolicyKVList([entityType, targetName], printer_id, app_id)
if printerId:
kvList.extend([Ent.PRINTER_ID, printerId])
elif appId:
kvList.extend([Ent.APP_ID, appId])
entityPerformActionModifierNumItems(kvList, Msg.MAXIMUM_OF, jcount, Ent.CHROME_POLICY) entityPerformActionModifierNumItems(kvList, Msg.MAXIMUM_OF, jcount, Ent.CHROME_POLICY)
Ind.Increment() Ind.Increment()
j = 0 j = 0
@@ -38318,6 +38377,7 @@ def _getCalendarEventAttribute(myarg, body, parameters, function):
for subfield in subfields: for subfield in subfields:
body.pop(subfield, None) body.pop(subfield, None)
cd = None
if function == 'insert' and myarg in {'id', 'eventid'}: if function == 'insert' and myarg in {'id', 'eventid'}:
body['id'] = getEventID() body['id'] = getEventID()
elif function == 'import' and myarg == 'icaluid': elif function == 'import' and myarg == 'icaluid':
@@ -38398,6 +38458,17 @@ def _getCalendarEventAttribute(myarg, body, parameters, function):
if responseStatus is not None: if responseStatus is not None:
addAttendee['responseStatus'] = responseStatus addAttendee['responseStatus'] = responseStatus
parameters['attendees'].append(addAttendee) parameters['attendees'].append(addAttendee)
elif function == 'update' and myarg == 'clearresources':
parameters['clearResources'] = True
elif myarg == 'resource':
if cd is None:
cd = buildGAPIObject(API.DIRECTORY)
parameters['attendees'].append({'email': _validateResourceId(cd, getString(Cmd.OB_RESOURCE_ID), 0, 0, True),
'responseStatus': 'accepted', 'resource': True})
elif myarg == 'removeresource':
if cd is None:
cd = buildGAPIObject(API.DIRECTORY)
parameters['removeAttendees'].add(_validateResourceId(cd, getString(Cmd.OB_RESOURCE_ID), 0, 0, True))
elif myarg == 'json': elif myarg == 'json':
jsonData = getJSON(EVENT_JSON_CLEAR_FIELDS) jsonData = getJSON(EVENT_JSON_CLEAR_FIELDS)
if function == 'insert': if function == 'insert':
@@ -38707,7 +38778,7 @@ def _validateCalendarGetEvents(origUser, user, origCal, calId, j, jcount, calend
def _getCalendarCreateImportUpdateEventOptions(function, entityType): def _getCalendarCreateImportUpdateEventOptions(function, entityType):
body = {} body = {}
parameters = {'clearAttendees': False, 'replaceMode': False, parameters = {'clearAttendees': False, 'replaceMode': False, 'clearResources': False,
'attendees': [], 'removeAttendees': set(), 'attendees': [], 'removeAttendees': set(),
'replaceDescription': [], 'sendUpdates': 'none', 'replaceDescription': [], 'sendUpdates': 'none',
'csvPF': None, 'FJQC': FormatJSONQuoteChar(None), 'showDayOfWeek': False} 'csvPF': None, 'FJQC': FormatJSONQuoteChar(None), 'showDayOfWeek': False}
@@ -38818,7 +38889,7 @@ def _updateCalendarEvents(origUser, user, origCal, calIds, count, calendarEventE
updateFieldList = [] updateFieldList = []
if parameters['replaceDescription']: if parameters['replaceDescription']:
updateFieldList.append('description') updateFieldList.append('description')
if not parameters['replaceMode'] and (parameters['attendees'] or parameters['removeAttendees']): if not parameters['replaceMode'] and (parameters['attendees'] or parameters['removeAttendees'] or parameters['clearResources']):
updateFieldList.append('attendees') updateFieldList.append('attendees')
updateFields = ','.join(updateFieldList) updateFields = ','.join(updateFieldList)
if 'attendees' not in updateFieldList: if 'attendees' not in updateFieldList:
@@ -38869,6 +38940,8 @@ def _updateCalendarEvents(origUser, user, origCal, calIds, count, calendarEventE
body['attendees'] = [] body['attendees'] = []
if parameters['removeAttendees']: if parameters['removeAttendees']:
body['attendees'] = [attendee for attendee in body['attendees'] if attendee['email'].lower() not in parameters['removeAttendees']] body['attendees'] = [attendee for attendee in body['attendees'] if attendee['email'].lower() not in parameters['removeAttendees']]
if parameters['clearResources']:
body['attendees'] = [attendee for attendee in body['attendees'] if not attendee['email'].lower().endswith('@resource.calendar.google.com')]
event = callGAPI(cal.events(), 'patch', event = callGAPI(cal.events(), 'patch',
throwReasons=GAPI.CALENDAR_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.DELETED, GAPI.FORBIDDEN, throwReasons=GAPI.CALENDAR_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.DELETED, GAPI.FORBIDDEN,
GAPI.INVALID, GAPI.REQUIRED, GAPI.TIME_RANGE_EMPTY, GAPI.EVENT_DURATION_EXCEEDS_LIMIT, GAPI.INVALID, GAPI.REQUIRED, GAPI.TIME_RANGE_EMPTY, GAPI.EVENT_DURATION_EXCEEDS_LIMIT,
@@ -39618,18 +39691,19 @@ def doCalendarsPrintShowSettings(calIds):
if csvPF: if csvPF:
csvPF.writeCSVfile('Calendar Settings') csvPF.writeCSVfile('Calendar Settings')
def _validateResourceId(resourceId, i, count): def _validateResourceId(cd, resourceId, i, count, exitOnNotFound):
cd = buildGAPIObject(API.DIRECTORY)
try: try:
return callGAPI(cd.resources().calendars(), 'get', return callGAPI(cd.resources().calendars(), 'get',
throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN], throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
customer=GC.Values[GC.CUSTOMER_ID], calendarResourceId=resourceId, fields='resourceEmail')['resourceEmail'] customer=GC.Values[GC.CUSTOMER_ID], calendarResourceId=resourceId, fields='resourceEmail')['resourceEmail']
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden): except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
if exitOnNotFound:
entityDoesNotExistExit(Ent.RESOURCE_CALENDAR, resourceId, i, count)
checkEntityAFDNEorAccessErrorExit(cd, Ent.RESOURCE_CALENDAR, resourceId, i, count) checkEntityAFDNEorAccessErrorExit(cd, Ent.RESOURCE_CALENDAR, resourceId, i, count)
return None return None
def _normalizeResourceIdGetRuleIds(resourceId, i, count, ACLScopeEntity, showAction=True): def _normalizeResourceIdGetRuleIds(cd, resourceId, i, count, ACLScopeEntity, showAction=True):
calId = _validateResourceId(resourceId, i, count) calId = _validateResourceId(cd, resourceId, i, count, False)
if not calId: if not calId:
return (None, None, 0) return (None, None, 0)
if ACLScopeEntity['dict']: if ACLScopeEntity['dict']:
@@ -39647,23 +39721,25 @@ def _normalizeResourceIdGetRuleIds(resourceId, i, count, ACLScopeEntity, showAct
# gam resources <ResourceEntity> create calendaracls <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>] # gam resources <ResourceEntity> create calendaracls <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>]
def doResourceCreateCalendarACLs(entityList): def doResourceCreateCalendarACLs(entityList):
cal = buildGAPIObject(API.CALENDAR) cal = buildGAPIObject(API.CALENDAR)
cd = buildGAPIObject(API.DIRECTORY)
role, ACLScopeEntity, sendNotifications = getCalendarCreateUpdateACLsOptions(True) role, ACLScopeEntity, sendNotifications = getCalendarCreateUpdateACLsOptions(True)
i = 0 i = 0
count = len(entityList) count = len(entityList)
for resourceId in entityList: for resourceId in entityList:
i += 1 i += 1
calId, ruleIds, jcount = _normalizeResourceIdGetRuleIds(resourceId, i, count, ACLScopeEntity) calId, ruleIds, jcount = _normalizeResourceIdGetRuleIds(cd, resourceId, i, count, ACLScopeEntity)
if jcount == 0: if jcount == 0:
continue continue
_createCalendarACLs(cal, Ent.RESOURCE_CALENDAR, calId, i, count, role, ruleIds, jcount, sendNotifications) _createCalendarACLs(cal, Ent.RESOURCE_CALENDAR, calId, i, count, role, ruleIds, jcount, sendNotifications)
def _resourceUpdateDeleteCalendarACLs(entityList, function, ACLScopeEntity, role, sendNotifications): def _resourceUpdateDeleteCalendarACLs(entityList, function, ACLScopeEntity, role, sendNotifications):
cal = buildGAPIObject(API.CALENDAR) cal = buildGAPIObject(API.CALENDAR)
cd = buildGAPIObject(API.DIRECTORY)
i = 0 i = 0
count = len(entityList) count = len(entityList)
for resourceId in entityList: for resourceId in entityList:
i += 1 i += 1
calId, ruleIds, jcount = _normalizeResourceIdGetRuleIds(resourceId, i, count, ACLScopeEntity) calId, ruleIds, jcount = _normalizeResourceIdGetRuleIds(cd, resourceId, i, count, ACLScopeEntity)
if jcount == 0: if jcount == 0:
continue continue
_updateDeleteCalendarACLs(cal, function, Ent.RESOURCE_CALENDAR, calId, i, count, role, ruleIds, jcount, sendNotifications) _updateDeleteCalendarACLs(cal, function, Ent.RESOURCE_CALENDAR, calId, i, count, role, ruleIds, jcount, sendNotifications)
@@ -39686,13 +39762,14 @@ def doResourceDeleteCalendarACLs(entityList):
# [formatjson] # [formatjson]
def doResourceInfoCalendarACLs(entityList): def doResourceInfoCalendarACLs(entityList):
cal = buildGAPIObject(API.CALENDAR) cal = buildGAPIObject(API.CALENDAR)
cd = buildGAPIObject(API.DIRECTORY)
ACLScopeEntity = getCalendarSiteACLScopeEntity() ACLScopeEntity = getCalendarSiteACLScopeEntity()
FJQC = _getCalendarInfoACLOptions() FJQC = _getCalendarInfoACLOptions()
i = 0 i = 0
count = len(entityList) count = len(entityList)
for resourceId in entityList: for resourceId in entityList:
i += 1 i += 1
calId, ruleIds, jcount = _normalizeResourceIdGetRuleIds(resourceId, i, count, ACLScopeEntity, showAction=not FJQC.formatJSON) calId, ruleIds, jcount = _normalizeResourceIdGetRuleIds(cd, resourceId, i, count, ACLScopeEntity, showAction=not FJQC.formatJSON)
if jcount == 0: if jcount == 0:
continue continue
_infoCalendarACLs(cal, resourceId, Ent.RESOURCE_CALENDAR, calId, i, count, ruleIds, jcount, FJQC) _infoCalendarACLs(cal, resourceId, Ent.RESOURCE_CALENDAR, calId, i, count, ruleIds, jcount, FJQC)
@@ -39711,12 +39788,13 @@ def doResourceInfoCalendarACLs(entityList):
# [formatjson] # [formatjson]
def doResourcePrintShowCalendarACLs(entityList): def doResourcePrintShowCalendarACLs(entityList):
cal = buildGAPIObject(API.CALENDAR) cal = buildGAPIObject(API.CALENDAR)
cd = buildGAPIObject(API.DIRECTORY)
csvPF, FJQC, noSelfOwner, addCSVData = _getCalendarPrintShowACLOptions(['resourceId', 'resourceEmail']) csvPF, FJQC, noSelfOwner, addCSVData = _getCalendarPrintShowACLOptions(['resourceId', 'resourceEmail'])
i = 0 i = 0
count = len(entityList) count = len(entityList)
for resourceId in entityList: for resourceId in entityList:
i += 1 i += 1
calId = _validateResourceId(resourceId, i, count) calId = _validateResourceId(cd, resourceId, i, count, False)
if not calId: if not calId:
continue continue
_printShowCalendarACLs(cal, resourceId, Ent.RESOURCE_CALENDAR, calId, i, count, csvPF, FJQC, noSelfOwner, addCSVData) _printShowCalendarACLs(cal, resourceId, Ent.RESOURCE_CALENDAR, calId, i, count, csvPF, FJQC, noSelfOwner, addCSVData)
@@ -59029,8 +59107,8 @@ def _copyPermissions(drive, user, i, count, j, jcount,
notCopiedMessage = f'domain {domain} excluded' notCopiedMessage = f'domain {domain} excluded'
elif domain and copyMoveOptions['includePermissionsFromDomains'] and domain not in copyMoveOptions['includePermissionsFromDomains']: elif domain and copyMoveOptions['includePermissionsFromDomains'] and domain not in copyMoveOptions['includePermissionsFromDomains']:
notCopiedMessage = f'domain {domain} not included' notCopiedMessage = f'domain {domain} not included'
elif permission.pop('deleted', False): elif permission.pop('deleted', False) or (permission['type'] in {'group', 'user'} and not emailAddress):
notCopiedMessage = f"{permission['type']} {permission['emailAddress']} deleted" notCopiedMessage = f"{permission['type']} deleted or has blank email address"
elif ((copyInherited == 'copySheetProtectedRangesInheritedPermissions' and copyMoveOptions[copyInherited]) or elif ((copyInherited == 'copySheetProtectedRangesInheritedPermissions' and copyMoveOptions[copyInherited]) or
(copyNonInherited == 'copySheetProtectedRangesNonInheritedPermissions' and (copyNonInherited == 'copySheetProtectedRangesNonInheritedPermissions' and
copyMoveOptions[copyNonInherited] != COPY_NONINHERITED_PERMISSIONS_NEVER)): copyMoveOptions[copyNonInherited] != COPY_NONINHERITED_PERMISSIONS_NEVER)):
@@ -65566,31 +65644,29 @@ def printShowSharedDrives(users, useDomainAdminAccess=False):
else: else:
matchedFeed = feed matchedFeed = feed
jcount = len(matchedFeed) jcount = len(matchedFeed)
if jcount == 0:
setSysExitRC(NO_ENTITIES_FOUND_RC)
if not csvPF: if not csvPF:
if not FJQC.formatJSON: if not FJQC.formatJSON:
entityPerformActionNumItems([Ent.USER, user], jcount, Ent.SHAREDDRIVE, i, count) entityPerformActionNumItems([Ent.USER, user], jcount, Ent.SHAREDDRIVE, i, count)
if jcount == 0: Ind.Increment()
setSysExitRC(NO_ENTITIES_FOUND_RC) j = 0
for shareddrive in matchedFeed:
j += 1
shareddrive = stripNonShowFields(shareddrive)
_showSharedDrive(user, shareddrive, j, jcount, FJQC)
Ind.Decrement()
else: else:
if not csvPF: for shareddrive in matchedFeed:
Ind.Increment() shareddrive = stripNonShowFields(shareddrive)
j = 0 if FJQC.formatJSON:
for shareddrive in matchedFeed: row = {'User': user, 'id': shareddrive['id'], 'name': shareddrive['name']}
j += 1 if not useDomainAdminAccess:
shareddrive = stripNonShowFields(shareddrive) row['role'] = shareddrive['role'] if not guiRoles else SHAREDDRIVE_API_GUI_ROLES_MAP[shareddrive['role']]
_showSharedDrive(user, shareddrive, j, jcount, FJQC) row['JSON'] = json.dumps(cleanJSON(shareddrive, timeObjects=SHAREDDRIVE_TIME_OBJECTS), ensure_ascii=False, sort_keys=True)
Ind.Decrement() csvPF.WriteRow(row)
else: else:
for shareddrive in matchedFeed: csvPF.WriteRowTitles(flattenJSON(shareddrive, flattened={'User': user}, timeObjects=SHAREDDRIVE_TIME_OBJECTS))
shareddrive = stripNonShowFields(shareddrive)
if FJQC.formatJSON:
row = {'User': user, 'id': shareddrive['id'], 'name': shareddrive['name']}
if not useDomainAdminAccess:
row['role'] = shareddrive['role'] if not guiRoles else SHAREDDRIVE_API_GUI_ROLES_MAP[shareddrive['role']]
row['JSON'] = json.dumps(cleanJSON(shareddrive, timeObjects=SHAREDDRIVE_TIME_OBJECTS), ensure_ascii=False, sort_keys=True)
csvPF.WriteRow(row)
else:
csvPF.WriteRowTitles(flattenJSON(shareddrive, flattened={'User': user}, timeObjects=SHAREDDRIVE_TIME_OBJECTS))
if csvPF: if csvPF:
csvPF.writeCSVfile('SharedDrives') csvPF.writeCSVfile('SharedDrives')
@@ -65649,29 +65725,27 @@ def doPrintShowOrgunitSharedDrives():
customer=_getCustomersCustomerIdWithC(), customer=_getCustomersCustomerIdWithC(),
filter="type == 'shared_drive'") filter="type == 'shared_drive'")
jcount = len(sds) jcount = len(sds)
if jcount == 0:
setSysExitRC(NO_ENTITIES_FOUND_RC)
if not csvPF: if not csvPF:
if not FJQC.formatJSON: if not FJQC.formatJSON:
entityPerformActionNumItems([Ent.ORGANIZATIONAL_UNIT, orgUnitPath], jcount, Ent.SHAREDDRIVE) entityPerformActionNumItems([Ent.ORGANIZATIONAL_UNIT, orgUnitPath], jcount, Ent.SHAREDDRIVE)
if jcount == 0: Ind.Increment()
setSysExitRC(NO_ENTITIES_FOUND_RC) j = 0
for shareddrive in sds:
j += 1
_getOrgUnitSharedDriveInfo(shareddrive)
_showOrgUnitSharedDrive(shareddrive, j, jcount, FJQC)
Ind.Decrement()
else: else:
if not csvPF: for shareddrive in sds:
Ind.Increment() _getOrgUnitSharedDriveInfo(shareddrive)
j = 0 if FJQC.formatJSON:
for shareddrive in sds: row = {'name': shareddrive['name']}
j += 1 row['JSON'] = json.dumps(cleanJSON(shareddrive), ensure_ascii=False, sort_keys=True)
_getOrgUnitSharedDriveInfo(shareddrive) csvPF.WriteRow(row)
_showOrgUnitSharedDrive(shareddrive, j, jcount, FJQC) else:
Ind.Decrement() csvPF.WriteRowTitles(flattenJSON(shareddrive))
else:
for shareddrive in sds:
_getOrgUnitSharedDriveInfo(shareddrive)
if FJQC.formatJSON:
row = {'name': shareddrive['name']}
row['JSON'] = json.dumps(cleanJSON(shareddrive), ensure_ascii=False, sort_keys=True)
csvPF.WriteRow(row)
else:
csvPF.WriteRowTitles(flattenJSON(shareddrive))
if csvPF: if csvPF:
csvPF.writeCSVfile('OrgUnit {orgUnitPath} SharedDrives') csvPF.writeCSVfile('OrgUnit {orgUnitPath} SharedDrives')
@@ -65756,7 +65830,7 @@ SHOW_NO_PERMISSIONS_DRIVES_CHOICE_MAP = {
# [oneitemperrow] [maxitems <Integer>] # [oneitemperrow] [maxitems <Integer>]
# [shownopermissionsdrives false|true|only] # [shownopermissionsdrives false|true|only]
# [<DrivePermissionsFieldName>*|(fields <DrivePermissionsFieldNameList>)] # [<DrivePermissionsFieldName>*|(fields <DrivePermissionsFieldNameList>)]
# [formatjsn] # [formatjson]
def printShowSharedDriveACLs(users, useDomainAdminAccess=False): def printShowSharedDriveACLs(users, useDomainAdminAccess=False):
def _printPermissionRow(baserow, permission): def _printPermissionRow(baserow, permission):
row = baserow.copy() row = baserow.copy()
@@ -65946,7 +66020,8 @@ def printShowSharedDriveACLs(users, useDomainAdminAccess=False):
if jcount == 0: if jcount == 0:
setSysExitRC(NO_ENTITIES_FOUND_RC) setSysExitRC(NO_ENTITIES_FOUND_RC)
if not csvPF: if not csvPF:
entityPerformActionNumItems([Ent.USER, user], jcount, Ent.SHAREDDRIVE, i, count) if not FJQC.formatJSON:
entityPerformActionNumItems([Ent.USER, user], jcount, Ent.SHAREDDRIVE, i, count)
Ind.Increment() Ind.Increment()
j = 0 j = 0
for shareddrive in matchFeed: for shareddrive in matchFeed:
@@ -67548,10 +67623,10 @@ def updatePhoto(users):
body = {'photoData': base64.urlsafe_b64encode(image_data).decode(UTF8)} body = {'photoData': base64.urlsafe_b64encode(image_data).decode(UTF8)}
try: try:
callGAPI(cd.users().photos(), 'update', callGAPI(cd.users().photos(), 'update',
throwReasons=[GAPI.USER_NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID_INPUT], throwReasons=[GAPI.USER_NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID_INPUT, GAPI.CONDITION_NOT_MET],
userKey=user, body=body, fields='') userKey=user, body=body, fields='')
entityActionPerformed([Ent.USER, user, Ent.PHOTO, filename], i, count) entityActionPerformed([Ent.USER, user, Ent.PHOTO, filename], i, count)
except GAPI.invalidInput as e: except (GAPI.invalidInput, GAPI.conditionNotMet) as e:
entityActionFailedWarning([Ent.USER, user, Ent.PHOTO, filename], str(e), i, count) entityActionFailedWarning([Ent.USER, user, Ent.PHOTO, filename], str(e), i, count)
except (GAPI.userNotFound, GAPI.forbidden): except (GAPI.userNotFound, GAPI.forbidden):
entityUnknownWarning(Ent.USER, user, i, count) entityUnknownWarning(Ent.USER, user, i, count)
@@ -71985,7 +72060,8 @@ def updateFormRequestUpdateMasks(ubody):
v['updateMask'] = ','.join(v['updateMask']) v['updateMask'] = ','.join(v['updateMask'])
break break
# gam <UserTypeEntity> create form title <String> [description <String>] [isquiz [<Boolean>]] # gam <UserTypeEntity> create form
# title <String> [description <String>] [isquiz [<Boolean>]] [<JSONData>]
# [drivefilename <DriveFileName>] [<DriveFileParentAttribute>] # [drivefilename <DriveFileName>] [<DriveFileParentAttribute>]
# [(csv [todrive <ToDriveAttribute>*]) | returnidonly] # [(csv [todrive <ToDriveAttribute>*]) | returnidonly]
def createForm(users): def createForm(users):
@@ -72004,6 +72080,9 @@ def createForm(users):
updateFormInfoRequest(myarg, getString(Cmd.OB_STRING, minLen=0), ubody) updateFormInfoRequest(myarg, getString(Cmd.OB_STRING, minLen=0), ubody)
elif myarg == 'isquiz': elif myarg == 'isquiz':
updateFormSettingsRequest('isQuiz', getBoolean(), ubody) updateFormSettingsRequest('isQuiz', getBoolean(), ubody)
elif myarg == 'json':
jsonData = getJSON([])
ubody['requests'].extend(jsonData.get('requests', []))
elif myarg == 'drivefilename': elif myarg == 'drivefilename':
body['name'] = getString(Cmd.OB_DRIVE_FILE_NAME) body['name'] = getString(Cmd.OB_DRIVE_FILE_NAME)
elif getDriveFileParentAttribute(myarg, parentParms): elif getDriveFileParentAttribute(myarg, parentParms):
@@ -72066,7 +72145,8 @@ def createForm(users):
if csvPF: if csvPF:
csvPF.writeCSVfile('Forms') csvPF.writeCSVfile('Forms')
# gam <UserTypeEntity> update form <DriveFileEntity> [title <String>] [description <String>] [isquiz [Boolean>] # gam <UserTypeEntity> update form <DriveFileEntity>
# [title <String>] [description <String>] [isquiz [Boolean>]] [<JSONData>]
def updateForm(users): def updateForm(users):
ubody = {'includeFormInResponse': False, 'requests': []} ubody = {'includeFormInResponse': False, 'requests': []}
fileIdEntity = getDriveFileEntity() fileIdEntity = getDriveFileEntity()
@@ -72078,6 +72158,9 @@ def updateForm(users):
updateFormInfoRequest(myarg, getString(Cmd.OB_STRING, minLen=0), ubody) updateFormInfoRequest(myarg, getString(Cmd.OB_STRING, minLen=0), ubody)
elif myarg == 'isquiz': elif myarg == 'isquiz':
updateFormSettingsRequest('isQuiz', getBoolean(), ubody) updateFormSettingsRequest('isQuiz', getBoolean(), ubody)
elif myarg == 'json':
jsonData = getJSON([])
ubody['requests'].extend(jsonData.get('requests', []))
else: else:
unknownArgumentExit() unknownArgumentExit()
updateFormRequestUpdateMasks(ubody) updateFormRequestUpdateMasks(ubody)

View File

@@ -12,4 +12,4 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
__version__ = "2.146.0" __version__ = "2.156.0"