Compare commits

...

20 Commits

Author SHA1 Message Date
Ross Scroggs
c8108dace0 Fixed bug in gam update resoldcustomer #1743
Some checks failed
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
Check for Google Root CA Updates / check-apis (push) Waiting to run
CodeQL / Analyze (python) (push) Has been cancelled
2025-02-02 08:49:24 -08:00
Ross Scroggs
83a70d656e Updated gam <UserTypeEntity> show labels nested to properly display label nesting when labels have embedded / characters in their names.
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-01 12:38:15 -08:00
Ross Scroggs
3a38609fbb Updated gam <UserTypeEntity> show labels nested to properly display label nesting when labels have embedded / characters in their names. 2025-02-01 12:34:27 -08:00
Ross Scroggs
e744aa29e3 Fix gam-install.sh #1741
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-30 19:09:20 -08:00
Ross Scroggs
367c23a13c Updated gam create project to retry the following unexpected error:
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
ERROR: 400 - invalidArgument - Service account gam-project-a1b2c@gam-project-a1b2c.iam.gserviceaccount.com does not exist.
2025-01-27 08:16:37 -08:00
Ross Scroggs
82e8977003 Updated gam create|use project to discontinue use of the Identity-Aware Proxy (IAP) OAuth Admin APIs
Some checks failed
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
Check for Google Root CA Updates / check-apis (push) Waiting to run
CodeQL / Analyze (python) (push) Has been cancelled
2025-01-26 15:30:45 -08:00
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
7 changed files with 379 additions and 164 deletions

View File

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

View File

@@ -1362,6 +1362,7 @@ gam create project [admin <EmailAddress>] [project <ProjectID>]
nokey]
gam use project [<EmailAddress>] [<ProjectID>]
gam use project [admin <EmailAddress>] [project <ProjectID>]
[appname <String>] [supportemail <EmailAddress>]
[saname <ServiceAccountName>] [sadisplayname <ServiceAccountDisplayName>]
[sadescription <ServiceAccountDescription>]
[(algorithm KEY_ALG_RSA_1024|KEY_ALG_RSA_2048)|
@@ -1677,6 +1678,7 @@ gam calendar <CalendarEntity> printacl [todrive <ToDriveAttribute>*]
(range <Date> <Date>)|
(recurrence <RRULE, EXRULE, RDATE and EXDATE line>)|
(reminder <Number> email|popup))|
(resource <ResourceID>)|
(selectattendees [<AttendeeAttendance>] [<AttendeeStatus>] <UserTypeEntity>)|
(sequence <Integer>)|
(sharedproperty <PropertyKey> <PropertyValue>)|
@@ -1707,8 +1709,10 @@ The following attributes are equivalent:
clearattendees|
clearhangoutsmeet|
(clearprivateproperty <PropertyKey>)|
clearresources|
(clearsharedproperty <PropertyKey>)|
(removeattendee <EmailAddress>)|
(removeresource <ResourceID>)|
(replacedescription <RegularExpression> <String>)|
(selectremoveattendees <UserTypeEntity>)
@@ -4448,7 +4452,7 @@ gam report <ActivityApplicationName> [todrive <ToDriveAttribute>*]
[event|events <EventNameList>] [ip <String>]
[groupidfilter <String>]
[maxactivities <Number>] [maxevents <Number>] [maxresults <Number>]
[countsonly [summary] [eventrowfilter]]
[countsonly [bydate|summary] [eventrowfilter]]
(addcsvdata <FieldName> <String>)* [shownoactivities]
<CustomerServiceName> ::=
@@ -6572,6 +6576,8 @@ gam <UserTypeEntity> copy drivefile <DriveFileEntity>
[copysubfolderpermissions [<Boolean>]]
[copysubfolderinheritedpermissions [<Boolean>]]
[copysubfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders]
[copypermissionroles <DriveFileACLRoleList>]
[copypermissiontypes <DriveFileACLTypeList>]
[excludepermissionsfromdomains|includepermissionsfromdomains <DomainNameList>]
(mappermissionsdomain <DomainName> <DomainName>)*
[copysheetprotectedranges [<Boolean>]]

View File

@@ -1,3 +1,70 @@
7.03.03
Fixed bug in `gam update resoldcustomer` that caused the following error:
```
ERROR: Got an unexpected keyword argument customerAuthToken
```
7.03.02
Updated `gam <UserTypeEntity> show labels nested` to properly display label nesting
when labels have embedded `/` characters in their names.
7.03.01
Updated `gam create project` to retry the following unexpected error:
```
ERROR: 400 - invalidArgument - Service account gam-project-a1b2c@gam-project-a1b2c.iam.gserviceaccount.com does not exist.
```
7.03.00
Updated `gam create|use project` to discontinue use of the `Identity-Aware Proxy (IAP) OAuth Admin APIs`
that are being deprecated by Google. You will see a set of instructions detailing how to
configure the Oauth Consent screen and create the Oauth client.
Added options `copypermissionroles <DriveFileACLRoleList>` and `copypermissiontypes <DriveFileACLTypeList>`
to `gam <UserTypeEntity> copy drivefile` that provide more control over what permissions are copied
from the source files/folders to the destination files/folders.
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

View File

@@ -112,6 +112,12 @@ else
check_type="authenticated"
curl_opts=( "$GHCLIENT" )
fi
curl_ver=$(curl --version|head -1|cut -d " " -f 2)
if [[ "${curl_ver:0:4}" < "7.76" ]]; then
curl_fail=( )
else
curl_fail=( "--fail-with-body" )
fi
echo_yellow "Checking GitHub URL $release_url for $gamversion GAM release ($check_type)..."
release_json=$(curl \
--silent \
@@ -119,7 +125,7 @@ release_json=$(curl \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"$release_url" \
--fail-with-body)
"${curl_fail[@]}")
curl_exit_code=$?
if [ $curl_exit_code -ne 0 ]; then
echo_red "ERROR retrieving URL: ${release_json}"

View File

@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
"""
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
__version__ = '7.02.06'
__version__ = '7.03.03'
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
#pylint: disable=wrong-import-position
@@ -4727,7 +4727,7 @@ def clearServiceCache(service):
DISCOVERY_URIS = [googleapiclient.discovery.V1_DISCOVERY_URI, googleapiclient.discovery.V2_DISCOVERY_URI]
# Used for API.CLOUDRESOURCEMANAGER, API.SERVICEUSAGE, API.IAM, API.IAP
# Used for API.CLOUDRESOURCEMANAGER, API.SERVICEUSAGE, API.IAM
def getAPIService(api, httpObj):
api, version, v2discovery = API.getVersion(api)
return googleapiclient.discovery.build(api, version, http=httpObj, cache_discovery=False,
@@ -11361,13 +11361,32 @@ def doEnableAPIs():
url = f'https://console.cloud.google.com/apis/enableflow?apiid={apiid}&project={projectId}'
writeStdout(f' {url}\n\n')
def _waitForSvcAcctCompletion(i):
sleep_time = i*5
if i > 3:
sys.stdout.write(Msg.WAITING_FOR_ITEM_CREATION_TO_COMPLETE_SLEEPING.format(Ent.Singular(Ent.SVCACCT), sleep_time))
time.sleep(sleep_time)
def _grantRotateRights(iam, projectId, service_account, email, account_type='serviceAccount'):
printEntityMessage([Ent.PROJECT, projectId, Ent.SVCACCT, email],
Msg.HAS_RIGHTS_TO_ROTATE_OWN_PRIVATE_KEY.format(email, service_account))
body = {'policy': {'bindings': [{'role': 'roles/iam.serviceAccountKeyAdmin',
'members': [f'{account_type}:{email}']}]}}
callGAPI(iam.projects().serviceAccounts(), 'setIamPolicy',
resource=f'projects/{projectId}/serviceAccounts/{service_account}', body=body)
maxRetries = 10
printEntityMessage([Ent.PROJECT, projectId, Ent.SVCACCT, email],
Msg.HAS_RIGHTS_TO_ROTATE_OWN_PRIVATE_KEY.format(email, service_account))
for retry in range(1, maxRetries+1):
try:
callGAPI(iam.projects().serviceAccounts(), 'setIamPolicy',
throwReasons=[GAPI.INVALID_ARGUMENT],
resource=f'projects/{projectId}/serviceAccounts/{service_account}', body=body)
return True
except GAPI.invalidArgument as e:
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, service_account], str(e))
if 'does not exist' not in str(e) or retry == maxRetries:
return False
_waitForSvcAcctCompletion(retry)
except Exception as e:
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, service_account], str(e))
return False
def _createOauth2serviceJSON(httpObj, projectInfo, svcAcctInfo, create_key=True):
iam = getAPIService(API.IAM, httpObj)
@@ -11392,24 +11411,12 @@ def _createOauth2serviceJSON(httpObj, projectInfo, svcAcctInfo, create_key=True)
clientId=service_account['uniqueId']):
return False
sa_email = service_account['name'].rsplit('/', 1)[-1]
_grantRotateRights(iam, projectInfo['projectId'], sa_email, sa_email)
return True
def setGAMProjectConsentScreen(httpObj, projectId, appInfo):
sys.stdout.write(Msg.SETTING_GAM_PROJECT_CONSENT_SCREEN)
iap = getAPIService(API.IAP, httpObj)
try:
callGAPI(iap.projects().brands(), 'create',
throwReasons=[GAPI.ALREADY_EXISTS, GAPI.INVALID_ARGUMENT],
parent=f'projects/{projectId}', body=appInfo)
except (GAPI.invalidArgument, GAPI.alreadyExists):
pass
return _grantRotateRights(iam, projectInfo['projectId'], sa_email, sa_email)
def _createClientSecretsOauth2service(httpObj, login_hint, appInfo, projectInfo, svcAcctInfo, create_key=True):
def _checkClientAndSecret(csHttpObj, client_id, client_secret):
post_data = {'client_id': client_id, 'client_secret': client_secret,
'code': 'ThisIsAnInvalidCodeOnlyBeingUsedToTestIfClientAndSecretAreValid',
# 'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob', 'grant_type': 'authorization_code'}
'redirect_uri': 'http://127.0.0.1:8080', 'grant_type': 'authorization_code'}
_, content = csHttpObj.request(API.GOOGLE_OAUTH2_TOKEN_ENDPOINT, 'POST', urlencode(post_data),
headers={'Content-type': 'application/x-www-form-urlencoded'})
@@ -11434,16 +11441,14 @@ def _createClientSecretsOauth2service(httpObj, login_hint, appInfo, projectInfo,
if not enableGAMProjectAPIs(httpObj, projectInfo['projectId'], login_hint, False):
return
if appInfo:
setGAMProjectConsentScreen(httpObj, projectInfo['projectId'], appInfo)
console_url = f'https://console.cloud.google.com/apis/credentials/oauthclient?project={projectInfo["projectId"]}&authuser={login_hint}'
sys.stdout.write(Msg.SETTING_GAM_PROJECT_CONSENT_SCREEN_CREATING_CLIENT)
console_url = f'https://console.cloud.google.com/auth/clients?project={projectInfo["projectId"]}&authuser={login_hint}'
csHttpObj = getHttpObj()
while True:
sys.stdout.write(Msg.CREATE_PROJECT_INSTRUCTIONS.format(console_url))
sys.stdout.write(Msg.CREATE_CLIENT_INSTRUCTIONS.format(console_url, appInfo['applicationTitle'], appInfo['supportEmail']))
client_id = readStdin(Msg.ENTER_YOUR_CLIENT_ID).strip()
if not client_id:
client_id = readStdin('').strip()
sys.stdout.write(Msg.GO_BACK_TO_YOUR_BROWSER_AND_COPY_YOUR_CLIENT_SECRET_VALUE)
client_secret = readStdin(Msg.ENTER_YOUR_CLIENT_SECRET).strip()
if not client_secret:
client_secret = readStdin('').strip()
@@ -11451,7 +11456,6 @@ def _createClientSecretsOauth2service(httpObj, login_hint, appInfo, projectInfo,
if client_valid:
break
sys.stdout.write('\n')
# Deleted: "redirect_uris": ["http://localhost", "urn:ietf:wg:oauth:2.0:oob"],
cs_data = f'''{{
"installed": {{
"auth_provider_x509_cert_url": "{API.GOOGLE_AUTH_PROVIDER_X509_CERT_URL}",
@@ -11464,7 +11468,6 @@ def _createClientSecretsOauth2service(httpObj, login_hint, appInfo, projectInfo,
}}
}}'''
writeFile(GC.Values[GC.CLIENT_SECRETS_JSON], cs_data, continueOnError=False)
sys.stdout.write(Msg.GO_BACK_TO_YOUR_BROWSER_AND_CLICK_OK_TO_CLOSE_THE_OAUTH_CLIENT_POPUP)
sys.stdout.write(Msg.TRUST_GAM_CLIENT_ID.format(GAM, client_id))
readStdin('')
if not _createOauth2serviceJSON(httpObj, projectInfo, svcAcctInfo, create_key):
@@ -11590,7 +11593,7 @@ def _getLoginHintProjectInfo(createCmd):
_checkProjectName(projectInfo['name'])
elif _getSvcAcctInfo(myarg, svcAcctInfo):
pass
elif createCmd and _getAppInfo(myarg, appInfo):
elif _getAppInfo(myarg, appInfo):
pass
elif myarg in {'algorithm', 'localkeysize', 'validityhours', 'yubikey'}:
Cmd.Backup()
@@ -11874,14 +11877,15 @@ def doCreateProject():
# gam use project [<EmailAddress>] [<ProjectID>]
# gam use project [admin <EmailAddress>] [project <ProjectID>]
# [appname <String>] [supportemail <EmailAddress>]
# [saname <ServiceAccountName>] [sadisplayname <ServiceAccountDisplayName>] [sadescription <ServiceAccountDescription>]
# [(algorithm KEY_ALG_RSA_1024|KEY_ALG_RSA_2048)|
# (localkeysize 1024|2048|4096 [validityhours <Number>])|
# (yubikey yubikey_pin yubikey_slot AUTHENTICATION yubikey_serialnumber <String>)]
def doUseProject():
_checkForExistingProjectFiles([GC.Values[GC.OAUTH2SERVICE_JSON], GC.Values[GC.CLIENT_SECRETS_JSON]])
_, httpObj, login_hint, _, projectInfo, svcAcctInfo, create_key = _getLoginHintProjectInfo(False)
_createClientSecretsOauth2service(httpObj, login_hint, {}, projectInfo, svcAcctInfo, create_key)
_, httpObj, login_hint, appInfo, projectInfo, svcAcctInfo, create_key = _getLoginHintProjectInfo(False)
_createClientSecretsOauth2service(httpObj, login_hint, appInfo, projectInfo, svcAcctInfo, create_key)
# gam update project [[admin] <EmailAddress>] [<ProjectIDEntity>]
def doUpdateProject():
@@ -12577,12 +12581,6 @@ def doProcessSvcAcctKeys(mode=None, iam=None, projectId=None, clientEmail=None,
else:
unknownArgumentExit()
def waitForCompletion(i):
sleep_time = i*5
if i > 3:
sys.stdout.write(Msg.WAITING_FOR_ITEM_CREATION_TO_COMPLETE_SLEEPING.format(Ent.Singular(Ent.SVCACCT), sleep_time))
time.sleep(sleep_time)
local_key_size = 2048
validityHours = 0
body = {}
@@ -12652,12 +12650,12 @@ def doProcessSvcAcctKeys(mode=None, iam=None, projectId=None, clientEmail=None,
if retry == maxRetries:
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, clientEmail], str(e))
return False
waitForCompletion(retry)
_waitForSvcAcctCompletion(retry)
except GAPI.permissionDenied:
if retry == maxRetries:
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, clientEmail], Msg.UPDATE_PROJECT_TO_VIEW_MANAGE_SAKEYS)
return False
waitForCompletion(retry)
_waitForSvcAcctCompletion(retry)
except GAPI.badRequest as e:
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, clientEmail], str(e))
return False
@@ -12670,7 +12668,7 @@ def doProcessSvcAcctKeys(mode=None, iam=None, projectId=None, clientEmail=None,
new_data['private_key'] = ''
newPrivateKeyId = ''
break
waitForCompletion(retry)
_waitForSvcAcctCompletion(retry)
new_data['private_key_id'] = newPrivateKeyId
oauth2service_data = _formatOAuth2ServiceData(new_data)
else:
@@ -12687,7 +12685,7 @@ def doProcessSvcAcctKeys(mode=None, iam=None, projectId=None, clientEmail=None,
if retry == maxRetries:
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, clientEmail], Msg.UPDATE_PROJECT_TO_VIEW_MANAGE_SAKEYS)
return False
waitForCompletion(retry)
_waitForSvcAcctCompletion(retry)
except GAPI.badRequest as e:
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, clientEmail], str(e))
return False
@@ -12728,7 +12726,7 @@ def doProcessSvcAcctKeys(mode=None, iam=None, projectId=None, clientEmail=None,
if retry == maxRetries:
entityActionFailedWarning([Ent.SVCACCT_KEY, keyName], Msg.UPDATE_PROJECT_TO_VIEW_MANAGE_SAKEYS)
break
waitForCompletion(retry)
_waitForSvcAcctCompletion(retry)
except GAPI.badRequest as e:
entityActionFailedWarning([Ent.SVCACCT_KEY, keyName], str(e), i, count)
break
@@ -13090,13 +13088,13 @@ def _checkDataRequiredServices(result, tryDate, dataRequiredServices, parameterS
# 0: Backup to earlier date
# 1: Data available
oneDay = datetime.timedelta(days=1)
warnings = result.get('warnings', [])
dataWarnings = result.get('warnings', [])
usageReports = result.get('usageReports', [])
# move to day before if we don't have at least one usageReport with parameters
if not usageReports or not usageReports[0].get('parameters', []):
tryDateTime = datetime.datetime.strptime(tryDate, YYYYMMDD_FORMAT)-oneDay
return (0, tryDateTime.strftime(YYYYMMDD_FORMAT), None)
for warning in warnings:
for warning in dataWarnings:
if warning['code'] == 'PARTIAL_DATA_AVAILABLE':
for app in warning['data']:
if app['key'] == 'application' and app['value'] != 'docs' and app['value'] in dataRequiredServices:
@@ -13521,7 +13519,7 @@ REPORT_ACTIVITIES_TIME_OBJECTS = {'time'}
# [event|events <EventNameList>] [ip <String>]
# [groupidfilter <String>]
# [maxactivities <Number>] [maxevents <Number>] [maxresults <Number>]
# [countsonly [summary] [eventrowfilter]]
# [countsonly [bydate|summary] [eventrowfilter]]
# (addcsvdata <FieldName> <String>)* [shownoactivities]
# gam report users|user [todrive <ToDriveAttribute>*]
# [(user all|<UserItem>)|(orgunit|org|ou <OrgUnitPath> [showorgunit])|(select <UserTypeEntity>)]
@@ -13794,8 +13792,8 @@ def doReport():
filterTimes = {}
maxActivities = maxEvents = 0
maxResults = 1000
aggregateByDate = aggregateByUser = convertMbToGb = countsOnly = eventRowFilter = exitUserLoop = \
noAuthorizedApps = normalizeUsers = select = summary = userCustomerRange = False
aggregateByDate = aggregateByUser = convertMbToGb = countsOnly = countsByDate = countsSummary = \
eventRowFilter = exitUserLoop = noAuthorizedApps = normalizeUsers = select = userCustomerRange = False
limitDateChanges = -1
allVerifyUser = userKey = 'all'
cd = orgUnit = orgUnitId = None
@@ -13893,8 +13891,10 @@ def doReport():
actorIpAddress = getString(Cmd.OB_STRING)
elif activityReports and myarg == 'countsonly':
countsOnly = True
elif activityReports and myarg == 'bydate':
countsByDate = True
elif activityReports and myarg == 'summary':
summary = True
countsSummary = True
elif activityReports and myarg == 'eventrowfilter':
eventRowFilter = True
elif activityReports and myarg == 'groupidfilter':
@@ -13928,6 +13928,8 @@ def doReport():
unknownArgumentExit()
if aggregateByDate and 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
if usageReports and not includeServices:
includeServices = set(fullDataServices)
@@ -14144,8 +14146,12 @@ def doReport():
pageMessage = getPageMessage()
users = [normalizeEmailAddressOrUID(userKey)]
orgUnitId = None
zeroEventCounts = {}
if not eventNames:
eventNames.append(None)
else:
for eventName in eventNames:
zeroEventCounts[eventName] = 0
i = 0
count = len(users)
for user in users:
@@ -14177,9 +14183,22 @@ def doReport():
accessErrorExit(None)
for activity in feed:
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:
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:
activity_row = flattenJSON(activity, timeObjects=REPORT_ACTIVITIES_TIME_OBJECTS)
purge_parameters = True
@@ -14230,18 +14249,32 @@ def doReport():
if numEvents >= maxEvents > 0:
break
elif csvPF.CheckRowTitles(row):
if not summary:
eventName = event['name']
if not countsSummary:
eventCounts.setdefault(actor, {})
eventCounts[actor].setdefault(event['name'], 0)
eventCounts[actor][event['name']] += 1
if not countsByDate:
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:
eventCounts.setdefault(event['name'], 0)
eventCounts[event['name']] += 1
elif not summary:
eventCounts.setdefault(eventName, 0)
eventCounts[eventName] += 1
elif not countsSummary:
eventCounts.setdefault(actor, {})
for event in events:
eventCounts[actor].setdefault(event['name'], 0)
eventCounts[actor][event['name']] += 1
if not countsByDate:
for event in events:
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:
for event in events:
eventCounts.setdefault(event['name'], 0)
@@ -14256,31 +14289,46 @@ def doReport():
else:
if eventRowFilter:
csvPF.SetRowFilter([], GC.Values[GC.CSV_OUTPUT_ROW_FILTER_MODE])
if not summary:
csvPF.SetTitles('emailAddress')
if not countsSummary:
titles = ['emailAddress']
if countsOnly and countsByDate:
titles.append('date')
csvPF.SetTitles(titles)
csvPF.SetSortTitles(titles)
if addCSVData:
csvPF.AddTitles(sorted(addCSVData.keys()))
if eventCounts:
for actor, events in iter(eventCounts.items()):
row = {'emailAddress': actor}
for event, count in iter(events.items()):
row[event] = count
if addCSVData:
row.update(addCSVData)
csvPF.WriteRowTitles(row)
if not countsByDate:
for actor, events in iter(eventCounts.items()):
row = {'emailAddress': actor}
row.update(zeroEventCounts)
for event, count in iter(events.items()):
row[event] = count
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:
row = {'emailAddress': 'NoActivities'}
if addCSVData:
row.update(addCSVData)
csvPF.WriteRow(row)
csvPF.SetSortTitles(['emailAddress'])
else:
csvPF.SetTitles(['event', 'count'])
if addCSVData:
csvPF.AddTitles(sorted(addCSVData.keys()))
if eventCounts:
for event in sorted(eventCounts):
row = {'event': event, 'count': eventCounts[event]}
for event, count in sorted(iter(eventCounts.items())):
row = {'event': event, 'count': count}
if addCSVData:
row.update(addCSVData)
csvPF.WriteRow(row)
@@ -15062,11 +15110,11 @@ def doCreateResoldCustomer():
def doUpdateResoldCustomer():
res = buildGAPIObject(API.RESELLER)
customerId = getString(Cmd.OB_CUSTOMER_ID)
customerAuthToken, body = _getResoldCustomerAttr()
_, body = _getResoldCustomerAttr()
try:
callGAPI(res.customers(), 'patch',
throwReasons=GAPI.RESELLER_THROW_REASONS,
customerId=customerId, body=body, customerAuthToken=customerAuthToken, fields='')
customerId=customerId, body=body, fields='')
entityActionPerformed([Ent.CUSTOMER_ID, customerId])
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden, GAPI.invalid) as e:
entityActionFailedWarning([Ent.CUSTOMER_ID, customerId], str(e))
@@ -27894,14 +27942,28 @@ def _getPolicyGroupTarget(cd, cp, myarg, orgUnit):
targetResource = f"groups/{convertEmailAddressToUID(targetName, cd, emailType='group')}"
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):
for request in body['requests']:
request.setdefault('policyTargetKey', {})
request['policyTargetKey']['targetResource'] = targetResource
if printer_id:
request['policyTargetKey']['additionalTargetKeys'] = {'printer_id': printer_id}
elif app_id:
if app_id:
request['policyTargetKey']['additionalTargetKeys'] = {'app_id': app_id}
elif printer_id:
request['policyTargetKey']['additionalTargetKeys'] = {'printer_id': printer_id}
# gam delete chromepolicy
# (<SchemaName> [<JSONData>])+
@@ -27937,15 +27999,14 @@ def doDeleteChromePolicy():
body['requests'][-1].setdefault('policyTargetKey', {})
for atk in jsonData['additionalTargetKeys']:
body['requests'][-1]['policyTargetKey']['additionalTargetKeys'] = {atk['name']: atk['value']}
if not targetResource:
missingArgumentExit('ou|org|orgunit|group')
checkPolicyArgs(targetResource, printer_id, app_id)
count = len(body['requests'])
if count != 1:
entityPerformActionNumItems([entityType, targetName], count, Ent.CHROME_POLICY)
if count == 0:
return
kvList = setPolicyKVList([entityType, targetName, Ent.CHROME_POLICY, ','.join(schemaNameList)], printer_id, app_id)
updatePolicyRequests(body, targetResource, printer_id, app_id)
kvList = [entityType, targetName, Ent.CHROME_POLICY, ','.join(schemaNameList)]
try:
callGAPI(service, function,
throwReasons=[GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED,
@@ -28191,12 +28252,11 @@ def doUpdateChromePolicy():
invalidArgumentExit(Msg.CHROME_TARGET_VERSION_FORMAT)
body['requests'][-1]['policyValue']['value'][casedField] = value
body['requests'][-1]['updateMask'] += f'{casedField},'
if not targetResource:
missingArgumentExit('ou|org|orgunit|group')
checkPolicyArgs(targetResource, printer_id, app_id)
count = len(body['requests'])
if count > 0 and not body['requests'][-1]['updateMask']:
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:
entityPerformActionNumItems(kvList, count, Ent.CHROME_POLICY)
if count == 0:
@@ -28238,10 +28298,10 @@ CHROME_POLICY_SHOW_CHOICE_MAP = {
def doPrintShowChromePolicies():
def normalizedPolicy(policy):
norm = {'name': policy['value']['policySchema']}
if printerId:
norm['printerId'] = printerId
elif appId:
norm['appId'] = appId
if app_id:
norm['appId'] = app_id
elif printer_id:
norm['printerId'] = printer_id
if entityType == Ent.ORGANIZATIONAL_UNIT:
orgUnitId = policy.get('targetKey', {}).get('targetResource')
norm['orgUnitPath'] = convertOrgUnitIDtoPath(cd, orgUnitId) if orgUnitId else UNKNOWN
@@ -28337,7 +28397,7 @@ def doPrintShowChromePolicies():
if csvPF:
csvPF.SetNoEscapeChar(True)
FJQC = FormatJSONQuoteChar(csvPF)
appId = groupEmail = orgUnit = printerId = None
app_id = groupEmail = orgUnit = printer_id = targetResource = None
showPolicies = CHROME_POLICY_SHOW_ALL
psFilters = []
while Cmd.ArgumentsRemaining():
@@ -28348,10 +28408,10 @@ def doPrintShowChromePolicies():
orgUnit, targetName, targetResource, entityType, _ = _getPolicyOrgUnitTarget(cd, cp, myarg, groupEmail)
elif myarg == 'group':
groupEmail, targetName, targetResource, entityType, _ = _getPolicyGroupTarget(cd, cp, myarg, orgUnit)
elif (not printerId and not appId) and myarg == 'printerid':
printerId = getString(Cmd.OB_PRINTER_ID)
elif (not printerId and not appId) and myarg == 'appid':
appId = getString(Cmd.OB_APP_ID)
elif myarg == 'printerid':
printer_id = getString(Cmd.OB_PRINTER_ID)
elif myarg == 'appid':
app_id = getString(Cmd.OB_APP_ID)
elif myarg == 'filter':
for psFilter in getString(Cmd.OB_STRING).replace(',', ' ').split():
psFilters.append(psFilter)
@@ -28365,20 +28425,19 @@ def doPrintShowChromePolicies():
showPolicies = getChoice(CHROME_POLICY_SHOW_CHOICE_MAP, mapChoice=True)
else:
FJQC.GetFormatJSONQuoteChar(myarg, False)
if not targetResource:
missingArgumentExit('ou|org|orgunit|group')
checkPolicyArgs(targetResource, printer_id, app_id)
body = {'policyTargetKey': {'targetResource': targetResource}}
if printerId:
body['policyTargetKey']['additionalTargetKeys'] = {'printer_id': printerId}
if not psFilters:
psFilters = ['chrome.printers.*']
elif appId:
body['policyTargetKey']['additionalTargetKeys'] = {'app_id': appId}
if app_id:
body['policyTargetKey']['additionalTargetKeys'] = {'app_id': app_id}
if not psFilters:
psFilters = ['chrome.users.apps.*',
'chrome.devices.kiosk.apps.*',
'chrome.devices.managedguest.apps.*',
]
elif printer_id:
body['policyTargetKey']['additionalTargetKeys'] = {'printer_id': printer_id}
if not psFilters:
psFilters = ['chrome.printers.*']
elif not psFilters:
if entityType == Ent.ORGANIZATIONAL_UNIT:
psFilters = ['chrome.users.*',
@@ -28412,10 +28471,10 @@ def doPrintShowChromePolicies():
csvPF.AddTitles(['group'])
csvPF.SetSortAllTitles()
if not FJQC.formatJSON:
if printerId:
csvPF.AddSortTitles(['printerId'])
elif appId:
if app_id:
csvPF.AddSortTitles(['appId'])
elif printer_id:
csvPF.AddSortTitles(['printerId'])
else:
csvPF.SetJSONTitles(csvPF.titlesList+['JSON'])
policies = []
@@ -28442,11 +28501,7 @@ def doPrintShowChromePolicies():
if not csvPF:
jcount = len(policies)
if not FJQC.formatJSON:
kvList = [entityType, targetName]
if printerId:
kvList.extend([Ent.PRINTER_ID, printerId])
elif appId:
kvList.extend([Ent.APP_ID, appId])
kvList = setPolicyKVList([entityType, targetName], printer_id, app_id)
entityPerformActionModifierNumItems(kvList, Msg.MAXIMUM_OF, jcount, Ent.CHROME_POLICY)
Ind.Increment()
j = 0
@@ -37388,7 +37443,7 @@ def _doDeleteResourceCalendars(entityList):
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
customer=GC.Values[GC.CUSTOMER_ID], calendarResourceId=resourceId)
entityActionPerformed([Ent.RESOURCE_CALENDAR, resourceId], i, count)
except GAPI.serviceNotAvailable as e:
except GAPI.serviceNotAvailable as e:
entityActionFailedWarning([Ent.RESOURCE_CALENDAR, resourceId], str(e), i, count)
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
checkEntityAFDNEorAccessErrorExit(cd, Ent.RESOURCE_CALENDAR, resourceId, i, count)
@@ -38320,6 +38375,7 @@ def _getCalendarEventAttribute(myarg, body, parameters, function):
for subfield in subfields:
body.pop(subfield, None)
cd = None
if function == 'insert' and myarg in {'id', 'eventid'}:
body['id'] = getEventID()
elif function == 'import' and myarg == 'icaluid':
@@ -38400,6 +38456,17 @@ def _getCalendarEventAttribute(myarg, body, parameters, function):
if responseStatus is not None:
addAttendee['responseStatus'] = responseStatus
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':
jsonData = getJSON(EVENT_JSON_CLEAR_FIELDS)
if function == 'insert':
@@ -38709,7 +38776,7 @@ def _validateCalendarGetEvents(origUser, user, origCal, calId, j, jcount, calend
def _getCalendarCreateImportUpdateEventOptions(function, entityType):
body = {}
parameters = {'clearAttendees': False, 'replaceMode': False,
parameters = {'clearAttendees': False, 'replaceMode': False, 'clearResources': False,
'attendees': [], 'removeAttendees': set(),
'replaceDescription': [], 'sendUpdates': 'none',
'csvPF': None, 'FJQC': FormatJSONQuoteChar(None), 'showDayOfWeek': False}
@@ -38820,7 +38887,7 @@ def _updateCalendarEvents(origUser, user, origCal, calIds, count, calendarEventE
updateFieldList = []
if parameters['replaceDescription']:
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')
updateFields = ','.join(updateFieldList)
if 'attendees' not in updateFieldList:
@@ -38871,6 +38938,8 @@ def _updateCalendarEvents(origUser, user, origCal, calIds, count, calendarEventE
body['attendees'] = []
if 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',
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,
@@ -39093,10 +39162,12 @@ def _wipeCalendarEvents(user, origCal, calIds, count):
continue
try:
callGAPI(cal.calendars(), 'clear',
throwReasons=GAPI.CALENDAR_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID, GAPI.REQUIRED_ACCESS_LEVEL],
throwReasons=GAPI.CALENDAR_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID,
GAPI.REQUIRED_ACCESS_LEVEL, GAPI.SERVICE_NOT_AVAILABLE],
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
calendarId=calId)
entityActionPerformed([Ent.CALENDAR, calId], i, count)
except (GAPI.notFound, GAPI.forbidden, GAPI.invalid, GAPI.requiredAccessLevel) as e:
except (GAPI.notFound, GAPI.forbidden, GAPI.invalid, GAPI.requiredAccessLevel, GAPI.serviceNotAvailable) as e:
entityActionFailedWarning([Ent.CALENDAR, calId], str(e), i, count)
except GAPI.notACalendarUser:
userCalServiceNotEnabledWarning(calId, i, count)
@@ -39620,18 +39691,19 @@ def doCalendarsPrintShowSettings(calIds):
if csvPF:
csvPF.writeCSVfile('Calendar Settings')
def _validateResourceId(resourceId, i, count):
cd = buildGAPIObject(API.DIRECTORY)
def _validateResourceId(cd, resourceId, i, count, exitOnNotFound):
try:
return callGAPI(cd.resources().calendars(), 'get',
throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
customer=GC.Values[GC.CUSTOMER_ID], calendarResourceId=resourceId, fields='resourceEmail')['resourceEmail']
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
if exitOnNotFound:
entityDoesNotExistExit(Ent.RESOURCE_CALENDAR, resourceId, i, count)
checkEntityAFDNEorAccessErrorExit(cd, Ent.RESOURCE_CALENDAR, resourceId, i, count)
return None
def _normalizeResourceIdGetRuleIds(resourceId, i, count, ACLScopeEntity, showAction=True):
calId = _validateResourceId(resourceId, i, count)
def _normalizeResourceIdGetRuleIds(cd, resourceId, i, count, ACLScopeEntity, showAction=True):
calId = _validateResourceId(cd, resourceId, i, count, False)
if not calId:
return (None, None, 0)
if ACLScopeEntity['dict']:
@@ -39649,23 +39721,25 @@ def _normalizeResourceIdGetRuleIds(resourceId, i, count, ACLScopeEntity, showAct
# gam resources <ResourceEntity> create calendaracls <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>]
def doResourceCreateCalendarACLs(entityList):
cal = buildGAPIObject(API.CALENDAR)
cd = buildGAPIObject(API.DIRECTORY)
role, ACLScopeEntity, sendNotifications = getCalendarCreateUpdateACLsOptions(True)
i = 0
count = len(entityList)
for resourceId in entityList:
i += 1
calId, ruleIds, jcount = _normalizeResourceIdGetRuleIds(resourceId, i, count, ACLScopeEntity)
calId, ruleIds, jcount = _normalizeResourceIdGetRuleIds(cd, resourceId, i, count, ACLScopeEntity)
if jcount == 0:
continue
_createCalendarACLs(cal, Ent.RESOURCE_CALENDAR, calId, i, count, role, ruleIds, jcount, sendNotifications)
def _resourceUpdateDeleteCalendarACLs(entityList, function, ACLScopeEntity, role, sendNotifications):
cal = buildGAPIObject(API.CALENDAR)
cd = buildGAPIObject(API.DIRECTORY)
i = 0
count = len(entityList)
for resourceId in entityList:
i += 1
calId, ruleIds, jcount = _normalizeResourceIdGetRuleIds(resourceId, i, count, ACLScopeEntity)
calId, ruleIds, jcount = _normalizeResourceIdGetRuleIds(cd, resourceId, i, count, ACLScopeEntity)
if jcount == 0:
continue
_updateDeleteCalendarACLs(cal, function, Ent.RESOURCE_CALENDAR, calId, i, count, role, ruleIds, jcount, sendNotifications)
@@ -39688,13 +39762,14 @@ def doResourceDeleteCalendarACLs(entityList):
# [formatjson]
def doResourceInfoCalendarACLs(entityList):
cal = buildGAPIObject(API.CALENDAR)
cd = buildGAPIObject(API.DIRECTORY)
ACLScopeEntity = getCalendarSiteACLScopeEntity()
FJQC = _getCalendarInfoACLOptions()
i = 0
count = len(entityList)
for resourceId in entityList:
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:
continue
_infoCalendarACLs(cal, resourceId, Ent.RESOURCE_CALENDAR, calId, i, count, ruleIds, jcount, FJQC)
@@ -39713,12 +39788,13 @@ def doResourceInfoCalendarACLs(entityList):
# [formatjson]
def doResourcePrintShowCalendarACLs(entityList):
cal = buildGAPIObject(API.CALENDAR)
cd = buildGAPIObject(API.DIRECTORY)
csvPF, FJQC, noSelfOwner, addCSVData = _getCalendarPrintShowACLOptions(['resourceId', 'resourceEmail'])
i = 0
count = len(entityList)
for resourceId in entityList:
i += 1
calId = _validateResourceId(resourceId, i, count)
calId = _validateResourceId(cd, resourceId, i, count, False)
if not calId:
continue
_printShowCalendarACLs(cal, resourceId, Ent.RESOURCE_CALENDAR, calId, i, count, csvPF, FJQC, noSelfOwner, addCSVData)
@@ -58806,6 +58882,8 @@ def initCopyMoveOptions(copyCmd):
'fileMimeTypes': set(),
'notMimeTypes': False,
'copySubFilesOwnedBy': None,
'copyPermissionRoles': set(DRIVEFILE_ACL_ROLES_MAP.values()),
'copyPermissionTypes': set(DRIVEFILE_ACL_PERMISSION_TYPES),
}
DUPLICATE_FILE_CHOICES = {
@@ -58894,6 +58972,20 @@ def getCopyMoveOptions(myarg, copyMoveOptions):
copyMoveOptions['copyFileInheritedPermissions'] = getBoolean()
elif myarg == 'copyfilenoninheritedpermissions':
copyMoveOptions['copyFileNonInheritedPermissions'] = COPY_NONINHERITED_PERMISSIONS_ALWAYS if getBoolean() else COPY_NONINHERITED_PERMISSIONS_NEVER
elif myarg == 'copypermissionroles':
copyMoveOptions['copyPermissionRoles'] = set()
for prole in getString(Cmd.OB_PERMISSION_ROLE_LIST).lower().replace(',', ' ').split():
if prole in DRIVEFILE_ACL_ROLES_MAP:
copyMoveOptions['copyPermissionRoles'].add(DRIVEFILE_ACL_ROLES_MAP[prole])
else:
invalidChoiceExit(prole, DRIVEFILE_ACL_ROLES_MAP, True)
elif myarg == 'copypermissiontypes':
copyMoveOptions['copyPermissionTypes'] = set()
for ptype in getString(Cmd.OB_PERMISSION_TYPE_LIST).lower().replace(',', ' ').split():
if ptype in DRIVEFILE_ACL_PERMISSION_TYPES:
copyMoveOptions['copyPermissionTypes'].add(ptype)
else:
invalidChoiceExit(ptype, DRIVEFILE_ACL_PERMISSION_TYPES, True)
elif myarg == 'copysheetprotectedranges':
if getBoolean():
copyMoveOptions['copySheetProtectedRangesInheritedPermissions'] = True
@@ -59007,15 +59099,20 @@ def _copyPermissions(drive, user, i, count, j, jcount,
def isPermissionCopyable(kvList, permission):
role = permission['role']
emailAddress = permission.get('emailAddress', '')
permissionType = permission['type']
domain = ''
if copyMoveOptions['excludePermissionsFromDomains'] or copyMoveOptions['includePermissionsFromDomains']:
if permission['type'] in {'group', 'user'}:
if permissionType in {'group', 'user'}:
atLoc = emailAddress.find('@')
if atLoc > 0:
domain = emailAddress[atLoc+1:]
elif permission['type'] == 'domain':
elif permissionType == 'domain':
domain = permission.get('domain', '')
if permission['inherited'] and not copyMoveOptions[copyInherited]:
if role not in copyMoveOptions['copyPermissionRoles']:
notCopiedMessage = f'role {role} not selected'
elif permissionType not in copyMoveOptions['copyPermissionTypes']:
notCopiedMessage = f'type {permissionType} not selected'
elif permission['inherited'] and not copyMoveOptions[copyInherited]:
notCopiedMessage = 'inherited not selected'
elif not permission['inherited'] and copyMoveOptions[copyNonInherited] == COPY_NONINHERITED_PERMISSIONS_NEVER:
notCopiedMessage = 'noninherited not selected'
@@ -59031,8 +59128,8 @@ def _copyPermissions(drive, user, i, count, j, jcount,
notCopiedMessage = f'domain {domain} excluded'
elif domain and copyMoveOptions['includePermissionsFromDomains'] and domain not in copyMoveOptions['includePermissionsFromDomains']:
notCopiedMessage = f'domain {domain} not included'
elif permission.pop('deleted', False):
notCopiedMessage = f"{permission['type']} {permission['emailAddress']} deleted"
elif permission.pop('deleted', False) or (permissionType in {'group', 'user'} and not emailAddress):
notCopiedMessage = f"{permissionType} deleted or has blank email address"
elif ((copyInherited == 'copySheetProtectedRangesInheritedPermissions' and copyMoveOptions[copyInherited]) or
(copyNonInherited == 'copySheetProtectedRangesNonInheritedPermissions' and
copyMoveOptions[copyNonInherited] != COPY_NONINHERITED_PERMISSIONS_NEVER)):
@@ -59470,6 +59567,8 @@ copyReturnItemMap = {
# [copysubfolderpermissions [<Boolean>]]
# [copysubfolderinheritedpermissions [<Boolean>]]
# [copysubfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders]
# [copypermissionroles <DriveFileACLRoleList>]
# [copypermissiontypes <DriveFileACLTypeList>]
# [excludepermissionsfromdomains|includepermissionsfromdomains <DomainNameList>]
# (mappermissionsdomain <DomainName> <DomainName>)*
# [copysheetprotectedranges [<Boolean>]]
@@ -60284,6 +60383,8 @@ def _updateMoveFilePermissions(drive, user, i, count,
# [copysubfolderpermissions [<Boolean>]]
# [copysubfolderinheritedpermissions [<Boolean>]]
# [copysubfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders]
# [copypermissionroles <DriveFileACLRoleList>]
# [copypermissiontypes <DriveFileACLTypeList>]
# [synctopfoldernoniheritedpermissions [<Boolean>]] [syncsubfoldernoninheritedpermissions [<Boolean>]]
# [excludepermissionsfromdomains|includepermissionsfromdomains <DomainNameList>]
# (mappermissionsdomain <DomainName> <DomainName>)*
@@ -67547,10 +67648,10 @@ def updatePhoto(users):
body = {'photoData': base64.urlsafe_b64encode(image_data).decode(UTF8)}
try:
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='')
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)
except (GAPI.userNotFound, GAPI.forbidden):
entityUnknownWarning(Ent.USER, user, i, count)
@@ -69300,13 +69401,18 @@ LABEL_COUNTS_FIELDS = ','.join(LABEL_COUNTS_FIELDS_LIST)
def printShowLabels(users):
def _buildLabelTree(labels):
def _checkChildLabel(label):
if label.find('/') != -1:
(parent, base) = label.rsplit('/', 1)
labelItemList = label.split('/')
i = len(labelItemList)-1
while i > 0:
parent = '/'.join(labelItemList[:i])
base = '/'.join(labelItemList[i:])
if parent in labelTree:
if label in labelTree:
labelTree[label]['info']['base'] = base
labelTree[parent]['children'].append(labelTree.pop(label))
_checkChildLabel(parent)
return
i -= 1
labelTree = {}
for label in labels['labels']:

View File

@@ -71,7 +71,6 @@ GROUPSMIGRATION = 'groupsmigration'
GROUPSSETTINGS = 'groupssettings'
IAM = 'iam'
IAM_CREDENTIALS = 'iamcredentials'
IAP = 'iap'
KEEP = 'keep'
LICENSING = 'licensing'
LOOKERSTUDIO = 'datastudio'
@@ -185,7 +184,6 @@ PROJECT_APIS = [
'groupsmigration.googleapis.com',
'groupssettings.googleapis.com',
'iam.googleapis.com',
'iap.googleapis.com',
'keep.googleapis.com',
'licensing.googleapis.com',
'meet.googleapis.com',
@@ -250,7 +248,6 @@ _INFO = {
GROUPSSETTINGS: {'name': 'Groups Settings API', 'version': 'v1', 'v2discovery': True},
IAM: {'name': 'Identity and Access Management API', 'version': 'v1', 'v2discovery': True},
IAM_CREDENTIALS: {'name': 'Identity and Access Management Credentials API', 'version': 'v1', 'v2discovery': True},
IAP: {'name': 'Cloud Identity-Aware Proxy API', 'version': 'v1', 'v2discovery': True},
KEEP: {'name': 'Keep 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},

View File

@@ -40,21 +40,43 @@ sign in as {0} and accept the Terms of Service (ToS). As soon as you've accepted
PROJECT_STILL_BEING_CREATED_SLEEPING = 'Project still being created. Sleeping {0} seconds\n'
FAILED_TO_CREATE_PROJECT = 'Failed to create project: {0}\n'
SETTING_GAM_PROJECT_CONSENT_SCREEN = 'Setting GAM project consent screen...\n'
CREATE_PROJECT_INSTRUCTIONS = '''
SETTING_GAM_PROJECT_CONSENT_SCREEN_CREATING_CLIENT = 'Setting GAM project consent screen, creating client...\n'
CREATE_CLIENT_INSTRUCTIONS = '''
Please go to:
{0}
1. Choose "Desktop App" or "Other" for "Application type".
2. Enter "GAM" or another desired value for "Name".
3. Click the blue "Create" button.
4. Copy your "Client ID" value that shows on the next page.
1. If "+ CREATE CLIENT" is on the screen, skip to step 14
2. Click "GET STARTED"
3. Under "App Information", enter {1} or another value in "App name *"
4. Under "App Information", enter {2} in "User support email *"
5. Click "NEXT"
6. Under "Audience", choose INTERNAL
7. Click "NEXT"
8. Under, "Contact Information", enter an email address in "Email addresses *"
9. Click "NEXT"
10. Under "Finish", click "I agree to the Google API Services: User Data Policy."
11. Click "CONTINUE"
12. Click "CREATE"
13. Click "Clients" in the left-hand column
14. Click "+ CREATE CLIENT"
15. Choose "Desktop App" for "Application type"
16. Enter {1} or another value in "Name *"
17. Click "Create"
18. Under "Name", click your client name
19. Copy the "Client ID" value under "Additional information"
20. Paste it at the "Enter your Client ID: " prompt in your terminal
21. Press return/enter in your terminal
22. Switch back to the browser
23. Copy the "Client secret" value under "Client Secrets"
24. Paste it at the "Enter your Client Secret: " prompt in your terminal
25. Press return/enter in your terminal
26. Switch back to the browser
27. Click "CANCEL"
28. These steps are complete
'''
ENTER_YOUR_CLIENT_ID = '\nEnter your Client ID: '
GO_BACK_TO_YOUR_BROWSER_AND_COPY_YOUR_CLIENT_SECRET_VALUE = '\n5. Go back to your browser and copy your "Client Secret" value.\n'
ENTER_YOUR_CLIENT_SECRET = '\nEnter your Client Secret: '
GO_BACK_TO_YOUR_BROWSER_AND_CLICK_OK_TO_CLOSE_THE_OAUTH_CLIENT_POPUP = '\n6. Go back to your browser and click OK to close the "OAuth client" popup if it\'s still open.\n'
IS_NOT_A_VALID_CLIENT_ID = '''
{0}
@@ -78,12 +100,12 @@ Please go to:
https://admin.google.com/ac/owl/list?tab=configuredApps
1. Click on: Configure new app > OAuth App Name Or Client ID.
2. Enter the following Client ID value:
1. Click on: Configure new app
2. Enter the following Client ID value in Search for app:
{1}
3. Press Search, select the {0} app, press Select, check the box and press Select.
3. Press Search, select the {0} app, click
4. Keep the default scope or select a preferred scope that includes your GAM admin.
5. Press Continue
6. Select Trusted radio button, press Continue and Finish.