Compare commits

...

38 Commits

Author SHA1 Message Date
Ross Scroggs
3ce48a95c9 Fixed bug in gam config timezone <String> to handle timezone abbreviations correctly 2025-10-09 17:08:44 -07:00
Ross Scroggs
2dafbfbcfc Update limited command data access
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 7, Build Intel MacOS, macos-13) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.14-dev, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14-dev freethread, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
2025-10-08 19:10:14 -07:00
Ross Scroggs
e03086866a Update limited command data access 2025-10-08 18:10:05 -07:00
Jay Lee
0422bf22ea only freeze_support if we are frozen 2025-10-08 21:52:26 +00:00
Jay Lee
f3d9f3d518 remove read command for DwD data 2025-10-08 21:39:01 +00:00
Jay Lee
ea9fd3f363 != not ==
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 7, Build Intel MacOS, macos-13) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.14-dev, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14-dev freethread, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
2025-10-08 14:52:34 +00:00
Jay Lee
bed9db37ad forkserver for Linux, #1843 2025-10-08 14:43:28 +00:00
Jay Lee
072dc4809a force fork on Linux, fixes #1843 2025-10-08 13:55:34 +00:00
Jay Lee
6db2309fc4 actions: rebuild for Python 3.14.0
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 7, Build Intel MacOS, macos-13) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.14-dev, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14-dev freethread, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
2025-10-07 12:53:59 -04:00
Ross Scroggs
cbb0c81652 Handle: ERROR: Authentication Token Error - invalid_account: Forbidden
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 7, Build Intel MacOS, macos-13) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.14-dev, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14-dev freethread, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
2025-10-06 13:00:47 -07:00
Ross Scroggs
f68aca8361 Handle: ERROR: Authentication Token Error - invalid_account: Forbidden 2025-10-06 12:15:18 -07:00
Ross Scroggs
d63fdb4ed9 Add drive/sheets read command data scopes
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 7, Build Intel MacOS, macos-13) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.14-dev, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14-dev freethread, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
2025-10-03 18:06:30 -07:00
Ross Scroggs
226781766b Add drive/sheets read command data scopes 2025-10-03 17:34:33 -07:00
Ross Scroggs
434e30d57c Update Vault-Takeout.md
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
2025-10-03 13:17:13 -07:00
Ross Scroggs
2ab059926b Fixed bug in gam print|show admins
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 7, Build Intel MacOS, macos-13) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.14-dev, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14-dev freethread, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
2025-10-03 08:50:29 -07:00
Ross Scroggs
5ae25495f7 Fixed bug in gam print|show admins 2025-10-03 07:27:31 -07:00
Ross Scroggs
20e226e57d Added option types <AdminAssigneeTypeList> to gam print|show admins
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 7, Build Intel MacOS, macos-13) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.14-dev, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14-dev freethread, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
2025-10-02 17:36:31 -07:00
Ross Scroggs
b4677585bb Added option types <AdminAssigneeTypeList> to gam print|show admins 2025-10-02 16:47:40 -07:00
Ross Scroggs
3a1437872c Update Administrators.md
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 7, Build Intel MacOS, macos-13) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.14-dev, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14-dev freethread, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
2025-10-02 13:33:48 -07:00
Ross Scroggs
602dce2f5a Update Administrators.md 2025-10-02 13:26:42 -07:00
Ross Scroggs
8ce930f01b Added option recursive to gam print|show admins 2025-10-02 13:24:19 -07:00
Ross Scroggs
9631882be0 Added option recursive to gam print|show admins 2025-10-02 12:27:06 -07:00
Jay Lee
32d2858e4b Update build.yml 2025-10-02 13:16:14 -04:00
Jay Lee
98370925e7 actions: fix caching excludes 2025-10-02 12:35:49 -04:00
Jay Lee
1ef5d030f6 actions: exclude .git folder from caching, rebuild
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 7, Build Intel MacOS, macos-13) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.14-dev, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14-dev freethread, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
2025-10-02 09:57:58 -04:00
Jay Lee
d50b5fb61e actions: update dependent action versions 2025-10-02 09:25:20 -04:00
Jay Lee
e070e92be2 Update pypi.yml 2025-10-02 09:15:29 -04:00
Ross Scroggs
b3b6fff2f1 Added option addcsvdata <FieldName> <String> to print events
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
2025-10-01 18:36:25 -07:00
Ross Scroggs
fea94fcc1c Added option addcsvdata <FieldName> <String> to 1print events`
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 7, Build Intel MacOS, macos-13) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.14-dev, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14-dev freethread, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
2025-10-01 16:03:32 -07:00
Ross Scroggs
a0cd228110 Merge branch 'main' of https://github.com/GAM-team/GAM 2025-10-01 12:52:06 -07:00
Jay Lee
acfcd8b723 actions: do export on OU level also 2025-10-01 13:42:54 -04:00
Jay Lee
a26494e5c6 Update build.yml 2025-10-01 13:26:54 -04:00
Jay Lee
5605e5d1b6 actions: place vault hold on OU not user to try to avoid license delays 2025-10-01 13:16:35 -04:00
Ross Scroggs
e0fdac6e17 Merge branch 'main' of https://github.com/GAM-team/GAM 2025-10-01 10:07:06 -07:00
Ross Scroggs
53dc8e3265 Update Domain-SharedContacts.md 2025-10-01 10:06:55 -07:00
Jay Lee
993a0b403e Update build.yml 2025-10-01 11:42:25 -04:00
Jay Lee
2d7d118d32 actions: rebuild for OpenSSL 3.6.0
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 7, Build Intel MacOS, macos-13) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.14-dev, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14-dev freethread, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
2025-10-01 08:30:58 -04:00
Ross Scroggs
f2bc704fd6 Upgraded to OpenSSL 3.5.4.
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 7, Build Intel MacOS, macos-13) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.14-dev, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14-dev freethread, ubuntu-24.04, 3.14-dev) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
2025-09-30 18:55:52 -07:00
24 changed files with 569 additions and 208 deletions

View File

@@ -158,7 +158,7 @@ jobs:
with:
path: |
cache.tar.xz
key: gam-${{ matrix.jid }}-20250930
key: gam-${{ matrix.jid }}-20251007
- name: Untar Cache archive
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
@@ -168,7 +168,7 @@ jobs:
- name: Use pre-compiled Python for testing
if: matrix.python != ''
uses: actions/setup-python@3d1e2d2ca0a067f27da6fec484fce7f5256def85 # v5.6.0
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ matrix.python }}
allow-prereleases: true
@@ -335,11 +335,11 @@ jobs:
# --libdir=lib is needed so Python can find OpenSSL libraries
"${PERL}" ./Configure --libdir=lib --prefix="${OPENSSL_INSTALL_PATH}" $OPENSSL_CONFIG_OPTS
# - name: Rename GNU link on Windows
# if: matrix.goal == 'build' && runner.os == 'Windows' && steps.cache-python-ssl.outputs.cache-hit != 'true'
# shell: bash
# run: |
# mv -v /usr/bin/link /usr/bin/gnulink
- name: Rename GNU link on Windows
if: matrix.goal == 'build' && runner.os == 'Windows' && steps.cache-python-ssl.outputs.cache-hit != 'true'
shell: bash
run: |
mv -v /usr/bin/link /usr/bin/gnulink
- name: Make OpenSSL
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit != 'true'
@@ -943,11 +943,11 @@ jobs:
$gam calendar $gam_user printevents after -0d
$gam config enable_dasa false save
matterid=uid:$($gam create vaultmatter name "GHA matter $newbase" description "test matter" returnidonly)
$gam create vaulthold matter $matterid name "GHA hold $newbase" corpus mail accounts $newuser
$gam create vaulthold matter $matterid name "GHA hold ${newbase}" corpus mail ou "$newou"
$gam print vaultmatters matterstate open
$gam print vaultholds matter $matterid
$gam print vaultcount matter $matterid corpus mail everyone todrive tdnobrowser
$gam create vaultexport matter $matterid name "GHA export $newbase" corpus mail accounts $newuser
$gam create vaultexport matter $matterid name "GHA export $newbase" corpus mail ou "$newou"
$gam print exports matter $matterid | $gam csv - gam info export $matterid id:~~id~~
$gam config enable_dasa true save
$gam csv sample.csv gam user ~email add calendar id:$newresource
@@ -1027,7 +1027,8 @@ jobs:
else
tar_folders="bin/"
fi
tar cJvvf cache.tar.xz $tar_folders
echo '.git*' > ./excludes.txt
tar cJvvf cache.tar.xz --exclude-from=excludes.txt $tar_folders
merge:
if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
@@ -1077,7 +1078,7 @@ jobs:
echo "dateversion=${dateversion}" >> $GITHUB_OUTPUT
- name: Publish draft release
uses: softprops/action-gh-release@fbadcc90e88ecface60a0a0d123795b784ceb239 # v2.3.2
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836 # v2.3.3
with:
draft: true
prerelease: false

View File

@@ -30,6 +30,6 @@ jobs:
python -m build
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
with:
attestation: true

View File

@@ -368,6 +368,7 @@ If an item contains spaces, it should be surrounded by ".
## Named items
<AccessToken> ::= <String>
<AdminAssigneeType> ::= group|user|serviceaccount|unknown
<AlertID> ::= <String>
<APIScopeURL> ::= <String>
<APPID> ::= <String>
@@ -691,6 +692,7 @@ If an item contains spaces, it should be surrounded by ".
## Lists of basic items
<AdminAssigneeTypeList> ::= "<AdminAssigneeType>(,<AdminAssigneeType>)*"
<APIScopeURLList> ::= "<APIScopeURL>(,<APIScopeURL>)*"
<ASPIDList> ::= "<ASPID>(,<ASPID>)*"
<AssetTagList> ::= "<AssetTag>(,<AssetTag>)*"
@@ -1551,11 +1553,17 @@ gam create|add admin <EmailAddress>|<UniqueID> <RoleItem> customer|(org_unit <Or
[condition securitygroup|nonsecuritygroup]
gam delete admin <RoleAssignmentId>
<AdminAssigneeType> ::= group|user|serviceaccount|unknown
<AdminAssigneeTypeList> ::= "<AdminAssigneeType>(,<AdminAssigneeType>)*"
gam print admins [todrive <ToDriveAttribute>*]
[user|group <EmailAddress>|<UniqueID>] [role <RoleItem>] [condition]
[privileges] [oneitemperrow]
[user|group <EmailAddress>|<UniqueID>] [role <RoleItem>]
[types <AdminAssigneeTypeList>]
[recursive] [condition] [privileges] [oneitemperrow]
gam show admins
[user|group <EmailAddress>|<UniqueID>] [role <RoleItem>] [condition] [privileges]
[user|group <EmailAddress>|<UniqueID>] [role <RoleItem>]
[types <AdminAssigneeTypeList>]
[recursive] [condition] [privileges]
# Alert Center
@@ -1932,12 +1940,12 @@ gam calendar|calendars <CalendarEntity> info events [<EventEntity>] [maxinstance
[formatjson]
gam calendar|calendars <CalendarEntity> show events [<EventEntity>] <EventDisplayProperty>*
[fields <EventFieldNameList>] [showdayofweek]
[countsonly]
[formatjson]
[countsonly|formatjson]
gam calendar|calendars <CalendarEntity> print events [<EventEntity>] <EventDisplayProperty>*
[fields <EventFieldNameList>] [showdayofweek]
[countsonly [eventrowfilter]]
[formatjson [quotechar <Character>]] [todrive <ToDriveAttribute>*]
(addcsvdata <FieldName> <String>)*
[eventrowfilter]
[countsonly|(formatjson [quotechar <Character>])] [todrive <ToDriveAttribute>*]
gam calendar <CalendarEntity> addevent <EventAttribute>+ [<EventNotificationAttribute>]
[showdayofweek]
@@ -3745,16 +3753,14 @@ gam print domaincontacts|peoplecontacts [todrive <ToDriveAttribute>*]
[sources <PeopleSourceName>]
[query <String>]
[mergesources <PeopleMergeSourceName>]
[coountsonly]
[allfields|(fields <PeopleFieldNameList>)] [showmetadata]
[formatjson [quotechar <Character>]]
[coountsonly|(formatjson [quotechar <Character>])]
gam show domaincontacts|peoplecontacts
[sources <PeopleSourceName>]
[query <String>]
[mergesources <PeopleMergeSourceName>]
[coountsonly]
[allfields|(fields <PeopleFieldNameList>)] [showmetadata]
[formatjson]
[coountsonly|formatjson]
gam info people|peopleprofile <PeopleResourceNameEntity>
[allfields|(fields <PeopleFieldNameList>)] [showmetadata]
@@ -3762,15 +3768,13 @@ gam info people|peopleprofile <PeopleResourceNameEntity>
gam print people|peopleprofile [todrive <ToDriveAttribute>*]
[query <String>]
[mergesources <PeopleMergeSourceName>]
[coountsonly]
[allfields|(fields <PeopleFieldNameList>)] [showmetadata]
[formatjson [quotechar <Character>]]
[coountsonly|(formatjson [quotechar <Character>])]
gam show people|peopleprofile
[query <String>]
[mergesources <PeopleMergeSourceName>]
[coountsonly]
[allfields|(fields <PeopleFieldNameList>)] [showmetadata]
[formatjson]
[coountsonly|formatjson]
# Email Audit Monitor
@@ -6315,12 +6319,11 @@ gam <UserTypeEntity> info events <UserCalendarEntity> [<EventEntity>] [maxinstan
[formatjson]
gam <UserTypeEntity> show events <UserCalendarEntity> [<EventEntity>] <EventDisplayProperty>*
[fields <EventFieldNameList>] [showdayofweek]
[countsonly]
[formatjson]
[countsonly|formatjson]
gam <UserTypeEntity> print events <UserCalendarEntity> [<EventEntity>] <EventDisplayProperty>*
[fields <EventFieldNameList>] [showdayofweek]
[countsonly [eventrowfilter]]
[formatjson [quotechar <Character>]] [todrive <ToDriveAttribute>*]
[eventrowfilter]]
[countsonly|(formatjson [quotechar <Character>])] [todrive <ToDriveAttribute>*]
gam <UserTypeEntity> update calattendees <UserCalendarEntity> <EventEntity> [anyorganizer]
[<EventNotificationAttribute>] [splitupdate] [dryrun|doit]
@@ -8344,13 +8347,13 @@ gam <UserTypeEntity> info contacts
gam <UserTypeEntity> show contacts
<PeoplePrintShowUserContactSelection>
[orderby firstname|lastname|(lastmodified ascending)|(lastnodified descending)
[countsonly|allfields|(fields <PeopleFieldNameList>)] [showgroups] [showmetadata]
[formatjson]
[allfields|(fields <PeopleFieldNameList>)] [showgroups] [showmetadata]
[countsonly|formatjson]
gam <UserTypeEntity> print contacts [todrive <ToDriveAttribute>*]
<PeoplePrintShowUserContactSelection>
[orderby firstname|lastname|(lastmodified ascending)|(lastnodified descending)
[countsonly|allfields|(fields <PeopleFieldNameList>)] [[showgroups|showgroupnameslist] showmetadata]
[formatjson [quotechar <Character>]]
[allfields|(fields <PeopleFieldNameList>)] [[showgroups|showgroupnameslist] showmetadata]
[countsonly|(formatjson [quotechar <Character>])]
<OtherContactsFieldName> ::=
emailaddresses|
@@ -8584,7 +8587,7 @@ gam <UserTypeEntity> info tasklist <TasklistEntity>
gam <UserTypeEntity> show tasklists
[countsonly|formatjson]
gam <UserTypeEntity> print tasklists [todrive <ToDriveAttribute>*]
[countsonly | (formatjson [quotechar <Character>])]
[countsonly|(formatjson [quotechar <Character>])]
# Users - Shared Drives

View File

@@ -1,3 +1,81 @@
7.25.01
Fixed bug in `gam config timezone <String>` to handle timezone abbreviations correctly;
they were incorrectly shifted to lowercase.
7.25.00
Removed a capabilty added in 7.24.00 that allowed reading command data from Google Docs and Sheets
when a user's service account access to Drive and Sheets had been disabled. Jay was concerned
that this change could be exploited to give access to all user's files.
This capability has been replaced by issuing the following commands. The admin specified in `gam oauth create`
can read command data from Docs and Sheets to which it has access.
```
gam config commanddata_clientaccess true save
gam oauth create
Enable the following and proceed to authorization.
[*] 42) Drive API - commanddata_clientaccess
[*] 54) Sheets API - commanddata_clientaccess
```
Fixed in bug in `gam report` that caused a trap with either of the `thismonth` or `previousmonths` options were used.
Upgraded to Python 3.14.0.
7.24.01
Updated GAM to handle the following error that occurs when GAM tries to authenticate
as a user that has been disabled by Google.
```
ERROR: Authentication Token Error - invalid_account: Forbidden
```
7.24.00
If you want to disable a user's service account access to Drive and Sheets but still allow reading command data from Google Docs and Sheets,
issue the following command and make these settings:
```
gam user user@domain.com update serviceaccount
[ ] 20) Drive API (supports readonly)
[*] 21) Drive API - read command data
[ ] 42) Sheets API (supports readonly)
[*] 43) Sheets API - read command data
```
7.23.07
Fixed bug in `gam print|show admins` where all admin assignments were not displayed when
`types <AdminAssigneeTypeList>` was not specified, i.e., all assignments should be displayed.
7.23.06
Added option `types <AdminAssigneeTypeList>` to `gam print|show admins` that allows filtering
of admin assignments by the type of the assignee; by default, all assignee types are displayed.
```
<AdminAssigneeType> ::= group|user|serviceaccount|unknown
<AdminAssigneeTypeList> ::= "<AdminAssigneeType>(,<AdminAssigneeType>)*"
```
7.23.05
Added option `recursive` that will display assignments to the members
of security groups assigned to roles; the security group membership is recursively expanded.
7.23.04
Added option `addcsvdata <FieldName> <String>` to `gam <UserTypeEntity> print events`
and `gam calendars <CalendarEntity> print events` that adds additional columns of data to the CSV file output.
An example would be to get the calendar name in addition to the calendar ID when printing events.
```
gam redirect csv ./Resources.csv print resources fields email,name
gam redirect csv ./ResourceEventCounts.csv multiprocess redirect stderr - multiprocess csv Resources.csv gam calendar "~resourceEmail" print events starttime -1y countsonly addcsvdata calendarName "~resourceName"
```
Upgraded to OpenSSL 3.6.0.
7.23.03
Upgraded to OpenSSL 3.5.4.

View File

@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
"""
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
__version__ = '7.23.03'
__version__ = '7.25.01'
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
#pylint: disable=wrong-import-position
@@ -2113,12 +2113,12 @@ class StartEndTime():
else:
firstMonth = getInteger(minVal=1, maxVal=6)
currDate = todaysDate()
self.startDateTime = currDate.shift(months=-firstMonth, day=1, hour=0, minute=0, second=0, microsecond=0)
self.startDateTime = currDate.replace(day=1, hour=0, minute=0, second=0, microsecond=0).shift(months=-firstMonth)
self.startTime = ISOformatTimeStamp(self.startDateTime)
if myarg == 'thismonth':
self.endDateTime = todaysTime()
else:
self.endDateTime = currDate.shift(day=1, hour=23, minute=59, second=59, microsecond=0).shift(days=-1)
self.endDateTime = currDate.replace(day=1, hour=23, minute=59, second=59, microsecond=0).shift(days=-1)
self.endTime = ISOformatTimeStamp(self.endDateTime)
if self.startDateTime and self.endDateTime and self.endDateTime < self.startDateTime:
Cmd.Backup()
@@ -3049,9 +3049,13 @@ def getGDocData(gformat):
mimeType = GDOC_FORMAT_MIME_TYPES[gformat]
user = getEmailAddress()
fileIdEntity = getDriveFileEntity(queryShortcutsOK=False)
user, drive, jcount = _validateUserGetFileIDs(user, 0, 0, fileIdEntity)
if not GC.Values[GC.COMMANDDATA_CLIENTACCESS]:
_, drive = buildGAPIServiceObject(API.DRIVE3, user)
else:
drive = buildGAPIObject(API.DRIVE3)
if not drive:
sys.exit(GM.Globals[GM.SYSEXITRC])
_, _, jcount = _validateUserGetFileIDs(user, 0, 0, fileIdEntity, drive=drive)
if jcount == 0:
getGDocSheetDataFailedExit([Ent.USER, user], Msg.NO_ENTITIES_FOUND.format(Ent.Singular(Ent.DRIVE_FILE)))
if jcount > 1:
@@ -3105,14 +3109,21 @@ def getGSheetData():
user = getEmailAddress()
fileIdEntity = getDriveFileEntity(queryShortcutsOK=False)
sheetEntity = getSheetEntity(False)
user, drive, jcount = _validateUserGetFileIDs(user, 0, 0, fileIdEntity)
if not GC.Values[GC.COMMANDDATA_CLIENTACCESS]:
user, drive = buildGAPIServiceObject(API.DRIVE3, user)
else:
drive = buildGAPIObject(API.DRIVE3)
if not drive:
sys.exit(GM.Globals[GM.SYSEXITRC])
_, _, jcount = _validateUserGetFileIDs(user, 0, 0, fileIdEntity, drive=drive)
if jcount == 0:
getGDocSheetDataFailedExit([Ent.USER, user], Msg.NO_ENTITIES_FOUND.format(Ent.Singular(Ent.DRIVE_FILE)))
if jcount > 1:
getGDocSheetDataFailedExit([Ent.USER, user], Msg.MULTIPLE_ENTITIES_FOUND.format(Ent.Plural(Ent.DRIVE_FILE), jcount, ','.join(fileIdEntity['list'])))
_, sheet = buildGAPIServiceObject(API.SHEETS, user)
if not GC.Values[GC.COMMANDDATA_CLIENTACCESS]:
_, sheet = buildGAPIServiceObject(API.SHEETS, user)
else:
sheet = buildGAPIObject(API.SHEETS)
if not sheet:
sys.exit(GM.Globals[GM.SYSEXITRC])
fileId = fileIdEntity['list'][0]
@@ -3705,12 +3716,12 @@ def SetGlobalVariables():
return stringlist
def _getCfgTimezone(sectionName, itemName):
value = _stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName).lower())
if value in {'utc', 'z'}:
value = _stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName))
if value.lower() in {'utc', 'z'}:
GM.Globals[GM.CONVERT_TO_LOCAL_TIME] = False
return arrow.now('utc').tzinfo
GM.Globals[GM.CONVERT_TO_LOCAL_TIME] = True
if value == 'local':
if value.lower() == 'local':
return arrow.now(value).tzinfo
try:
return arrow.now(value).tzinfo
@@ -4799,10 +4810,7 @@ def defaultSvcAcctScopes():
saScopes[scope['api']].append(scope['scope'])
else:
saScopes[scope['api']].extend(scope['scope'])
saScopes[API.DRIVEACTIVITY].append(API.DRIVE_SCOPE)
saScopes[API.DRIVE2] = saScopes[API.DRIVE3]
saScopes[API.DRIVETD] = saScopes[API.DRIVE3]
saScopes[API.SHEETSTD] = saScopes[API.SHEETS]
return saScopes
def _getSvcAcctData():
@@ -5609,6 +5617,12 @@ def getSaUser(user):
GM.Globals[GM.CURRENT_CLIENT_API_SCOPES] = currentClientAPIScopes
return userEmail
def chooseSaAPI(api1, api2):
_getSvcAcctData()
if api1 in GM.Globals[GM.SVCACCT_SCOPES]:
return api1
return api2
def buildGAPIServiceObject(api, user, i=0, count=0, displayError=True):
userEmail = getSaUser(user)
httpObj = getHttpObj(cache=GM.Globals[GM.CACHE_DIR])
@@ -7868,6 +7882,13 @@ class CSVPrintFile():
if title not in self.titlesSet:
self.AddTitle(title)
def InsertTitles(self, position, titles):
for title in titles if isinstance(titles, list) else [titles]:
if title not in self.titlesSet:
self.titlesSet.add(title)
self.titlesList.insert(position, title)
position += 1
def SetTitles(self, titles):
self.titlesSet = set()
self.titlesList = []
@@ -8023,7 +8044,7 @@ class CSVPrintFile():
def getDriveObject():
if not GC.Values[GC.TODRIVE_CLIENTACCESS]:
_, drive = buildGAPIServiceObject(API.DRIVETD, self.todrive['user'])
_, drive = buildGAPIServiceObject(chooseSaAPI(API.DRIVETD, API.DRIVE3), self.todrive['user'])
if not drive:
invalidTodriveUserExit(Ent.USER, Msg.NOT_FOUND)
else:
@@ -8176,7 +8197,7 @@ class CSVPrintFile():
if result['mimeType'] != MIMETYPE_GA_SPREADSHEET:
invalidTodriveFileIdExit([], f'{Msg.NOT_A} {Ent.Singular(Ent.SPREADSHEET)}', tdfileidLocation)
if not GC.Values[GC.TODRIVE_CLIENTACCESS]:
_, sheet = buildGAPIServiceObject(API.SHEETSTD, self.todrive['user'])
_, sheet = buildGAPIServiceObject(chooseSaAPI(API.SHEETSTD, API.SHEETS), self.todrive['user'])
if sheet is None:
invalidTodriveUserExit(Ent.USER, Msg.NOT_FOUND)
else:
@@ -8689,7 +8710,7 @@ class CSVPrintFile():
sheetTitle += tdtime.strftime(self.todrive['sheettimeformat'])
action = Act.Get()
if not GC.Values[GC.TODRIVE_CLIENTACCESS]:
user, drive = buildGAPIServiceObject(API.DRIVETD, self.todrive['user'])
user, drive = buildGAPIServiceObject(chooseSaAPI(API.DRIVETD, API.DRIVE3), self.todrive['user'])
if not drive:
closeFile(csvFile)
return
@@ -8722,7 +8743,7 @@ class CSVPrintFile():
if result['mimeType'] != MIMETYPE_GA_SPREADSHEET:
todriveCSVErrorExit(entityValueList, f'{Msg.NOT_A} {Ent.Singular(Ent.SPREADSHEET)}')
if not GC.Values[GC.TODRIVE_CLIENTACCESS]:
_, sheet = buildGAPIServiceObject(API.SHEETSTD, user)
_, sheet = buildGAPIServiceObject(chooseSaAPI(API.SHEETSTD, API.SHEETS), user)
if sheet is None:
return
else:
@@ -8870,7 +8891,7 @@ class CSVPrintFile():
(self.todrive['sheetEntity'] or self.todrive['locale'] or self.todrive['timeZone'] or
self.todrive['sheettitle'] or self.todrive['cellwrap'] or self.todrive['cellnumberformat'])):
if not GC.Values[GC.TODRIVE_CLIENTACCESS]:
_, sheet = buildGAPIServiceObject(API.SHEETSTD, user)
_, sheet = buildGAPIServiceObject(chooseSaAPI(API.SHEETSTD, API.SHEETS), user)
if sheet is None:
return
else:
@@ -9583,7 +9604,7 @@ def CSVFileQueueHandler(mpQueue, mpQueueStdout, mpQueueStderr, csvPF, datetimeNo
clearRowFilters = False
# if sys.platform.startswith('win'):
# signal.signal(signal.SIGINT, signal.SIG_IGN)
if multiprocessing.get_start_method() == 'spawn':
if multiprocessing.get_start_method() != 'fork':
signal.signal(signal.SIGINT, signal.SIG_IGN)
Cmd = glclargs.GamCLArgs()
else:
@@ -9625,7 +9646,7 @@ def CSVFileQueueHandler(mpQueue, mpQueueStdout, mpQueueStderr, csvPF, datetimeNo
Cmd.InitializeArguments(dataItem)
elif dataType == GM.REDIRECT_QUEUE_GLOBALS:
GM.Globals = dataItem
if multiprocessing.get_start_method() == 'spawn':
if multiprocessing.get_start_method() != 'fork':
reopenSTDFile(GM.STDOUT)
reopenSTDFile(GM.STDERR)
elif dataType == GM.REDIRECT_QUEUE_VALUES:
@@ -9671,7 +9692,7 @@ def initializeCSVFileQueueHandler(mpManager, mpQueueStdout, mpQueueStderr):
def terminateCSVFileQueueHandler(mpQueue, mpQueueHandler):
GM.Globals[GM.PARSER] = None
GM.Globals[GM.CSVFILE][GM.REDIRECT_QUEUE] = None
if multiprocessing.get_start_method() == 'spawn':
if multiprocessing.get_start_method() != 'fork':
mpQueue.put((GM.REDIRECT_QUEUE_ARGS, Cmd.AllArguments()))
savedValues = saveNonPickleableValues()
mpQueue.put((GM.REDIRECT_QUEUE_GLOBALS, GM.Globals))
@@ -9701,13 +9722,13 @@ def StdQueueHandler(mpQueue, stdtype, gmGlobals, gcValues):
# if sys.platform.startswith('win'):
# signal.signal(signal.SIGINT, signal.SIG_IGN)
if multiprocessing.get_start_method() == 'spawn':
if multiprocessing.get_start_method() != 'fork':
signal.signal(signal.SIGINT, signal.SIG_IGN)
GM.Globals = gmGlobals.copy()
GC.Values = gcValues.copy()
pid0DataItem = [KEYBOARD_INTERRUPT_RC, None]
pidData = {}
if multiprocessing.get_start_method() == 'spawn':
if multiprocessing.get_start_method() != 'fork':
if GM.Globals[stdtype][GM.REDIRECT_NAME] == 'null':
fd = open(os.devnull, GM.Globals[stdtype][GM.REDIRECT_MODE], encoding=UTF8)
elif GM.Globals[stdtype][GM.REDIRECT_NAME] == '-':
@@ -9795,7 +9816,7 @@ def ProcessGAMCommandMulti(pid, numItems, logCmd, mpQueueCSVFile, mpQueueStdout,
with mplock:
initializeLogging()
# if sys.platform.startswith('win'):
if multiprocessing.get_start_method() == 'spawn':
if multiprocessing.get_start_method() != 'fork':
signal.signal(signal.SIGINT, signal.SIG_IGN)
GM.Globals[GM.API_CALLS_RETRY_DATA] = {}
GM.Globals[GM.CMDLOG_LOGGER] = None
@@ -9936,7 +9957,7 @@ def MultiprocessGAMCommands(items, showCmds):
mpManager = multiprocessing.Manager()
l = mpManager.Lock()
try:
if multiprocessing.get_start_method() == 'spawn':
if multiprocessing.get_start_method() != 'fork':
pool = mpManager.Pool(processes=numPoolProcesses, initializer=initGamWorker, initargs=(l,), maxtasksperchild=200)
else:
pool = multiprocessing.Pool(processes=numPoolProcesses, initializer=initGamWorker, initargs=(l,), maxtasksperchild=200)
@@ -9945,7 +9966,7 @@ def MultiprocessGAMCommands(items, showCmds):
except AssertionError as e:
Cmd.SetLocation(0)
usageErrorExit(str(e))
if multiprocessing.get_start_method() == 'spawn':
if multiprocessing.get_start_method() != 'fork':
savedValues = saveNonPickleableValues()
if GM.Globals[GM.STDOUT][GM.REDIRECT_MULTIPROCESS]:
mpQueueStdout, mpQueueHandlerStdout = initializeStdQueueHandler(mpManager, GM.STDOUT, GM.Globals, GC.Values)
@@ -9960,7 +9981,7 @@ def MultiprocessGAMCommands(items, showCmds):
mpQueueStderr = mpQueueStdout
else:
mpQueueStderr = None
if multiprocessing.get_start_method() == 'spawn':
if multiprocessing.get_start_method() != 'fork':
restoreNonPickleableValues(savedValues)
if mpQueueStdout:
mpQueueStdout.put((0, GM.REDIRECT_QUEUE_DATA, GM.Globals[GM.STDOUT][GM.REDIRECT_MULTI_FD].getvalue()))
@@ -11124,7 +11145,7 @@ class Credentials(google.oauth2.credentials.Credentials):
def doOAuthRequest(currentScopes, login_hint, verifyScopes=False):
client_id, client_secret = getOAuthClientIDAndSecret()
scopesList = API.getClientScopesList(GC.Values[GC.TODRIVE_CLIENTACCESS])
scopesList = API.getClientScopesList(GC.Values[GC.COMMANDDATA_CLIENTACCESS], GC.Values[GC.TODRIVE_CLIENTACCESS])
if not currentScopes or verifyScopes:
selectedScopes = getScopesFromUser(scopesList, True, currentScopes)
if selectedScopes is None:
@@ -11170,7 +11191,7 @@ def doOAuthCreate():
else:
login_hint = None
scopes = []
scopesList = API.getClientScopesList(GC.Values[GC.TODRIVE_CLIENTACCESS])
scopesList = API.getClientScopesList(GC.Values[GC.COMMANDDATA_CLIENTACCESS], GC.Values[GC.TODRIVE_CLIENTACCESS])
while Cmd.ArgumentsRemaining():
myarg = getArgument()
if myarg == 'admin':
@@ -11186,7 +11207,9 @@ def doOAuthCreate():
scopes.append(uscope)
break
else:
invalidChoiceExit(uscope, API.getClientScopesURLs(GC.Values[GC.TODRIVE_CLIENTACCESS]), True)
invalidChoiceExit(uscope,
API.getClientScopesURLs(GC.Values[GC.COMMANDDATA_CLIENTACCESS], GC.Values[GC.TODRIVE_CLIENTACCESS]),
True)
else:
unknownArgumentExit()
if len(scopes) == 0:
@@ -11297,7 +11320,7 @@ def doOAuthUpdate():
if 'scopes' in jsonDict:
currentScopes = jsonDict['scopes']
else:
currentScopes = API.getClientScopesURLs(GC.Values[GC.TODRIVE_CLIENTACCESS])
currentScopes = API.getClientScopesURLs(GC.Values[GC.COMMANDDATA_CLIENTACCESS], GC.Values[GC.TODRIVE_CLIENTACCESS])
else:
currentScopes = []
except (AttributeError, IndexError, KeyError, SyntaxError, TypeError, ValueError) as e:
@@ -12327,8 +12350,6 @@ def checkServiceAccount(users):
saScopes[scope['api']].append(scope['roscope'])
checkScopesSet.add(scope['roscope'])
i += 1
if API.DRIVEACTIVITY in saScopes and API.DRIVE3 in saScopes:
saScopes[API.DRIVEACTIVITY].append(API.DRIVE_SCOPE)
if API.DRIVE3 in saScopes:
saScopes[API.DRIVE2] = saScopes[API.DRIVE3]
GM.Globals[GM.OAUTH2SERVICE_JSON_DATA][API.OAUTH2SA_SCOPES] = saScopes
@@ -16256,7 +16277,7 @@ def _showCustomerLicenseInfo(customerInfo, FJQC):
while True:
try:
result = callGAPI(rep.customerUsageReports(), 'get',
throwReasons=[GAPI.INVALID, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
throwReasons=[GAPI.INVALID, GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
date=tryDate, customerId=customerInfo['id'],
fields='warnings,usageReports', parameters=parameters)
usageReports = numUsersAvailable(result)
@@ -16269,7 +16290,7 @@ def _showCustomerLicenseInfo(customerInfo, FJQC):
if fullData == 0:
continue
break
except GAPI.invalid as e:
except (GAPI.invalid, GAPI.failedPrecondition) as e:
tryDate = _adjustTryDate(str(e), 0, -1, tryDate)
if not tryDate:
return
@@ -16983,22 +17004,39 @@ def doDeleteAdmin():
except (GAPI.forbidden, GAPI.permissionDenied) as e:
ClientAPIAccessDeniedExit(str(e))
ASSIGNEE_EMAILTYPE_TOFIELD_MAP = {
ADMIN_ASSIGNEE_TYPE_TO_ASSIGNEDTO_FIELD_MAP = {
'user': 'assignedToUser',
'group': 'assignedToGroup',
'serviceaccount': 'assignedToServiceAccount',
'unknown': 'assignedToUnknown',
}
ALL_ASSIGNEE_TYPES = ['user', 'group', 'serviceaccount']
PRINT_ADMIN_FIELDS = ['roleAssignmentId', 'roleId', 'assignedTo', 'scopeType', 'orgUnitId']
PRINT_ADMIN_TITLES = ['roleAssignmentId', 'roleId', 'role',
'assignedTo', 'assignedToUser', 'assignedToGroup', 'assignedToServiceAccount', 'assignedToUnknown',
'scopeType', 'orgUnitId', 'orgUnit']
# gam print admins [todrive <ToDriveAttribute>*]
# [user|group <EmailAddress>|<UniqueID>] [role <RoleItem>] [condition]
# [privileges] [oneitemperrow]
# [user|group <EmailAddress>|<UniqueID>] [role <RoleItem>]
# [types <AdminAssigneeTypeList>]
# [recursive] [condition] [privileges] [oneitemperrow]
# gam show admins
# [user|group <EmailAddress>|<UniqueID>] [role <RoleItem>] [condition] [privileges]
# [user|group <EmailAddress>|<UniqueID>] [role <RoleItem>]
# [types <AdminAssigneeTypeList>]
# [recursive] [condition] [privileges]
def doPrintShowAdmins():
def _getAssigneeTypes(myarg):
if myarg in {'type', 'types'}:
for gtype in getString(Cmd.OB_ADMIN_ASSIGNEE_TYPE_LIST).lower().replace(',', ' ').split():
if gtype in ADMIN_ASSIGNEE_TYPE_TO_ASSIGNEDTO_FIELD_MAP:
typesSet.add(ADMIN_ASSIGNEE_TYPE_TO_ASSIGNEDTO_FIELD_MAP[gtype])
else:
invalidChoiceExit(gtype, ADMIN_ASSIGNEE_TYPE_TO_ASSIGNEDTO_FIELD_MAP, True)
else:
return False
return True
def _getPrivileges(admin):
if showPrivileges:
roleId = admin['roleId']
@@ -17026,17 +17064,14 @@ def doPrintShowAdmins():
assignedTo = admin['assignedTo']
admin['assignedToUnknown'] = False
if assignedTo not in assignedToIdEmailMap:
assigneeType = admin.get('assigneeType')
assignedToField = ASSIGNEE_EMAILTYPE_TOFIELD_MAP.get(assigneeType, None)
assigneeEmail, assigneeType = convertUIDtoEmailAddressWithType(f'uid:{assignedTo}', cd, sal,
emailTypes=list(ASSIGNEE_EMAILTYPE_TOFIELD_MAP.keys()))
if not assignedToField and assigneeType in ASSIGNEE_EMAILTYPE_TOFIELD_MAP:
assignedToField = ASSIGNEE_EMAILTYPE_TOFIELD_MAP[assigneeType]
if assigneeType == 'unknown':
assignedToField = 'assignedToUnknown'
emailTypes = ALL_ASSIGNEE_TYPES if admin.get('assigneeType', '') != 'group' else ['group']
assigneeEmail, assigneeType = convertUIDtoEmailAddressWithType(f'uid:{assignedTo}', cd, sal, emailTypes=emailTypes)
assignedToField = ADMIN_ASSIGNEE_TYPE_TO_ASSIGNEDTO_FIELD_MAP.get(assigneeType, 'assignedToUnknown')
if assignedToField == 'assignedToUnknown':
assigneeEmail = True
assignedToIdEmailMap[assignedTo] = {'assignedToField': assignedToField, 'assigneeEmail': assigneeEmail}
admin[assignedToIdEmailMap[assignedTo]['assignedToField']] = assignedToIdEmailMap[assignedTo]['assigneeEmail']
admin['assignedToField'] = assignedToIdEmailMap[assignedTo]['assignedToField']
if privileges is not None:
admin.update(privileges)
if 'orgUnitId' in admin:
@@ -17046,16 +17081,22 @@ def doPrintShowAdmins():
admin['condition'] = 'securitygroup'
elif admin['condition'] == NONSECURITY_GROUP_CONDITION:
admin['condition'] = 'nonsecuritygroup'
if debug:
print('******', admin['assignedTo'], admin.get('assigneeType', 'no type'),
admin['assignedToField'], not typesSet or admin['assignedToField'] in typesSet)
return not typesSet or admin['assignedToField'] in typesSet
cd = buildGAPIObject(API.DIRECTORY)
sal = buildGAPIObject(API.SERVICEACCOUNTLOOKUP)
csvPF = CSVPrintFile(PRINT_ADMIN_TITLES) if Act.csvFormat() else None
roleId = None
userKey = None
oneItemPerRow = showPrivileges = False
debug = oneItemPerRow = recursive = showPrivileges = False
typesSet = set()
kwargs = {}
rolePrivileges = {}
fieldsList = PRINT_ADMIN_FIELDS
allGroupRoles = ','.join(sorted(ALL_GROUP_ROLES))
fieldsList = PRINT_ADMIN_FIELDS+['assigneeType']
assignedToIdEmailMap = {}
while Cmd.ArgumentsRemaining():
myarg = getArgument()
@@ -17065,6 +17106,16 @@ def doPrintShowAdmins():
userKey = kwargs['userKey'] = getEmailAddress()
elif myarg == 'role':
_, roleId = getRoleId()
elif _getAssigneeTypes(myarg):
pass
elif myarg == 'recursive':
recursive = True
memberOptions = initMemberOptions()
memberOptions[MEMBEROPTION_INCLUDEDERIVEDMEMBERSHIP] = True
memberOptions[MEMBEROPTION_DISPLAYMATCH] = False
memberDisplayOptions = initIPSGMGroupMemberDisplayOptions()
for role in [Ent.ROLE_MEMBER, Ent.ROLE_MANAGER, Ent.ROLE_OWNER]:
memberDisplayOptions[role]['show'] = True
elif myarg == 'condition':
fieldsList.append('condition')
if csvPF:
@@ -17073,6 +17124,8 @@ def doPrintShowAdmins():
showPrivileges = True
elif myarg == 'oneitemperrow':
oneItemPerRow = True
elif myarg == 'debug':
debug = True
else:
unknownArgumentExit()
if roleId and not kwargs:
@@ -17084,7 +17137,7 @@ def doPrintShowAdmins():
admins = callGAPIpages(cd.roleAssignments(), 'list', 'items',
pageMessage=getPageMessage(),
throwReasons=[GAPI.INVALID, GAPI.USER_NOT_FOUND,
GAPI.FORBIDDEN, GAPI.SERVICE_NOT_AVAILABLE,
GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.SERVICE_NOT_AVAILABLE,
GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND,
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
@@ -17092,39 +17145,75 @@ def doPrintShowAdmins():
except (GAPI.invalid, GAPI.userNotFound):
entityUnknownWarning(Ent.ADMINISTRATOR, userKey)
return
except (GAPI.serviceNotAvailable) as e:
entityActionFailedExit([Ent.ADMINISTRATOR, userKey, Ent.ADMIN_ROLE, roleId], str(e))
except GAPI.notFound as e:
entityActionFailedExit([Ent.ADMIN_ROLE, kwargs['roleId']], str(e))
except GAPI.serviceNotAvailable as e:
entityActionFailedExit([Ent.ADMINISTRATOR, userKey], str(e))
except (GAPI.badRequest, GAPI.customerNotFound):
accessErrorExit(cd)
except (GAPI.forbidden, GAPI.permissionDenied) as e:
ClientAPIAccessDeniedExit(str(e))
count = len(admins)
groupMembers = {}
expandedAdmins = []
i = 0
for admin in admins:
i += 1
if roleId and roleId != admin['roleId']:
continue
assignedTo = admin['assignedTo']
if admin['assigneeType'] != 'group' or not recursive:
if _setNamesFromIds(admin, _getPrivileges(admin)):
expandedAdmins.append(admin)
continue
if assignedTo not in groupMembers:
membersList = []
membersSet = set()
level = 0
getGroupMembers(cd, assignedTo, allGroupRoles, membersList, membersSet, i, count,
memberOptions, memberDisplayOptions, level, {Ent.TYPE_USER})
groupMembers[assignedTo] = membersList[:]
if not _setNamesFromIds(admin, _getPrivileges(admin)):
continue
if not groupMembers[assignedTo]:
expandedAdmins.append(admin)
continue
admin['assigneeType'] = 'user'
admin['assignedToGroup'] = assignedToIdEmailMap[assignedTo]['assigneeEmail']
for member in groupMembers[assignedTo]:
userAdmin = admin.copy()
userAdmin['assignedTo'] = member['id']
_setNamesFromIds(userAdmin, _getPrivileges(admin))
expandedAdmins.append(userAdmin)
admins = expandedAdmins
count = len(expandedAdmins)
if not csvPF:
count = len(admins)
performActionNumItems(count, Ent.ADMIN_ROLE_ASSIGNMENT)
Ind.Increment()
i = 0
for admin in admins:
for admin in expandedAdmins:
i += 1
if roleId and roleId != admin['roleId']:
continue
_setNamesFromIds(admin, _getPrivileges(admin))
printEntity([Ent.ADMIN_ROLE_ASSIGNMENT, admin['roleAssignmentId']], i, count)
Ind.Increment()
for field in PRINT_ADMIN_TITLES:
if field in admin:
if field == 'roleAssignmentId':
if (field == 'roleAssignmentId') or (field == 'assignedToUnknown' and not admin[field]):
continue
if field != 'rolePrivileges':
printKeyValueList([field, admin[field]])
else:
showJSON(None, admin[field])
printKeyValueList([field, admin[field]])
if showPrivileges:
rolePrivileges = admin.get('rolePrivileges', [])
jcount = len(rolePrivileges)
if jcount > 0:
printKeyValueList(['rolePrivileges', jcount])
Ind.Increment()
showJSON(None, rolePrivileges)
Ind.Decrement()
Ind.Decrement()
Ind.Decrement()
else:
for admin in admins:
if roleId and roleId != admin['roleId']:
continue
_setNamesFromIds(admin, _getPrivileges(admin))
for admin in expandedAdmins:
admin.pop('assigneeType', None)
admin.pop('assignedToField', None)
if not oneItemPerRow or 'rolePrivileges' not in admin:
csvPF.WriteRowTitles(flattenJSON(admin))
else:
@@ -22429,12 +22518,12 @@ def infoUserPeopleContacts(users):
# gam <UserTypeEntity> print contacts [todrive <ToDriveAttribute>*] <PeoplePrintShowUserContactSelection>
# [showgroups|showgroupnameslist] [orderby firstname|lastname|(lastmodified ascending)|(lastnodified descending)
# [countsonly|allfields|fields <PeopleFieldNameList>] [showmetadata]
# [formatjson [quotechar <Character>]]
# [allfields|fields <PeopleFieldNameList>] [showmetadata]
# [countsonly|(formatjson [quotechar <Character>])]
# gam <UserTypeEntity> show contacts <PeoplePrintShowUserContactSelection>
# [showgroups] [orderby firstname|lastname|(lastmodified ascending)|(lastnodified descending)
# [countsonly|allfields|(fields <PeopleFieldNameList>)] [showmetadata]
# [formatjson]
# [allfields|(fields <PeopleFieldNameList>)] [showmetadata]
# [countsonly|formatjson]
def printShowUserPeopleContacts(users):
entityType = Ent.USER
entityTypeName = Ent.Singular(entityType)
@@ -22473,6 +22562,8 @@ def printShowUserPeopleContacts(users):
else:
FJQC.GetFormatJSONQuoteChar(myarg, True)
if countsOnly:
if csvPF:
csvPF.SetFormatJSON(False)
fieldsList = ['emailAddresses']
if contactQuery['mainContacts']:
fields = _getPersonFields(PEOPLE_FIELDS_CHOICE_MAP, PEOPLE_CONTACTS_DEFAULT_FIELDS, fieldsList, parameters)
@@ -22710,11 +22801,11 @@ def processUserPeopleOtherContacts(users):
Ind.Decrement()
# gam <UserTypeEntity> print othercontacts [todrive <ToDriveAttribute>*] <OtherContactSelection>
# [countsonly|allfields|(fields <OtherContactFieldNameList>)] [showmetadata]
# [formatjson [quotechar <Character>]]
# [allfields|(fields <OtherContactFieldNameList>)] [showmetadata]
# [countsonly|(formatjson [quotechar <Character>])]
# gam <UserTypeEntity> show othercontacts <OtherContactSelection>
# [countsonly|allfields|(fields <OtherContactFieldNameList>)] [showmetadata]
# [formatjson]
# [allfields|(fields <OtherContactFieldNameList>)] [showmetadata]
# [countsonly|formatjson]
def printShowUserPeopleOtherContacts(users):
entityType = Ent.USER
entityTypeName = Ent.Singular(entityType)
@@ -22744,6 +22835,8 @@ def printShowUserPeopleOtherContacts(users):
else:
FJQC.GetFormatJSONQuoteChar(myarg, True)
if countsOnly:
if csvPF:
csvPF.SetFormatJSON(False)
fieldsList = ['emailAddresses']
fields = _getPersonFields(PEOPLE_OTHER_CONTACTS_FIELDS_CHOICE_MAP, PEOPLE_CONTACTS_DEFAULT_FIELDS, fieldsList, parameters)
i, count, users = getEntityArgument(users)
@@ -22813,6 +22906,8 @@ def _printShowPeople(source):
function = 'searchDirectoryPeople'
else:
FJQC.GetFormatJSONQuoteChar(myarg, True)
if countsOnly and csvPF:
csvPF.SetFormatJSON(False)
fields = _getPersonFields(PEOPLE_FIELDS_CHOICE_MAP, PEOPLE_CONTACTS_DEFAULT_FIELDS, fieldsList, parameters)
printGettingAllEntityItemsForWhom(peopleEntityType, GC.Values[GC.DOMAIN], query=kwargs.get('query'))
try:
@@ -22850,29 +22945,24 @@ def doInfoDomainPeopleContacts():
# gam print people|peopleprofile [todrive <ToDriveAttribute>*]
# [query <String>]
# [mergesources <PeopleMergeSourceName>]
# [countsonly]
# [allfields|(fields <PeopleFieldNameList>)] [showmetadata]
# [formatjson [quotechar <Character>]]
# [countsonly|(formatjson [quotechar <Character>])]
# gam show people|peopleprofile
# [query <String>]
# [mergesources <PeopleMergeSourceName>]
# [countsonly]
# [allfields|(fields <PeopleFieldNameList>)] [showmetadata]
# [formatjson]
# [countsonlyformatjson]
# gam print domaincontacts|peoplecontacts [todrive <ToDriveAttribute>*]
# [sources <PeopleSourceName>]
# [query <String>]
# [mergesources <PeopleMergeSourceName>]
# [countsonly]
# [allfields|(fields <PeopleFieldNameList>)] [showmetadata]
# [formatjson [quotechar <Character>]]
# [countsonly|(formatjson [quotechar <Character>])]
# gam show domaincontacts|peoplecontacts
# [sources <PeopleSourceName>]
# [query <String>]
# [mergesources <PeopleMergeSourceName>]
# [countsonly]
# [allfields|(fields <PeopleFieldNameList>)] [showmetadata]
# [formatjson]
# [countsonlyformatjson]
def doPrintShowDomainPeopleProfiles():
_printShowPeople('profile')
@@ -40125,7 +40215,7 @@ def _createCalendarEvents(user, origCal, function, calIds, count, body, paramete
else:
if parameters['showDayOfWeek']:
_getEventDaysOfWeek(event)
_printCalendarEvent(user, calId, event, parameters['csvPF'], parameters['FJQC'])
_printCalendarEvent(user, calId, event, parameters['csvPF'], parameters['FJQC'], {})
except (GAPI.invalid, GAPI.required, GAPI.timeRangeEmpty, GAPI.eventDurationExceedsLimit,
GAPI.requiredAccessLevel, GAPI.participantIsNeitherOrganizerNorAttendee,
GAPI.malformedWorkingLocationEvent, GAPI.badRequest) as e:
@@ -40229,7 +40319,7 @@ def _updateCalendarEvents(origUser, user, origCal, calIds, count, calendarEventE
else:
if parameters['showDayOfWeek']:
_getEventDaysOfWeek(event)
_printCalendarEvent(user, calId, event, parameters['csvPF'], parameters['FJQC'])
_printCalendarEvent(user, calId, event, parameters['csvPF'], parameters['FJQC'], {})
except (GAPI.notFound, GAPI.deleted) as e:
if not checkCalendarExists(cal, calId, j, jcount):
entityUnknownWarning(Ent.CALENDAR, calId, j, jcount)
@@ -40526,10 +40616,12 @@ def _showCalendarEvent(primaryEmail, calId, eventEntityType, event, k, kcount, F
showJSON(None, event, skipObjects)
Ind.Decrement()
def _printCalendarEvent(user, calId, event, csvPF, FJQC):
def _printCalendarEvent(user, calId, event, csvPF, FJQC, addCSVData):
row = {'calendarId': calId, 'id': event['id']}
if user:
row['primaryEmail'] = user
if addCSVData:
row.update(addCSVData)
flattenJSON(event, flattened=row, timeObjects=EVENT_TIME_OBJECTS)
if not FJQC.formatJSON:
csvPF.WriteRowTitles(row)
@@ -40542,7 +40634,7 @@ def _printCalendarEvent(user, calId, event, csvPF, FJQC):
csvPF.WriteRowNoFilter(row)
def _printShowCalendarEvents(origUser, user, origCal, calIds, count, calendarEventEntity,
csvPF, FJQC, fieldsList):
csvPF, FJQC, fieldsList, addCSVData):
i = 0
for calId in calIds:
i += 1
@@ -40568,7 +40660,7 @@ def _printShowCalendarEvents(origUser, user, origCal, calIds, count, calendarEve
for event in events:
if calendarEventEntity['showDayOfWeek']:
_getEventDaysOfWeek(event)
_printCalendarEvent(user, calId, event, csvPF, FJQC)
_printCalendarEvent(user, calId, event, csvPF, FJQC, addCSVData)
elif GC.Values[GC.CSV_OUTPUT_USERS_AUDIT] and user:
csvPF.WriteRowNoFilter({'calendarId': calId, 'primaryEmail': user, 'id': ''})
else:
@@ -40586,6 +40678,8 @@ def _printShowCalendarEvents(origUser, user, origCal, calIds, count, calendarEve
row = {'calendarId': calId}
if user:
row['primaryEmail'] = user
if addCSVData:
row.update(addCSVData)
row['events'] = jcount
if not calendarEventEntity['eventRowFilter']:
csvPF.WriteRow(row)
@@ -40816,6 +40910,8 @@ def _getCalendarPrintShowEventOptions(calendarEventEntity, entityType):
csvPF = CSVPrintFile(['primaryEmail', 'calendarId', 'id'] if entityType == Ent.USER else ['calendarId', 'id'], 'sortall', indexedTitles=EVENT_INDEXED_TITLES) if Act.csvFormat() else None
FJQC = FormatJSONQuoteChar(csvPF)
fieldsList = []
addCSVData = {}
addCSVDataLoc = 2 if entityType == Ent.USER else 1
while Cmd.ArgumentsRemaining():
myarg = getArgument()
if csvPF and myarg == 'todrive':
@@ -40824,6 +40920,9 @@ def _getCalendarPrintShowEventOptions(calendarEventEntity, entityType):
pass
elif myarg == 'fields':
_getEventFields(fieldsList)
elif csvPF and myarg == 'addcsvdata':
k = getString(Cmd.OB_STRING)
addCSVData[k] = getString(Cmd.OB_STRING, minLen=0)
elif myarg == 'countsonly':
calendarEventEntity['countsOnly'] = True
elif myarg == 'showdayofweek':
@@ -40836,27 +40935,35 @@ def _getCalendarPrintShowEventOptions(calendarEventEntity, entityType):
fieldsList = ['id']
if csvPF:
if calendarEventEntity['countsOnly']:
csvPF.SetFormatJSON(False)
csvPF.RemoveTitles(['id'])
if addCSVData:
csvPF.InsertTitles(addCSVDataLoc, sorted(addCSVData.keys()))
csvPF.AddTitles(['events'])
csvPF.SetSortAllTitles()
calendarEventEntity['countsOnlyTitles'] = csvPF.titlesList[:]
elif not FJQC.formatJSON and not fieldsList:
csvPF.AddSortTitles(EVENT_PRINT_ORDER)
else:
if addCSVData:
csvPF.InsertTitles(addCSVDataLoc, sorted(addCSVData.keys()))
if not FJQC.formatJSON and not fieldsList:
csvPF.AddTitles(EVENT_PRINT_ORDER)
csvPF.SetSortAllTitles()
_addEventEntitySelectFields(calendarEventEntity, fieldsList)
return (csvPF, FJQC, fieldsList)
return (csvPF, FJQC, fieldsList, addCSVData)
# gam calendars <CalendarEntity> print events <EventEntity> <EventDisplayProperties>*
# [fields <EventFieldNameList>] [showdayofweek]
# [countsonly [eventrowfilter]]
# [formatjson [quotechar <Character>]] [todrive <ToDriveAttribute>*]
# (addcsvdata <FieldName> <String>)*
# [eventrowfilter]
# [countsonly|(formatjson [quotechar <Character>])] [todrive <ToDriveAttribute>*]
# gam calendars <CalendarEntity> show events <EventEntity> <EventDisplayProperties>*
# [fields <EventFieldNameList>] [showdayofweek]
# [countsonly]
# [formatjson]
# [countsonly|formatjson]
def doCalendarsPrintShowEvents(calIds):
calendarEventEntity = getCalendarEventEntity()
csvPF, FJQC, fieldsList = _getCalendarPrintShowEventOptions(calendarEventEntity, Ent.CALENDAR)
csvPF, FJQC, fieldsList, addCSVData = _getCalendarPrintShowEventOptions(calendarEventEntity, Ent.CALENDAR)
_printShowCalendarEvents(None, None, None, calIds, len(calIds), calendarEventEntity,
csvPF, FJQC, fieldsList)
csvPF, FJQC, fieldsList, addCSVData)
if csvPF:
if calendarEventEntity['countsOnly'] and calendarEventEntity['eventRowFilter']:
csvPF.SetTitles(calendarEventEntity['countsOnlyTitles'])
@@ -48863,13 +48970,15 @@ def _doInfoCourses(courseIdList):
# gam info courses <CourseEntity> [owneraccess]
# [owneremail] [alias|aliases] [show none|all|students|teachers] [countsonly]
# [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>] [formatjson]
# [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>]
# [formatjson]
def doInfoCourses():
_doInfoCourses(getEntityList(Cmd.OB_COURSE_ENTITY, shlexSplit=True))
# gam info course <CourseID> [owneraccess]
# [owneremail] [alias|aliases] [show none|all|students|teachers] [countsonly]
# [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>] [formatjson]
# [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>]
# [formatjson]
def doInfoCourse():
_doInfoCourses(getStringReturnInList(Cmd.OB_COURSE_ID))
@@ -49187,7 +49296,7 @@ COURSE_ANNOUNCEMENTS_INDEXED_TITLES = ['materials']
# (orderby <CourseAnnouncementOrderByFieldName> [ascending|descending])*)
# [showcreatoremails|creatoremail] [fields <CourseAnnouncementFieldNameList>]
# [timefilter creationtime|updatetime|scheduledtime] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
# [countsonly] [formatjson [quotechar <Character>]]
# [countsonly|(formatjson [quotechar <Character>])]
def doPrintCourseAnnouncements():
def _printCourseAnnouncement(course, courseAnnouncement, i, count):
if applyCourseItemFilter and not _courseItemPassesFilter(courseAnnouncement, courseItemFilter):
@@ -49243,6 +49352,8 @@ def doPrintCourseAnnouncements():
coursesInfo = _getCoursesInfo(croom, courseSelectionParameters, courseShowProperties)
if coursesInfo is None:
return
if countsOnly:
csvPF.SetFormatJSON(False)
applyCourseItemFilter = _setApplyCourseItemFilter(courseItemFilter, fieldsList)
if showCreatorEmail and fieldsList:
fieldsList.append('creatorUserId')
@@ -49299,7 +49410,7 @@ COURSE_TOPICS_SORT_TITLES = ['courseId', 'courseName', 'topicId', 'name', 'updat
# (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] states <CourseStateList>])
# [topicids <CourseTopicIDEntity>]
# [timefilter updatetime] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
# [countsonly] [formatjson [quotechar <Character>]]
# [countsonly|(formatjson [quotechar <Character>])]
def doPrintCourseTopics():
def _printCourseTopic(course, courseTopic):
if applyCourseItemFilter and not _courseItemPassesFilter(courseTopic, courseItemFilter):
@@ -49340,6 +49451,8 @@ def doPrintCourseTopics():
coursesInfo = _getCoursesInfo(croom, courseSelectionParameters, courseShowProperties)
if coursesInfo is None:
return
if countsOnly:
csvPF.SetFormatJSON(False)
applyCourseItemFilter = _setApplyCourseItemFilter(courseItemFilter, fieldsList)
courseTopicIdsLists = courseTopicIds if isinstance(courseTopicIds, dict) else None
i = 0
@@ -49584,6 +49697,8 @@ def doPrintCourseWM(entityIDType, entityStateType):
coursesInfo = _getCoursesInfo(croom, courseSelectionParameters, courseShowProperties)
if coursesInfo is None:
return
if countsOnly:
csvPF.SetFormatJSON(False)
applyCourseItemFilter = _setApplyCourseItemFilter(courseItemFilter, fieldsList)
courseWMIds = courseWMSelectionParameters['courseWMIds']
courseWMIdsLists = courseWMIds if isinstance(courseWMIds, dict) else {}
@@ -49639,7 +49754,7 @@ def doPrintCourseWM(entityIDType, entityStateType):
# [showcreatoremails|creatoremail] [showtopicnames] [fields <CourseMaterialFieldNameList>]
# [timefilter creationtime|updatetime|scheduledtime] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
# [oneitemperrow]
# [countsonly] [formatjson [quotechar <Character>]]
# [countsonly|(formatjson [quotechar <Character>])]
def doPrintCourseMaterials():
doPrintCourseWM(Ent.COURSE_MATERIAL_ID, Ent.COURSE_MATERIAL_STATE)
@@ -49651,7 +49766,7 @@ def doPrintCourseMaterials():
# [showstudentsaslist [<Boolean>]] [delimiter <Character>]
# [timefilter creationtime|updatetime] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
# [oneitemperrow]
# [countsonly] [formatjson [quotechar <Character>]]
# [countsonly|(formatjson [quotechar <Character>])]
def doPrintCourseWork():
doPrintCourseWM(Ent.COURSE_WORK_ID, Ent.COURSE_WORK_STATE)
@@ -49695,7 +49810,7 @@ def _gettingCourseSubmissionQuery(courseSubmissionStates, late, userId):
# (submissionids <CourseSubmissionIDEntity>)|((submissionstates <CourseSubmissionStateList>)*) [late|notlate]
# [fields <CourseSubmissionFieldNameList>] [showuserprofile]
# [timefilter creationtime|updatetime] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
# [countsonly] [formatjson [quotechar <Character>]]
# [countsonly|(formatjson [quotechar <Character>])]
def doPrintCourseSubmissions():
def _printCourseSubmission(course, courseSubmission):
if applyCourseItemFilter and not _courseItemPassesFilter(courseSubmission, courseItemFilter):
@@ -49777,6 +49892,8 @@ def doPrintCourseSubmissions():
coursesInfo = _getCoursesInfo(croom, courseSelectionParameters, courseShowProperties, getOwnerId=True)
if coursesInfo is None:
return
if countsOnly:
csvPF.SetFormatJSON(False)
applyCourseItemFilter = _setApplyCourseItemFilter(courseItemFilter, fieldsList)
courseWorkIds = courseWMSelectionParameters['courseWMIds']
courseWorkIdsLists = courseWorkIds if isinstance(courseWorkIds, dict) else {}
@@ -53523,16 +53640,16 @@ def infoCalendarEvents(users):
# gam <UserTypeEntity> print events <UserCalendarEntity> <EventEntity> <EventDisplayProperties>*
# [fields <EventFieldNameList>] [showdayofweek]
# [countsonly [eventrowfilter]]
# [formatjson [quotechar <Character>]] [todrive <ToDriveAttribute>*]
# (addcsvdata <FieldName> <String>)*
# [eventrowfilter]
# [countsonly|(formatjson [quotechar <Character>])] [todrive <ToDriveAttribute>*]
# gam <UserTypeEntity> show events <UserCalendarEntity> <EventEntity> <EventDisplayProperties>*
# [fields <EventFieldNameList>] [showdayofweek]
# [countsonly]]
# [formatjson]
# ~[countsonly|formatjson]
def printShowCalendarEvents(users):
calendarEntity = getUserCalendarEntity()
calendarEventEntity = getCalendarEventEntity()
csvPF, FJQC, fieldsList = _getCalendarPrintShowEventOptions(calendarEventEntity, Ent.USER)
csvPF, FJQC, fieldsList, addCSVData = _getCalendarPrintShowEventOptions(calendarEventEntity, Ent.USER)
i, count, users = getEntityArgument(users)
for user in users:
i += 1
@@ -53543,7 +53660,7 @@ def printShowCalendarEvents(users):
continue
Ind.Increment()
_printShowCalendarEvents(origUser, user, cal, calIds, jcount, calendarEventEntity,
csvPF, FJQC, fieldsList)
csvPF, FJQC, fieldsList, addCSVData)
Ind.Decrement()
if csvPF:
if calendarEventEntity['countsOnly'] and calendarEventEntity['eventRowFilter']:
@@ -53987,7 +54104,7 @@ def printShowStatusEvent(users, eventType):
for event in events:
if showDayOfWeek:
_getEventDaysOfWeek(event)
_printCalendarEvent(user, calId, event, csvPF, FJQC)
_printCalendarEvent(user, calId, event, csvPF, FJQC, {})
if 'pdelta' in wlDate:
first = first.shift(**wlDate['pdelta'])
last = last.shift(**wlDate['pdelta'])
@@ -77238,7 +77355,7 @@ TASK_QUERY_STATE_MAP = {
# [updatedmin <Time>]
# [showcompleted [<Boolean>]] [showdeleted [<Boolean>]] [showhidden [<Boolean>]] [showall]
# [orderby completed|due|updated]
# [countsonly | (formatjson [quotechar <Character>])]
# [countsonly|(formatjson [quotechar <Character>])]
def printShowTasks(users):
def _showTaskAndChildren(tasklist, taskId, k, compact):
if taskId in taskParentsProcessed:
@@ -77305,8 +77422,11 @@ def printShowTasks(users):
csvPF.SetTitles(['User', CSVTitle])
else:
FJQC.GetFormatJSONQuoteChar(myarg, False)
if csvPF and FJQC.formatJSON:
csvPF.SetJSONTitles(['User', 'tasklistId', 'id', 'taskId', 'title', 'JSON'])
if csvPF:
if countsOnly:
csvPF.SetFormatJSON(False)
elif FJQC.formatJSON:
csvPF.SetJSONTitles(['User', 'tasklistId', 'id', 'taskId', 'title', 'JSON'])
i, count, users = getEntityArgument(users)
for user in users:
i += 1
@@ -77505,7 +77625,7 @@ def processTasklists(users):
# gam <UserTypeEntity> show tasklists
# [countsonly|formatjson]
# gam <UserTypeEntity> print tasklists [todrive <ToDriveAttribute>*]
# [countsonly | (formatjson [quotechar <Character>])]
# [countsonly|(formatjson [quotechar <Character>])]
def printShowTasklists(users):
csvPF = CSVPrintFile(['User', 'id', 'title']) if Act.csvFormat() else None
if csvPF:
@@ -77523,6 +77643,8 @@ def printShowTasklists(users):
csvPF.SetTitles(['User', CSVTitle])
else:
FJQC.GetFormatJSONQuoteChar(myarg, True)
if countsOnly and csvPF:
csvPF.SetFormatJSON(False)
i, count, users = getEntityArgument(users)
for user in users:
i += 1

View File

@@ -34,7 +34,12 @@ def main():
# Run from command line
if __name__ == '__main__':
if platform.system() != 'Linux':
if getattr(sys, 'frozen', False): # we're frozen:
multiprocessing.freeze_support()
if platform.system() == 'Linux':
# set explictly since it's not default in Python < 3.14, forkserver should
# be safer than fork and less likely to see bulk command hangs.
multiprocessing.set_start_method('forkserver')
else:
multiprocessing.set_start_method('spawn')
main()

View File

@@ -105,6 +105,8 @@ YOUTUBE = 'youtube'
BUSINESSACCOUNTMANAGEMENT_SCOPE = 'https://www.googleapis.com/auth/business.manage'
CHROMEVERSIONHISTORY_URL = 'https://versionhistory.googleapis.com/v1/chrome/platforms'
DRIVE_SCOPE = 'https://www.googleapis.com/auth/drive'
DRIVE_FILE_SCOPE = 'https://www.googleapis.com/auth/drive.file'
DRIVE_READONLY_SCOPE = 'https://www.googleapis.com/auth/drive.readonly'
GMAIL_SEND_SCOPE = 'https://www.googleapis.com/auth/gmail.send'
GOOGLE_AUTH_PROVIDER_X509_CERT_URL = 'https://www.googleapis.com/oauth2/v1/certs'
GOOGLE_OAUTH2_ENDPOINT = 'https://accounts.google.com/o/oauth2/v2/auth'
@@ -156,6 +158,7 @@ OAUTH2_TOKEN_ERRORS = [
'access_denied: Account restricted',
'internal_failure: Backend Error',
'internal_failure: None',
'invalid_account: Forbidden',
'invalid_grant',
'invalid_grant: Bad Request',
'invalid_grant: Invalid email or User ID',
@@ -253,7 +256,7 @@ _INFO = {
DOCS: {'name': 'Docs API', 'version': 'v1', 'v2discovery': True},
DRIVE2: {'name': 'Drive API v2', 'version': 'v2', 'v2discovery': False, 'mappedAPI': 'drive'},
DRIVE3: {'name': 'Drive API v3', 'version': 'v3', 'v2discovery': False, 'mappedAPI': 'drive'},
DRIVETD: {'name': 'Drive API v3 - todrive', 'version': 'v3', 'v2discovery': False, 'mappedAPI': 'drive'},
DRIVETD: {'name': 'Drive API v3 - write todrive data', 'version': 'v3', 'v2discovery': False, 'mappedAPI': 'drive'},
DRIVEACTIVITY: {'name': 'Drive Activity API v2', 'version': 'v2', 'v2discovery': True},
DRIVELABELS_ADMIN: {'name': 'Drive Labels API - Admin', 'version': 'v2', 'v2discovery': True, 'mappedAPI': DRIVELABELS},
DRIVELABELS_USER: {'name': 'Drive Labels API - User', 'version': 'v2', 'v2discovery': True, 'mappedAPI': DRIVELABELS},
@@ -283,7 +286,7 @@ _INFO = {
SERVICEMANAGEMENT: {'name': 'Service Management API', 'version': 'v1', 'v2discovery': True},
SERVICEUSAGE: {'name': 'Service Usage API', 'version': 'v1', 'v2discovery': True},
SHEETS: {'name': 'Sheets API', 'version': 'v4', 'v2discovery': True},
SHEETSTD: {'name': 'Sheets API - todrive', 'version': 'v4', 'v2discovery': True, 'mappedAPI': SHEETS},
SHEETSTD: {'name': 'Sheets API - write todrive data', 'version': 'v4', 'v2discovery': True, 'mappedAPI': SHEETS},
SITEVERIFICATION: {'name': 'Site Verification API', 'version': 'v1', 'v2discovery': True},
STORAGE: {'name': 'Cloud Storage API', 'version': 'v1', 'v2discovery': True},
STORAGEREAD: {'name': 'Cloud Storage API - Read', 'version': 'v1', 'v2discovery': True, 'mappedAPI': STORAGE},
@@ -530,6 +533,17 @@ _CLIENT_SCOPES = [
'scope': 'https://www.googleapis.com/auth/ediscovery'},
]
_COMMANDDATA_CLIENT_SCOPES = [
{'name': 'Drive API - commanddata_clientaccess',
'api': DRIVE3,
'subscopes': [],
'scope': DRIVE_READONLY_SCOPE},
{'name': 'Sheets API - commanddata_clientaccess',
'api': SHEETS,
'subscopes': [],
'scope': 'https://www.googleapis.com/auth/spreadsheets.readonly'},
]
_TODRIVE_CLIENT_SCOPES = [
{'name': 'Drive API - todrive_clientaccess',
'api': DRIVE3,
@@ -538,7 +552,7 @@ _TODRIVE_CLIENT_SCOPES = [
{'name': 'Drive File API - todrive_clientaccess',
'api': DRIVE3,
'subscopes': [],
'scope': 'https://www.googleapis.com/auth/drive.file'},
'scope': DRIVE_FILE_SCOPE},
{'name': 'Gmail API - todrive_clientaccess',
'api': GMAIL,
'subscopes': [],
@@ -643,7 +657,8 @@ _SVCACCT_SCOPES = [
{'name': 'Drive Activity API v2 - must pair with Drive API',
'api': DRIVEACTIVITY,
'subscopes': [],
'scope': 'https://www.googleapis.com/auth/drive.activity'},
'scope': [DRIVE_READONLY_SCOPE,
'https://www.googleapis.com/auth/drive.activity']},
{'name': 'Drive Labels API - Admin',
'api': DRIVELABELS_ADMIN,
'subscopes': READONLY,
@@ -656,10 +671,12 @@ _SVCACCT_SCOPES = [
'api': DOCS,
'subscopes': READONLY,
'scope': 'https://www.googleapis.com/auth/documents'},
{'name': 'Forms API',
{'name': 'Forms API - must pair with Drive API',
'api': FORMS,
'subscopes': [],
'scope': DRIVE_SCOPE},
'scope': [DRIVE_READONLY_SCOPE,
'https://www.googleapis.com/auth/forms.body',
'https://www.googleapis.com/auth/forms.responses.readonly']},
{'name': 'Gmail API - Full Access (Labels, Messages)',
'api': GMAIL,
'subscopes': [],
@@ -750,9 +767,10 @@ _SVCACCT_SCOPES = [
]
_SVCACCT_SPECIAL_SCOPES = [
{'name': 'Drive API - todrive',
{'name': 'Drive API - write todrive data - has access to all Drive',
'api': DRIVETD,
'subscopes': [],
'offByDefault': True,
'scope': DRIVE_SCOPE},
{'name': 'Gmail API - Full Access - read only',
'api': GMAIL,
@@ -764,8 +782,9 @@ _SVCACCT_SPECIAL_SCOPES = [
'subscopes': [],
'offByDefault': True,
'scope': GMAIL_SEND_SCOPE},
{'name': 'Sheets API - todrive',
{'name': 'Sheets API - write todrive data - has access to all Sheets',
'api': SHEETSTD,
'offByDefault': True,
'subscopes': [],
'scope': 'https://www.googleapis.com/auth/spreadsheets'},
]
@@ -789,14 +808,18 @@ def getVersion(api):
def getClientScopesSet(api):
return {scope['scope'] for scope in _CLIENT_SCOPES if scope['api'] == api}
def getClientScopesList(todriveClientAccess):
def getClientScopesList(commanddataClientAccess, todriveClientAccess):
caScopes = _CLIENT_SCOPES[:]
if commanddataClientAccess:
caScopes.extend(_COMMANDDATA_CLIENT_SCOPES)
if todriveClientAccess:
caScopes.extend(_TODRIVE_CLIENT_SCOPES)
return sorted(caScopes, key=lambda k: k['name'])
def getClientScopesURLs(todriveClientAccess):
def getClientScopesURLs(commanddataClientAccess, todriveClientAccess):
caScopes = _CLIENT_SCOPES[:]
if commanddataClientAccess:
caScopes.extend(_COMMANDDATA_CLIENT_SCOPES)
if todriveClientAccess:
caScopes.extend(_TODRIVE_CLIENT_SCOPES)
return sorted({scope['scope'] for scope in _CLIENT_SCOPES})

View File

@@ -85,6 +85,8 @@ CMDLOG_MAX__BACKUPS = 'cmdlog_max__backups'
CMDLOG_MAX_BACKUPS = 'cmdlog_max_backups'
# Command logging max kilo bytes per log file
CMDLOG_MAX_KILO_BYTES = 'cmdlog_max_kilo_bytes'
# Use client access for command data from Google Docs/Sheets
COMMANDDATA_CLIENTACCESS = 'commanddata_clientaccess'
# GAM config directory containing client_secrets.json, oauth2.txt, oauth2service.json, extra_args.txt
CONFIG_DIR = 'config_dir'
# When retrieving lists of Google Contacts from API, how many should be retrieved in each chunk
@@ -344,6 +346,7 @@ Defaults = {
CMDLOG: '',
CMDLOG_MAX_BACKUPS: 5,
CMDLOG_MAX_KILO_BYTES: 1000,
COMMANDDATA_CLIENTACCESS: FALSE,
CONFIG_DIR: '',
CONTACT_MAX_RESULTS: '100',
CSV_INPUT_COLUMN_DELIMITER: ',',
@@ -512,6 +515,7 @@ VAR_INFO = {
CMDLOG: {VAR_TYPE: TYPE_FILE, VAR_ACCESS: os.W_OK},
CMDLOG_MAX_BACKUPS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 10)},
CMDLOG_MAX_KILO_BYTES: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (100, 10000)},
COMMANDDATA_CLIENTACCESS: {VAR_TYPE: TYPE_BOOLEAN},
CONFIG_DIR: {VAR_TYPE: TYPE_DIRECTORY, VAR_ENVVAR: 'GAMUSERCONFIGDIR'},
CONTACT_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 10000)},
CSV_INPUT_COLUMN_DELIMITER: {VAR_TYPE: TYPE_CHARACTER},

View File

@@ -1138,6 +1138,7 @@ class GamCLArgs():
OB_ARGUMENT = 'argument'
OB_ASP_ID_LIST = 'ASPIDList'
OB_ASSET_ID = 'AssetID'
OB_ADMIN_ASSIGNEE_TYPE_LIST = 'AdminAssigneeTypeList'
OB_BROWSER_ENROLLEMNT_TOKEN_ID = 'BrowserEnrollmentTokenID'
OB_BROWSER_ENTITY = 'BrowserEntity'
OB_BUILDING_ID = 'BuildingID'

View File

@@ -19,6 +19,8 @@
## Definitions
```
<AdminAssigneeType> ::= group|user|serviceaccount|unknown
<AdminAssigneeTypeList> ::= "<AdminAssigneeType>(,<AdminAssigneeType>)*"
<DomainName> ::= <String>(.<String>)+
<EmailAddress> ::= <String>@<DomainName>
<GroupItem> ::= <EmailAddress>|<UniqueID>|<String>
@@ -1475,16 +1477,25 @@ gam delete admin <RoleAssignmentId>
## Display administrators
```
gam print admins [todrive <ToDriveAttribute>*]
[user|group <EmailAddress>|<UniqueID>] [role <RoleItem>] [condition]
[privileges] [oneitemperrow]
[user|group <EmailAddress>|<UniqueID>] [role <RoleItem>]
[types <AdminAssigneeTypeList>]
[recursive] [condition] [privileges] [oneitemperrow]
gam show admins
[user|group <EmailAddress>|<UniqueID>] [role <RoleItem>] [condition] [privileges]
[user|group <EmailAddress>|<UniqueID>] [role <RoleItem>]
[types <AdminAssigneeTypeList>]
[recursive] [condition] [privileges]
```
By default, all administrators and roles are displayed; choose from the following
options to limit the display:
* `user <UserItem>` - Display only this administrator
* `user|group <EmailAddress>|<UniqueID>` - Display assignments to this administrator
* `role <RoleItem>` - Display only administrators with this role
By default, all admin assignee types are displayed. use `types <AdminAssigneeTypeList>` to filter
admin assignments by the type of the assignee.
By default, assignments to security groups are displayed as a single item; use `recursive`
to display assignments to the members of the security groups; the security group membershop is recursively expanded.
* `condition` - Display any conditions associated with a role assignment
* `privileges` - Display privileges associated with each role assignment

View File

@@ -265,6 +265,7 @@
## Named items
```
<AccessToken> ::= <String>
<AdminAssigneeType> ::= group|user|serviceaccount|unknown
<AlertID> ::= <String>
<APIScopeURL> ::= <String>
<APPID> ::= <String>

View File

@@ -567,7 +567,7 @@ By default, Gam displays the information as an indented list of keys and values.
```
gam calendar <CalendarEntity> show events [<EventEntity>] <EventDisplayProperty>*
[fields <EventFieldNameList>] [showdayofweek]
[countsly] [formatjson]
[countsly|formatjson]
```
In `<EventEntity>`, any `<EventSelectProperty>` options must precede all other options.
@@ -586,8 +586,9 @@ By default, Gam displays event details, use `countsonly` to display only the num
```
gam calendar <CalendarEntity> print events [<EventEntity>] <EventDisplayProperty>*
[fields <EventFieldNameList>] [showdayofweek]
[countsonly [eventrowfilter]]
[formatjson [quotechar <Character>]] [todrive <ToDriveAttribute>*]
(addcsvdata <FieldName> <String>)*
[eventrowfilter]
[countsonly|(formatjson [quotechar <Character>])] [todrive <ToDriveAttribute>*]
```
In `<EventEntity>`, any `<EventSelectProperty>` options must precede all other options.
@@ -598,6 +599,9 @@ option `singleevents` to display all instances of a recurring event.
`showdayofweek` displays columns `start.dayOfWeek` and `end.dayOfWeek` when event start and end times are displayed.
Add additional columns of data from the command line to the output after the calendarId.
* `addcsvdata <FieldName> <String>`
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format,
* `formatjson` - Display the fields in JSON format.

View File

@@ -5,6 +5,7 @@
- [Plain Text](#plain-text)
- [HTML](#html)
- [Read data from a Google Sheet](#read-data-from-a-google-sheet)
- [Limited Service Account Access](#limited-service-account-access)
- [Read data from a Google Cloud Storage File](#read-data-from-a-google-cloud-storage-file)
- [Plain Text](#plain-text)
- [CSV](#csv)
@@ -79,6 +80,25 @@ Example:
```
gam csv gsheet you@exmaple.com <DriveFileIDEntity> "Sheet 1" gam create user firstname "~FirstName" lastname "~lastName" email "~email"
```
## Limited Service Account Access
If you want to disable a user's service account access to Drive and Sheets but still allow reading command data from Google Docs and Sheets,
issue the following commands. The admin specified in `gam oauth create` can read command data from Docs and Sheets to which it has access.
```
gam config commanddata_clientaccess true save
gam oauth create
Enable the following and proceed to authorization.
[*] 42) Drive API - commanddata_clientaccess
[*] 54) Sheets API - commanddata_clientaccess
```
In these options, the `<EmailAddress> is not used, but for clarity you may want to specify the
email address of the admin specified in `gam oauth create`.
```
gdoc <EmailAddress> <DriveFileIDEntity>|<DriveFileNameEntity>|(<SharedDriveEntity> <SharedDriveFileNameEntity>)
gsheet <EmailAddress> <DriveFileIDEntity>|<DriveFileNameEntity>|(<SharedDriveEntity> <SharedDriveFileNameEntity>) <SheetEntity>
```
## Read data from a Google Cloud Storage File
```
<StorageBucketName> ::= <String>

View File

@@ -10,7 +10,7 @@
- [Delete duplicate email addresses from contacts](#delete-duplicate-email-addresses-from-contacts)
- [Manage domain contact photos](#manage-domain-contact-photos)
- [Display domain shared contacts](#display-domain-shared-contacts)
- [Display global address list](#display-global-address-list)
- [Display global address list](#Global-Address-List)
## API documentation
* [Domain Shared Contacts API](https://developers.google.com/admin-sdk/domain-shared-contacts)

View File

@@ -10,6 +10,85 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
See [Downloads-Installs-GAM7](https://github.com/GAM-team/GAM/wiki/Downloads-Installs) for Windows or other options, including manual installation
### 7.25.00
Removed a capabilty added in 7.24.00 that allowed reading command data from Google Docs and Sheets
when a user's service account access to Drive and Sheets had been disabled. Jay was concerned
that this change could be exploited to give access to all user's files.
This capability has been replaced by issuing the following commands. The admin specified in `gam oauth create`
can read command data from Docs and Sheets to which it has access.
```
gam config commanddata_clientaccess true save
gam oauth create
Enable the following and proceed to authorization.
[*] 42) Drive API - commanddata_clientaccess
[*] 54) Sheets API - commanddata_clientaccess
```
* See: https://github.com/GAM-team/GAM/wiki/Command-Data-From-Google-Docs-Sheets-Storage#limited-service-account-access
Fixed in bug in `gam report` that caused a trap with either of the `thismonth` or `previousmonths` options were used.
Upgraded to Python 3.14.0.
### 7.24.01
Updated GAM to handle the following error that occurs when GAM tries to authenticate
as a user that has been disabled by Google.
```
ERROR: Authentication Token Error - invalid_account: Forbidden
```
### 7.24.00
If you want to disable a user's service account access to Drive and Sheets but still allow reading command data from Google Docs and Sheets,
issue the following command and make these settings:
```
gam user user@domain.com update serviceaccount
[ ] 20) Drive API (supports readonly)
[*] 21) Drive API - read command data
[ ] 42) Sheets API (supports readonly)
[*] 43) Sheets API - read command data
```
### 7.23.07
Fixed bug in `gam print|show admins` where all admin assignments were not displayed when
`types <AdminAssigneeTypeList>` was not specified, i.e., all assignments should be displayed.
### 7.23.06
Added option `types <AdminAssigneeTypeList>` to `gam print|show admins` that allows filtering
of admin assignments by the type of the assignee; by default, all assignee types are displayed.
```
<AdminAssigneeType> ::= group|user|serviceaccount|unknown
<AdminAssigneeTypeList> ::= "<AdminAssigneeType>(,<AdminAssigneeType>)*"
```
### 7.23.05
Added option `recursive` to `gam print|show admins` that will display assignments to the members
of security groups assigned to roles; the security group membership is recursively expanded.
### 7.23.04
Added option `addcsvdata <FieldName> <String>` to `gam <UserTypeEntity> print events`
and `gam calendars <CalendarEntity> print events` that adds additional columns of data to the CSV file output.
An example would be to get the calendar name in addition to the calendar ID when printing events.
```
gam redirect csv ./Resources.csv print resources fields email,name
gam redirect csv ./ResourceEventCounts.csv multiprocess redirect stderr - multiprocess csv Resources.csv gam calendar "~resourceEmail" print events starttime -1y countsonly addcsvdata calendarName "~resourceName"
```
Upgraded to OpenSSL 3.6.0.
### 7.23.03
Upgraded to OpenSSL 3.5.4.
### 7.23.02
Added option `oneitemperrow` to 'gam print course-materials|course-work` to have each of a

View File

@@ -252,9 +252,9 @@ writes the credentials into the file oauth2.txt.
admin@server:/Users/admin$ rm -f /Users/admin/GAMConfig/oauth2.txt
admin@server:/Users/admin$ gam version
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
GAM 7.23.02 - https://github.com/GAM-team/GAM - pyinstaller
GAM 7.25.00 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.7 64-bit final
Python 3.14.0 64-bit final
macOS Tahoe 26.0.1 x86_64
Path: /Users/admin/bin/gam7
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
@@ -990,9 +990,9 @@ writes the credentials into the file oauth2.txt.
C:\>del C:\GAMConfig\oauth2.txt
C:\>gam version
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
GAM 7.22.00 - https://github.com/GAM-team/GAM - pythonsource
GAM 7.25.00 - https://github.com/GAM-team/GAM - pythonsource
GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.7 64-bit final
Python 3.14.0 64-bit final
Windows-10-10.0.17134 AMD64
Path: C:\GAM7
Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com

View File

@@ -5,6 +5,7 @@
## Lists of basic items
```
<AdminAssigneeTypeList> ::= "<AdminAssigneeType>(,<AdminAssigneeType>)*"
<APIScopeURLList> ::= "<APIScopeURL>(,<APIScopeURL>)*"
<ASPIDList> ::= "<ASPID>(,<ASPID>)*"
<AssetTagList> ::= "<AssetTag>(,<AssetTag>)*"

View File

@@ -330,16 +330,16 @@ you want the updated data copied to `Latest` so you don't have to remember what
gam redirect csv - todrive tdfileid <DriveFileID> tdupdatesheet tdsheet Tuesday tdbackupsheet "Backup Tuesday" tdcopysheet "Latest" ...
```
## Limited Service Account Access
If you want to limit a user's service account access but still allow `todrive',
issue the following command and authorize the additional service account APIs:
If you want to limit a user's service account access to Drive, Gmail and Sheets but still allow `todrive`,
issue the following command and make these settings:
```
gam user user@domain.com update serviceaccount`
gam user user@domain.com update serviceaccount
Authorize these APIs:
Drive API - todrive
Gmail API - Send Messages - including todrive
Sheets API - todrive
[ ] 20) Drive API (supports readonly)
[*] 22) Drive API - write todrive data - has access to all Drive
[*] 31) Gmail API - Send Messages - including todrive
[ ] 42) Sheets API (supports readonly)
[*] 44) Sheets API - write todrive data - has access to all Sheets
```
## No Service Account Access

View File

@@ -653,7 +653,7 @@ By default, Gam displays the information as an indented list of keys and values.
```
gam <UserTypeEntity> show events <UserCalendarEntity> [<EventEntity>] <EventDisplayProperty>*
[fields <EventFieldNameList>] [showdayofweek]
[countsonly] [formatjson]
[countsonly|formatjson]
```
In `<EventEntity>`, any `<EventSelectProperty>` options must precede all other options.
@@ -672,8 +672,8 @@ By default, Gam displays event details, use `countsonly` to display only the num
```
gam <UserTypeEntity> print events <UserCalendarEntity> [<EventEntity>] <EventDisplayProperty>*
[fields <EventFieldNameList>] [showdayofweek]
[countsonly]
[formatjson [quotechar <Character>]] [todrive <ToDriveAttribute>*]
(addcsvdata <FieldName> <String>)*
[eventrowfilter] [countsonly|(formatjson [quotechar <Character>])] [todrive <ToDriveAttribute>*]
```
In `<EventEntity>`, any `<EventSelectProperty>` options must precede all other options.
@@ -684,6 +684,9 @@ option `singleevents` to display all instances of a recurring event.
`showdayofweek` displays columns `start.dayOfWeek` and `end.dayOfWeek` when event start and end times are displayed.
Add additional columns of data from the command line to the output after the calendarId.
* `addcsvdata <FieldName> <String>`
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format,
* `formatjson` - Display the fields in JSON format.

View File

@@ -398,8 +398,8 @@ By default, Gam displays the information as an indented list of keys and values.
gam <UserTypeEntity> show contacts
<PeoplePrintShowUserContactSelection>
[orderby firstname|lastname|(lastmodified ascending)|(lastnodified descending)
[countsonly|allfields|(fields <PeopleFieldNameList>)] [showgroups] [showmetadata]
[formatjson]
[allfields|(fields <PeopleFieldNameList>)] [showgroups] [showmetadata]
[countsonly|formatjson]
```
By default, Gam displays all of a user's people contacts.
* `query <String>` - Display contacts based on the data in their fields
@@ -416,8 +416,8 @@ By default, Gam displays the information as an indented list of keys and values.
gam <UserTypeEntity> print contacts [todrive <ToDriveAttribute>*]
<PeoplePrintShowUserContactSelection>
[orderby firstname|lastname|(lastmodified ascending)|(lastnodified descending)
[countsonly|allfields|(fields <PeopleFieldNameList>)] [showgroups] [showmetadata]
[formatjson [quotechar <Character>]]
[allfields|(fields <PeopleFieldNameList>)] [showgroups] [showmetadata]
[countsonly|(formatjson [quotechar <Character>])]
```
By default, Gam displays all of a user's people contacts.
* `query <String>` - Display contacts based on the data in their fields
@@ -547,8 +547,8 @@ User: user@domain.com, Delete maximum of 15 Other Contacts
```
gam <UserTypeEntity> show othercontacts
[<OtherContactsSelection>]
[countsonly|allfields|(fields <OtherContactsFieldNameList>)] [showmetadata]
[formatjson]
[allfields|(fields <OtherContactsFieldNameList>)] [showmetadata]
[countsonly|formatjson]
```
By default, Gam displays all of a user's Other Contacts; use
`<OtherContactsSelection>` to display a selection of Other Contacts.
@@ -563,8 +563,8 @@ By default, Gam displays the information as an indented list of keys and values.
```
gam <UserTypeEntity> print othercontacts [todrive <ToDriveAttribute>*]
[<OtherContactsSelection>]
[countsonly|allfields|(fields <OtherContactsFieldNameList>)] [showmetadata]
[formatjson [quotechar <Character>]]
[allfields|(fields <OtherContactsFieldNameList>)] [showmetadata]
[countsonly|(formatjson [quotechar <Character>])]
```
By default, Gam displays all of a user's Other Contacts; use
`<OtherContactsSelection>` to display a selection of Other Contacts.

View File

@@ -122,7 +122,7 @@ gam <UserTypeEntity> show tasks [tasklists <TasklistEntity>]
[updatedmin <Time>]
[showcompleted [<Boolean>]] [showdeleted [<Boolean>]] [showhidden [<Boolean>]] [showall]
[orderby completed|due|updated]
[countsonly|compact|formatjson]
[compact|countsonly|formatjson]
```
The API only supports dates in `duemin` and `duemax' but you must supply a null time:
* `duemin YYYY-MM-DDT00:00:00Z` - Specify the starting due date
@@ -152,7 +152,7 @@ gam <UserTypeEntity> print tasks [tasklists <TasklistEntity>] [todrive <ToDriveA
[updatedmin <Time>]
[showcompleted [<Boolean>]] [showdeleted [<Boolean>]] [showhidden [<Boolean>]] [showall]
[orderby completed|due|updated]
[countsonly | (formatjson [quotechar <Character>])]
[countsonly|(formatjson [quotechar <Character>])]
```
The API only supports dates in `duemin` and `duemax' but you must supply a null time:
* `duemin YYYY-MM-DDT00:00:00Z` - Specify the starting due date
@@ -230,7 +230,7 @@ By default, Gam displays the task lists as an indented list of keys and values.
```
gam <UserTypeEntity> print tasklists [todrive <ToDriveAttribute>*]
[countsonly | (formatjson [quotechar <Character>])]
[countsonly|(formatjson [quotechar <Character>])]
```
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format,
* `formatjson` - Display the fields in JSON format.

View File

@@ -27,7 +27,7 @@
- [Delete Vault Saved Queries](#delete-vault-saved-queries)
- [Display Vault Saved Queries](#display-vault-saved-queries)
- [Takeout](#takeout)
- [Copy a Takeout Bucket](#copy-a-takeoutbucket)
- [Copy a Takeout Bucket](#copy-a-takeout-bucket)
- [Download a Takeout Bucket](#download-a-takeout-bucket)
## API documentation
@@ -848,7 +848,7 @@ gam create vaultquery <MatterItem> [name <String>]
[<JSONData>]
[shownames]
[showdetails|returnidonly|formatjson]
``
```
If `name <String>` is omitted, the query is named `GAM <corpus> Query - <Time>`
@@ -928,7 +928,7 @@ Select fields to display:
The `shownames` argument controls whether org unit and shared drive names are displayed in queries; additional API calls are required to get the names.
# Takeout
## Takeout
Many thanks to Jay for these commands and documentation.
GAM 6.42.00 and newer support copying and downloading Google Cloud Storage (GCS) buckets generated by [organization-wide Takeout](https://support.google.com/a/answer/100458?hl=en).

View File

@@ -3,9 +3,9 @@
Print the current version of Gam with details
```
gam version
GAM 7.23.02 - https://github.com/GAM-team/GAM - pyinstaller
GAM 7.25.00 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.7 64-bit final
Python 3.14.0 64-bit final
macOS Tahoe 26.0.1 x86_64
Path: /Users/Admin/bin/gam7
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
@@ -15,9 +15,9 @@ Time: 2023-06-02T21:10:00-07:00
Print the current version of Gam with details and time offset information
```
gam version timeoffset
GAM 7.23.02 - https://github.com/GAM-team/GAM - pyinstaller
GAM 7.25.00 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.7 64-bit final
Python 3.14.0 64-bit final
macOS Tahoe 26.0.1 x86_64
Path: /Users/Admin/bin/gam7
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
@@ -27,9 +27,9 @@ Your system time differs from www.googleapis.com by less than 1 second
Print the current version of Gam with extended details and SSL information
```
gam version extended
GAM 7.23.02 - https://github.com/GAM-team/GAM - pyinstaller
GAM 7.25.00 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.7 64-bit final
Python 3.14.0 64-bit final
macOS Tahoe 26.0.1 x86_64
Path: /Users/Admin/bin/gam7
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
@@ -68,7 +68,7 @@ MacOS High Sierra 10.13.6 x86_64
Path: /Users/Admin/bin/gam7
Version Check:
Current: 5.35.08
Latest: 7.22.00
Latest: 7.25.00
echo $?
1
```
@@ -76,7 +76,7 @@ echo $?
Print the current version number without details
```
gam version simple
7.22.00
7.25.00
```
In Linux/MacOS you can do:
```
@@ -86,9 +86,9 @@ echo $VER
Print the current version of Gam and address of this Wiki
```
gam help
GAM 7.22.00 - https://github.com/GAM-team/GAM
GAM 7.25.00 - https://github.com/GAM-team/GAM
GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.7 64-bit final
Python 3.14.0 64-bit final
macOS Tahoe 26.0.1 x86_64
Path: /Users/Admin/bin/gam7
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com

View File

@@ -140,6 +140,11 @@ cmdlog_max_kilo_bytes
Maximum kilobytes per log file
Default: 1000
Range: 100 - 10000
commanddata_clientaccess
Enable/disable use of client access rather than service account access for the
admin specified in `gam oauth create` when reading command data from Docs and Sheets
to which it has access.
Default: False
config_dir
GAM config directory containing client_secrets.json, oauth2.txt, oauth2service.json
and extra_args.txt