mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-07 07:41:38 +00:00
Compare commits
411 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95caeaba5e | ||
|
|
d8ad1b27a4 | ||
|
|
fefeae7c60 | ||
|
|
65f7b82d53 | ||
|
|
bebafb428d | ||
|
|
5e59363a0c | ||
|
|
4b2e0db720 | ||
|
|
938b2bf5a4 | ||
|
|
34ff0329c4 | ||
|
|
bed610405b | ||
|
|
1b0c8b75cb | ||
|
|
6eb7e59d56 | ||
|
|
5b4cf97702 | ||
|
|
997bd56bd6 | ||
|
|
e66db1a117 | ||
|
|
e3a5f33981 | ||
|
|
877465a82f | ||
|
|
7e9477c6ea | ||
|
|
1b2fc06f6f | ||
|
|
3d3b3eac85 | ||
|
|
882b930928 | ||
|
|
4d804177c4 | ||
|
|
de71baff60 | ||
|
|
79de854440 | ||
|
|
f0406af938 | ||
|
|
d51ca45626 | ||
|
|
00953b2984 | ||
|
|
735b131b44 | ||
|
|
cb6069bcb5 | ||
|
|
3a18143ba7 | ||
|
|
5021f685c1 | ||
|
|
2dd88a7d9e | ||
|
|
3496c2c96a | ||
|
|
98404e91b6 | ||
|
|
ddc36b42ba | ||
|
|
1cae3daa4a | ||
|
|
cc7b5c1a14 | ||
|
|
cd266ebec9 | ||
|
|
c1010d412b | ||
|
|
b41c49ea69 | ||
|
|
8617e9f57f | ||
|
|
b47f2fc4ea | ||
|
|
77f0d3abb3 | ||
|
|
71721d06f2 | ||
|
|
d51428f3dc | ||
|
|
b92239fb6f | ||
|
|
b50376656e | ||
|
|
7796baf685 | ||
|
|
6639e1be33 | ||
|
|
a8b666b32d | ||
|
|
97ce3e9b8d | ||
|
|
f9402cb21a | ||
|
|
1dc7868078 | ||
|
|
c0dc8ae790 | ||
|
|
8c12e33321 | ||
|
|
d1d48f3b90 | ||
|
|
3e52d6a924 | ||
|
|
c6e2031d45 | ||
|
|
186541d751 | ||
|
|
5efde2a967 | ||
|
|
83ed93a298 | ||
|
|
986672370a | ||
|
|
c313c5fa83 | ||
|
|
aaae733452 | ||
|
|
c810e1c8df | ||
|
|
e95ba0818e | ||
|
|
4b234c44a8 | ||
|
|
266bd68c94 | ||
|
|
36bf671251 | ||
|
|
ee71be86b5 | ||
|
|
0c3edfea62 | ||
|
|
4e85960954 | ||
|
|
61c23e2862 | ||
|
|
0613eb2c5f | ||
|
|
5b192a8f67 | ||
|
|
a3eedc360b | ||
|
|
c3225344ee | ||
|
|
dddf8a389d | ||
|
|
61847d0d89 | ||
|
|
e11510b2bc | ||
|
|
52b5745b85 | ||
|
|
82f5dd1864 | ||
|
|
b9ae49cf43 | ||
|
|
2cf9f1d5c6 | ||
|
|
544263099b | ||
|
|
085988dfde | ||
|
|
4a330ec1b6 | ||
|
|
7a69cd0b19 | ||
|
|
1be149bba2 | ||
|
|
7911317184 | ||
|
|
14f74b0d0a | ||
|
|
bb2635565d | ||
|
|
399149a946 | ||
|
|
b9237f9f63 | ||
|
|
dacd8f3c48 | ||
|
|
86b260d302 | ||
|
|
6396740269 | ||
|
|
e3931cff8d | ||
|
|
f5568ff474 | ||
|
|
38f8bdc910 | ||
|
|
10c1557494 | ||
|
|
71bd2f9cbc | ||
|
|
fc99f9b29b | ||
|
|
201f0b0eab | ||
|
|
9ad64c9efa | ||
|
|
4fb7448d40 | ||
|
|
993ab3d8d2 | ||
|
|
3befbf4419 | ||
|
|
06b2c83937 | ||
|
|
c171b6100b | ||
|
|
fa243f0894 | ||
|
|
59b61715aa | ||
|
|
2717908558 | ||
|
|
ae3c5f2ef6 | ||
|
|
0df08967ce | ||
|
|
6dbdc4db07 | ||
|
|
f4aed33e30 | ||
|
|
90fb2309ec | ||
|
|
9151de0f35 | ||
|
|
69c27d2553 | ||
|
|
1c433b69e4 | ||
|
|
b44e104b50 | ||
|
|
210d4720c2 | ||
|
|
e313006f54 | ||
|
|
ae058424f6 | ||
|
|
5c09998f9a | ||
|
|
985b6cc5e2 | ||
|
|
f7ac9aab21 | ||
|
|
5c2c049774 | ||
|
|
e290d6d200 | ||
|
|
006b885e7f | ||
|
|
bdfa8cbec7 | ||
|
|
a47ca4f602 | ||
|
|
9ba4eb88a6 | ||
|
|
69fd2ef738 | ||
|
|
a0733242ef | ||
|
|
7546ed2fe1 | ||
|
|
e7db6ac815 | ||
|
|
27d5a1c0b3 | ||
|
|
87dc1f2ec8 | ||
|
|
076f9dd376 | ||
|
|
74db8d503e | ||
|
|
b5298ec025 | ||
|
|
d01847ab25 | ||
|
|
c3b08d2d59 | ||
|
|
2cc22880f1 | ||
|
|
f2603f414c | ||
|
|
73d0d9e19a | ||
|
|
3f37bfe4cd | ||
|
|
47886770fd | ||
|
|
da3ab64267 | ||
|
|
35054b574b | ||
|
|
0640bca3e4 | ||
|
|
b148a821a3 | ||
|
|
f9e0e4b8bf | ||
|
|
6cbc47da13 | ||
|
|
66fcd01a63 | ||
|
|
4adb667db6 | ||
|
|
45f95a2dd7 | ||
|
|
cb70fe7e0d | ||
|
|
a66d53f6f3 | ||
|
|
f6a473ab43 | ||
|
|
158ec79880 | ||
|
|
03bff5df8c | ||
|
|
f98baf0cc2 | ||
|
|
512bde45f4 | ||
|
|
b818002202 | ||
|
|
33065438d8 | ||
|
|
e4880a3814 | ||
|
|
a2bd409d51 | ||
|
|
352f09fad8 | ||
|
|
221a18fc51 | ||
|
|
158138f344 | ||
|
|
0d32e451e9 | ||
|
|
38780e2ba9 | ||
|
|
f3e6afbca4 | ||
|
|
cb1c7ad6fe | ||
|
|
3ee8bf2841 | ||
|
|
71d82f0f87 | ||
|
|
398a91b987 | ||
|
|
0cf17be7ca | ||
|
|
28d76c5aee | ||
|
|
04371eee53 | ||
|
|
70cf32f6ed | ||
|
|
d2495f0ed8 | ||
|
|
2d3c1e5aa8 | ||
|
|
7855447014 | ||
|
|
0028955412 | ||
|
|
c3b59a9c10 | ||
|
|
fbe1bb69c3 | ||
|
|
b2573b465b | ||
|
|
6171e3c2ef | ||
|
|
19e13a9052 | ||
|
|
b349d80be5 | ||
|
|
c5c4553ae0 | ||
|
|
ef77e6f7e9 | ||
|
|
66816863e0 | ||
|
|
7d67cd08f6 | ||
|
|
0d1b622831 | ||
|
|
a1000f7778 | ||
|
|
30fea18f93 | ||
|
|
8bbb9b6e85 | ||
|
|
4b5390f6cf | ||
|
|
941abe608a | ||
|
|
0d23175216 | ||
|
|
c9c9fbd604 | ||
|
|
9d0d7c5aa8 | ||
|
|
65b23113a9 | ||
|
|
4d3edf7203 | ||
|
|
3c5d3fc569 | ||
|
|
f0d984c693 | ||
|
|
6efe1a596f | ||
|
|
598e5cf315 | ||
|
|
3fb0b840a1 | ||
|
|
ee3fa9715c | ||
|
|
3369a7a506 | ||
|
|
a6d176c033 | ||
|
|
120d72e67a | ||
|
|
0082a5a0b9 | ||
|
|
9971cdbfb3 | ||
|
|
837bb9f84f | ||
|
|
805b196532 | ||
|
|
a23238f97f | ||
|
|
e88e2f0d7f | ||
|
|
13ed3fe80c | ||
|
|
37bfcc1251 | ||
|
|
cb7e70ce31 | ||
|
|
25006765de | ||
|
|
594164944e | ||
|
|
56ed6e8a81 | ||
|
|
159184be73 | ||
|
|
51f4f3c401 | ||
|
|
320d5425c1 | ||
|
|
6d9839a328 | ||
|
|
1002f71d32 | ||
|
|
101a01cef0 | ||
|
|
45230860f6 | ||
|
|
ef1018f286 | ||
|
|
63c0c58bf6 | ||
|
|
aa443ae6cb | ||
|
|
dbec314359 | ||
|
|
8270f0a82a | ||
|
|
2a4cd66227 | ||
|
|
a87ff9effc | ||
|
|
df793c2bbb | ||
|
|
3bc32da275 | ||
|
|
ce7e506c29 | ||
|
|
a9d8ac27d3 | ||
|
|
58912ae7ac | ||
|
|
f882439cbd | ||
|
|
56bc52aa28 | ||
|
|
416125abac | ||
|
|
904292ded3 | ||
|
|
5f55bcc812 | ||
|
|
b35de53f5d | ||
|
|
3c34948678 | ||
|
|
0be73db60b | ||
|
|
5b57b51384 | ||
|
|
139896ec3b | ||
|
|
9b52c0bf18 | ||
|
|
b9c9b59f7b | ||
|
|
0e0877e084 | ||
|
|
bdce13e97b | ||
|
|
9c4a17e12c | ||
|
|
a64f4d4a46 | ||
|
|
c396a3b901 | ||
|
|
78453a15af | ||
|
|
a0282ba775 | ||
|
|
7b708bfeea | ||
|
|
fedb49ca9d | ||
|
|
87b4917fb0 | ||
|
|
5a9486c08a | ||
|
|
e7074cb0bc | ||
|
|
f894e5ffd7 | ||
|
|
5d1379e830 | ||
|
|
aa1b373245 | ||
|
|
1bed2383ff | ||
|
|
332d6c0761 | ||
|
|
597bbe2db9 | ||
|
|
fcb50e1e93 | ||
|
|
048d88c7a0 | ||
|
|
bd4208607b | ||
|
|
7b510075e6 | ||
|
|
882d7b5833 | ||
|
|
d4f5495909 | ||
|
|
b132e789f7 | ||
|
|
701824d984 | ||
|
|
4c63de65a5 | ||
|
|
d1d1040ec3 | ||
|
|
fe4268230e | ||
|
|
bda51867c8 | ||
|
|
a913c8f128 | ||
|
|
89ac556933 | ||
|
|
48c23c2f98 | ||
|
|
3f2a261a99 | ||
|
|
beb76c5879 | ||
|
|
bd22dc1b8b | ||
|
|
2258cd69a5 | ||
|
|
a523f9c0f7 | ||
|
|
ea41cf52de | ||
|
|
aec92f19ae | ||
|
|
df99e6ea8e | ||
|
|
d16166ffac | ||
|
|
1bd75c31ae | ||
|
|
8830da9908 | ||
|
|
fdc6c34c91 | ||
|
|
c6be86946e | ||
|
|
920c9a344a | ||
|
|
ec9f3b9e79 | ||
|
|
326e83a05d | ||
|
|
61c2b06021 | ||
|
|
60093404c1 | ||
|
|
228d3bba95 | ||
|
|
9f5dfc1a0a | ||
|
|
2b5c4561d1 | ||
|
|
4bdce171af | ||
|
|
1f68c8db00 | ||
|
|
963cbebba0 | ||
|
|
c0edbfe596 | ||
|
|
47617c2823 | ||
|
|
11e0f1c760 | ||
|
|
6c4b481eb1 | ||
|
|
c0cbddc93d | ||
|
|
b50d92404f | ||
|
|
19408f8f4c | ||
|
|
0dd8e099c5 | ||
|
|
5738cf5435 | ||
|
|
0739bdc642 | ||
|
|
ddd1924c2c | ||
|
|
a6fb1d7c0f | ||
|
|
6aeed76e70 | ||
|
|
83f94c8122 | ||
|
|
056f23c6cb | ||
|
|
7b1619f95d | ||
|
|
fe4ea3fe41 | ||
|
|
f5edd6bf81 | ||
|
|
7340557a8c | ||
|
|
66ec9d0d4b | ||
|
|
cc6ccd1338 | ||
|
|
25c167ee0a | ||
|
|
f620850a58 | ||
|
|
73ad3cc3e5 | ||
|
|
b03083cb09 | ||
|
|
6642e23e81 | ||
|
|
a237272440 | ||
|
|
d3ac277523 | ||
|
|
e21ff2bec2 | ||
|
|
369df07748 | ||
|
|
b218abaae7 | ||
|
|
967898fa86 | ||
|
|
80570f2fda | ||
|
|
6437547e33 | ||
|
|
f87f000be2 | ||
|
|
08f6f86d10 | ||
|
|
e70bfca92a | ||
|
|
2be5d40f44 | ||
|
|
170e188f1f | ||
|
|
60d6188769 | ||
|
|
626eb1eadc | ||
|
|
db40ada5d0 | ||
|
|
ba8c27339e | ||
|
|
822488dce5 | ||
|
|
bbd76ec23f | ||
|
|
e2a6f8badf | ||
|
|
2462aa7dcb | ||
|
|
d7a0da6e52 | ||
|
|
9922ed4994 | ||
|
|
3a0c52d8eb | ||
|
|
f3e7c46561 | ||
|
|
b42c916516 | ||
|
|
4fd7172f7a | ||
|
|
e670cf3e6a | ||
|
|
e305cc0789 | ||
|
|
d7b9d43c63 | ||
|
|
75e3ae8144 | ||
|
|
130a483e4d | ||
|
|
cbd04bcec4 | ||
|
|
a51b245015 | ||
|
|
64356a9736 | ||
|
|
c18375abb7 | ||
|
|
c9c0cac57e | ||
|
|
8ca3717f97 | ||
|
|
cd0d82e994 | ||
|
|
f29f27577c | ||
|
|
cb5e5d1943 | ||
|
|
88bdfd2883 | ||
|
|
e875acf428 | ||
|
|
5d213e9951 | ||
|
|
35d61da0a0 | ||
|
|
da04ead86d | ||
|
|
5526c987ea | ||
|
|
d9795b3f83 | ||
|
|
39a17bacb1 | ||
|
|
af94ea6e54 | ||
|
|
c220f41cbe | ||
|
|
8a32e53652 | ||
|
|
372f86a79a | ||
|
|
7f307254bf | ||
|
|
2ae7b4a4b5 | ||
|
|
6dde273ee9 | ||
|
|
b66f6f60fe | ||
|
|
01fcefc647 | ||
|
|
a59e3008c5 | ||
|
|
eb82da4ff2 | ||
|
|
c4aa399446 | ||
|
|
f1713ec685 | ||
|
|
74924c9c0e | ||
|
|
8d3b65f5f1 | ||
|
|
260f2d3f5c | ||
|
|
475275add7 | ||
|
|
d71832096a |
255
.github/workflows/build.yml
vendored
255
.github/workflows/build.yml
vendored
@@ -30,6 +30,7 @@ env:
|
||||
PYTHON_SOURCE_PATH: ${{ github.workspace }}/src/cpython
|
||||
CRYPTOGRAPHY_BUILD_OPENSSL_NO_LEGACY: 1
|
||||
CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1
|
||||
WINDOWS_CODESIGN_CERT_HASH: 3B11D9340A45CF078FF7FD984F1C3E30DA82FD05
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -76,57 +77,65 @@ jobs:
|
||||
jid: 9
|
||||
goal: build
|
||||
name: Build Arm MacOS 15
|
||||
- os: windows-2022
|
||||
- os: macos-15-intel
|
||||
jid: 10
|
||||
goal: build
|
||||
name: Build x86_64 macOS 15
|
||||
- os: macos-26
|
||||
jid: 11
|
||||
goal: build
|
||||
name: Build Arm MacOS 26
|
||||
- os: windows-2025
|
||||
jid: 12
|
||||
goal: build
|
||||
name: Build Intel Windows
|
||||
- os: windows-11-arm
|
||||
jid: 11
|
||||
jid: 13
|
||||
goal: build
|
||||
name: Build Arm Windows
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.10"
|
||||
jid: 12
|
||||
jid: 14
|
||||
name: Test Python 3.10
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.11"
|
||||
jid: 13
|
||||
name: Test Python 3.11
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.12"
|
||||
jid: 14
|
||||
name: Test Python 3.12
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.14-dev"
|
||||
jid: 15
|
||||
name: Test Python 3.14-dev
|
||||
name: Test Python 3.11
|
||||
#- os: ubuntu-24.04
|
||||
# goal: test
|
||||
# python: "3.12"
|
||||
# jid: 16
|
||||
# name: Test Python 3.12
|
||||
#- os: ubuntu-24.04
|
||||
# goal: test
|
||||
# python: "3.14-dev"
|
||||
# jid: 16
|
||||
# name: Test Python 3.14-dev
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
- id: auth
|
||||
name: Authenticate to Google Cloud
|
||||
uses: google-github-actions/auth@v2
|
||||
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
|
||||
with:
|
||||
workload_identity_provider: projects/297925809119/locations/global/workloadIdentityPools/gha-pool/providers/gha-provider
|
||||
service_account: github-actions-testing-for-gam@gam-project-wyo-lub-ivl.iam.gserviceaccount.com
|
||||
|
||||
- name: Cache multiple paths
|
||||
if: matrix.goal == 'build'
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@638ed79f9dc94c1de1baef91bcab5edaa19451f4 # v4.2.4
|
||||
id: cache-python-ssl
|
||||
with:
|
||||
path: |
|
||||
cache.tar.xz
|
||||
key: gam-${{ matrix.jid }}-20250611
|
||||
key: gam-${{ matrix.jid }}-20250922
|
||||
|
||||
- name: Untar Cache archive
|
||||
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
|
||||
@@ -136,7 +145,7 @@ jobs:
|
||||
|
||||
- name: Use pre-compiled Python for testing
|
||||
if: matrix.python != ''
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@3d1e2d2ca0a067f27da6fec484fce7f5256def85 # v5.6.0
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
allow-prereleases: true
|
||||
@@ -187,7 +196,7 @@ jobs:
|
||||
export PYTHON=$(which python3)
|
||||
export PIP=$(which pip3)
|
||||
export gam="${PYTHON} -m gam"
|
||||
export gampath="$(readlink -e .)"
|
||||
export gampath="$(readlink -e .)/gam"
|
||||
echo -e "PYTHON: ${PYTHON}\nPIP: ${PIP}\gam: ${gam}\ngampath: ${gampath}"
|
||||
echo "PYTHON=${PYTHON}" >> $GITHUB_ENV
|
||||
echo "PIP=${PIP}" >> $GITHUB_ENV
|
||||
@@ -216,14 +225,13 @@ jobs:
|
||||
|
||||
- name: MacOS import developer certificates for signing
|
||||
if: runner.os == 'macOS'
|
||||
uses: apple-actions/import-codesign-certs@v3
|
||||
uses: apple-actions/import-codesign-certs@11e1bb2d3771ad8ffa8459dfe527bc26b2dd4b62 # v5.0.3
|
||||
with:
|
||||
keychain: signing_temp
|
||||
p12-file-base64: ${{ secrets.CERTIFICATES_P12 }}
|
||||
p12-password: ${{ secrets.CERTIFICATES_P12_PASSWORD }}
|
||||
|
||||
- name: Windows Configure VCode
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
|
||||
if: runner.os == 'Windows' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||
with:
|
||||
arch: ${{ runner.arch }}
|
||||
@@ -285,17 +293,17 @@ jobs:
|
||||
echo "COMPILED_OPENSSL_VERSION=${COMPILED_OPENSSL_VERSION}" >> $GITHUB_ENV
|
||||
|
||||
- name: Windows NASM Install
|
||||
uses: ilammy/setup-nasm@v1
|
||||
uses: ilammy/setup-nasm@72793074d3c8cdda771dba85f6deafe00623038b # v1.5.2
|
||||
if: matrix.goal == 'build' && runner.os == 'Windows' && runner.arch == 'X64' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||
|
||||
- name: Config OpenSSL
|
||||
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd "${OPENSSL_SOURCE_PATH}"
|
||||
if ([ "$RUNNER_OS" == "Windows" ] && [ "$RUNNER_ARCH" == "ARM64" ]); then
|
||||
#if ([ "$RUNNER_OS" == "Windows" ] && [ "$RUNNER_ARCH" == "ARM64" ]); then
|
||||
# https://github.com/openssl/openssl/issues/26239
|
||||
export CFLAGS=-DNO_INTERLOCKEDOR64
|
||||
fi
|
||||
#fi
|
||||
# --libdir=lib is needed so Python can find OpenSSL libraries
|
||||
"${PERL}" ./Configure --libdir=lib --prefix="${OPENSSL_INSTALL_PATH}" $OPENSSL_CONFIG_OPTS
|
||||
|
||||
@@ -454,33 +462,11 @@ jobs:
|
||||
"$PYTHON" -m pip install --upgrade setuptools-scm
|
||||
"$PYTHON" -m pip list
|
||||
|
||||
- name: Custom wheels for Win arm64
|
||||
if: runner.os == 'Windows' && runner.arch == 'ARM64'
|
||||
run: |
|
||||
latest_lxml_whl=$(curl https://api.github.com/repos/GAM-team/lxml-wheel/releases/latest -s | jq -r .assets.[0].browser_download_url)
|
||||
echo "Downloading ${latest_lxml_whl}..."
|
||||
curl -O -L "$latest_lxml_whl"
|
||||
"$PYTHON" -m pip install lxml*.whl
|
||||
latest_crypt_whl=$(curl https://api.github.com/repos/jay0lee/cryptography/releases/latest -s | jq -r .assets.[0].browser_download_url)
|
||||
echo "Downloading ${latest_crypt_whl}..."
|
||||
curl -O -L "$latest_crypt_whl"
|
||||
"$PYTHON" -m pip install cryptography*.whl
|
||||
|
||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
|
||||
# - name: Compile cryptography from source (no legacy)
|
||||
# if: runner.os != 'Windows' || runner.arch != 'ARM64'
|
||||
# run: |
|
||||
# pip install --no-binary ":all:" --force cryptography
|
||||
|
||||
- name: Install pip requirements
|
||||
run: |
|
||||
echo "before anything..."
|
||||
"$PYTHON" -m pip list
|
||||
"$PYTHON" -m pip install --upgrade -r requirements.txt
|
||||
echo "after requirements..."
|
||||
"$PYTHON" -m pip list
|
||||
#"$PYTHON" -m pip install --force-reinstall --no-deps --upgrade cryptography
|
||||
"$PYTHON" -m pip install --upgrade ..[yubikey]
|
||||
echo "after everything..."
|
||||
"$PYTHON" -m pip list
|
||||
|
||||
@@ -550,7 +536,7 @@ jobs:
|
||||
- name: Copy extra package files
|
||||
if: matrix.goal == 'build'
|
||||
run: |
|
||||
cp -v cacerts.pem "$gampath"
|
||||
cp -v gam/cacerts.pem "$gampath"
|
||||
cp -v LICENSE "$gampath"
|
||||
cp -v GamCommands.txt "$gampath"
|
||||
cp -v GamUpdate.txt "$gampath"
|
||||
@@ -600,12 +586,77 @@ jobs:
|
||||
- name: Basic Tests all jobs
|
||||
id: basictests
|
||||
run: |
|
||||
$PYTHON -m unittest discover --start-directory ./ --pattern "*_test.py" --buffer || if [ $? != 5 ]; then exit $?; fi # exit 5 is no tests
|
||||
$gam version extended nooffseterror
|
||||
export GAMVERSION=$($gam version simple)
|
||||
echo "GAM Version ${GAMVERSION}"
|
||||
echo "GAMVERSION=${GAMVERSION}" >> $GITHUB_ENV
|
||||
|
||||
- name: Install WinAppDriver
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
choco install -y winappdriver
|
||||
|
||||
- name: Enabled dev mode for WinAppDriver
|
||||
if: runner.os == 'Windows'
|
||||
shell: cmd
|
||||
run : |
|
||||
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"
|
||||
|
||||
- name: Install appium and totp tools
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
echo "Installing appium..."
|
||||
npm install -g appium
|
||||
echo "Installing totp-generator..."
|
||||
npm install "totp-generator"
|
||||
echo "Installing wdio..."
|
||||
npm install @wdio/cli
|
||||
echo "Installing appium win driver..."
|
||||
appium driver install windows
|
||||
|
||||
- name: Install Certum MSI
|
||||
if: runner.os == 'Windows'
|
||||
shell: pwsh
|
||||
run: |
|
||||
$url = "https://files.certum.eu/software/SimplySignDesktop/Windows/9.3.2.67/SimplySignDesktop-9.3.2.67-64-bit-en.msi"
|
||||
$file = "SimplySignDesktop-9.3.2.67-64-bit-en.msi"
|
||||
Invoke-WebRequest $url -OutFile $file
|
||||
$log = "install.log"
|
||||
$procMain = Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru
|
||||
$procLog = Start-Process "powershell" "Get-Content -Path `"$log`" -Wait" -NoNewWindow -PassThru
|
||||
$procMain.WaitForExit()
|
||||
$procLog.Kill()
|
||||
|
||||
- name: Login to Certum
|
||||
if: runner.os == 'Windows'
|
||||
shell: pwsh
|
||||
env:
|
||||
TOTP_SECRET: ${{ secrets.TOTP_SECRET }}
|
||||
run: |
|
||||
# disable win private firewall that interferes with appium server
|
||||
Set-NetFirewallProfile -Profile Private -Enabled False
|
||||
$appiumCmd = Get-Command appium
|
||||
$appiumPath = $appiumCmd.Path
|
||||
Start-Process -Filepath "powershell.exe" -ArgumentList "-File", $appiumPath, "--address", "127.0.0.1", "--log-level", "error"
|
||||
Start-Sleep -Seconds 10
|
||||
write-host "appium started"
|
||||
write-host "running SimplySignDesktop login..."
|
||||
node tools/ssd.mjs --log-level warn
|
||||
write-host "sleeping during login..."
|
||||
Start-Sleep 10
|
||||
|
||||
- name: Sign gam.exe
|
||||
if: runner.os == 'Windows'
|
||||
shell: pwsh
|
||||
run: |
|
||||
write-Host "Signing ${env:gam}...."
|
||||
# Always explicitely use x64 version os signtool.exe, arm64 version apparently can't
|
||||
# see Certum certs since SimplySignDesktop is x64-only today.
|
||||
Start-Process -Wait -NoNewWindow -ErrorAction Continue -FilePath 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe' -ArgumentList "sign", "/sha1", "$env:WINDOWS_CODESIGN_CERT_HASH", "/tr", "http://time.certum.pl", "/td", "SHA256", "/fd", "SHA256", "/v", "$env:gam"
|
||||
write-Host "Verifying signature of ${env:gam}...."
|
||||
# verify signature. If we failed to sign we should fail to verify and die.
|
||||
& 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe' verify /pa /v "$env:gam"
|
||||
|
||||
- name: Configure user and service account auth
|
||||
id: configserviceaccount
|
||||
env:
|
||||
@@ -614,36 +665,8 @@ jobs:
|
||||
../.github/actions/decrypt.sh "${GAMCFGDIR}"
|
||||
$gam create signjwtserviceaccount
|
||||
|
||||
- name: Upload gam.exe Windows for signing
|
||||
if: runner.os == 'Windows' && matrix.goal != 'test'
|
||||
run: |
|
||||
export folder_number=$(date +%s)
|
||||
export folder_id=$($gam user gam-win-signer@pdl.jaylee.us add drivefile drivefilename "UPLOADING_FOR_SIGN ${folder_number}" parentid "1Xz3hYq4Mfa_r6D8EcBZHLDtHDFurYSvp" mimetype gfolder returnidonly)
|
||||
$gam user gam-win-signer@pdl.jaylee.us add drivefile localfile "$gam" parentid "$folder_id"
|
||||
$gam user gam-win-signer@pdl.jaylee.us update drivefile "$folder_id" newfilename "READYTOSIGN ${folder_number}"
|
||||
export signed_folder="SIGNED ${folder_number}"
|
||||
zero_results="gam-win-signer@pdl.jaylee.us,0"
|
||||
while true; do
|
||||
result_counts=$($gam user gam-win-signer@pdl.jaylee.us print filelist query "name = '${signed_folder}' and '1Xz3hYq4Mfa_r6D8EcBZHLDtHDFurYSvp' in parents and mimeType = 'application/vnd.google-apps.folder'" countsonly)
|
||||
echo "$result_counts"
|
||||
if [[ ! "$result_counts" =~ "$zero_results" ]]; then
|
||||
echo "looks like we have results"
|
||||
break
|
||||
fi
|
||||
echo "no results, sleeping 10..."
|
||||
sleep 10
|
||||
done
|
||||
# download signed gam.exe
|
||||
$gam user gam-win-signer@pdl.jaylee.us print filelist query "name = '${signed_folder}' and '1Xz3hYq4Mfa_r6D8EcBZHLDtHDFurYSvp' in parents and mimeType = 'application/vnd.google-apps.folder'" id | $gam csv - gam user gam-win-signer@pdl.jaylee.us print filelist query "'~~id~~' in parents and name = 'gam.exe'" id | $gam csv - gam user gam-win-signer@pdl.jaylee.us get drivefile ~id targetfolder "$gampath" targetname "signed-gam.exe" overwrite true acknowledgeabuse true
|
||||
# delete signed folder on drive
|
||||
$gam user gam-win-signer@pdl.jaylee.us print filelist query "name = '${signed_folder}' and '1Xz3hYq4Mfa_r6D8EcBZHLDtHDFurYSvp' in parents and mimeType = 'application/vnd.google-apps.folder'" id | $gam csv - gam user gam-win-signer@pdl.jaylee.us trash drivefile "~id"
|
||||
# remove unsigned gam.exe and rename signed-gam.exe
|
||||
rm -v -f "${gampath}/gam.exe"
|
||||
mv -v -f "${gampath}/signed-gam.exe" "${gampath}/gam.exe"
|
||||
#"/c/Program Files (x86)/Windows Kits/10/bin/10.0.22621.0/x64/signtool.exe" verify /v /pa "$gam"
|
||||
|
||||
- name: Attest gam executable was generated from this Action
|
||||
uses: actions/attest-build-provenance@v1
|
||||
uses: actions/attest-build-provenance@0b6e9809265278d02c58acf52849a95818a5a306 # v3.0.0
|
||||
if: matrix.goal == 'build'
|
||||
with:
|
||||
subject-path: ${{ env.gam }}
|
||||
@@ -694,34 +717,20 @@ jobs:
|
||||
rm -v -f *.wixobj
|
||||
echo "MSI_FILENAME=${MSI_FILENAME}" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload gam MSI Windows for signing
|
||||
if: runner.os == 'Windows' && matrix.goal != 'test'
|
||||
- name: Sign GAM MSI
|
||||
if: runner.os == 'Windows'
|
||||
shell: pwsh
|
||||
run: |
|
||||
export folder_number=$(date +%s)
|
||||
export folder_id=$($gam user gam-win-signer@pdl.jaylee.us add drivefile drivefilename "UPLOADING_FOR_SIGN ${folder_number}" parentid "1Xz3hYq4Mfa_r6D8EcBZHLDtHDFurYSvp" mimetype gfolder returnidonly)
|
||||
$gam user gam-win-signer@pdl.jaylee.us add drivefile localfile "$MSI_FILENAME" parentid "$folder_id"
|
||||
rm -f -v "$MSI_FILENAME"
|
||||
$gam user gam-win-signer@pdl.jaylee.us update drivefile "$folder_id" newfilename "READYTOSIGN ${folder_number}"
|
||||
export signed_folder="SIGNED ${folder_number}"
|
||||
zero_results="gam-win-signer@pdl.jaylee.us,0"
|
||||
while true; do
|
||||
result_counts=$($gam user gam-win-signer@pdl.jaylee.us print filelist query "name = '${signed_folder}' and '1Xz3hYq4Mfa_r6D8EcBZHLDtHDFurYSvp' in parents and mimeType = 'application/vnd.google-apps.folder'" countsonly)
|
||||
echo "$result_counts"
|
||||
if [[ ! "$result_counts" =~ "$zero_results" ]]; then
|
||||
echo "looks like we have results"
|
||||
break
|
||||
fi
|
||||
echo "no results, sleeping 10..."
|
||||
sleep 10
|
||||
done
|
||||
# download signed package
|
||||
$gam user gam-win-signer@pdl.jaylee.us print filelist query "name = '${signed_folder}' and '1Xz3hYq4Mfa_r6D8EcBZHLDtHDFurYSvp' in parents and mimeType = 'application/vnd.google-apps.folder'" id | $gam csv - gam user gam-win-signer@pdl.jaylee.us print filelist query "'~~id~~' in parents and name contains '.msi'" id | $gam csv - gam user gam-win-signer@pdl.jaylee.us get drivefile ~id targetfolder "$GITHUB_WORKSPACE" targetname "$MSI_FILENAME" overwrite true acknowledgeabuse true
|
||||
# delete signed folder on drive
|
||||
$gam user gam-win-signer@pdl.jaylee.us print filelist query "name = '${signed_folder}' and '1Xz3hYq4Mfa_r6D8EcBZHLDtHDFurYSvp' in parents and mimeType = 'application/vnd.google-apps.folder'" id | $gam csv - gam user gam-win-signer@pdl.jaylee.us trash drivefile "~id"
|
||||
#"/c/Program Files (x86)/Windows Kits/10/bin/10.0.22621.0/x64/signtool.exe" verify /v /pa "$MSI_FILENAME"
|
||||
write-Host "Signing ${env:MSI_FILENAME}...."
|
||||
# Always explicitely use x64 version os signtool.exe, arm64 version apparently can't
|
||||
# see Certum certs since SimplySignDesktop is x64-only today.
|
||||
Start-Process -Wait -NoNewWindow -ErrorAction Continue -FilePath 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe' -ArgumentList "sign", "/sha1", "$env:WINDOWS_CODESIGN_CERT_HASH", "/tr", "http://time.certum.pl", "/td", "SHA256", "/fd", "SHA256", "/v", "$env:MSI_FILENAME"
|
||||
write-Host "Verifying signature of ${env:MSI_FILENAME}...."
|
||||
# verify signature. If we failed to sign we should fail to verify and die.
|
||||
& 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe' verify /pa /v "$env:MSI_FILENAME"
|
||||
|
||||
- name: Attest that gam package files were generated from this Action
|
||||
uses: actions/attest-build-provenance@v1
|
||||
uses: actions/attest-build-provenance@0b6e9809265278d02c58acf52849a95818a5a306 # v3.0.0
|
||||
if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && matrix.goal == 'build'
|
||||
with:
|
||||
subject-path: |
|
||||
@@ -730,7 +739,7 @@ jobs:
|
||||
gam*.msi
|
||||
|
||||
- name: Archive production artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # 4.6.2
|
||||
if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && matrix.goal != 'test'
|
||||
with:
|
||||
name: gam-binaries-${{ env.GAMOS }}-${{ env.arch }}-${{ matrix.jid }}
|
||||
@@ -738,6 +747,7 @@ jobs:
|
||||
gam*.tar.xz
|
||||
gam*.zip
|
||||
gam*.msi
|
||||
*.png
|
||||
|
||||
- name: Basic Tests build jobs only
|
||||
if: matrix.goal != 'test' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||
@@ -810,7 +820,7 @@ jobs:
|
||||
echo "Created shared drive ${driveid}"
|
||||
$gam create user $newuser firstname GHA lastname $JID displayname "Github Actions ${JID}" password random recoveryphone 12125121110 recoveryemail jay0lee@gmail.com gha.jid $JID languages en+,en-GB- ou "${newou}"
|
||||
$gam user $newuser add license workspaceenterpriseplus
|
||||
$gam user $newuser update photo https://dummyimage.com/400x600/000/fff
|
||||
$gam user $newuser update photo https://dummyimage.com/98x98/000/fff.jpg
|
||||
$gam user $newuser get photo
|
||||
$gam user $newuser delete photo
|
||||
$gam create alias $newalias user $newuser
|
||||
@@ -830,9 +840,10 @@ jobs:
|
||||
$gam config enable_dasa false save
|
||||
# 9/17/24 temp disable due to Google API sluggishness to see new users for admin commands
|
||||
# $gam create admin $newuser _GROUPS_EDITOR_ROLE CUSTOMER # condition nonsecuritygroup
|
||||
$gam create admin $newgroup _HELP_DESK_ADMIN_ROLE org_unit "${newou}"
|
||||
$gam config csv_output_row_filter "assignedToUser:regex:${newuser}" print admins | $gam csv - gam delete admin "~roleAssignmentId"
|
||||
$gam config csv_output_row_filter "assignedToGroup:regex:${newgroup}" print admins | $gam csv - gam delete admin "~roleAssignmentId"
|
||||
# 9/13/25 temp disable due to hangs
|
||||
# $gam create admin $newgroup _HELP_DESK_ADMIN_ROLE org_unit "${newou}"
|
||||
# $gam config csv_output_row_filter "assignedToUser:regex:${newuser}" print admins | $gam csv - gam delete admin "~roleAssignmentId"
|
||||
# $gam config csv_output_row_filter "assignedToGroup:regex:${newgroup}" print admins | $gam csv - gam delete admin "~roleAssignmentId"
|
||||
$gam config enable_dasa false save
|
||||
$gam csv sample.csv gam create user ~~email~~ firstname "GHA Bulk" lastname ~~email~~ gha.jid $JID ou "${newou}"
|
||||
$gam csv sample.csv gam update user ~~email~~ recoveryphone 12125121110 recoveryemail jay0lee@gmail.com password random displayname "GitHub Actions Bulk ${JID}"
|
||||
@@ -857,7 +868,7 @@ jobs:
|
||||
$gam user $newuser show labels > labels.txt
|
||||
$gam user $gam_user importemail subject "GHA import $newbase" message "This is a test import" labels IMPORTANT,UNREAD,INBOX,STARRED
|
||||
$gam user $gam_user insertemail subject "GHA insert $newbase" file gam.py labels INBOX,UNREAD # yep body is gam code
|
||||
$gam user $gam_user sendemail subject "GHA send $gam_user $newbase" file gam.py recipient admin@pdl.jaylee.us
|
||||
$gam user $gam_user sendemail recipient admin@pdl.jaylee.us subject "GHA send $gam_user $newbase" file gam.py
|
||||
$gam user $gam_user draftemail subject "GHA draft $newbase" message "Draft message test"
|
||||
$gam csvfile sample.csv:email waitformailbox retries 20
|
||||
$gam user $newuser delegate to "${newbase}-bulkuser-1" || if [ $? != 50 ]; then exit $?; fi # expect a 50 return code (delegation failed)
|
||||
@@ -920,7 +931,7 @@ jobs:
|
||||
$gam config enable_dasa true save
|
||||
$gam print users query "gha.jid=$JID" | $gam csv - gam delete user ~primaryEmail || if [ $? != 50 ]; then exit $?; fi # expect a 50 return code (vault hold on user)
|
||||
$gam print mobile
|
||||
$gam print devices
|
||||
$gam print devices clientstates
|
||||
$gam print browsers
|
||||
$gam print cros allfields orderby serialnumber
|
||||
$gam show crostelemetry storagepercentonly
|
||||
@@ -978,7 +989,7 @@ jobs:
|
||||
packages: write
|
||||
steps:
|
||||
- name: Merge Artifacts
|
||||
uses: actions/upload-artifact/merge@v4
|
||||
uses: actions/upload-artifact/merge@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: gam-binaries
|
||||
pattern: gam-binaries-*
|
||||
@@ -994,16 +1005,16 @@ jobs:
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # 5.0.0
|
||||
|
||||
- name: VirusTotal Scan
|
||||
uses: crazy-max/ghaction-virustotal@v4
|
||||
uses: crazy-max/ghaction-virustotal@d34968c958ae283fe976efed637081b9f9dcf74f # 4.2.0
|
||||
with:
|
||||
vt_api_key: ${{ secrets.VT_API_KEY }}
|
||||
files: |
|
||||
@@ -1016,12 +1027,14 @@ jobs:
|
||||
echo "Date version: ${dateversion}"
|
||||
echo "dateversion=${dateversion}" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: "marvinpinto/action-automatic-releases@latest"
|
||||
name: Publish draft release
|
||||
- name: Publish draft release
|
||||
uses: softprops/action-gh-release@fbadcc90e88ecface60a0a0d123795b784ceb239 # v2.3.2
|
||||
with:
|
||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
automatic_release_tag: "${{ steps.dateversion.outputs.dateversion }}"
|
||||
prerelease: false
|
||||
draft: true
|
||||
prerelease: false
|
||||
tag_name: "${{ steps.dateversion.outputs.dateversion }}"
|
||||
fail_on_unmatched_files: true
|
||||
files: |
|
||||
gam-binaries/*
|
||||
|
||||
|
||||
|
||||
4
.github/workflows/codeql-analysis.yml
vendored
4
.github/workflows/codeql-analysis.yml
vendored
@@ -39,9 +39,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
|
||||
6
.github/workflows/get-cacerts.yml
vendored
6
.github/workflows/get-cacerts.yml
vendored
@@ -13,13 +13,13 @@ on:
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
working-directory: src
|
||||
working-directory: src/gam
|
||||
|
||||
jobs:
|
||||
check-apis:
|
||||
check-certs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token
|
||||
fetch-depth: 0 # otherwise, you will failed to push refs to dest repo
|
||||
|
||||
6
.github/workflows/pushwiki.yml
vendored
6
.github/workflows/pushwiki.yml
vendored
@@ -5,6 +5,8 @@ on:
|
||||
push:
|
||||
paths:
|
||||
- 'wiki/**'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
pushwiki:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -16,7 +18,7 @@ jobs:
|
||||
git clone https://github.com/GAM-team/GAM
|
||||
|
||||
- name: Checkout Wiki source
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
with:
|
||||
path: GAM.wiki
|
||||
repository: GAM-team/GAM.wiki
|
||||
@@ -35,7 +37,7 @@ jobs:
|
||||
cd GAM.wiki
|
||||
git config --local user.email "action@github.com"
|
||||
git config --local user.name "GitHub Action"
|
||||
git add *.md
|
||||
git add -A
|
||||
git commit -m "[no ci] Push Wiki changes"
|
||||
git status
|
||||
git push
|
||||
|
||||
2
.github/workflows/pypi.yml
vendored
2
.github/workflows/pypi.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
id-token: write
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
# See https://pre-commit.com for more information
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v2.5.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: double-quote-string-fixer
|
||||
- id: check-yaml
|
||||
- id: check-docstring-first
|
||||
- id: name-tests-test
|
||||
- id: requirements-txt-fixer
|
||||
- id: check-merge-conflict
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-yapf
|
||||
rev: v0.30.0
|
||||
hooks:
|
||||
- id: yapf
|
||||
args: [--style=google, --in-place]
|
||||
|
||||
- repo: https://github.com/PyCQA/pylint
|
||||
rev: pylint-2.5.0
|
||||
hooks:
|
||||
- id: pylint
|
||||
args: [--output-format=colorized]
|
||||
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.31.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py37-plus]
|
||||
@@ -18,6 +18,11 @@ this will download GAM, install it and start setup.
|
||||
|
||||
Download the MSI Installer from the [GitHub Releases] page. Install the MSI and you'll be prompted to setup GAM.
|
||||
|
||||
## Use your own Python
|
||||
If you'd prefer to install GAM as a Python package you can install with pip:
|
||||
```
|
||||
pip install gam7
|
||||
```
|
||||
# Documentation
|
||||
|
||||
The GAM documentation is hosted in the [GitHub Wiki]
|
||||
|
||||
@@ -7,8 +7,10 @@ authors = [
|
||||
{ name="Jay Lee", email="jay0lee@gmail.com" },
|
||||
{ name="Ross Scroggs", email="Ross.Scroggs@gmail.com" },
|
||||
]
|
||||
# # The following files should be edited to match: setup.cfg, requirements.txt
|
||||
# notice that yubikey-manager remains optional further down since it is less command and adds
|
||||
#significant compile dependencies.
|
||||
dependencies = [
|
||||
"arrow>=1.3.0",
|
||||
"chardet>=5.2.0",
|
||||
"cryptography>=44.0.2",
|
||||
"distro; sys_platform=='linux'",
|
||||
@@ -17,12 +19,11 @@ dependencies = [
|
||||
"google-auth-httplib2>=0.2.0",
|
||||
"google-auth-oauthlib>=1.2.2",
|
||||
"google-auth>=2.39.0",
|
||||
"httplib2>=0.22.0",
|
||||
"httplib2>=0.31.0",
|
||||
"lxml>=5.4.0",
|
||||
"passlib>=1.7.4",
|
||||
"pathvalidate>=3.2.3",
|
||||
"python-dateutil",
|
||||
"yubikey-manager>=5.6.1",
|
||||
"pysocks>=1.7.1",
|
||||
]
|
||||
description = "CLI tool to manage Google Workspace"
|
||||
readme = "README.md"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,549 @@
|
||||
7.23.00
|
||||
|
||||
Added `chat_max_results` variable to `gam.cfg`.
|
||||
```
|
||||
chat_max_results
|
||||
When retrieving lists of Chat items from API,
|
||||
how many should be retrieved in each API call
|
||||
Default: 100
|
||||
Range: 1 - 1000
|
||||
```
|
||||
Previously, this vaule was always set to 1000 which could cause errors.
|
||||
|
||||
7.22.07
|
||||
|
||||
Added options `showdetails` and `returnidonly` to `gam create|copy vaultquery`.
|
||||
|
||||
Added option `<JSONData>` to `gam create vaultexport|vaultquery` and `gam print vaultcounts`.
|
||||
|
||||
7.22.06
|
||||
|
||||
Added commands to create, copy and delete Vault saved queries.
|
||||
```
|
||||
gam create vaultquery <MatterItem> [name <String>]
|
||||
corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
|
||||
[scope all_data|held_data|unprocessed_data]
|
||||
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
(documentids (<DriveFileIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
(shareddrives|teamdrives (<SharedDriveIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
[(includeshareddrives <Boolean>)|(shareddrivesoption included|included_if_account_is_not_a_member|not_included)]
|
||||
(sitesurl (<URLList>||(select <FileSelector>|<CSVFileSelector>)))
|
||||
[driveversiondate <Date>|<Time>]
|
||||
[includerooms <Boolean>]
|
||||
(rooms (<ChatSpaceList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
|
||||
[locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
|
||||
[responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
|
||||
(covereddata calllogs|textmessages|voicemails)*
|
||||
[shownames] [formatjson]
|
||||
|
||||
gam copy vaultquery <MatterItem> <QueryItem> [targetmatter <MatterItem>] [name <String>]
|
||||
[shownames] [formatjson]
|
||||
|
||||
gam delete vaultquery <QueryItem> matter <MatterItem>
|
||||
gam delete vaultquery <MatterItem> <QueryItem>
|
||||
```
|
||||
|
||||
Added a variant of `gam print vaultcounts` that gets its query parameters from a saved Vault query.
|
||||
```
|
||||
gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
matter <MatterItem> <QueryItem>
|
||||
[wait <Integer>]
|
||||
```
|
||||
|
||||
7.22.05
|
||||
|
||||
Added a variant of `gam create vaultexport` that gets its query parameters from a saved Vault query.
|
||||
|
||||
```
|
||||
gam create vaultexport|export matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[driveclientsideencryption any|encrypted|unencrypted]
|
||||
[includeaccessinfo <Boolean>]
|
||||
[excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
|
||||
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
[format ics|mbox|pst|xml]
|
||||
[region any|europe|us] [showdetails|returnidonly]
|
||||
```
|
||||
|
||||
7.22.04
|
||||
|
||||
Added a variant of `gam create vaulthold` that gets its parameters from a saved Vault query.
|
||||
```
|
||||
gam create vaulthold matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[showdetails|returnidonly]
|
||||
```
|
||||
|
||||
7.22.03
|
||||
|
||||
Fix backwards compatability bug introduced in 7.22.00 for `gam print users` that changed `suspended`
|
||||
from a field name to a query option; it is now correctly interpreted as a field name.
|
||||
|
||||
7.22.02
|
||||
|
||||
An update to the httplib2 library caused GAM proxy connections to fail; this has been fixed
|
||||
by including the pysocks library needed by the latest httplib2 library.
|
||||
|
||||
7.22.00
|
||||
|
||||
Expanded `<UserTypeEntity>` to allow specification of non-archived/archived users.
|
||||
* See [Collections of Users](Collections-of-Users)
|
||||
|
||||
These commands have been updated:
|
||||
* `gam print aliases`
|
||||
* `gam update groups`
|
||||
* `gam info orgs`
|
||||
* `gam print orgs`
|
||||
* `gam print users`
|
||||
|
||||
Added `datetime <DateTimeFormat>` command that can be embedded in Gam batch files. The current time is formatted with `<DateTimeFormat>`
|
||||
and subsequent lines in `<BatchContent>` will have `%datetime%` replaced with the formatted time value.
|
||||
|
||||
See: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes
|
||||
|
||||
7.21.03
|
||||
|
||||
Added option `notifyrecoveryemail` to `gam create user` and `gam <UserTypeEntity> update user password <String>`
|
||||
that sends the passsword notification email to the user's recovery email address (if defined).
|
||||
|
||||
7.21.02
|
||||
|
||||
GAM now builds on macOS 26 Tahoe and properly identifies the OS.
|
||||
|
||||
A custom build of the cryptography library is no longer needed for Windows arm64 builds as the project now releases their own build for the OS.
|
||||
|
||||
Upgrade to OpenSSL 3.5.3 latest
|
||||
|
||||
7.21.01
|
||||
|
||||
Replaced datetime, dateutil, calendar and iso8601 Python libraries with arrow library.
|
||||
This should have no performance impact; report any problems.
|
||||
|
||||
You can now use timezone names when setting `timezone` in `gam.cfg`.
|
||||
* See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||
```
|
||||
gam config timezone America/Los_Angeles save
|
||||
```
|
||||
|
||||
7.20.04
|
||||
|
||||
Cleaned up Python library imports: googleapiclient, iso8601.
|
||||
|
||||
7.20.03
|
||||
|
||||
Rebranded license SKU `1010470004` from `Gemini Education` to `Google AI Pro for Education`.
|
||||
|
||||
Additional updates to student groups in Google Classroom.
|
||||
|
||||
7.20.02
|
||||
|
||||
Upgraded `gam create course-studentgroups` to allow specification of multiple student group titles;
|
||||
multiple student groups can be created in a single command.
|
||||
* `((title <String>)|(select <StringEntity))+`
|
||||
|
||||
7.20.01
|
||||
|
||||
Added option `showaccesssettings` to `gam [<UserTypeEntity>] print|show chatspaces`. When listing
|
||||
Chat Spaces, the Chat API does not return the `accessSettings` field; if you need to see this field,
|
||||
add `showaccesssettings` to the command. This requires an additional Chat API call per chat space of type `SPACE`
|
||||
to get the `accessSettings` field.
|
||||
|
||||
7.20.00
|
||||
|
||||
Added initial support for student groups in Google Classroom. This is a work in progress and requires Developer Preview membership.
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Classroom-StudentGroups#notes
|
||||
|
||||
7.19.03
|
||||
|
||||
Fixed bug where specifying a `<UserItem>` as `id:1234567890` could lead to errors like this:
|
||||
```
|
||||
ERROR: 400: invalidArgument - Resource name has invalid email.
|
||||
```
|
||||
|
||||
7.19.02
|
||||
|
||||
Update `gam info user <UserItem>` to eliminate 5 second delay when getting license info.
|
||||
|
||||
Additional information:
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Licenses#info-user-performance
|
||||
|
||||
7.19.01
|
||||
|
||||
Updated `gam <UserTypeEntity> print|show signature` to handle the following error
|
||||
that occurs when an alias is specified.
|
||||
```
|
||||
ERROR: 404: notFound - Requested entity was not found.
|
||||
```
|
||||
|
||||
7.19.00
|
||||
|
||||
Eliminated `drive_v3_beta` and `meet_v2_beta` from `gam.cfg` as the API betas are no longer used.
|
||||
|
||||
Updated `Meet API` scopes so that GAM can read metadata about additional Meet spaces.
|
||||
```
|
||||
[*] 34) Meet API - Manage/Display Meeting Spaces
|
||||
[*] 35) Meet API - Read Meeting Spaces metadata
|
||||
```
|
||||
|
||||
7.18.07
|
||||
|
||||
Updated `gam <UserTypeEntity> print drivelastmodification` to put `addcsvdata` columns
|
||||
after `User,id,name` rather than after the last column.
|
||||
|
||||
7.18.06
|
||||
|
||||
Updated `gam <UserTypeEntity> delete|modify messages` to improve the handling
|
||||
of the following error.
|
||||
```
|
||||
quotaExceeded - User-rate limit exceeded
|
||||
```
|
||||
|
||||
7.18.05
|
||||
|
||||
Added support for Inbound SSO OIDC profiles.
|
||||
|
||||
Currently, if you enter `gam select <SectionName>` and nothing else on the command line,
|
||||
GAM performs no action. Now, it will be treated as if you entered:
|
||||
`gam select <SectionName> save`
|
||||
|
||||
Updated to Python 3.13.7.
|
||||
|
||||
7.18.04
|
||||
|
||||
Added commands to display/manage Alert Center Pub/Sub notifications.
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Alert-Center#configuring-settings
|
||||
|
||||
7.18.03
|
||||
|
||||
Updated `gam oauth create` to give a warning if the number of selected scopes will
|
||||
probably cause Google to generate a "Something went wrong" error.
|
||||
|
||||
7.18.02
|
||||
|
||||
Upgraded to OpenSSL 3.5.2.
|
||||
|
||||
7.18.01
|
||||
|
||||
Added option `nosystemroles` to `gam print|show adminroles` that causes GAM
|
||||
to only display non-system roles.
|
||||
|
||||
Added option `formatjson` to `gam info|print|show adminroles`; this will be most useful
|
||||
when the `privileges` option is used.
|
||||
|
||||
Updated `gam create|update adminrole` to allow specification of privileges with
|
||||
JSON data: `privileges <JSONData>`. These two updates make it easier to copy admin roles.
|
||||
|
||||
Updated `gam create|update adminrole` to allow output of the created/updated
|
||||
role data in CSV format; by default, GAM displays `<RoleName>(<RoleID>) created|updated`.
|
||||
```
|
||||
csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]] (addcsvdata <FieldName> <String>)*
|
||||
```
|
||||
|
||||
7.18.00
|
||||
|
||||
Added commands to display Business Profile Accounts.
|
||||
These are special purpose commands and will not generally be used.
|
||||
```
|
||||
gam show businessprofileaccounts
|
||||
gam print businessprofileaccounts [todrive <ToDriveAttribute>*]
|
||||
```
|
||||
|
||||
7.17.03
|
||||
|
||||
Fixed bug in `gam <UserItem> print|show chatspaces asadmin fields <ChatSpaceFieldNameList>` that caused a trap
|
||||
when `displayname` was not in `<ChatSpaceFieldNameList>`.
|
||||
|
||||
7.17.02
|
||||
|
||||
Updated `gam <UserTypeEntity> print|show webmastersites` to handle the following error
|
||||
that occurs if you haven't updated your project to include the Google Search Console API.
|
||||
```
|
||||
ERROR: 403: permissionDenied - Google Search Console API has not been used in project 111055363999 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/searchconsole.googleapis.com/overview?project=111055363999 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
|
||||
```
|
||||
|
||||
7.17.01
|
||||
|
||||
Fixed bug in `gam <UserTypeEntity> show webmastersites` that caused a trap.
|
||||
|
||||
7.17.00
|
||||
|
||||
Added commands to discover Sites and WebResources that managed users (previously unmanaged) may have access to for better governance and visibility.
|
||||
These are special purpose commands and will not generally be used.
|
||||
```
|
||||
gam <UserTypeEntity> show webresources
|
||||
gam <UserTypeEntity> print webresources [todrive <ToDriveAttribute>*]
|
||||
gam <UserTypeEntity> show webmastersites
|
||||
gam <UserTypeEntity> print webmastersites [todrive <ToDriveAttribute>*]
|
||||
```
|
||||
|
||||
7.16.01
|
||||
|
||||
The Drive API now supports setting download restrictions on individual files.
|
||||
|
||||
Added `downloadrestictions` and `<DriveDownloadRestrictionsSubfieldName>` to `<DriveFieldName>`.
|
||||
```
|
||||
<DriveDownloadRestrictionsSubfieldName> ::=
|
||||
downloadrestrictions.itemdownloadrestriction|
|
||||
downloadrestrictions.effectivedownloadrestrictionwithcontext
|
||||
```
|
||||
|
||||
Added `itemdownloadrestriction restrictedforreaders|restrictedforwriters [<Boolean>]`
|
||||
to `<DriveFileAttribute>`.
|
||||
|
||||
From the Drive API documentation:
|
||||
```
|
||||
itemDownloadRestriction - The download restriction of the file applied directly by the owner or organizer. This does not take into account shared drive settings or DLP rules.
|
||||
effectiveDownloadRestrictionWithContext - Output only. The effective download restriction applied to this file. This considers all restriction settings and DLP rules.
|
||||
restrictedForReaders - Whether download and copy is restricted for readers.
|
||||
restrictedForWriters - Whether download and copy is restricted for writers. If true, download is also restricted for readers.
|
||||
```
|
||||
|
||||
7.16.00
|
||||
|
||||
Removed `drive_v3_native_names` from `gam.cfg`; GAM now only uses Drive API v3 fields names on output.
|
||||
If you had `drive_v3_native_names = False` in `gam.cfg` or are updating from Legacy GAM:
|
||||
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Drive-REST-API-v3
|
||||
|
||||
7.15.01
|
||||
|
||||
Added `downloadrestrictions.restrictedforreaders` and `downloadrestrictions.restrictedforwriters`
|
||||
to `<SharedDriveRestrictionsSubfieldName>`; previously, only the abbreviations `downloadrestrictedforreaders`
|
||||
and `downloadrestrictedforwriters` were supported (they are still supported).
|
||||
|
||||
Updated `gam <UserTypeEntity> copy drivefile` to handle unexpected data returned by Google that caused a trap.
|
||||
|
||||
7.15.00
|
||||
|
||||
Updated `gam print shareddriveorganizers` to make `shownoorganizerdrives` default to `True`
|
||||
as documented; it was defaulting to `False`.
|
||||
|
||||
Cleaned up code for processing Python dictionary structures; this should have no noticable effect.
|
||||
|
||||
7.14.04
|
||||
|
||||
Fixed bug in `gam print|show cigroups cimember <UserItem>` that generated the following error:
|
||||
```
|
||||
ERROR: Cloud Identity Group: groups/-, Print Failed: Error(4013): Insufficient permissions to retrieve memberships.
|
||||
```
|
||||
|
||||
Updated `gam <UserTypeEntity> update user suspended off` and `gam <UserTypeEntity> unsuspend users`
|
||||
to handle the following error that occurs when trying to unsuspend a user that has been suspended for abuse.
|
||||
```
|
||||
ERROR: 412: adminCannotUnsuspend - Cannot restore a user suspended for abuse.
|
||||
```
|
||||
|
||||
* See: https://support.google.com/a/answer/1110339
|
||||
|
||||
7.14.03
|
||||
|
||||
Fixed bug in `gam print cigroup-members includederivedmembership` that caused a trap.
|
||||
|
||||
7.14.02
|
||||
|
||||
Fixed bug in `gam print|show cigroups|cigroups-members cimember <UserItem>` that generated the following error:
|
||||
```
|
||||
Cloud Identity Group Print Failed: Request contains an invalid argument.
|
||||
```
|
||||
|
||||
7.14.01
|
||||
|
||||
Don't install yubikey library via pip by default. To install with yubikey support use pip install gam7[yubikey]
|
||||
|
||||
7.14.00
|
||||
|
||||
Added commands to display Google Tag Manager accounts, containers, workspaces, tags and user permissions.
|
||||
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Users-Tag-Manager
|
||||
|
||||
7.13.03
|
||||
|
||||
Added option `csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]]]`
|
||||
to `gam create chromeprofilecommand` so that command details are displayed in CSV format.
|
||||
|
||||
Added option `commands <ChromeProfileCommandNameList>|<FileSelector>|<CSVFileSelector>` to `<ChromeProfileNameEntity>`
|
||||
so that `gam print|show chromeprofilecommands` can directly display the commands generated by
|
||||
`gam create chromeprofilecommand` with the `csv` option.
|
||||
|
||||
7.13.02
|
||||
|
||||
Fixed bug in `gam create chromeprofilecommand` where `select|filter` were not recognized.
|
||||
|
||||
Updated `gam create datatransfer <OldOwnerID> datastudio <NewOwnerID>` that generated the following
|
||||
error due to an unhandled API change.
|
||||
```
|
||||
ERROR: Invalid choice (google data studio): Expected <calendar|looker studio|drive and docs>
|
||||
```
|
||||
|
||||
7.13.01
|
||||
|
||||
Enhanced `gam create|print|show chromeprofilecommand` to allow specification
|
||||
of multiple Chrome browser profiles rather than just one.
|
||||
```
|
||||
<ChromeProfilePermanentID> ::= <String>
|
||||
<ChromeProfileName> ::= customers/<CustomerID>/profiles/<ChromeProfilePermanentID> | <ChromeProfilePermanentID>
|
||||
<ChromeProfileNameList> ::= "<ChromeProfileName>(,<ChromeProfileName>)*"
|
||||
<ChromeProfileNameEntity> ::=
|
||||
<ChromeProfileNameList> |
|
||||
(select <FileSelector>|<CSVFileSelector>) |
|
||||
(filter <String> (filtertime<String> <Time>)* [orderby <ChromeProfileOrderByFieldName> [ascending|descending]])
|
||||
|
||||
gam create|print_show chromeprofilecommand <ChromeProfileNameEntity>
|
||||
```
|
||||
|
||||
7.13.00
|
||||
|
||||
Added commands that send remote commands to Chrome browser profiles and display the results;
|
||||
at the moment, these commands can clear the browser cache and cookies.
|
||||
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Chrome-Profile-Management#create-a-chrome-profile-command
|
||||
|
||||
7.12.02
|
||||
|
||||
Updated `gam print users` to handle the following error:
|
||||
```
|
||||
ERROR: 503: serviceNotAvailable - The service is currently unavailable
|
||||
```
|
||||
|
||||
7.12.01
|
||||
|
||||
Added support for `plan free` in `gam create resoldsubscription`.
|
||||
|
||||
* The free plan is exclusive to the Cloud Identity SKU and does not incur any billing.
|
||||
|
||||
7.12.00
|
||||
|
||||
Started updated handling of missing scopes messages in client access commands;
|
||||
this is a work in progress.
|
||||
|
||||
Updated `gam info|show shareddrive` to handle changes in the Drive API that caused traps.
|
||||
|
||||
Added `downloadrestrictedforreaders` and `downloadrestrictedforwriters` to
|
||||
`<SharedDriveRestrictionsSubfieldName>` to support new Shared Drive restrictions.
|
||||
|
||||
Updated `gam course <CourseID> create|update announcement` to accept input from
|
||||
a literal string, a file or a Google Doc.
|
||||
```
|
||||
<CourseAnnouncementContent> ::=
|
||||
((text <String>)|
|
||||
(textfile <FileName> [charset <Charset>])|
|
||||
(gdoc <UserGoogleDoc>)|
|
||||
(gcsdoc <StorageBucketObjectName>))
|
||||
```
|
||||
|
||||
Added command `gam check suspended <UserItem>` that checks the suspension status of a user
|
||||
and sets the return code to 0 if the user is not suspended or 26 if it is.
|
||||
```
|
||||
$ gam check suspended testok@domain.com
|
||||
User: testok@domain.com, Account Suspended: False
|
||||
$ echo $?
|
||||
0
|
||||
|
||||
$ gam check suspended testsusp@domain.com
|
||||
User: testsusp@domain.com, Account Suspended: True, Suspension Reason: ADMIN
|
||||
$ echo $?
|
||||
26
|
||||
```
|
||||
|
||||
Updated `gam <UserTypeEntity> sendemail` to verify that one of `recipient|to|from`
|
||||
immediately follows `sendemail`.
|
||||
|
||||
7.11.00
|
||||
|
||||
Added commands to manage classroom/course announcements.
|
||||
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Classroom-Courses#manage-course-announcements
|
||||
|
||||
Upgraded to OpenSSL 3.5.1.
|
||||
|
||||
7.10.10
|
||||
|
||||
Added choices `text` and `hyperlink` to option `showwebviewlink` in `gam [<UserTypeEntity>] print|show shareddrives`.
|
||||
* `showwebviewlink text` - Displays `https://drive.google.com/drive/folders/<SharedDriveID>`
|
||||
* `showwebviewlink hyperlink` - Displays `=HYPERLINK("https://drive.google.com/drive/folders/<SharedDriveID>", "<SharedDriveName>")`
|
||||
|
||||
7.10.09
|
||||
|
||||
Added option `showwebviewlink` to `gam [<UserTypeEntity>] print|show shareddrives` that
|
||||
displays the web view link for the Shared Drive: `https://drive.google.com/drive/folders/<SharedDriveID>`.
|
||||
|
||||
7.10.08
|
||||
|
||||
Fixed bug in commands that modify messages where the `labelids <LabelIdList>` option
|
||||
could not be used unless one of these options was also specified: `query`, `matchlabel`, `ids`;
|
||||
it can be now be used by itself.
|
||||
|
||||
7.10.07
|
||||
|
||||
Updated `gam <UserTypeEntity> copy|move drivefile` to hanndle additional instances of
|
||||
the `cannotModifyInheritedPermission` error.
|
||||
|
||||
Added license SKU `Google AI Ultra for Business`
|
||||
* ProductID - 101047
|
||||
* SKUID - 1010470008 | geminiultra
|
||||
|
||||
7.10.06
|
||||
|
||||
Added option `clientstates` to `gam print devices` to include client states in device output.
|
||||
|
||||
7.10.05
|
||||
|
||||
Google renamed an error: `cannotModifyInheritedTeamDrivePermission` became `cannotModifyInheritedPermission`.
|
||||
GAM will now handle the new error.
|
||||
|
||||
7.10.04
|
||||
|
||||
Updated `gam report <ActivityApplicationName>` to accept accept application names as defined
|
||||
in the Reports API discovery document; this means that GAM does not have to be updated when
|
||||
Google defines a new application name.
|
||||
|
||||
`gemini_in_workspace_apps` is now available in `gam report`.
|
||||
|
||||
7.10.03
|
||||
|
||||
Fixed bug in commands that modify messages where the `labelids <LabelIdList>` option
|
||||
was not being applied.
|
||||
|
||||
7.10.02
|
||||
|
||||
Added option `labelids <LabelIdList>` to all commands that process messages;
|
||||
this option causes GAM to only return messages with labels that match all of the specified label IDs.
|
||||
|
||||
Updated `gam <UserTypeEntity> print|show forms` to always display `isPublished` and
|
||||
`isAcceptingResponses` in `publishSettings/publishState` regardless of their value;
|
||||
the API doesn't return these values when they are False.
|
||||
|
||||
7.10.01
|
||||
|
||||
Added options `ispublished [<Boolean>]` and `isacceptingresponses [<Boolean>]` to
|
||||
`gam <UserTypeEntity> create|update form`.
|
||||
|
||||
7.10.00
|
||||
|
||||
Added commands to manage/display Chat Custom Emojis.
|
||||
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Users-Chat#manage-chat-emojis
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Users-Chat#display-chat-emojis
|
||||
|
||||
Updated `gam <UserItem> print|show chatspaces|chatmembers asadmin` to display
|
||||
the spaces in ascending display name order.
|
||||
|
||||
7.09.07
|
||||
|
||||
Added `webviewlink` to `<FileTreeFieldName>` for use in `gam <UserTypeEntity> print|show filetree`.
|
||||
|
||||
7.09.06
|
||||
|
||||
Upddated `gam print|show shareddrives`, `gam print|show shareddriveacls`, `gam print shareddriveorganizers`
|
||||
to display the Shared Drives in ascending name order; the API returns them in an unidentifiable order.
|
||||
|
||||
7.09.05
|
||||
|
||||
Improved output of `gam info|show chromeschemas [std]` to more accurately display the schemas.
|
||||
|
||||
Fixed bugs in `gam update chromepolicy` that caused invalid error messaages.
|
||||
|
||||
7.09.04
|
||||
|
||||
Fixed bug in `gam whatis <EmailItem>` where the check for an invitable user always failed.
|
||||
@@ -12655,7 +13201,7 @@ gam <UserTypeEntity> update teamdrive <TeamDriveEntity> [adminaccess|asadmin] [n
|
||||
Updated gam report users to support new orgUnitID argument in Reports API.
|
||||
|
||||
gam report users|user [todrive <ToDriveAttribute>*] [date <Date>] [nodatechange | (fulldatarequired all|<ReportsAppList>)]
|
||||
[(user all|<UserItem>)|(orgunit|org|ou <OrgUnitPath>)|(select <UserTypeEntity>)] (filtertime.* <Time>)* [filter|filters <String>] [fields|parameters <String>]
|
||||
[(user all|<UserItem>)|(orgunit|org|ou <OrgUnitPath>)|(select <UserTypeEntity>)] (filtertime<String> <Time>)* [filter|filters <String>] [fields|parameters <String>]
|
||||
[maxactivities <Number>] [maxresults <Number>]
|
||||
|
||||
Select the users for whom information is desired.
|
||||
@@ -13246,15 +13792,15 @@ gam print cros query "sync:#querytime1#.." querytime1 -30d
|
||||
For example, to print information about CrOS devices synced between 45 days ago and 30 days ago:
|
||||
gam print cros query "sync:#querytime1#..#querytime2#" querytime1 -45d querytime2 -30d
|
||||
|
||||
Added filtertime.* <Time> option to gam report to allow times, usually relative, to be substituted into the filter <String> option.
|
||||
The filtertime.* value replaces the string #filtertime.*# in the filter <String>.
|
||||
Added filtertime<String> <Time> option to gam report to allow times, usually relative, to be substituted into the filter <String> option.
|
||||
The filtertime<String> value replaces the string #filtertime<String># in the filter <String>.
|
||||
The characters following filtertime can be any combination of lowercase letters and numbers.
|
||||
gam report users|user [todrive <ToDriveAttribute>*] [date <Date>] [nodatechange | (fulldatarequired all|<ReportsAppList>)]
|
||||
[(user all|<UserItem>)|(select <UserTypeEntity>)] (filtertime.* <Time>)* [filter|filters <String>] [fields|parameters <String>]
|
||||
[(user all|<UserItem>)|(select <UserTypeEntity>)] (filtertime<String> <Time>)* [filter|filters <String>] [fields|parameters <String>]
|
||||
[maxactivities <Number>] [maxresults <Number>]
|
||||
gam report admin|calendar|calendars|drive|docs|doc|gplus|groups|group|logins|login|mobile|rules|tokens|token [todrive <ToDriveAttribute>*] [maxresults <Number>] [maxactivities <Number>]
|
||||
[([start <Time>] [end <Time>])|yesterday] [(user all|<UserItem>)|(select <UserTypeEntity>)]
|
||||
[event <String>] (filtertime.* <Time>)* [filter|filters <String>] [ip <String>] [countsonly] [summary]
|
||||
[event <String>] (filtertime<String> <Time>)* [filter|filters <String>] [ip <String>] [countsonly] [summary]
|
||||
|
||||
For example, this command reports on the users that haven't logged in in the last 5 years.
|
||||
gam report users parameters accounts:last_login_time filters "accounts:last_login_time<#filtertime#" filtertime -5y
|
||||
@@ -13410,21 +13956,21 @@ Added units of years to <Date>, <DateTime> and <Time>; a year is 365 days. Added
|
||||
never|
|
||||
now|today
|
||||
|
||||
Added filtertime <Time> option to gam report to allow times, usually relative, to be substituted into the filter <String> option.
|
||||
If both filtertime and filter are specified, the filtertime value replaces the string #filtertime# in the filter <String>.
|
||||
Added filtertime<String> <Time> option to gam report to allow times, usually relative, to be substituted into the filter <String> option.
|
||||
If both filtertime<String> and filter are specified, the filtertime value replaces the string #filtertime<String># in the filter <String>.
|
||||
|
||||
gam report users|user [todrive <ToDriveAttribute>*] [date <Date>] [nodatechange | (fulldatarequired all|<ReportsAppList>)]
|
||||
[(user all|<UserItem>)|(select <UserTypeEntity>)] [filtertime <Time>] [filter|filters <String>] [fields|parameters <String>]
|
||||
[(user all|<UserItem>)|(select <UserTypeEntity>)] [filtertime<String> <Time>] [filter|filters <String>] [fields|parameters <String>]
|
||||
[maxactivities <Number>] [maxresults <Number>]
|
||||
gam report admin|calendar|calendars|drive|docs|doc|gplus|groups|group|logins|login|mobile|rules|tokens|token [todrive <ToDriveAttribute>*] [maxresults <Number>] [maxactivities <Number>]
|
||||
[([start <Time>] [end <Time>])|yesterday] [(user all|<UserItem>)|(select <UserTypeEntity>)]
|
||||
[event <String>] [filtertime <Time>] [filter|filters <String>] [ip <String>] [countsonly] [summary]
|
||||
[event <String>] [filtertime<String> <Time>] [filter|filters <String>] [ip <String>] [countsonly] [summary]
|
||||
|
||||
For example, this command reports on the users that haven't logged in in the last 5 years.
|
||||
gam report users parameters accounts:last_login_time filters "accounts:last_login_time<#filtertime#" filtertime -5y
|
||||
gam report users parameters accounts:last_login_time filters "accounts:last_login_time<#filtertime5y#" filtertime5y -5y
|
||||
|
||||
For example, this command reports on the users that haven't ever logged in.
|
||||
gam report users parameters accounts:last_login_time filters "accounts:last_login_time==#filtertime#" filtertime never
|
||||
gam report users parameters accounts:last_login_time filters "accounts:last_login_time==#filtertimeNever#" filtertimeNever never
|
||||
|
||||
4.60.14
|
||||
|
||||
|
||||
1
src/README.md
Symbolic link
1
src/README.md
Symbolic link
@@ -0,0 +1 @@
|
||||
../README.md
|
||||
847
src/cacerts.pem
847
src/cacerts.pem
@@ -1,847 +0,0 @@
|
||||
# Operating CA: DigiCert
|
||||
# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com
|
||||
# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com
|
||||
# Label: "DigiCert Assured ID Root CA"
|
||||
# Serial: 17154717934120587862167794914071425081
|
||||
# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72
|
||||
# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43
|
||||
# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
|
||||
b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG
|
||||
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
|
||||
cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi
|
||||
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c
|
||||
JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP
|
||||
mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+
|
||||
wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4
|
||||
VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/
|
||||
AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB
|
||||
AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
|
||||
BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun
|
||||
pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC
|
||||
dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf
|
||||
fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm
|
||||
NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx
|
||||
H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
|
||||
+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: DigiCert
|
||||
# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com
|
||||
# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com
|
||||
# Label: "DigiCert Assured ID Root G2"
|
||||
# Serial: 15385348160840213938643033620894905419
|
||||
# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d
|
||||
# SHA1 Fingerprint: a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f
|
||||
# SHA256 Fingerprint: 7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:49:45:2f:ab:7d:2f:c1:85
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
|
||||
b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG
|
||||
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
|
||||
cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi
|
||||
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA
|
||||
n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc
|
||||
biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp
|
||||
EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA
|
||||
bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu
|
||||
YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB
|
||||
AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW
|
||||
BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI
|
||||
QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I
|
||||
0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni
|
||||
lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9
|
||||
B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv
|
||||
ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo
|
||||
IhNzbM8m9Yop5w==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: DigiCert
|
||||
# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com
|
||||
# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com
|
||||
# Label: "DigiCert Assured ID Root G3"
|
||||
# Serial: 15459312981008553731928384953135426796
|
||||
# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb
|
||||
# SHA1 Fingerprint: f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89
|
||||
# SHA256 Fingerprint: 7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:b1:00:71:7f:43:05:3f:c2
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw
|
||||
CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
|
||||
ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg
|
||||
RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV
|
||||
UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu
|
||||
Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq
|
||||
hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf
|
||||
Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q
|
||||
RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
|
||||
BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD
|
||||
AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY
|
||||
JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv
|
||||
6pZjamVFkpUBtA==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: DigiCert
|
||||
# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com
|
||||
# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com
|
||||
# Label: "DigiCert Global Root CA"
|
||||
# Serial: 10944719598952040374951832963794454346
|
||||
# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e
|
||||
# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36
|
||||
# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: DigiCert
|
||||
# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com
|
||||
# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com
|
||||
# Label: "DigiCert Global Root G2"
|
||||
# Serial: 4293743540046975378534879503202253541
|
||||
# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44
|
||||
# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4
|
||||
# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
|
||||
MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI
|
||||
2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx
|
||||
1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ
|
||||
q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz
|
||||
tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ
|
||||
vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP
|
||||
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV
|
||||
5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY
|
||||
1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4
|
||||
NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG
|
||||
Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91
|
||||
8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe
|
||||
pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
|
||||
MrY=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: DigiCert
|
||||
# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com
|
||||
# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com
|
||||
# Label: "DigiCert Global Root G3"
|
||||
# Serial: 7089244469030293291760083333884364146
|
||||
# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca
|
||||
# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e
|
||||
# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw
|
||||
CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
|
||||
ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe
|
||||
Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw
|
||||
EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x
|
||||
IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF
|
||||
K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG
|
||||
fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO
|
||||
Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd
|
||||
BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx
|
||||
AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/
|
||||
oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8
|
||||
sycX
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: DigiCert
|
||||
# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com
|
||||
# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com
|
||||
# Label: "DigiCert High Assurance EV Root CA"
|
||||
# Serial: 3553400076410547919724730734378100087
|
||||
# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a
|
||||
# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25
|
||||
# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||
ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
|
||||
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||
LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
|
||||
RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
|
||||
+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
|
||||
PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
|
||||
xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
|
||||
Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
|
||||
hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
|
||||
EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
|
||||
MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
|
||||
FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
|
||||
nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
|
||||
eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
|
||||
hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
|
||||
Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
|
||||
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
|
||||
+OkuE6N36B9K
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: DigiCert
|
||||
# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com
|
||||
# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com
|
||||
# Label: "DigiCert Trusted Root G4"
|
||||
# Serial: 7451500558977370777930084869016614236
|
||||
# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49
|
||||
# SHA1 Fingerprint: dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4
|
||||
# SHA256 Fingerprint: 55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:03:d1:d9:d2:0a:c8:99:88
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg
|
||||
RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV
|
||||
UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu
|
||||
Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG
|
||||
SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y
|
||||
ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If
|
||||
xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV
|
||||
ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO
|
||||
DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ
|
||||
jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/
|
||||
CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi
|
||||
EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM
|
||||
fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY
|
||||
uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK
|
||||
chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t
|
||||
9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
|
||||
hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD
|
||||
ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2
|
||||
SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd
|
||||
+SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc
|
||||
fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa
|
||||
sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N
|
||||
cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N
|
||||
0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie
|
||||
4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI
|
||||
r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1
|
||||
/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm
|
||||
gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: GlobalSign
|
||||
# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA
|
||||
# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA
|
||||
# Label: "GlobalSign Root CA"
|
||||
# Serial: 4835703278459707669005204
|
||||
# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a
|
||||
# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c
|
||||
# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
|
||||
A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
|
||||
b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
|
||||
MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
|
||||
YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
|
||||
aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
|
||||
jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
|
||||
xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
|
||||
1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
|
||||
snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
|
||||
U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
|
||||
9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
|
||||
BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
|
||||
AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
|
||||
yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
|
||||
38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
|
||||
AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
|
||||
DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
|
||||
HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: GlobalSign
|
||||
# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3
|
||||
# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3
|
||||
# Label: "GlobalSign Root CA - R3"
|
||||
# Serial: 4835703278459759426209954
|
||||
# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28
|
||||
# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad
|
||||
# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
|
||||
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
|
||||
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
|
||||
MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
|
||||
A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
|
||||
hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
|
||||
RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
|
||||
gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
|
||||
KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
|
||||
QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
|
||||
XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
|
||||
DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
|
||||
LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
|
||||
RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
|
||||
jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
|
||||
6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
|
||||
mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
|
||||
Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
|
||||
WD9f
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: GlobalSign
|
||||
# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5
|
||||
# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5
|
||||
# Label: "GlobalSign ECC Root CA - R5"
|
||||
# Serial: 32785792099990507226680698011560947931244
|
||||
# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08
|
||||
# SHA1 Fingerprint: 1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa
|
||||
# SHA256 Fingerprint: 17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:13:f6:eb:ec:10:0c:89:24
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk
|
||||
MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH
|
||||
bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
|
||||
DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
|
||||
QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
|
||||
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc
|
||||
8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke
|
||||
hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD
|
||||
VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI
|
||||
KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg
|
||||
515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO
|
||||
xwy8p2Fp8fc74SrL+SvzZpA3
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: GlobalSign
|
||||
# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6
|
||||
# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6
|
||||
# Label: "GlobalSign Root CA - R6"
|
||||
# Serial: 1417766617973444989252670301619537
|
||||
# MD5 Fingerprint: 4f:dd:07:e4:d4:22:64:39:1e:0c:37:42:ea:d1:c6:ae
|
||||
# SHA1 Fingerprint: 80:94:64:0e:b5:a7:a1:ca:11:9c:1f:dd:d5:9f:81:02:63:a7:fb:d1
|
||||
# SHA256 Fingerprint: 2c:ab:ea:fe:37:d0:6c:a2:2a:ba:73:91:c0:03:3d:25:98:29:52:c4:53:64:73:49:76:3a:3a:b5:ad:6c:cf:69
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg
|
||||
MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh
|
||||
bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx
|
||||
MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET
|
||||
MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ
|
||||
KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI
|
||||
xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k
|
||||
ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD
|
||||
aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw
|
||||
LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw
|
||||
1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX
|
||||
k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2
|
||||
SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h
|
||||
bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n
|
||||
WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY
|
||||
rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce
|
||||
MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD
|
||||
AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu
|
||||
bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN
|
||||
nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt
|
||||
Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61
|
||||
55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj
|
||||
vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf
|
||||
cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz
|
||||
oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp
|
||||
nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs
|
||||
pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v
|
||||
JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R
|
||||
8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4
|
||||
5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Note: "GlobalSign Root CA - R7" not added on purpose. It is P-521.
|
||||
|
||||
# Operating CA: GoDaddy
|
||||
# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.
|
||||
# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.
|
||||
# Label: "Go Daddy Root Certificate Authority - G2"
|
||||
# Serial: 0
|
||||
# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01
|
||||
# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b
|
||||
# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx
|
||||
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT
|
||||
EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp
|
||||
ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz
|
||||
NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH
|
||||
EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE
|
||||
AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw
|
||||
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD
|
||||
E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH
|
||||
/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy
|
||||
DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh
|
||||
GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR
|
||||
tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA
|
||||
AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
|
||||
FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX
|
||||
WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu
|
||||
9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr
|
||||
gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo
|
||||
2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
|
||||
LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI
|
||||
4uJEvlz36hz1
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: GoDaddy
|
||||
# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc.
|
||||
# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc.
|
||||
# Label: "Starfield Root Certificate Authority - G2"
|
||||
# Serial: 0
|
||||
# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96
|
||||
# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e
|
||||
# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
|
||||
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
|
||||
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs
|
||||
ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw
|
||||
MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
|
||||
b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj
|
||||
aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp
|
||||
Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg
|
||||
nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1
|
||||
HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N
|
||||
Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN
|
||||
dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0
|
||||
HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
|
||||
BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G
|
||||
CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU
|
||||
sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3
|
||||
4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg
|
||||
8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
|
||||
pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
|
||||
mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: GoDaddy
|
||||
# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority
|
||||
# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority
|
||||
# Label: "Starfield Class 2 CA"
|
||||
# Serial: 0
|
||||
# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24
|
||||
# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a
|
||||
# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
|
||||
MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
|
||||
U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
|
||||
NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
|
||||
ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
|
||||
ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
|
||||
8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
|
||||
+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
|
||||
X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
|
||||
K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
|
||||
1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
|
||||
A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
|
||||
zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
|
||||
YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
|
||||
bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
|
||||
DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
|
||||
L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
|
||||
eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
|
||||
xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
|
||||
VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
|
||||
WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: GoDaddy
|
||||
# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority
|
||||
# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority
|
||||
# Label: "Go Daddy Class 2 CA"
|
||||
# Serial: 0
|
||||
# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67
|
||||
# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4
|
||||
# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
|
||||
MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
|
||||
YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
|
||||
MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
|
||||
ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
|
||||
MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
|
||||
ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
|
||||
PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
|
||||
wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
|
||||
EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
|
||||
avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
|
||||
YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
|
||||
sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
|
||||
/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
|
||||
IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
|
||||
YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
|
||||
ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
|
||||
OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
|
||||
TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
|
||||
HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
|
||||
dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
|
||||
ReYNnyicsbkqWletNw+vHX/bvZ8=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: Sectigo
|
||||
# Issuer: CN=AAA Certificate Services O=Comodo CA Limited
|
||||
# Subject: CN=AAA Certificate Services O=Comodo CA Limited
|
||||
# Label: "Comodo AAA Services root"
|
||||
# Serial: 1
|
||||
# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0
|
||||
# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49
|
||||
# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
|
||||
MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
|
||||
GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
|
||||
YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
|
||||
MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
|
||||
BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
|
||||
GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
|
||||
BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
|
||||
3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
|
||||
YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
|
||||
rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
|
||||
ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
|
||||
oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
|
||||
MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
|
||||
QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
|
||||
b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
|
||||
AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
|
||||
GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
|
||||
Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
|
||||
G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
|
||||
l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
|
||||
smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: Sectigo
|
||||
# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited
|
||||
# Subject: CN=COMODO Certification Authority O=COMODO CA Limited
|
||||
# Label: "COMODO Certification Authority"
|
||||
# Serial: 43390818032842818540635488309124489234
|
||||
# MD5 Fingerprint: 20:E7:4F:82:C2:7E:94:80:34:82:8A:13:A9:17:1D:97
|
||||
# SHA1 Fingerprint EE:86:93:87:FF:FD:83:49:AB:5A:D1:43:22:58:87:89:A4:57:B0:12
|
||||
# SHA256 Fingerprint: 1A:0D:20:44:5D:E5:BA:18:62:D1:9E:F8:80:85:8C:BC:E5:01:02:B3:6E:8F:0A:04:0C:3C:69:E7:45:22:FE:6E
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID0DCCArigAwIBAgIQIKTEf93f4cdTYwcTiHdgEjANBgkqhkiG9w0BAQUFADCB
|
||||
gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
|
||||
BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xMTAxMDEwMDAw
|
||||
MDBaFw0zMDEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl
|
||||
YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P
|
||||
RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0
|
||||
aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3
|
||||
UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI
|
||||
2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8
|
||||
Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp
|
||||
+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+
|
||||
DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O
|
||||
nKVIrLsm9wIDAQABo0IwQDAdBgNVHQ4EFgQUC1jli8ZMFTekQKkwqSG+RzZaVv8w
|
||||
DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
|
||||
ggEBAC/JxBwHO89hAgCx2SFRdXIDMLDEFh9sAIsQrK/xR9SuEDwMGvjUk2ysEDd8
|
||||
t6aDZK3N3w6HM503sMZ7OHKx8xoOo/lVem0DZgMXlUrxsXrfViEGQo+x06iF3u6X
|
||||
HWLrp+cxEmbDD6ZLLkGC9/3JG6gbr+48zuOcrigHoSybJMIPIyaDMouGDx8rEkYl
|
||||
Fo92kANr3ryqImhrjKGsKxE5pttwwn1y6TPn/CbxdFqR5p2ErPioBhlG5qfpqjQi
|
||||
pKGfeq23sqSaM4hxAjwu1nqyH6LKwN0vEJT9s4yEIHlG1QXUEOTS22RPuFvuG8Ug
|
||||
R1uUq27UlTMdphVx8fiUylQ5PsE=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: Sectigo
|
||||
# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited
|
||||
# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited
|
||||
# Label: "COMODO ECC Certification Authority"
|
||||
# Serial: 41578283867086692638256921589707938090
|
||||
# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23
|
||||
# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11
|
||||
# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL
|
||||
MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
|
||||
BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT
|
||||
IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw
|
||||
MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy
|
||||
ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N
|
||||
T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv
|
||||
biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR
|
||||
FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J
|
||||
cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW
|
||||
BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
|
||||
BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm
|
||||
fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv
|
||||
GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: Sectigo
|
||||
# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited
|
||||
# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited
|
||||
# Label: "COMODO RSA Certification Authority"
|
||||
# Serial: 101909084537582093308941363524873193117
|
||||
# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18
|
||||
# SHA1 Fingerprint: af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4
|
||||
# SHA256 Fingerprint: 52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:34:63:53:4b:32:b4:02:34
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB
|
||||
hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
|
||||
BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5
|
||||
MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
|
||||
EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
|
||||
Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh
|
||||
dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR
|
||||
6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X
|
||||
pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC
|
||||
9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV
|
||||
/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf
|
||||
Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z
|
||||
+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w
|
||||
qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah
|
||||
SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC
|
||||
u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf
|
||||
Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq
|
||||
crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E
|
||||
FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB
|
||||
/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl
|
||||
wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM
|
||||
4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV
|
||||
2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna
|
||||
FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ
|
||||
CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK
|
||||
boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke
|
||||
jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL
|
||||
S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb
|
||||
QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl
|
||||
0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB
|
||||
NVOFBkpdn627G190
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: Sectigo
|
||||
# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST Network
|
||||
# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST Network
|
||||
# Label: "USERTrust ECC Certification Authority"
|
||||
# Serial: 123013823720199481456569720443997572134
|
||||
# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1
|
||||
# SHA1 Fingerprint: d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0
|
||||
# SHA256 Fingerprint: 4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:86:e0:6a:dc:d2:a9:ad:7a
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL
|
||||
MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl
|
||||
eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT
|
||||
JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx
|
||||
MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
|
||||
Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg
|
||||
VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm
|
||||
aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo
|
||||
I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng
|
||||
o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G
|
||||
A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD
|
||||
VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB
|
||||
zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW
|
||||
RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: Sectigo
|
||||
# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network
|
||||
# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network
|
||||
# Label: "USERTrust RSA Certification Authority"
|
||||
# Serial: 2645093764781058787591871645665788717
|
||||
# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5
|
||||
# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e
|
||||
# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw
|
||||
MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV
|
||||
BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
|
||||
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy
|
||||
dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
|
||||
AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B
|
||||
3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY
|
||||
tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/
|
||||
Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2
|
||||
VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT
|
||||
79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6
|
||||
c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT
|
||||
Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l
|
||||
c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee
|
||||
UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE
|
||||
Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
|
||||
BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G
|
||||
A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF
|
||||
Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO
|
||||
VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3
|
||||
ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs
|
||||
8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR
|
||||
iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze
|
||||
Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ
|
||||
XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/
|
||||
qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB
|
||||
VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
|
||||
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
|
||||
jjxDah2nGN59PRbxYvnKkKj9
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: Google Trust Services LLC
|
||||
# Subject: C = US, O = Google Trust Services LLC, CN = GTS Root R1
|
||||
# Issuer: C = US, O = Google Trust Services LLC, CN = GTS Root R1
|
||||
# Label: "GTS Root R1"
|
||||
# Serial: 0203E5936F31B01349886BA217
|
||||
# MD5 Fingerprint: 05:FE:D0:BF:71:A8:A3:76:63:DA:01:E0:D8:52:DC:40
|
||||
# SHA1 Fingerprint: E5:8C:1C:C4:91:3B:38:63:4B:E9:10:6E:E3:AD:8E:6B:9D:D9:81:4A
|
||||
# SHA256 Fingerprint: D9:47:43:2A:BD:E7:B7:FA:90:FC:2E:6B:59:10:1B:12:80:E0:E1:C7:E4:E4:0F:A3:C6:88:7F:FF:57:A7:F4:CF
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw
|
||||
CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
|
||||
MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
|
||||
MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
|
||||
Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA
|
||||
A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo
|
||||
27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w
|
||||
Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw
|
||||
TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl
|
||||
qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH
|
||||
szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8
|
||||
Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk
|
||||
MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92
|
||||
wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p
|
||||
aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN
|
||||
VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID
|
||||
AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
|
||||
FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb
|
||||
C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe
|
||||
QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy
|
||||
h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4
|
||||
7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J
|
||||
ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef
|
||||
MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/
|
||||
Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT
|
||||
6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ
|
||||
0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm
|
||||
2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb
|
||||
bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: Google Trust Services LLC
|
||||
# Subject: C = US, O = Google Trust Services LLC, CN = GTS Root R2
|
||||
# Issuer: C = US, O = Google Trust Services LLC, CN = GTS Root R2
|
||||
# Label: "GTS Root R2"
|
||||
# Serial: 0203E5AEC58D04251AAB1125AA
|
||||
# MD5 Fingerprint=1E:39:C0:53:E6:1E:29:82:0B:CA:52:55:36:5D:57:DC
|
||||
# SHA1 Fingerprint=9A:44:49:76:32:DB:DE:FA:D0:BC:FB:5A:7B:17:BD:9E:56:09:24:94
|
||||
# SHA256 Fingerprint=8D:25:CD:97:22:9D:BF:70:35:6B:DA:4E:B3:CC:73:40:31:E2:4C:F0:0F:AF:CF:D3:2D:C7:6E:B5:84:1C:7E:A8
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw
|
||||
CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
|
||||
MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
|
||||
MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
|
||||
Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUA
|
||||
A4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3LvCvpt
|
||||
nfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY
|
||||
6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAu
|
||||
MC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7k
|
||||
RXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWg
|
||||
f9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1mKPV
|
||||
+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K8Yzo
|
||||
dDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW
|
||||
Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKa
|
||||
G73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCq
|
||||
gc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwID
|
||||
AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
|
||||
FgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBAB/Kzt3H
|
||||
vqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8
|
||||
0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyC
|
||||
B19m3H0Q/gxhswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2u
|
||||
NmSRXbBoGOqKYcl3qJfEycel/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMg
|
||||
yALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVnjWQye+mew4K6Ki3pHrTgSAai/Gev
|
||||
HyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y59PYjJbigapordwj6
|
||||
xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M7YNR
|
||||
TOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924Sg
|
||||
JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV
|
||||
7LXTWtiBmelDGDfrs7vRWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl
|
||||
6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjWHYbL
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: Google Trust Services LLC
|
||||
# Subject: C = US, O = Google Trust Services LLC, CN = GTS Root R3
|
||||
# Issuer: C = US, O = Google Trust Services LLC, CN = GTS Root R3
|
||||
# Label: "GTS Root R3"
|
||||
# Serial: 0203E5B882EB20F825276D3D66
|
||||
# MD5 Fingerprint: 3E:E7:9D:58:02:94:46:51:94:E5:E0:22:4A:8B:E7:73
|
||||
# SHA1 Fingerprint: ED:E5:71:80:2B:C8:92:B9:5B:83:3C:D2:32:68:3F:09:CD:A0:1E:46
|
||||
# SHA256 Fingerprint: 34:D8:A7:3E:E2:08:D9:BC:DB:0D:95:65:20:93:4B:4E:40:E6:94:82:59:6E:8B:6F:73:C8:42:6B:01:0A:6F:48
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD
|
||||
VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG
|
||||
A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw
|
||||
WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz
|
||||
IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
|
||||
AAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout736G
|
||||
jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2
|
||||
4CejQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
|
||||
BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7
|
||||
VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm
|
||||
ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: Google Trust Services LLC
|
||||
# Subject: C = US, O = Google Trust Services LLC, CN = GTS Root R4
|
||||
# Issuer: C = US, O = Google Trust Services LLC, CN = GTS Root R4
|
||||
# Label: "GTS Root R4"
|
||||
# Serial: 0203E5C068EF631A9C72905052
|
||||
# MD5 Fingerprint=43:96:83:77:19:4D:76:B3:9D:65:52:E4:1D:22:A5:E8
|
||||
# SHA1 Fingerprint=77:D3:03:67:B5:E0:0C:15:F6:0C:38:61:DF:7C:E1:3B:92:46:4D:47
|
||||
# SHA256 Fingerprint=34:9D:FA:40:58:C5:E2:63:12:3B:39:8A:E7:95:57:3C:4E:13:13:C8:3F:E6:8F:93:55:6C:D5:E8:03:1B:3C:7D
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD
|
||||
VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG
|
||||
A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw
|
||||
WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz
|
||||
IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
|
||||
AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi
|
||||
QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR
|
||||
HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
|
||||
BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D
|
||||
9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8
|
||||
p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: Google Trust Services LLC
|
||||
# Subject: OU = GlobalSign ECC Root CA - R4, O = GlobalSign, CN = GlobalSign
|
||||
# Issuer: OU = GlobalSign ECC Root CA - R4, O = GlobalSign, CN = GlobalSign
|
||||
# Label: "GlobalSign R4"
|
||||
# Serial: 0203E57EF53F93FDA50921B2A6
|
||||
# MD5 Fingerprint: 26:29:F8:6D:E1:88:BF:A2:65:7F:AA:C4:CD:0F:7F:FC
|
||||
# SHA1 Fingerprint: 6B:A0:B0:98:E1:71:EF:5A:AD:FE:48:15:80:77:10:F4:BD:6F:0B:28
|
||||
# SHA256 Fingerprint: B0:85:D7:0B:96:4F:19:1A:73:E4:AF:0D:54:AE:7A:0E:07:AA:FD:AF:9B:71:DD:08:62:13:8A:B7:32:5A:24:A2
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD
|
||||
VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh
|
||||
bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw
|
||||
MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g
|
||||
UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT
|
||||
BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx
|
||||
uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV
|
||||
HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/
|
||||
+wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147
|
||||
bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm
|
||||
-----END CERTIFICATE-----
|
||||
@@ -33,7 +33,6 @@ datas += [('gam/contactdelegation-v1.json', '.')]
|
||||
datas += [('gam/datastudio-v1.json', '.')]
|
||||
datas += [('gam/meet-v2beta.json', '.')]
|
||||
datas += [('gam/serviceaccountlookup-v1.json', '.')]
|
||||
datas += [('cacerts.pem', '.')]
|
||||
hiddenimports = [
|
||||
'gam.gamlib.yubikey',
|
||||
]
|
||||
@@ -49,7 +48,7 @@ a = Analysis(
|
||||
binaries=[],
|
||||
datas=datas,
|
||||
hiddenimports=hiddenimports,
|
||||
hookspath=[],
|
||||
hookspath=['tools/hooks'],
|
||||
hooksconfig={},
|
||||
runtime_hooks=runtime_hooks,
|
||||
excludes=excludes,
|
||||
|
||||
5253
src/gam/__init__.py
5253
src/gam/__init__.py
File diff suppressed because it is too large
Load Diff
@@ -433,106 +433,6 @@ pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
|
||||
mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: GoDaddy
|
||||
# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority
|
||||
# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority
|
||||
# Label: "Starfield Class 2 CA"
|
||||
# Serial: 0
|
||||
# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24
|
||||
# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a
|
||||
# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
|
||||
MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
|
||||
U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
|
||||
NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
|
||||
ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
|
||||
ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
|
||||
8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
|
||||
+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
|
||||
X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
|
||||
K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
|
||||
1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
|
||||
A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
|
||||
zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
|
||||
YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
|
||||
bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
|
||||
DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
|
||||
L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
|
||||
eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
|
||||
xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
|
||||
VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
|
||||
WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: GoDaddy
|
||||
# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority
|
||||
# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority
|
||||
# Label: "Go Daddy Class 2 CA"
|
||||
# Serial: 0
|
||||
# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67
|
||||
# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4
|
||||
# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
|
||||
MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
|
||||
YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
|
||||
MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
|
||||
ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
|
||||
MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
|
||||
ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
|
||||
PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
|
||||
wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
|
||||
EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
|
||||
avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
|
||||
YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
|
||||
sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
|
||||
/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
|
||||
IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
|
||||
YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
|
||||
ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
|
||||
OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
|
||||
TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
|
||||
HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
|
||||
dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
|
||||
ReYNnyicsbkqWletNw+vHX/bvZ8=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: Sectigo
|
||||
# Issuer: CN=AAA Certificate Services O=Comodo CA Limited
|
||||
# Subject: CN=AAA Certificate Services O=Comodo CA Limited
|
||||
# Label: "Comodo AAA Services root"
|
||||
# Serial: 1
|
||||
# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0
|
||||
# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49
|
||||
# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
|
||||
MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
|
||||
GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
|
||||
YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
|
||||
MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
|
||||
BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
|
||||
GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
|
||||
BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
|
||||
3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
|
||||
YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
|
||||
rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
|
||||
ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
|
||||
oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
|
||||
MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
|
||||
QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
|
||||
b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
|
||||
AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
|
||||
GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
|
||||
Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
|
||||
G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
|
||||
l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
|
||||
smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: Sectigo
|
||||
# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited
|
||||
# Subject: CN=COMODO Certification Authority O=COMODO CA Limited
|
||||
|
||||
@@ -24,8 +24,10 @@ ACCESSCONTEXTMANAGER = 'accesscontextmanager'
|
||||
ALERTCENTER = 'alertcenter'
|
||||
ANALYTICS_ADMIN = 'analyticsadmin'
|
||||
CALENDAR = 'calendar'
|
||||
BUSINESSACCOUNTMANAGEMENT = 'mybusinessaccountmanagement'
|
||||
CBCM = 'cbcm'
|
||||
CHAT = 'chat'
|
||||
CHAT_CUSTOM_EMOJIS = 'chatcustomemojis'
|
||||
CHAT_EVENTS = 'chatevents'
|
||||
CHAT_MEMBERSHIPS = 'chatmemberships'
|
||||
CHAT_MEMBERSHIPS_ADMIN = 'chatmembershipsadmin'
|
||||
@@ -73,8 +75,8 @@ IAM_CREDENTIALS = 'iamcredentials'
|
||||
KEEP = 'keep'
|
||||
LICENSING = 'licensing'
|
||||
LOOKERSTUDIO = 'datastudio'
|
||||
MEET = 'meet'
|
||||
MEET_BETA = 'meetbeta'
|
||||
MEET_SPACES = 'meet'
|
||||
MEET_READONLY = 'meetreadonly'
|
||||
OAUTH2 = 'oauth2'
|
||||
ORGPOLICY = 'orgpolicy'
|
||||
PEOPLE = 'people'
|
||||
@@ -84,6 +86,7 @@ PRINTERS = 'printers'
|
||||
PUBSUB = 'pubsub'
|
||||
REPORTS = 'reports'
|
||||
RESELLER = 'reseller'
|
||||
SEARCHCONSOLE = 'searchconsole'
|
||||
SERVICEACCOUNTLOOKUP = 'serviceaccountlookup'
|
||||
SERVICEMANAGEMENT = 'servicemanagement'
|
||||
SERVICEUSAGE = 'serviceusage'
|
||||
@@ -93,10 +96,13 @@ SITEVERIFICATION = 'siteVerification'
|
||||
STORAGE = 'storage'
|
||||
STORAGEREAD = 'storageread'
|
||||
STORAGEWRITE = 'storagewrite'
|
||||
TAGMANAGER = 'tagmanager'
|
||||
TAGMANAGER_USERS = 'tagmanagerusers'
|
||||
TASKS = 'tasks'
|
||||
VAULT = 'vault'
|
||||
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'
|
||||
GMAIL_SEND_SCOPE = 'https://www.googleapis.com/auth/gmail.send'
|
||||
@@ -113,6 +119,7 @@ USERINFO_PROFILE_SCOPE = 'https://www.googleapis.com/auth/userinfo.profile' # pr
|
||||
VAULT_SCOPES = ['https://www.googleapis.com/auth/ediscovery', 'https://www.googleapis.com/auth/ediscovery.readonly']
|
||||
REQUIRED_SCOPES = [USERINFO_EMAIL_SCOPE, USERINFO_PROFILE_SCOPE]
|
||||
REQUIRED_SCOPES_SET = set(REQUIRED_SCOPES)
|
||||
NUM_CLIENT_SCOPES_ERROR_LIMIT = 48
|
||||
#
|
||||
JWT_APIS = {
|
||||
ACCESSCONTEXTMANAGER: [CLOUD_PLATFORM_SCOPE],
|
||||
@@ -170,6 +177,7 @@ PROJECT_APIS = [
|
||||
'alertcenter.googleapis.com',
|
||||
'analyticsadmin.googleapis.com',
|
||||
# 'audit.googleapis.com',
|
||||
'mybusinessaccountmanagement.googleapis.com',
|
||||
'calendar-json.googleapis.com',
|
||||
'chat.googleapis.com',
|
||||
'chromemanagement.googleapis.com',
|
||||
@@ -195,9 +203,11 @@ PROJECT_APIS = [
|
||||
'people.googleapis.com',
|
||||
'pubsub.googleapis.com',
|
||||
'reseller.googleapis.com',
|
||||
'searchconsole.googleapis.com',
|
||||
'sheets.googleapis.com',
|
||||
'siteverification.googleapis.com',
|
||||
'storage-api.googleapis.com',
|
||||
'tagmanager.googleapis.com',
|
||||
'tasks.googleapis.com',
|
||||
'vault.googleapis.com',
|
||||
'youtube.googleapis.com',
|
||||
@@ -207,9 +217,11 @@ _INFO = {
|
||||
ACCESSCONTEXTMANAGER: {'name': 'Access Context Manager API', 'version': 'v1', 'v2discovery': True},
|
||||
ALERTCENTER: {'name': 'AlertCenter API', 'version': 'v1beta1', 'v2discovery': True},
|
||||
ANALYTICS_ADMIN: {'name': 'Analytics Admin API', 'version': 'v1beta', 'v2discovery': True},
|
||||
BUSINESSACCOUNTMANAGEMENT: {'name': 'Business Account Management API', 'version': 'v1', 'v2discovery': True},
|
||||
CALENDAR: {'name': 'Calendar API', 'version': 'v3', 'v2discovery': True, 'mappedAPI': 'calendar-json'},
|
||||
CBCM: {'name': 'Chrome Browser Cloud Management API', 'version': 'v1.1beta1', 'v2discovery': True, 'localjson': True},
|
||||
CHAT: {'name': 'Chat API', 'version': 'v1', 'v2discovery': True},
|
||||
CHAT_CUSTOM_EMOJIS: {'name': 'Chat API - Custom Emojis', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_EVENTS: {'name': 'Chat API - Events', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_MEMBERSHIPS: {'name': 'Chat API - Memberships', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_MEMBERSHIPS_ADMIN: {'name': 'Chat API - Memberships Admin', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
@@ -224,15 +236,15 @@ _INFO = {
|
||||
CHROMEMANAGEMENT_TELEMETRY: {'name': 'Chrome Management API - Telemetry', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHROMEMANAGEMENT},
|
||||
CHROMEPOLICY: {'name': 'Chrome Policy API', 'version': 'v1', 'v2discovery': True},
|
||||
CHROMEVERSIONHISTORY: {'name': 'Chrome Version History API', 'version': 'v1', 'v2discovery': True},
|
||||
CLOUDCHANNEL: {'name': 'Channel Channel API', 'version': 'v1', 'v2discovery': True},
|
||||
CLOUDIDENTITY_DEVICES: {'name': 'Cloud Identity Devices API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||
CLOUDIDENTITY_GROUPS: {'name': 'Cloud Identity Groups API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||
CLOUDIDENTITY_GROUPS_BETA: {'name': 'Cloud Identity Groups API', 'version': 'v1beta1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||
CLOUDIDENTITY_INBOUND_SSO: {'name': 'Cloud Identity Inbound SSO API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||
CLOUDIDENTITY_ORGUNITS: {'name': 'Cloud Identity OrgUnits API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||
CLOUDIDENTITY_ORGUNITS_BETA: {'name': 'Cloud Identity OrgUnits API', 'version': 'v1beta1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||
CLOUDIDENTITY_POLICY: {'name': 'Cloud Identity Policy API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||
CLOUDIDENTITY_USERINVITATIONS: {'name': 'Cloud Identity User Invitations API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||
CLOUDCHANNEL: {'name': 'Cloud Channel API', 'version': 'v1', 'v2discovery': True},
|
||||
CLOUDIDENTITY_DEVICES: {'name': 'Cloud Identity API - Devices', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||
CLOUDIDENTITY_GROUPS: {'name': 'Cloud Identity API - Groups', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||
CLOUDIDENTITY_GROUPS_BETA: {'name': 'Cloud Identity API - Groups Beta', 'version': 'v1beta1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||
CLOUDIDENTITY_INBOUND_SSO: {'name': 'Cloud Identity API - Inbound SSO Settings', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||
CLOUDIDENTITY_ORGUNITS: {'name': 'Cloud Identity API - OrgUnits', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||
CLOUDIDENTITY_ORGUNITS_BETA: {'name': 'Cloud Identity API - OrgUnits Beta', 'version': 'v1beta1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||
CLOUDIDENTITY_POLICY: {'name': 'Cloud Identity API - Policy', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||
CLOUDIDENTITY_USERINVITATIONS: {'name': 'Cloud Identity API - User Invitations', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
|
||||
CLOUDRESOURCEMANAGER: {'name': 'Cloud Resource Manager API v3', 'version': 'v3', 'v2discovery': True},
|
||||
CONTACTS: {'name': 'Contacts API', 'version': 'v3', 'v2discovery': False},
|
||||
CONTACTDELEGATION: {'name': 'Contact Delegation API', 'version': 'v1', 'v2discovery': True, 'localjson': True},
|
||||
@@ -255,17 +267,18 @@ _INFO = {
|
||||
KEEP: {'name': 'Keep API', 'version': 'v1', 'v2discovery': True},
|
||||
LICENSING: {'name': 'License Manager API', 'version': 'v1', 'v2discovery': True},
|
||||
LOOKERSTUDIO: {'name': 'Looker Studio API', 'version': 'v1', 'v2discovery': True, 'localjson': True},
|
||||
MEET: {'name': 'Meet API', 'version': 'v2', 'v2discovery': True},
|
||||
MEET_BETA: {'name': 'Meet API', 'version': 'v2beta', 'v2discovery': True, 'localjson': True, 'mappedAPI': MEET},
|
||||
MEET_SPACES: {'name': 'Meet API - Manage/Display Meeting Spaces', 'version': 'v2', 'v2discovery': True},
|
||||
MEET_READONLY: {'name': 'Meet API - Read Meeting Spaces metadata', 'version': 'v2', 'v2discovery': True, 'mappedAPI': MEET_SPACES},
|
||||
OAUTH2: {'name': 'OAuth2 API', 'version': 'v2', 'v2discovery': False},
|
||||
ORGPOLICY: {'name': 'Organization Policy API', 'version': 'v2', 'v2discovery': True},
|
||||
PEOPLE: {'name': 'People API', 'version': 'v1', 'v2discovery': True},
|
||||
PEOPLE_DIRECTORY: {'name': 'People Directory API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': PEOPLE},
|
||||
PEOPLE_OTHERCONTACTS: {'name': 'People API - Other Contacts', 'version': 'v1', 'v2discovery': True, 'mappedAPI': PEOPLE},
|
||||
PRINTERS: {'name': 'Directory API Printers', 'version': 'directory_v1', 'v2discovery': True, 'mappedAPI': 'admin'},
|
||||
PRINTERS: {'name': 'Directory API - Printers', 'version': 'directory_v1', 'v2discovery': True, 'mappedAPI': 'admin'},
|
||||
PUBSUB: {'name': 'Pub / Sub API', 'version': 'v1', 'v2discovery': True},
|
||||
REPORTS: {'name': 'Reports API', 'version': 'reports_v1', 'v2discovery': True, 'mappedAPI': 'admin'},
|
||||
RESELLER: {'name': 'Reseller API', 'version': 'v1', 'v2discovery': True},
|
||||
SEARCHCONSOLE: {'name': 'Search Console API', 'version': 'v1', 'v2discovery': True},
|
||||
SERVICEACCOUNTLOOKUP: {'name': 'Service Account Lookup pseudo-API', 'version': 'v1', 'v2discovery': True, 'localjson': True},
|
||||
SERVICEMANAGEMENT: {'name': 'Service Management API', 'version': 'v1', 'v2discovery': True},
|
||||
SERVICEUSAGE: {'name': 'Service Usage API', 'version': 'v1', 'v2discovery': True},
|
||||
@@ -275,6 +288,8 @@ _INFO = {
|
||||
STORAGE: {'name': 'Cloud Storage API', 'version': 'v1', 'v2discovery': True},
|
||||
STORAGEREAD: {'name': 'Cloud Storage API - Read', 'version': 'v1', 'v2discovery': True, 'mappedAPI': STORAGE},
|
||||
STORAGEWRITE: {'name': 'Cloud Storage API - Write', 'version': 'v1', 'v2discovery': True, 'mappedAPI': STORAGE},
|
||||
TAGMANAGER: {'name': 'Tag Manager API - Accounts, Containers, Workspaces, Tags', 'version': 'v2', 'v2discovery': True},
|
||||
TAGMANAGER_USERS: {'name': 'Tag Manager API - Users', 'version': 'v2', 'v2discovery': True, 'mappedAPI': TAGMANAGER},
|
||||
TASKS: {'name': 'Tasks API', 'version': 'v1', 'v2discovery': True},
|
||||
VAULT: {'name': 'Vault API', 'version': 'v1', 'v2discovery': True},
|
||||
YOUTUBE: {'name': 'Youtube API', 'version': 'v3', 'v2discovery': True},
|
||||
@@ -283,6 +298,11 @@ _INFO = {
|
||||
READONLY = ['readonly',]
|
||||
|
||||
_CLIENT_SCOPES = [
|
||||
{'name': 'Business Account Management API',
|
||||
'api': BUSINESSACCOUNTMANAGEMENT,
|
||||
'subscopes': [],
|
||||
'offByDefault': True,
|
||||
'scope': BUSINESSACCOUNTMANAGEMENT_SCOPE},
|
||||
{'name': 'Calendar API',
|
||||
'api': CALENDAR,
|
||||
'subscopes': READONLY,
|
||||
@@ -360,29 +380,29 @@ _CLIENT_SCOPES = [
|
||||
'subscopes': READONLY,
|
||||
'offByDefault': True,
|
||||
'scope': 'https://www.googleapis.com/auth/apps.order'},
|
||||
{'name': 'Cloud Identity Groups API',
|
||||
{'name': 'Cloud Identity API - Groups',
|
||||
'api': CLOUDIDENTITY_GROUPS,
|
||||
'subscopes': READONLY,
|
||||
'scope': 'https://www.googleapis.com/auth/cloud-identity.groups'},
|
||||
{'name': 'Cloud Identity Groups API Beta (Enables group locking/unlocking)',
|
||||
{'name': 'Cloud Identity API - Groups Beta (Enables group locking/unlocking)',
|
||||
'api': CLOUDIDENTITY_GROUPS_BETA,
|
||||
'subscopes': [],
|
||||
'scope': 'https://www.googleapis.com/auth/cloud-identity.groups'},
|
||||
{'name': 'Cloud Identity - Inbound SSO Settings',
|
||||
{'name': 'Cloud Identity API - Inbound SSO Settings',
|
||||
'api': CLOUDIDENTITY_INBOUND_SSO,
|
||||
'subscopes': READONLY,
|
||||
'scope': 'https://www.googleapis.com/auth/cloud-identity.inboundsso'},
|
||||
{'name': 'Cloud Identity OrgUnits API',
|
||||
{'name': 'Cloud Identity API - OrgUnits Beta',
|
||||
'api': CLOUDIDENTITY_ORGUNITS_BETA,
|
||||
'subscopes': READONLY,
|
||||
'scope': 'https://www.googleapis.com/auth/cloud-identity.orgunits'},
|
||||
{'name': 'Cloud Identity - Policy',
|
||||
{'name': 'Cloud Identity API - Policy',
|
||||
'api': CLOUDIDENTITY_POLICY,
|
||||
'subscopes': READONLY,
|
||||
'roByDefault': True,
|
||||
'scope': 'https://www.googleapis.com/auth/cloud-identity.policies'
|
||||
},
|
||||
{'name': 'Cloud Identity User Invitations API',
|
||||
{'name': 'Cloud Identity API - User Invitations',
|
||||
'api': CLOUDIDENTITY_USERINVITATIONS,
|
||||
'subscopes': READONLY,
|
||||
'scope': 'https://www.googleapis.com/auth/cloud-identity.userinvitations'},
|
||||
@@ -544,6 +564,10 @@ _SVCACCT_SCOPES = [
|
||||
'api': CALENDAR,
|
||||
'subscopes': READONLY,
|
||||
'scope': 'https://www.googleapis.com/auth/calendar'},
|
||||
{'name': 'Chat API - Custom Emojis',
|
||||
'api': CHAT_CUSTOM_EMOJIS,
|
||||
'subscopes': READONLY,
|
||||
'scope': 'https://www.googleapis.com/auth/chat.customemojis'},
|
||||
{'name': 'Chat API - Memberships',
|
||||
'api': CHAT_MEMBERSHIPS,
|
||||
'subscopes': READONLY,
|
||||
@@ -644,7 +668,7 @@ _SVCACCT_SCOPES = [
|
||||
'api': GMAIL,
|
||||
'subscopes': [],
|
||||
'scope': 'https://www.googleapis.com/auth/gmail.modify'},
|
||||
{'name': 'Gmail API - Basic Settings (Filters,IMAP, Language, POP, Vacation) - read/write, Sharing Settings (Delegates, Forwarding, SendAs) - read',
|
||||
{'name': 'Gmail API - Basic Settings (Filters, IMAP, Language, POP, Vacation) - read/write, Sharing Settings (Delegates, Forwarding, SendAs) - read',
|
||||
'api': GMAIL,
|
||||
'subscopes': [],
|
||||
'scope': 'https://www.googleapis.com/auth/gmail.settings.basic'},
|
||||
@@ -665,11 +689,15 @@ _SVCACCT_SCOPES = [
|
||||
'api': LOOKERSTUDIO,
|
||||
'subscopes': READONLY,
|
||||
'scope': 'https://www.googleapis.com/auth/datastudio'},
|
||||
{'name': 'Meet API',
|
||||
'api': MEET,
|
||||
'subscopes': READONLY,
|
||||
'scope': 'https://www.googleapis.com/auth/meetings.space.created',
|
||||
'roscope': 'https://www.googleapis.com/auth/meetings.space.readonly'},
|
||||
{'name': 'Meet API - Manage/Display Meeting Spaces',
|
||||
'api': MEET_SPACES,
|
||||
'subscopes': [],
|
||||
'scope': ['https://www.googleapis.com/auth/meetings.space.created',
|
||||
'https://www.googleapis.com/auth/meetings.space.settings']},
|
||||
{'name': 'Meet API - Read Meeting Spaces metadata',
|
||||
'api': MEET_READONLY,
|
||||
'subscopes': [],
|
||||
'scope': 'https://www.googleapis.com/auth/meetings.space.readonly'},
|
||||
{'name': 'OAuth2 API',
|
||||
'api': OAUTH2,
|
||||
'subscopes': [],
|
||||
@@ -686,10 +714,30 @@ _SVCACCT_SCOPES = [
|
||||
'api': PEOPLE_OTHERCONTACTS,
|
||||
'subscopes': [],
|
||||
'scope': 'https://www.googleapis.com/auth/contacts.other.readonly'},
|
||||
{'name': 'Search Console API - read only',
|
||||
'api': SEARCHCONSOLE,
|
||||
'subscopes': [],
|
||||
'offByDefault': True,
|
||||
'scope': 'https://www.googleapis.com/auth/webmasters.readonly'},
|
||||
{'name': 'Sheets API',
|
||||
'api': SHEETS,
|
||||
'subscopes': READONLY,
|
||||
'scope': 'https://www.googleapis.com/auth/spreadsheets'},
|
||||
{'name': 'Site Verification API',
|
||||
'api': SITEVERIFICATION,
|
||||
'subscopes': [],
|
||||
'offByDefault': True,
|
||||
'scope': 'https://www.googleapis.com/auth/siteverification'},
|
||||
{'name': 'Tag Manager API - Accounts, Containers, Workspaces, Tags - read only',
|
||||
'api': TAGMANAGER,
|
||||
'subscopes': [],
|
||||
'offByDefault': True,
|
||||
'scope': 'https://www.googleapis.com/auth/tagmanager.readonly'},
|
||||
{'name': 'Tag Manager API - Users',
|
||||
'api': TAGMANAGER_USERS,
|
||||
'subscopes': [],
|
||||
'offByDefault': True,
|
||||
'scope': 'https://www.googleapis.com/auth/tagmanager.manage.users'},
|
||||
{'name': 'Tasks API',
|
||||
'api': TASKS,
|
||||
'subscopes': READONLY,
|
||||
@@ -729,56 +777,6 @@ _USER_SVCACCT_ONLY_SCOPES = [
|
||||
'scope': 'https://www.googleapis.com/auth/apps.groups.migration'},
|
||||
]
|
||||
|
||||
DRIVE3_TO_DRIVE2_ABOUT_FIELDS_MAP = {
|
||||
'displayName': 'name',
|
||||
'limit': 'quotaBytesTotal',
|
||||
'usage': 'quotaBytesUsedAggregate',
|
||||
'usageInDrive': 'quotaBytesUsed',
|
||||
'usageInDriveTrash': 'quotaBytesUsedInTrash',
|
||||
}
|
||||
|
||||
DRIVE3_TO_DRIVE2_CAPABILITIES_FIELDS_MAP = {
|
||||
'canComment': 'canComment',
|
||||
'canReadRevisions': 'canReadRevisions',
|
||||
'canCopy': 'copyable',
|
||||
'canEdit': 'editable',
|
||||
'canShare': 'shareable',
|
||||
}
|
||||
|
||||
DRIVE3_TO_DRIVE2_CAPABILITIES_NAMES_MAP = {
|
||||
'canChangeViewersCanCopyContent': 'canChangeRestrictedDownload',
|
||||
}
|
||||
|
||||
DRIVE3_TO_DRIVE2_FILES_FIELDS_MAP = {
|
||||
'allowFileDiscovery': 'withLink',
|
||||
'createdTime': 'createdDate',
|
||||
'expirationTime': 'expirationDate',
|
||||
'modifiedByMe': 'modified',
|
||||
'modifiedByMeTime': 'modifiedByMeDate',
|
||||
'modifiedTime': 'modifiedDate',
|
||||
'name': 'title',
|
||||
'restrictionTime': 'restrictionDate',
|
||||
'sharedWithMeTime': 'sharedWithMeDate',
|
||||
'size': 'fileSize',
|
||||
'trashedTime': 'trashedDate',
|
||||
'viewedByMe': 'viewed',
|
||||
'viewedByMeTime': 'lastViewedByMeDate',
|
||||
'webViewLink': 'alternateLink',
|
||||
}
|
||||
|
||||
DRIVE3_TO_DRIVE2_LABELS_MAP = {
|
||||
'modifiedByMe': 'modified',
|
||||
'starred': 'starred',
|
||||
'trashed': 'trashed',
|
||||
'viewedByMe': 'viewed',
|
||||
}
|
||||
|
||||
DRIVE3_TO_DRIVE2_REVISIONS_FIELDS_MAP = {
|
||||
'modifiedTime': 'modifiedDate',
|
||||
'keepForever': 'pinned',
|
||||
'size': 'fileSize',
|
||||
}
|
||||
|
||||
def getAPIName(api):
|
||||
return _INFO[api]['name']
|
||||
|
||||
@@ -827,3 +825,26 @@ def getSvcAcctScopesList(userServiceAccountAccessOnly, svcAcctSpecialScopes):
|
||||
|
||||
def hasLocalJSON(api):
|
||||
return _INFO[api].get('localjson', False)
|
||||
|
||||
def findAPIforScope(scopesList):
|
||||
def checkScopeMatch(scope, cscope):
|
||||
if cscope['scope'] == scope:
|
||||
requiredAPIs.append(cscope['name'])
|
||||
return True
|
||||
if cscope['subscopes'] == READONLY and cscope['scope']+'.readonly' == scope:
|
||||
requiredAPIs.append(cscope['name']+' (supports readonly)')
|
||||
return True
|
||||
return False
|
||||
|
||||
requiredAPIs = []
|
||||
for scope in scopesList:
|
||||
for cscope in _CLIENT_SCOPES:
|
||||
if checkScopeMatch(scope, cscope):
|
||||
break
|
||||
else:
|
||||
for cscope in _SVCACCT_SCOPES:
|
||||
if checkScopeMatch(scope, cscope):
|
||||
break
|
||||
if not requiredAPIs:
|
||||
requiredAPIs = scopesList
|
||||
return ' or '.join(requiredAPIs)
|
||||
|
||||
@@ -69,6 +69,8 @@ CACHE_DISCOVERY_ONLY = 'cache_discovery_only'
|
||||
CHANNEL_CUSTOMER_ID = 'channel_customer_id'
|
||||
# Character set of batch, csv, data files
|
||||
CHARSET = 'charset'
|
||||
# When retrieving lists of Chat items from API, how many should be retrieved in each chunk
|
||||
CHAT_MAX_RESULTS = 'chat_max_results'
|
||||
# When retrieving lists of Google Classroom items from API, how many should be retrieved in each chunk
|
||||
CLASSROOM_MAX_RESULTS = 'classroom_max_results'
|
||||
# Path to client_secrets.json
|
||||
@@ -145,6 +147,8 @@ CSV_OUTPUT_USERS_AUDIT = 'csv_output_users_audit'
|
||||
CUSTOMER_ID = 'customer_id'
|
||||
# If debug_level > 0: extra_args['prettyPrint'] = True, httplib2.debuglevel = gam_debug_level, appsObj.debug = True
|
||||
DEBUG_LEVEL = 'debug_level'
|
||||
# Developer Preview API Key
|
||||
DEVELOPER_PREVIEW_API_KEY = 'developer_preview_api_key'
|
||||
# When retrieving lists of ChromeOS devices from API, how many should be retrieved in each chunk
|
||||
DEVICE_MAX_RESULTS = 'device_max_results'
|
||||
# Domain obtained from gam.cfg or oauth2.txt
|
||||
@@ -153,10 +157,6 @@ DOMAIN = 'domain'
|
||||
DRIVE_DIR = 'drive_dir'
|
||||
# When retrieving lists of Drive files/folders from API, how many should be retrieved in each chunk
|
||||
DRIVE_MAX_RESULTS = 'drive_max_results'
|
||||
# Use Drive V3 beta
|
||||
DRIVE_V3_BETA = 'drive_v3_beta'
|
||||
# Use Drive V3 ntive names
|
||||
DRIVE_V3_NATIVE_NAMES = 'drive_v3_native_names'
|
||||
# When processing email messages in batches, how many should be processed in each batch
|
||||
EMAIL_BATCH_SIZE = 'email_batch_size'
|
||||
# Enable Delegated Admin Service Account
|
||||
@@ -179,8 +179,6 @@ INTER_BATCH_WAIT = 'inter_batch_wait'
|
||||
LICENSE_MAX_RESULTS = 'license_max_results'
|
||||
# License SKUs to process
|
||||
LICENSE_SKUS = 'license_skus'
|
||||
# Use Meet V2 beta
|
||||
MEET_V2_BETA = 'meet_v2_beta'
|
||||
# When retrieving lists of Google Group members from API, how many should be retrieved in each chunk
|
||||
MEMBER_MAX_RESULTS = 'member_max_results'
|
||||
# CI API Group members max page size when view=BASIC
|
||||
@@ -339,6 +337,7 @@ Defaults = {
|
||||
CACHE_DISCOVERY_ONLY: TRUE,
|
||||
CHARSET: DEFAULT_CHARSET,
|
||||
CHANNEL_CUSTOMER_ID: '',
|
||||
CHAT_MAX_RESULTS: '100',
|
||||
CLASSROOM_MAX_RESULTS: '0',
|
||||
CLIENT_SECRETS_JSON: FN_CLIENT_SECRETS_JSON,
|
||||
CLOCK_SKEW_IN_SECONDS: '10',
|
||||
@@ -376,13 +375,12 @@ Defaults = {
|
||||
CSV_OUTPUT_USERS_AUDIT: FALSE,
|
||||
CUSTOMER_ID: MY_CUSTOMER,
|
||||
DEBUG_LEVEL: '0',
|
||||
DEVELOPER_PREVIEW_API_KEY: '',
|
||||
DEVICE_MAX_RESULTS: '200',
|
||||
DOMAIN: '',
|
||||
DRIVE_DIR: '',
|
||||
ENFORCE_EXPANSIVE_ACCESS: TRUE,
|
||||
DRIVE_MAX_RESULTS: '1000',
|
||||
DRIVE_V3_BETA: FALSE,
|
||||
DRIVE_V3_NATIVE_NAMES: TRUE,
|
||||
EMAIL_BATCH_SIZE: '50',
|
||||
ENABLE_DASA: FALSE,
|
||||
ENABLE_GCLOUD_REAUTH: FALSE,
|
||||
@@ -393,7 +391,6 @@ Defaults = {
|
||||
INTER_BATCH_WAIT: '0',
|
||||
LICENSE_MAX_RESULTS: '100',
|
||||
LICENSE_SKUS: '',
|
||||
MEET_V2_BETA: FALSE,
|
||||
MEMBER_MAX_RESULTS: '200',
|
||||
MEMBER_MAX_RESULTS_CI_BASIC: '1000',
|
||||
MEMBER_MAX_RESULTS_CI_FULL: '500',
|
||||
@@ -508,6 +505,7 @@ VAR_INFO = {
|
||||
CACHE_DISCOVERY_ONLY: {VAR_TYPE: TYPE_BOOLEAN, VAR_SIGFILE: 'allcache.txt', VAR_SFFT: (TRUE, FALSE)},
|
||||
CHARSET: {VAR_TYPE: TYPE_STRING, VAR_ENVVAR: 'GAM_CHARSET', VAR_LIMITS: (1, None)},
|
||||
CHANNEL_CUSTOMER_ID: {VAR_TYPE: TYPE_STRING, VAR_LIMITS: (0, None)},
|
||||
CHAT_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 1000)},
|
||||
CLASSROOM_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (0, 1000)},
|
||||
CLIENT_SECRETS_JSON: {VAR_TYPE: TYPE_FILE, VAR_ENVVAR: 'CLIENTSECRETS', VAR_ACCESS: os.R_OK},
|
||||
CLOCK_SKEW_IN_SECONDS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (10, 3600)},
|
||||
@@ -545,13 +543,12 @@ VAR_INFO = {
|
||||
CSV_OUTPUT_USERS_AUDIT: {VAR_TYPE: TYPE_BOOLEAN},
|
||||
CUSTOMER_ID: {VAR_TYPE: TYPE_STRING, VAR_ENVVAR: 'CUSTOMER_ID', VAR_LIMITS: (0, None)},
|
||||
DEBUG_LEVEL: {VAR_TYPE: TYPE_INTEGER, VAR_SIGFILE: 'debug.gam', VAR_LIMITS: (0, None), VAR_SFFT: ('0', '4')},
|
||||
DEVELOPER_PREVIEW_API_KEY: {VAR_TYPE: TYPE_STRING, VAR_LIMITS: (0, None)},
|
||||
DEVICE_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 200)},
|
||||
DOMAIN: {VAR_TYPE: TYPE_STRING, VAR_ENVVAR: 'GA_DOMAIN', VAR_LIMITS: (0, None)},
|
||||
DRIVE_DIR: {VAR_TYPE: TYPE_DIRECTORY, VAR_ENVVAR: 'GAMDRIVEDIR'},
|
||||
ENFORCE_EXPANSIVE_ACCESS: {VAR_TYPE: TYPE_BOOLEAN},
|
||||
DRIVE_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 1000)},
|
||||
DRIVE_V3_BETA: {VAR_TYPE: TYPE_BOOLEAN},
|
||||
DRIVE_V3_NATIVE_NAMES: {VAR_TYPE: TYPE_BOOLEAN},
|
||||
EMAIL_BATCH_SIZE: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 100)},
|
||||
ENABLE_DASA: {VAR_TYPE: TYPE_BOOLEAN, VAR_SIGFILE: 'enabledasa.txt', VAR_SFFT: (FALSE, TRUE)},
|
||||
ENABLE_GCLOUD_REAUTH: {VAR_TYPE: TYPE_BOOLEAN},
|
||||
@@ -562,7 +559,6 @@ VAR_INFO = {
|
||||
INTER_BATCH_WAIT: {VAR_TYPE: TYPE_FLOAT, VAR_LIMITS: (0.0, 60.0)},
|
||||
LICENSE_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (10, 1000)},
|
||||
LICENSE_SKUS: {VAR_TYPE: TYPE_STRING, VAR_LIMITS: (0, None)},
|
||||
MEET_V2_BETA: {VAR_TYPE: TYPE_BOOLEAN},
|
||||
MEMBER_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 200)},
|
||||
MEMBER_MAX_RESULTS_CI_BASIC: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 1000)},
|
||||
MEMBER_MAX_RESULTS_CI_FULL: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 500)},
|
||||
|
||||
@@ -49,43 +49,71 @@ class GamCLArgs():
|
||||
ENTITY_CROS_OUS_AND_CHILDREN_QUERIES = 'cros_ous_and_children_queries'
|
||||
ENTITY_CROS_SN = 'cros_sn'
|
||||
ENTITY_DOMAINS = 'domains'
|
||||
ENTITY_DOMAINS_NA = 'domains_na'
|
||||
ENTITY_DOMAINS_ARCH = 'domains_arch'
|
||||
ENTITY_DOMAINS_NS = 'domains_ns'
|
||||
ENTITY_DOMAINS_SUSP = 'domains_susp'
|
||||
ENTITY_DOMAINS_NA_NS = 'domains_na_ns'
|
||||
ENTITY_GROUP = 'group'
|
||||
ENTITY_GROUP_INDE = 'group_inde'
|
||||
ENTITY_GROUP_NA = 'group_na'
|
||||
ENTITY_GROUP_ARCH = 'group_arch'
|
||||
ENTITY_GROUP_NS = 'group_ns'
|
||||
ENTITY_GROUP_SUSP = 'group_susp'
|
||||
ENTITY_GROUP_NA_NS = 'group_na_ns'
|
||||
ENTITY_GROUPS = 'groups'
|
||||
ENTITY_GROUPS_INDE = 'groups_inde'
|
||||
ENTITY_GROUPS_NA = 'groups_na'
|
||||
ENTITY_GROUPS_ARCH = 'groups_arch'
|
||||
ENTITY_GROUPS_NS = 'groups_ns'
|
||||
ENTITY_GROUPS_SUSP = 'groups_susp'
|
||||
ENTITY_GROUPS_NA_NS = 'groups_na_ns'
|
||||
ENTITY_GROUP_USERS = 'group_users'
|
||||
ENTITY_GROUP_USERS_NA = 'group_users_na'
|
||||
ENTITY_GROUP_USERS_ARCH = 'group_users_arch'
|
||||
ENTITY_GROUP_USERS_NS = 'group_users_ns'
|
||||
ENTITY_GROUP_USERS_SUSP = 'group_users_susp'
|
||||
ENTITY_GROUP_USERS_NA_NS = 'group_users_na_ns'
|
||||
ENTITY_GROUP_USERS_SELECT = 'group_users_select'
|
||||
ENTITY_LICENSES = 'licenses'
|
||||
ENTITY_OAUTHUSER = 'oauthuser'
|
||||
ENTITY_OU = 'ou'
|
||||
ENTITY_OU_NA = 'ou_na'
|
||||
ENTITY_OU_ARCH = 'ou_arch'
|
||||
ENTITY_OU_NS = 'ou_ns'
|
||||
ENTITY_OU_SUSP = 'ou_susp'
|
||||
ENTITY_OU_NA_NS = 'ou_na_ns'
|
||||
ENTITY_OU_AND_CHILDREN = 'ou_and_children'
|
||||
ENTITY_OU_AND_CHILDREN_NA = 'ou_and_children_na'
|
||||
ENTITY_OU_AND_CHILDREN_ARCH = 'ou_and_children_arch'
|
||||
ENTITY_OU_AND_CHILDREN_NS = 'ou_and_children_ns'
|
||||
ENTITY_OU_AND_CHILDREN_SUSP = 'ou_and_children_susp'
|
||||
ENTITY_OU_AND_CHILDREN_NA_NS = 'ou_and_children_na_ns'
|
||||
ENTITY_OUS = 'ous'
|
||||
ENTITY_OUS_NA = 'ous_na'
|
||||
ENTITY_OUS_ARCH = 'ous_arch'
|
||||
ENTITY_OUS_NS = 'ous_ns'
|
||||
ENTITY_OUS_SUSP = 'ous_susp'
|
||||
ENTITY_OUS_NA_NS = 'ous_na_ns'
|
||||
ENTITY_OUS_AND_CHILDREN = 'ous_and_children'
|
||||
ENTITY_OUS_AND_CHILDREN_NA = 'ous_and_children_na'
|
||||
ENTITY_OUS_AND_CHILDREN_ARCH = 'ous_and_children_arch'
|
||||
ENTITY_OUS_AND_CHILDREN_NS = 'ous_and_children_ns'
|
||||
ENTITY_OUS_AND_CHILDREN_SUSP = 'ous_and_children_susp'
|
||||
ENTITY_OUS_AND_CHILDREN_NA_NS = 'ous_and_children_na_ns'
|
||||
ENTITY_QUERIES = 'queries'
|
||||
ENTITY_QUERY = 'query'
|
||||
ENTITY_STUDENTS = 'students'
|
||||
ENTITY_TEACHERS = 'teachers'
|
||||
ENTITY_USER = 'user'
|
||||
ENTITY_USERS = 'users'
|
||||
ENTITY_USERS_NA = 'users_na'
|
||||
ENTITY_USERS_ARCH = 'users_arch'
|
||||
ENTITY_USERS_NS = 'users_ns'
|
||||
ENTITY_USERS_NS_SUSP = 'users_ns_susp'
|
||||
ENTITY_USERS_SUSP = 'users_susp'
|
||||
ENTITY_USERS_NA_NS = 'users_na_ns'
|
||||
ENTITY_USERS_ARCH_OR_SUSP = 'users_arch_or_susp'
|
||||
ENTITY_USERS_NS_SUSP = 'users_ns_susp'
|
||||
#
|
||||
BROWSER_ENTITIES = [
|
||||
ENTITY_BROWSER,
|
||||
@@ -118,34 +146,58 @@ class GamCLArgs():
|
||||
ENTITY_CIGROUP_USERS,
|
||||
ENTITY_COURSEPARTICIPANTS,
|
||||
ENTITY_DOMAINS,
|
||||
ENTITY_DOMAINS_NA,
|
||||
ENTITY_DOMAINS_ARCH,
|
||||
ENTITY_DOMAINS_NS,
|
||||
ENTITY_DOMAINS_SUSP,
|
||||
ENTITY_DOMAINS_NA_NS,
|
||||
ENTITY_GROUP,
|
||||
ENTITY_GROUP_INDE,
|
||||
ENTITY_GROUP_NA,
|
||||
ENTITY_GROUP_ARCH,
|
||||
ENTITY_GROUP_NS,
|
||||
ENTITY_GROUP_SUSP,
|
||||
ENTITY_GROUP_NA_NS,
|
||||
ENTITY_GROUPS,
|
||||
ENTITY_GROUPS_INDE,
|
||||
ENTITY_GROUPS_NA,
|
||||
ENTITY_GROUPS_ARCH,
|
||||
ENTITY_GROUPS_NS,
|
||||
ENTITY_GROUPS_SUSP,
|
||||
ENTITY_GROUPS_NA_NS,
|
||||
ENTITY_GROUP_USERS,
|
||||
ENTITY_GROUP_USERS_NA,
|
||||
ENTITY_GROUP_USERS_ARCH,
|
||||
ENTITY_GROUP_USERS_NS,
|
||||
ENTITY_GROUP_USERS_SUSP,
|
||||
ENTITY_GROUP_USERS_NA_NS,
|
||||
ENTITY_GROUP_USERS_SELECT,
|
||||
ENTITY_LICENSES,
|
||||
ENTITY_OAUTHUSER,
|
||||
ENTITY_OU,
|
||||
ENTITY_OU_NA,
|
||||
ENTITY_OU_ARCH,
|
||||
ENTITY_OU_NS,
|
||||
ENTITY_OU_SUSP,
|
||||
ENTITY_OU_NA_NS,
|
||||
ENTITY_OU_AND_CHILDREN,
|
||||
ENTITY_OU_AND_CHILDREN_NA,
|
||||
ENTITY_OU_AND_CHILDREN_ARCH,
|
||||
ENTITY_OU_AND_CHILDREN_NS,
|
||||
ENTITY_OU_AND_CHILDREN_SUSP,
|
||||
ENTITY_OU_AND_CHILDREN_NA_NS,
|
||||
ENTITY_OUS,
|
||||
ENTITY_OUS_NA,
|
||||
ENTITY_OUS_ARCH,
|
||||
ENTITY_OUS_NS,
|
||||
ENTITY_OUS_SUSP,
|
||||
ENTITY_OUS_NA_NS,
|
||||
ENTITY_OUS_AND_CHILDREN,
|
||||
ENTITY_OUS_AND_CHILDREN_NA,
|
||||
ENTITY_OUS_AND_CHILDREN_ARCH,
|
||||
ENTITY_OUS_AND_CHILDREN_NS,
|
||||
ENTITY_OUS_AND_CHILDREN_SUSP,
|
||||
ENTITY_OUS_AND_CHILDREN_NA_NS,
|
||||
ENTITY_QUERIES,
|
||||
ENTITY_QUERY,
|
||||
ENTITY_STUDENTS,
|
||||
@@ -222,29 +274,53 @@ class GamCLArgs():
|
||||
'licence': ENTITY_LICENSES,
|
||||
'licences': ENTITY_LICENSES,
|
||||
'org': ENTITY_OU,
|
||||
'org_na': ENTITY_OU_NA,
|
||||
'org_arch': ENTITY_OU_ARCH,
|
||||
'org_ns': ENTITY_OU_NS,
|
||||
'org_susp': ENTITY_OU_SUSP,
|
||||
'org_na_ns': ENTITY_OU_NA_NS,
|
||||
'org_and_child': ENTITY_OU_AND_CHILDREN,
|
||||
'org_and_child_na': ENTITY_OU_AND_CHILDREN_NA,
|
||||
'org_and_child_arch': ENTITY_OU_AND_CHILDREN_ARCH,
|
||||
'org_and_child_ns': ENTITY_OU_AND_CHILDREN_NS,
|
||||
'org_and_child_susp': ENTITY_OU_AND_CHILDREN_SUSP,
|
||||
'org_and_child_na_ns': ENTITY_OU_AND_CHILDREN_NA_NS,
|
||||
'org_and_children': ENTITY_OU_AND_CHILDREN,
|
||||
'org_and_children_na': ENTITY_OU_AND_CHILDREN_NA,
|
||||
'org_and_children_arch': ENTITY_OU_AND_CHILDREN_ARCH,
|
||||
'org_and_children_ns': ENTITY_OU_AND_CHILDREN_NS,
|
||||
'org_and_children_susp': ENTITY_OU_AND_CHILDREN_SUSP,
|
||||
'org_and_children_na_ns': ENTITY_OU_AND_CHILDREN_NA_NS,
|
||||
'orgs': ENTITY_OUS,
|
||||
'orgs_na': ENTITY_OUS_NA,
|
||||
'orgs_arch': ENTITY_OUS_ARCH,
|
||||
'orgs_ns': ENTITY_OUS_NS,
|
||||
'orgs_susp': ENTITY_OUS_SUSP,
|
||||
'orgs_na_ns': ENTITY_OUS_NA_NS,
|
||||
'orgs_and_child': ENTITY_OUS_AND_CHILDREN,
|
||||
'orgs_and_child_na': ENTITY_OUS_AND_CHILDREN_NA,
|
||||
'orgs_and_child_arch': ENTITY_OUS_AND_CHILDREN_ARCH,
|
||||
'orgs_and_child_ns': ENTITY_OUS_AND_CHILDREN_NS,
|
||||
'orgs_and_child_susp': ENTITY_OUS_AND_CHILDREN_SUSP,
|
||||
'orgs_and_child_na_ns': ENTITY_OUS_AND_CHILDREN_NA_NS,
|
||||
'orgs_and_children': ENTITY_OUS_AND_CHILDREN,
|
||||
'orgs_and_children_na': ENTITY_OUS_AND_CHILDREN_NA,
|
||||
'orgs_and_children_arch': ENTITY_OUS_AND_CHILDREN_ARCH,
|
||||
'orgs_and_children_ns': ENTITY_OUS_AND_CHILDREN_NS,
|
||||
'orgs_and_children_susp': ENTITY_OUS_AND_CHILDREN_SUSP,
|
||||
'orgs_and_children_na_ns': ENTITY_OUS_AND_CHILDREN_NA_NS,
|
||||
'ou_and_child': ENTITY_OU_AND_CHILDREN,
|
||||
'ou_and_child_na': ENTITY_OU_AND_CHILDREN_NA,
|
||||
'ou_and_child_arch': ENTITY_OU_AND_CHILDREN_ARCH,
|
||||
'ou_and_child_ns': ENTITY_OU_AND_CHILDREN_NS,
|
||||
'ou_and_child_susp': ENTITY_OU_AND_CHILDREN_SUSP,
|
||||
'ou_and_child_na_ns': ENTITY_OU_AND_CHILDREN_NA_NS,
|
||||
'ous_and_child': ENTITY_OUS_AND_CHILDREN,
|
||||
'ous_and_child_na': ENTITY_OUS_AND_CHILDREN_NA,
|
||||
'ous_and_child_arch': ENTITY_OUS_AND_CHILDREN_ARCH,
|
||||
'ous_and_child_ns': ENTITY_OUS_AND_CHILDREN_NS,
|
||||
'ous_and_child_susp': ENTITY_OUS_AND_CHILDREN_SUSP,
|
||||
'ous_and_child_na_ns': ENTITY_OUS_AND_CHILDREN_NA_NS,
|
||||
}
|
||||
# CL entity source selectors
|
||||
ENTITY_SELECTOR_ALL = 'all'
|
||||
@@ -315,30 +391,217 @@ class GamCLArgs():
|
||||
]
|
||||
USER_ENTITY_SELECTOR_ALL_SUBTYPES = [
|
||||
ENTITY_USERS,
|
||||
ENTITY_USERS_NA,
|
||||
ENTITY_USERS_ARCH,
|
||||
ENTITY_USERS_NS,
|
||||
ENTITY_USERS_NS_SUSP,
|
||||
ENTITY_USERS_SUSP,
|
||||
ENTITY_USERS_ARCH_OR_SUSP,
|
||||
ENTITY_USERS_NA_NS,
|
||||
ENTITY_USERS_NS_SUSP,
|
||||
]
|
||||
#
|
||||
ENTITY_ALL_CROS = ENTITY_SELECTOR_ALL+' '+ENTITY_CROS
|
||||
ENTITY_ALL_USERS = ENTITY_SELECTOR_ALL+' '+ENTITY_USERS
|
||||
ENTITY_ALL_USERS_NA = ENTITY_SELECTOR_ALL+' '+ENTITY_USERS_NA
|
||||
ENTITY_ALL_USERS_ARCH = ENTITY_SELECTOR_ALL+' '+ENTITY_USERS_ARCH
|
||||
ENTITY_ALL_USERS_NS = ENTITY_SELECTOR_ALL+' '+ENTITY_USERS_NS
|
||||
ENTITY_ALL_USERS_NS_SUSP = ENTITY_SELECTOR_ALL+' '+ENTITY_USERS_NS_SUSP
|
||||
ENTITY_ALL_USERS_SUSP = ENTITY_SELECTOR_ALL+' '+ENTITY_USERS_SUSP
|
||||
ENTITY_ALL_USERS_NA_NS = ENTITY_SELECTOR_ALL+' '+ENTITY_USERS_NA_NS
|
||||
ENTITY_ALL_USERS_ARCH_OR_SUSP = ENTITY_SELECTOR_ALL+' '+ENTITY_USERS_ARCH_OR_SUSP
|
||||
ENTITY_ALL_USERS_NS_SUSP = ENTITY_SELECTOR_ALL+' '+ENTITY_USERS_NS_SUSP
|
||||
#
|
||||
ALL_USER_ENTITY_TYPES = {
|
||||
ENTITY_ALL_USERS,
|
||||
ENTITY_ALL_USERS_NA,
|
||||
ENTITY_ALL_USERS_ARCH,
|
||||
ENTITY_ALL_USERS_NS,
|
||||
ENTITY_ALL_USERS_SUSP,
|
||||
ENTITY_ALL_USERS_NA_NS,
|
||||
ENTITY_ALL_USERS_NS_SUSP,
|
||||
}
|
||||
DOMAIN_ENTITY_TYPES = {
|
||||
ENTITY_DOMAINS,
|
||||
ENTITY_DOMAINS_NA,
|
||||
ENTITY_DOMAINS_ARCH,
|
||||
ENTITY_DOMAINS_NS,
|
||||
ENTITY_DOMAINS_SUSP,
|
||||
ENTITY_DOMAINS_NA_NS,
|
||||
}
|
||||
GROUP_ENTITY_TYPES = {
|
||||
ENTITY_GROUP,
|
||||
ENTITY_GROUP_NA,
|
||||
ENTITY_GROUP_ARCH,
|
||||
ENTITY_GROUP_NS,
|
||||
ENTITY_GROUP_SUSP,
|
||||
ENTITY_GROUP_NA_NS,
|
||||
ENTITY_GROUP_INDE,
|
||||
}
|
||||
GROUPS_ENTITY_TYPES = {
|
||||
ENTITY_GROUPS,
|
||||
ENTITY_GROUPS_NA,
|
||||
ENTITY_GROUPS_ARCH,
|
||||
ENTITY_GROUPS_NS,
|
||||
ENTITY_GROUPS_SUSP,
|
||||
ENTITY_GROUPS_NA_NS,
|
||||
ENTITY_GROUPS_INDE,
|
||||
}
|
||||
GROUP_USERS_ENTITY_TYPES = {
|
||||
ENTITY_GROUP_USERS,
|
||||
ENTITY_GROUP_USERS_NA,
|
||||
ENTITY_GROUP_USERS_ARCH,
|
||||
ENTITY_GROUP_USERS_NS,
|
||||
ENTITY_GROUP_USERS_SUSP,
|
||||
ENTITY_GROUP_USERS_NA_NS,
|
||||
ENTITY_GROUP_USERS_SELECT,
|
||||
}
|
||||
OU_ENTITY_TYPES = {
|
||||
ENTITY_OU,
|
||||
ENTITY_OU_AND_CHILDREN,
|
||||
ENTITY_OU_NA,
|
||||
ENTITY_OU_AND_CHILDREN_NA,
|
||||
ENTITY_OU_ARCH,
|
||||
ENTITY_OU_AND_CHILDREN_ARCH,
|
||||
ENTITY_OU_NS,
|
||||
ENTITY_OU_AND_CHILDREN_NS,
|
||||
ENTITY_OU_SUSP,
|
||||
ENTITY_OU_AND_CHILDREN_SUSP,
|
||||
ENTITY_OU_NA_NS,
|
||||
ENTITY_OU_AND_CHILDREN_NA_NS,
|
||||
}
|
||||
OUS_ENTITY_TYPES = {
|
||||
ENTITY_OUS,
|
||||
ENTITY_OUS_AND_CHILDREN,
|
||||
ENTITY_OUS_NA,
|
||||
ENTITY_OUS_AND_CHILDREN_NA,
|
||||
ENTITY_OUS_ARCH,
|
||||
ENTITY_OUS_AND_CHILDREN_ARCH,
|
||||
ENTITY_OUS_NS,
|
||||
ENTITY_OUS_AND_CHILDREN_NS,
|
||||
ENTITY_OUS_SUSP,
|
||||
ENTITY_OUS_AND_CHILDREN_SUSP,
|
||||
ENTITY_OUS_NA_NS,
|
||||
ENTITY_OUS_AND_CHILDREN_NA_NS,
|
||||
}
|
||||
OU_DIRECT_ENTITY_TYPES = {
|
||||
ENTITY_OU,
|
||||
ENTITY_OUS,
|
||||
ENTITY_OU_NA,
|
||||
ENTITY_OUS_NA,
|
||||
ENTITY_OU_ARCH,
|
||||
ENTITY_OUS_ARCH,
|
||||
ENTITY_OU_NS,
|
||||
ENTITY_OUS_NS,
|
||||
ENTITY_OU_SUSP,
|
||||
ENTITY_OUS_SUSP,
|
||||
ENTITY_OU_NA_NS,
|
||||
ENTITY_OUS_NA_NS,
|
||||
}
|
||||
CROS_OU_ENTITY_TYPES = {
|
||||
ENTITY_CROS_OU,
|
||||
ENTITY_CROS_OU_AND_CHILDREN,
|
||||
ENTITY_CROS_OU_QUERY,
|
||||
ENTITY_CROS_OU_AND_CHILDREN_QUERY,
|
||||
ENTITY_CROS_OU_QUERIES,
|
||||
ENTITY_CROS_OU_AND_CHILDREN_QUERIES,
|
||||
}
|
||||
CROS_OUS_ENTITY_TYPES = {
|
||||
ENTITY_CROS_OUS,
|
||||
ENTITY_CROS_OUS_AND_CHILDREN,
|
||||
ENTITY_CROS_OUS_QUERY,
|
||||
ENTITY_CROS_OUS_AND_CHILDREN_QUERY,
|
||||
ENTITY_CROS_OUS_QUERIES,
|
||||
ENTITY_CROS_OUS_AND_CHILDREN_QUERIES,
|
||||
}
|
||||
CROS_OU_CHILDREN_ENTITY_TYPES = {
|
||||
ENTITY_CROS_OU_AND_CHILDREN,
|
||||
ENTITY_CROS_OU_AND_CHILDREN_QUERY,
|
||||
ENTITY_CROS_OU_AND_CHILDREN_QUERIES,
|
||||
ENTITY_CROS_OUS_AND_CHILDREN,
|
||||
ENTITY_CROS_OUS_AND_CHILDREN_QUERY,
|
||||
ENTITY_CROS_OUS_AND_CHILDREN_QUERIES,
|
||||
}
|
||||
CROS_OU_QUERY_ENTITY_TYPES = {
|
||||
ENTITY_CROS_OU_QUERY,
|
||||
ENTITY_CROS_OU_AND_CHILDREN_QUERY,
|
||||
ENTITY_CROS_OUS_QUERY,
|
||||
ENTITY_CROS_OUS_AND_CHILDREN_QUERY,
|
||||
}
|
||||
CROS_OU_QUERIES_ENTITY_TYPES = {
|
||||
ENTITY_CROS_OU_QUERIES,
|
||||
ENTITY_CROS_OU_AND_CHILDREN_QUERIES,
|
||||
ENTITY_CROS_OUS_QUERIES,
|
||||
ENTITY_CROS_OUS_AND_CHILDREN_QUERIES,
|
||||
}
|
||||
#
|
||||
ALL_USERS_QUERY_MAP = {
|
||||
ENTITY_ALL_USERS: 'isSuspended=False',
|
||||
ENTITY_ALL_USERS_NA: 'isArchived=False',
|
||||
ENTITY_ALL_USERS_ARCH: 'isArchived=True',
|
||||
ENTITY_ALL_USERS_NS: 'isSuspended=False',
|
||||
ENTITY_ALL_USERS_NS_SUSP: None,
|
||||
ENTITY_ALL_USERS_SUSP: 'isSuspended=True',
|
||||
ENTITY_ALL_USERS_NA_NS: 'isArchived=False isSuspended=False',
|
||||
ENTITY_ALL_USERS_NS_SUSP: None,
|
||||
}
|
||||
DOMAINS_QUERY_MAP = {
|
||||
ENTITY_DOMAINS: None,
|
||||
ENTITY_DOMAINS_NA: 'isArchived=False',
|
||||
ENTITY_DOMAINS_ARCH: 'isArchived=True',
|
||||
ENTITY_DOMAINS_NS: 'isSuspended=False',
|
||||
ENTITY_DOMAINS_SUSP: 'isSuspended=True',
|
||||
ENTITY_DOMAINS_NA_NS: 'isArchived=False isSuspended=False',
|
||||
}
|
||||
GROUPS_QUERY_MAP = { #(isArchived, isSuspended)
|
||||
ENTITY_GROUP_NA: (False, None),
|
||||
ENTITY_GROUPS_NA: (False, None),
|
||||
ENTITY_GROUP_ARCH: (True, None),
|
||||
ENTITY_GROUPS_ARCH: (True, None),
|
||||
ENTITY_GROUP_NS: (None, False),
|
||||
ENTITY_GROUPS_NS: (None, False),
|
||||
ENTITY_GROUP_SUSP: (None, True),
|
||||
ENTITY_GROUPS_SUSP: (None, True),
|
||||
ENTITY_GROUP_NA_NS: (False, False),
|
||||
ENTITY_GROUPS_NA_NS: (False, False),
|
||||
}
|
||||
GROUP_USERS_QUERY_MAP = { #(isArchived, isSuspended)
|
||||
ENTITY_GROUP_USERS_NA: (False, None),
|
||||
ENTITY_GROUP_USERS_ARCH: (True, None),
|
||||
ENTITY_GROUP_USERS_NS: (None, False),
|
||||
ENTITY_GROUP_USERS_SUSP: (None, True),
|
||||
ENTITY_GROUP_USERS_NA_NS: (False, False),
|
||||
}
|
||||
OU_QUERY_MAP = { #(isArchived, isSuspended)
|
||||
ENTITY_OU_NA: (False, None),
|
||||
ENTITY_OUS_NA: (False, None),
|
||||
ENTITY_OU_AND_CHILDREN_NA: (False, None),
|
||||
ENTITY_OUS_AND_CHILDREN_NA: (False, None),
|
||||
ENTITY_OU_ARCH: (True, None),
|
||||
ENTITY_OUS_ARCH: (True, None),
|
||||
ENTITY_OU_AND_CHILDREN_ARCH: (True, None),
|
||||
ENTITY_OUS_AND_CHILDREN_ARCH: (True, None),
|
||||
ENTITY_OU_NS: (None, False),
|
||||
ENTITY_OUS_NS: (None, False),
|
||||
ENTITY_OU_AND_CHILDREN_NS: (None, False),
|
||||
ENTITY_OUS_AND_CHILDREN_NS: (None, False),
|
||||
ENTITY_OU_SUSP: (None, True),
|
||||
ENTITY_OUS_SUSP: (None, True),
|
||||
ENTITY_OU_AND_CHILDREN_SUSP: (None, True),
|
||||
ENTITY_OUS_AND_CHILDREN_SUSP: (None, True),
|
||||
ENTITY_OU_NA_NS: (False, False),
|
||||
ENTITY_OUS_NA_NS: (False, False),
|
||||
ENTITY_OU_AND_CHILDREN_NA_NS: (False, False),
|
||||
ENTITY_OUS_AND_CHILDREN_NA_NS: (False, False),
|
||||
}
|
||||
#
|
||||
ENTITY_SELECTOR_ALL_SUBTYPES_MAP = {
|
||||
ENTITY_CROS: ENTITY_ALL_CROS,
|
||||
ENTITY_USERS: ENTITY_ALL_USERS,
|
||||
ENTITY_USERS_NA: ENTITY_ALL_USERS_NA,
|
||||
ENTITY_USERS_ARCH: ENTITY_ALL_USERS_ARCH,
|
||||
ENTITY_USERS_NS: ENTITY_ALL_USERS_NS,
|
||||
ENTITY_USERS_NS_SUSP: ENTITY_ALL_USERS_NS_SUSP,
|
||||
ENTITY_USERS_SUSP: ENTITY_ALL_USERS_SUSP,
|
||||
ENTITY_USERS_NA_NS: ENTITY_ALL_USERS_NA_NS,
|
||||
ENTITY_USERS_ARCH_OR_SUSP: ENTITY_ALL_USERS_ARCH_OR_SUSP,
|
||||
ENTITY_USERS_NS_SUSP: ENTITY_ALL_USERS_NS_SUSP,
|
||||
}
|
||||
# Allowed values for CL source selector datafile, csvkmd
|
||||
CROS_ENTITY_SELECTOR_DATAFILE_CSVKMD_SUBTYPES = [
|
||||
@@ -352,22 +615,37 @@ class GamCLArgs():
|
||||
ENTITY_CIGROUPS,
|
||||
ENTITY_CIGROUP_USERS,
|
||||
ENTITY_DOMAINS,
|
||||
ENTITY_DOMAINS_NA,
|
||||
ENTITY_DOMAINS_ARCH,
|
||||
ENTITY_DOMAINS_NS,
|
||||
ENTITY_DOMAINS_SUSP,
|
||||
ENTITY_DOMAINS_NA_NS,
|
||||
ENTITY_GROUPS,
|
||||
ENTITY_GROUPS_INDE,
|
||||
ENTITY_GROUPS_NA,
|
||||
ENTITY_GROUPS_ARCH,
|
||||
ENTITY_GROUPS_NS,
|
||||
ENTITY_GROUPS_SUSP,
|
||||
ENTITY_GROUPS_NA_NS,
|
||||
ENTITY_GROUP_USERS,
|
||||
ENTITY_GROUP_USERS_NA,
|
||||
ENTITY_GROUP_USERS_ARCH,
|
||||
ENTITY_GROUP_USERS_NS,
|
||||
ENTITY_GROUP_USERS_SUSP,
|
||||
ENTITY_GROUP_USERS_NA_NS,
|
||||
ENTITY_GROUP_USERS_SELECT,
|
||||
ENTITY_OUS,
|
||||
ENTITY_OUS_NA,
|
||||
ENTITY_OUS_ARCH,
|
||||
ENTITY_OUS_NS,
|
||||
ENTITY_OUS_SUSP,
|
||||
ENTITY_OUS_NA_NS,
|
||||
ENTITY_OUS_AND_CHILDREN,
|
||||
ENTITY_OUS_AND_CHILDREN_NA,
|
||||
ENTITY_OUS_AND_CHILDREN_ARCH,
|
||||
ENTITY_OUS_AND_CHILDREN_NS,
|
||||
ENTITY_OUS_AND_CHILDREN_SUSP,
|
||||
ENTITY_OUS_AND_CHILDREN_NA_NS,
|
||||
ENTITY_COURSEPARTICIPANTS,
|
||||
ENTITY_STUDENTS,
|
||||
ENTITY_TEACHERS,
|
||||
@@ -377,6 +655,7 @@ class GamCLArgs():
|
||||
GAM_CMD = 'gam'
|
||||
COMMIT_BATCH_CMD = 'commit-batch'
|
||||
PRINT_CMD = 'print'
|
||||
DATETIME_CMD = 'datetime'
|
||||
SET_CMD = 'set'
|
||||
CLEAR_CMD = 'clear'
|
||||
SLEEP_CMD = 'sleep'
|
||||
@@ -411,6 +690,7 @@ class GamCLArgs():
|
||||
ARG_ALERTFEEDBACK = 'alertfeedback'
|
||||
ARG_ALERTFEEDBACKS = 'alertfeedbacks'
|
||||
ARG_ALERTSFEEDBACK = 'alertsfeedback'
|
||||
ARG_ALERTSETTINGS = 'alertsettings'
|
||||
ARG_ALIAS = 'alias'
|
||||
ARG_ALIASES = 'aliases'
|
||||
ARG_ALIASDOMAIN = 'aliasdomain'
|
||||
@@ -441,6 +721,8 @@ class GamCLArgs():
|
||||
ARG_BUCKETS = 'buckets'
|
||||
ARG_BUILDING = 'building'
|
||||
ARG_BUILDINGS = 'buildings'
|
||||
ARG_BUSINESSPROFILEACCOUNT = 'businessprofileaccount'
|
||||
ARG_BUSINESSPROFILEACCOUNTS = 'businessprofileaccounts'
|
||||
ARG_CAALEVEL = 'caalevel'
|
||||
ARG_CAALEVELS = 'caalevels'
|
||||
ARG_CALATTENDEES = 'calattendees'
|
||||
@@ -461,6 +743,8 @@ class GamCLArgs():
|
||||
ARG_CHANNELSKU = 'channelsku'
|
||||
ARG_CHANNELSKUS = 'channelskus'
|
||||
ARG_CHAT = 'chat'
|
||||
ARG_CHATEMOJI = 'chatemoji'
|
||||
ARG_CHATEMOJIS = 'chatemojis'
|
||||
ARG_CHATEVENT = 'chatevent'
|
||||
ARG_CHATEVENTS = 'chatevents'
|
||||
ARG_CHATMEMBER = 'chatmember'
|
||||
@@ -483,6 +767,8 @@ class GamCLArgs():
|
||||
ARG_CHROMEPOLICIES = 'chromepolicies'
|
||||
ARG_CHROMEPROFILE = 'chromeprofile'
|
||||
ARG_CHROMEPROFILES = 'chromeprofiles'
|
||||
ARG_CHROMEPROFILECOMMAND = 'chromeprofilecommand'
|
||||
ARG_CHROMEPROFILECOMMANDS = 'chromeprofilecommands'
|
||||
ARG_CHROMESCHEMA = 'chromeschema'
|
||||
ARG_CHROMESCHEMAS = 'chromeschemas'
|
||||
ARG_CHROMESNVALIDITY = 'chromesnvalidity'
|
||||
@@ -521,6 +807,9 @@ class GamCLArgs():
|
||||
ARG_COURSEANNOUNCEMENTS = 'courseannouncements'
|
||||
ARG_COURSEMATERIALS = 'coursematerials'
|
||||
ARG_COURSEPARTICIPANTS = 'courseparticipants'
|
||||
ARG_COURSESTUDENTGROUP = 'coursestudentgroup'
|
||||
ARG_COURSESTUDENTGROUPS = 'coursestudentgroups'
|
||||
ARG_COURSESTUDENTGROUPMEMBERS = 'coursestudentgroupmembers'
|
||||
ARG_COURSESUBMISSIONS = 'coursesubmissions'
|
||||
ARG_COURSETOPICS = 'coursetopics'
|
||||
ARG_COURSEWORK = 'coursework'
|
||||
@@ -775,8 +1064,19 @@ class GamCLArgs():
|
||||
ARG_STORAGEBUCKETS = 'storagebuckets'
|
||||
ARG_STORAGEFILE = 'storagefile'
|
||||
ARG_STORAGEFILES = 'storagefiles'
|
||||
ARG_SUSPENDED = 'suspended'
|
||||
ARG_SVCACCT = 'svcacct'
|
||||
ARG_SVCACCTS = 'svcaccts'
|
||||
ARG_TAGMANAGERACCOUNT = 'tagmanageraccount'
|
||||
ARG_TAGMANAGERACCOUNTS = 'tagmanageraccounts'
|
||||
ARG_TAGMANAGERCONTAINER = 'tagmanagercontainer'
|
||||
ARG_TAGMANAGERCONTAINERS = 'tagmanagercontainers'
|
||||
ARG_TAGMANAGERPERMISSION = 'tagmanagerpermission'
|
||||
ARG_TAGMANAGERPERMISSIONS = 'tagmanagerpermissions'
|
||||
ARG_TAGMANAGERTAG = 'tagmanagertag'
|
||||
ARG_TAGMANAGERTAGS = 'tagmanagertags'
|
||||
ARG_TAGMANAGERWORKSPACE = 'tagmanagerworkspace'
|
||||
ARG_TAGMANAGERWORKSPACES = 'tagmanagerworkspaces'
|
||||
ARG_TASK = 'task'
|
||||
ARG_TASKS = 'tasks'
|
||||
ARG_TASKLIST = 'tasklist'
|
||||
@@ -815,6 +1115,10 @@ class GamCLArgs():
|
||||
ARG_VERIFICATION = 'verification'
|
||||
ARG_VERIFICATIONCODES = 'verificationcodes'
|
||||
ARG_VERIFY = 'verify'
|
||||
ARG_WEBMASTERSITE = 'webmastersite'
|
||||
ARG_WEBMASTERSITES = 'webmastersites'
|
||||
ARG_WEBRESOURCE = 'webresource'
|
||||
ARG_WEBRESOURCES = 'webresources'
|
||||
ARG_WORKINGLOCATION = 'workinglocation'
|
||||
ARG_WORKINGLOCATIONS = 'workinglocations'
|
||||
ARG_YOUTUBECHANNEL = 'youtubechannel'
|
||||
@@ -843,6 +1147,8 @@ class GamCLArgs():
|
||||
OB_CHARACTER = 'Character'
|
||||
OB_CHAR_SET = 'CharacterSet'
|
||||
OG_CHAT_ATTACHMENT = 'ChatAttachment'
|
||||
OB_CHAT_EMOJI = 'ChatEmoji'
|
||||
OB_CHAT_EMOJI_NAME = 'ChatEmojiName'
|
||||
OB_CHAT_EVENT = 'ChatEvent'
|
||||
OB_CHAT_MEMBER = 'ChatMember'
|
||||
OB_CHAT_MESSAGE = 'ChatMessage'
|
||||
@@ -850,7 +1156,10 @@ class GamCLArgs():
|
||||
OB_CHAT_SPACE = 'ChatSpace'
|
||||
OB_CHAT_SPACE_LIST = 'ChatSpaceList'
|
||||
OB_CHAT_THREAD = 'ChatThread'
|
||||
OB_CHROMEPROFILE_ID = 'ChromeProfileId'
|
||||
OB_CHROMEPROFILE_NAME = 'ChromeProfileName'
|
||||
OB_CHROMEPROFILE_NAME_LIST = 'ChromeProfileNameList'
|
||||
OB_CHROMEPROFILE_COMMAND_NAME = 'ChromeProfileCommandName'
|
||||
OB_CHROMEPROFILE_COMMAND_NAME_LIST = 'ChromeProfileNameCommandList'
|
||||
OB_CHROME_VERSION = 'ChromeVersion'
|
||||
OB_CIDR_NETMASK = 'CIDRnetmask'
|
||||
OB_CIGROUP_ALIAS_LIST = "CIGroupAliasList"
|
||||
@@ -871,8 +1180,11 @@ class GamCLArgs():
|
||||
OB_CONTACT_GROUP_ITEM = 'ContactGroupItem'
|
||||
OB_COURSE_ALIAS = 'CourseAlias'
|
||||
OB_COURSE_ALIAS_ENTITY = 'CourseAliasEntity'
|
||||
OB_COURSE_ANNOUNCEMENT_ID = "CourseAnnouncementID"
|
||||
OB_COURSE_ANNOUNCEMENT_ID_ENTITY = "CourseAnnouncementIDEntity"
|
||||
OB_COURSE_ANNOUNCEMENT_STATE_LIST = "CourseAnnouncementStateList"
|
||||
OB_COURSE_ANNOUNCEMENT_ADD_STATE_LIST = "CourseAnnouncementAddStateList"
|
||||
OB_COURSE_ANNOUNCEMENT_UPDATE_STATE_LIST = "CourseAnnouncementUpdateStateList"
|
||||
OB_COURSE_ENTITY = 'CourseEntity'
|
||||
OB_COURSE_ID = 'CourseID'
|
||||
OB_COURSE_MATERIAL_ID_ENTITY = 'CourseMaterialIDEntity'
|
||||
@@ -891,6 +1203,7 @@ class GamCLArgs():
|
||||
OB_CSE_KEYPAIR_ID = 'CSEKeyPairID'
|
||||
OB_CUSTOMER_ID = 'CustomerID'
|
||||
OB_CUSTOMER_AUTH_TOKEN = 'CustomerAuthToken'
|
||||
OB_DATETIME_FORMAT = 'DateTimeFormat'
|
||||
OB_DEVICE_FILE_ENTITY = 'DeviceFileEntity'
|
||||
OB_DEVICE_ENTITY = 'DeviceEntity'
|
||||
OB_DEVICE_ID = 'DeviceID'
|
||||
@@ -903,6 +1216,7 @@ class GamCLArgs():
|
||||
OB_DOMAIN_NAME_LIST = 'DomainNameList'
|
||||
OB_DRIVE_FILE_ENTITY = 'DriveFileEntity'
|
||||
OB_DRIVE_FILE_ID = 'DriveFileID'
|
||||
OB_DRIVE_FILE_ID_LIST = 'DriveFileIDList'
|
||||
OB_DRIVE_FILE_NAME = 'DriveFileName'
|
||||
OB_DRIVE_FILE_PERMISSION_ENTITY = 'DriveFilePermissionEntity'
|
||||
OB_DRIVE_FILE_PERMISSION_ID = 'DriveFilePermissionID'
|
||||
@@ -930,6 +1244,7 @@ class GamCLArgs():
|
||||
OB_FILE_NAME = 'FileName'
|
||||
OB_FILE_NAME_FIELD_NAME = OB_FILE_NAME+'(:'+OB_FIELD_NAME+')+'
|
||||
OB_FILE_NAME_OR_URL = 'FileName|URL'
|
||||
OB_FILE_NAME_PATTERN = 'FileNamePattern'
|
||||
OB_FILE_PATH = 'FilePath'
|
||||
OB_FILTER_ID_ENTITY = 'FilterIDEntity'
|
||||
OB_FORMAT_LIST = 'FormatList'
|
||||
@@ -975,7 +1290,6 @@ class GamCLArgs():
|
||||
OB_PERMISSION_ID_LIST = 'PermissionIDList'
|
||||
OB_PERMISSION_ROLE_LIST = 'PermissionRoleList'
|
||||
OB_PERMISSION_TYPE_LIST = 'PermissionTypeList'
|
||||
OB_PHOTO_FILENAME_PATTERN = 'FilenameNamePattern'
|
||||
OB_PRINTER_ID = 'PrinterID'
|
||||
OB_PRIVILEGE_LIST = 'PrivilegeList'
|
||||
OB_PRODUCT_ID = 'ProductID'
|
||||
@@ -984,6 +1298,7 @@ class GamCLArgs():
|
||||
OB_PROJECT_ID_ENTITY = 'ProjectIDEntity'
|
||||
OB_PROPERTY_KEY = 'PropertyKey'
|
||||
OB_PROPERTY_VALUE = 'PropertyValue'
|
||||
OB_PUBSUB_TOPIC_NAME = 'PubSubTopicName'
|
||||
OB_QUERY = 'Query'
|
||||
OB_QUERY_ITEM = 'QueryItem'
|
||||
OB_QUERY_LIST = 'QueryList'
|
||||
@@ -1023,9 +1338,13 @@ class GamCLArgs():
|
||||
OB_SPREADSHEET_RANGE_LIST = 'SpreadsheetRangeList'
|
||||
OB_STATE_NAME_LIST = "StateNameList"
|
||||
OB_STRING = 'String'
|
||||
OB_STRING_ENTITY = 'StringEntity'
|
||||
OB_STRING_LIST = 'StringList'
|
||||
OB_STUDENTGROUP_ID = 'StudentGroupID'
|
||||
OB_STUDENTGROUP_ID_ENTITY = 'StudentGroupIDEntity'
|
||||
OB_STUDENT_ITEM = 'StudentItem'
|
||||
OB_TAG = 'Tag'
|
||||
OB_TAGMANAGER_PATH_LIST = 'TagManagerPathList'
|
||||
OB_TASK_ID = 'TaskID'
|
||||
OB_TASKLIST_ID = 'TaskListID'
|
||||
OB_TASKLIST_ID_ENTITY = 'TaskListIDEntity'
|
||||
|
||||
@@ -54,6 +54,7 @@ class GamEntity():
|
||||
ALERT_ID = 'alri'
|
||||
ALERT_FEEDBACK = 'alfb'
|
||||
ALERT_FEEDBACK_ID = 'alfi'
|
||||
ALERT_SETTINGS = 'alrs'
|
||||
ALIAS = 'alia'
|
||||
ALIAS_EMAIL = 'alie'
|
||||
ALIAS_TARGET = 'alit'
|
||||
@@ -75,6 +76,7 @@ class GamEntity():
|
||||
BACKUP_VERIFICATION_CODES = 'buvc'
|
||||
BUILDING = 'bldg'
|
||||
BUILDING_ID = 'bldi'
|
||||
BUSINESS_PROFILE_ACCOUNT = 'bpac'
|
||||
CAA_LEVEL = 'calv'
|
||||
CALENDAR = 'cale'
|
||||
CALENDAR_ACL = 'cacl'
|
||||
@@ -86,6 +88,7 @@ class GamEntity():
|
||||
CHANNEL_SKU = 'chsk'
|
||||
CHAT_BOT = 'chbo'
|
||||
CHAT_ADMIN = 'chad'
|
||||
CHAT_EMOJI = 'chem'
|
||||
CHAT_EVENT = 'chev'
|
||||
CHAT_MANAGER_USER = 'chgu'
|
||||
CHAT_MEMBER = 'chme'
|
||||
@@ -93,6 +96,7 @@ class GamEntity():
|
||||
CHAT_MEMBER_USER = 'chmu'
|
||||
CHAT_MESSAGE = 'chms'
|
||||
CHAT_MESSAGE_ID = 'chmi'
|
||||
CHAT_OWNER_USER = 'chou'
|
||||
CHAT_SPACE = 'chsp'
|
||||
CHAT_THREAD = 'chth'
|
||||
CHILD_ORGANIZATIONAL_UNIT = 'corg'
|
||||
@@ -110,6 +114,7 @@ class GamEntity():
|
||||
CHROME_POLICY_IMAGE = 'cpim'
|
||||
CHROME_POLICY_SCHEMA = 'cpsc'
|
||||
CHROME_PROFILE = 'cpro'
|
||||
CHROME_PROFILE_COMMAND = 'cpcm'
|
||||
CHROME_RELEASE = 'crel'
|
||||
CHROME_VERSION = 'cver'
|
||||
CLASSIFICATION_LABEL = 'dlab'
|
||||
@@ -151,6 +156,8 @@ class GamEntity():
|
||||
COURSE_MATERIAL_STATE = 'cmst'
|
||||
COURSE_NAME = 'cona'
|
||||
COURSE_STATE = 'cost'
|
||||
COURSE_STUDENTGROUP = 'cosg'
|
||||
COURSE_STUDENTGROUP_MEMBER = 'csgm'
|
||||
COURSE_SUBMISSION_ID = 'csid'
|
||||
COURSE_SUBMISSION_STATE = 'csst'
|
||||
COURSE_TOPIC = 'ctop'
|
||||
@@ -282,10 +289,11 @@ class GamEntity():
|
||||
MIMETYPE = 'mime'
|
||||
MOBILE_DEVICE = 'mobi'
|
||||
NAME = 'name'
|
||||
NONEDITABLE_ALIAS = 'neal'
|
||||
NOTE = 'note'
|
||||
NOTE_ACL = 'nota'
|
||||
NOTES_ACLS = 'naac'
|
||||
NONEDITABLE_ALIAS = 'neal'
|
||||
NOTIFICATION = 'noti'
|
||||
OAUTH2_TXT_FILE = 'oaut'
|
||||
OAUTH2SERVICE_JSON_FILE = 'oau2'
|
||||
ORGANIZATIONAL_UNIT = 'orgu'
|
||||
@@ -356,7 +364,12 @@ class GamEntity():
|
||||
SUBSCRIPTION = 'subs'
|
||||
SVCACCT = 'svac'
|
||||
SVCACCT_KEY = 'svky'
|
||||
TARGET_USER = 'tgt'
|
||||
TAGMANAGER_ACCOUNT = 'tmac'
|
||||
TAGMANAGER_CONTAINER = 'tmco'
|
||||
TAGMANAGER_PERMISSION = 'tmpm'
|
||||
TAGMANAGER_TAG = 'tmtg'
|
||||
TAGMANAGER_WORKSPACE = 'tmws'
|
||||
TARGET_USER = 'tgt '
|
||||
TASK = 'task'
|
||||
TASKLIST = 'tali'
|
||||
TEACHER = 'teac'
|
||||
@@ -372,11 +385,13 @@ class GamEntity():
|
||||
URL = 'url '
|
||||
USER = 'user'
|
||||
USER_ALIAS = 'uali'
|
||||
USER_NOT_ARCHIVED = 'usna'
|
||||
USER_ARCHIVED = 'usar'
|
||||
USER_EMAIL = 'uema'
|
||||
USER_INVITATION = 'uinv'
|
||||
USER_NOT_SUSPENDED = 'uns'
|
||||
USER_SCHEMA = 'usch'
|
||||
USER_NOT_SUSPENDED = 'usns'
|
||||
USER_SUSPENDED = 'usup'
|
||||
USER_SCHEMA = 'usch'
|
||||
VACATION = 'vaca'
|
||||
VACATION_ENABLED = 'vace'
|
||||
VALUE = 'val'
|
||||
@@ -387,6 +402,8 @@ class GamEntity():
|
||||
VAULT_MATTER_ID = 'vlmi'
|
||||
VAULT_OPERATION = 'vlto'
|
||||
VAULT_QUERY = 'vltq'
|
||||
WEB_MASTERSITE = 'wems'
|
||||
WEB_RESOURCE = 'were'
|
||||
WEBCLIPS_ENABLED = 'webc'
|
||||
YOUTUBE_CHANNEL = 'ytch'
|
||||
# _NAMES[0] is plural, _NAMES[1] is singular unless the item name is explicitly plural (Calendar Settings)
|
||||
@@ -404,6 +421,7 @@ class GamEntity():
|
||||
ALERT_ID: ['Alert IDs', 'Alert ID'],
|
||||
ALERT_FEEDBACK: ['Alert Feedbacks', 'Alert Feedback'],
|
||||
ALERT_FEEDBACK_ID: ['Alert Feedback IDs', 'Alert Feedback ID'],
|
||||
ALERT_SETTINGS: ['Alert Settings', 'Alert Settings'],
|
||||
ALIAS: ['Aliases', 'Alias'],
|
||||
ALIAS_EMAIL: ['Alias Emails', 'Alias Email'],
|
||||
ALIAS_TARGET: ['Alias Targets', 'Alias Target'],
|
||||
@@ -425,6 +443,7 @@ class GamEntity():
|
||||
BACKUP_VERIFICATION_CODES: ['Backup Verification Codes', 'Backup Verification Codes'],
|
||||
BUILDING: ['Buildings', 'Building'],
|
||||
BUILDING_ID: ['Building IDs', 'Building ID'],
|
||||
BUSINESS_PROFILE_ACCOUNT: ['Business Profile Accounts', 'Business Profile Account'],
|
||||
CAA_LEVEL: ['CAA Levels', 'CAA Level'],
|
||||
CALENDAR: ['Calendars', 'Calendar'],
|
||||
CALENDAR_ACL: ['Calendar ACLs', 'Calendar ACL'],
|
||||
@@ -436,6 +455,7 @@ class GamEntity():
|
||||
CHANNEL_SKU: ['Channel SKUs', 'Channel SKU'],
|
||||
CHAT_BOT: ['Chat BOTs', 'Chat BOT'],
|
||||
CHAT_ADMIN: ['Chat Admins', 'Chat Admin'],
|
||||
CHAT_EMOJI: ['Chat Emojis', 'Chat Emoji'],
|
||||
CHAT_EVENT: ['Chat Events', 'Chat Event'],
|
||||
CHAT_MANAGER_USER: ['Chat User Managers', 'Chat User Manager'],
|
||||
CHAT_MESSAGE: ['Chat Messages', 'Chat Message'],
|
||||
@@ -443,6 +463,7 @@ class GamEntity():
|
||||
CHAT_MEMBER: ['Chat Members', 'Chat Member'],
|
||||
CHAT_MEMBER_GROUP: ['Chat Group Members', 'Chat Group Member'],
|
||||
CHAT_MEMBER_USER: ['Chat User Members', 'Chat User Member'],
|
||||
CHAT_OWNER_USER: ['Chat User Owners', 'Chat User Owner'],
|
||||
CHAT_SPACE: ['Chat Spaces', 'Chat Space'],
|
||||
CHAT_THREAD: ['Chat Threads', 'Chat Thread'],
|
||||
CHILD_ORGANIZATIONAL_UNIT: ['Child Organizational Units', 'Child Organizational Unit'],
|
||||
@@ -460,6 +481,7 @@ class GamEntity():
|
||||
CHROME_POLICY_IMAGE: ['Chrome Policy Images', 'Chrome Policy Image'],
|
||||
CHROME_POLICY_SCHEMA: ['Chrome Policy Schemas', 'Chrome Policy Schema'],
|
||||
CHROME_PROFILE: ['Chrome Profiles', 'Chrome Profile'],
|
||||
CHROME_PROFILE_COMMAND: ['Chrome Profile Commands', 'Chrome Profile Command'],
|
||||
CHROME_RELEASE: ['Chrome Releases', 'Chrome Release'],
|
||||
CHROME_VERSION: ['Chrome Versions', 'Chrome Version'],
|
||||
CLASSIFICATION_LABEL: ['Classification Labels', 'Classification Label'],
|
||||
@@ -501,6 +523,8 @@ class GamEntity():
|
||||
COURSE_MATERIAL_STATE: ['Course Material States', 'Course Material State'],
|
||||
COURSE_NAME: ['Course Names', 'Course Name'],
|
||||
COURSE_STATE: ['Course States', 'Course State'],
|
||||
COURSE_STUDENTGROUP: ['Course Student Groups', 'Course Student Group'],
|
||||
COURSE_STUDENTGROUP_MEMBER: ['Course Student Group Members', 'Course Student Group Member'],
|
||||
COURSE_SUBMISSION_ID: ['Course Submission IDs', 'Course Submission ID'],
|
||||
COURSE_SUBMISSION_STATE: ['Course Submission States', 'Course Submission State'],
|
||||
COURSE_TOPIC: ['Course Topics', 'Course Topic'],
|
||||
@@ -632,10 +656,11 @@ class GamEntity():
|
||||
MIMETYPE: ['MIME Types', 'MIME Type'],
|
||||
MOBILE_DEVICE: ['Mobile Devices', 'Mobile Device'],
|
||||
NAME: ['Names', 'Name'],
|
||||
NONEDITABLE_ALIAS: ['Non-Editable Aliases', 'Non-Editable Alias'],
|
||||
NOTE: ['Notes', 'Note'],
|
||||
NOTE_ACL: ['Note ACLs', 'Note ACL'],
|
||||
NOTES_ACLS: ["'Note's ACLs", "Note's ACLs"],
|
||||
NONEDITABLE_ALIAS: ['Non-Editable Aliases', 'Non-Editable Alias'],
|
||||
NOTIFICATION: ['Notifications', 'Notification'],
|
||||
OAUTH2_TXT_FILE: ['Client OAuth2 File', 'Client OAuth2 File'],
|
||||
OAUTH2SERVICE_JSON_FILE: ['Service Account OAuth2 File', 'Service Account OAuth2 File'],
|
||||
ORGANIZATIONAL_UNIT: ['Organizational Units', 'Organizational Unit'],
|
||||
@@ -706,6 +731,11 @@ class GamEntity():
|
||||
SUBSCRIPTION: ['Subscriptions', 'Subscription'],
|
||||
SVCACCT: ['Service Accounts', 'Service Account'],
|
||||
SVCACCT_KEY: ['Service Account Keys', 'Service Account Key'],
|
||||
TAGMANAGER_ACCOUNT: ['Tag Manager Accounts', 'Tag Manager Account'],
|
||||
TAGMANAGER_CONTAINER: ['Tag Manager Containers', 'Tag Manager Container'],
|
||||
TAGMANAGER_PERMISSION: ['Tag Manager Permissions', 'Tag Manager Permission'],
|
||||
TAGMANAGER_TAG: ['Tag Manager Tags', 'Tag Manager Tag'],
|
||||
TAGMANAGER_WORKSPACE: ['Tag Manager Workspaces', 'Tag Manager Workspace'],
|
||||
TARGET_USER: ['Target Users', 'Target User'],
|
||||
TASK: ['Tasks', 'Task'],
|
||||
TASKLIST: ['Tasklists', 'Tasklist'],
|
||||
@@ -722,11 +752,13 @@ class GamEntity():
|
||||
URL: ['URLs', 'URL'],
|
||||
USER: ['Users', 'User'],
|
||||
USER_ALIAS: ['User Aliases', 'User Alias'],
|
||||
USER_NOT_ARCHIVED: ['Users (Not archived)', 'User (Not archived)'],
|
||||
USER_ARCHIVED: ['Users (Archived)', 'User (Archived)'],
|
||||
USER_EMAIL: ['User Emails', 'User Email'],
|
||||
USER_INVITATION: ['User Invitations', 'User Invitation'],
|
||||
USER_NOT_SUSPENDED: ['Users (Not suspended)', 'User (Not suspended)'],
|
||||
USER_SCHEMA: ['Schemas', 'Schema'],
|
||||
USER_SUSPENDED: ['Users (Suspended)', 'User (Suspended)'],
|
||||
USER_SCHEMA: ['Schemas', 'Schema'],
|
||||
VACATION: ['Vacation', 'Vacation'],
|
||||
VACATION_ENABLED: ['Vacation Enabled', 'Vacation Enabled'],
|
||||
VALUE: ['Values', 'Value'],
|
||||
@@ -738,6 +770,8 @@ class GamEntity():
|
||||
VAULT_OPERATION: ['Vault Operations', 'Vault Operation'],
|
||||
VAULT_QUERY: ['Vault Queries', 'Vault Query'],
|
||||
WEBCLIPS_ENABLED: ['Web Clips Enabled', 'Web Clips Enabled'],
|
||||
WEB_MASTERSITE: ['Web Master Sites', 'Web Master Site'],
|
||||
WEB_RESOURCE: ['Web Resources', 'Web Resource'],
|
||||
YOUTUBE_CHANNEL: ['YouTube Channels', 'YouTube Channel'],
|
||||
ROLE_MANAGER: ['Managers', 'Manager'],
|
||||
ROLE_MEMBER: ['Members', 'Member'],
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
ABORTED = 'aborted'
|
||||
ABUSIVE_CONTENT_RESTRICTION = 'abusiveContentRestriction'
|
||||
ACCESS_NOT_CONFIGURED = 'accessNotConfigured'
|
||||
ADMIN_CANNOT_UNSUSPEND = 'adminCannotUnsuspend'
|
||||
ALREADY_EXISTS = 'alreadyExists'
|
||||
APPLY_LABEL_FORBIDDEN = 'applyLabelForbidden'
|
||||
AUTH_ERROR = 'authError'
|
||||
@@ -41,6 +42,7 @@ CANNOT_DELETE_PERMISSION = 'cannotDeletePermission'
|
||||
CANNOT_DELETE_PRIMARY_CALENDAR = 'cannotDeletePrimaryCalendar'
|
||||
CANNOT_DELETE_PRIMARY_SENDAS = 'cannotDeletePrimarySendAs'
|
||||
CANNOT_DELETE_RESOURCE_WITH_CHILDREN = 'cannotDeleteResourceWithChildren'
|
||||
CANNOT_MODIFY_INHERITED_PERMISSION = 'cannotModifyInheritedPermission'
|
||||
CANNOT_MODIFY_INHERITED_TEAMDRIVE_PERMISSION = 'cannotModifyInheritedTeamDrivePermission'
|
||||
CANNOT_MODIFY_RESTRICTED_LABEL = 'cannotModifyRestrictedLabel'
|
||||
CANNOT_MODIFY_VIEWERS_CAN_COPY_CONTENT = 'cannotModifyViewersCanCopyContent'
|
||||
@@ -133,6 +135,7 @@ OPERATION_NOT_SUPPORTED = 'operationNotSupported'
|
||||
ORGANIZER_ON_NON_TEAMDRIVE_NOT_SUPPORTED = 'organizerOnNonTeamDriveNotSupported'
|
||||
ORGANIZER_ON_NON_TEAMDRIVE_ITEM_NOT_SUPPORTED = 'organizerOnNonTeamDriveItemNotSupported'
|
||||
ORGUNIT_NOT_FOUND = 'orgunitNotFound'
|
||||
OUTSIDE_DOMAIN_MEMBER_CANNOT_CHANGE_TEAMDRIVE_RESTRICTIONS = 'outsideDomainMemberCannotChangeTeamDriveRestrictions'
|
||||
OWNER_ON_TEAMDRIVE_ITEM_NOT_SUPPORTED = 'ownerOnTeamDriveItemNotSupported'
|
||||
OWNERSHIP_CHANGE_ACROSS_DOMAIN_NOT_PERMITTED = 'ownershipChangeAcrossDomainNotPermitted'
|
||||
PARTICIPANT_IS_NEITHER_ORGANIZER_NOR_ATTENDEE = 'participantIsNeitherOrganizerNorAttendee'
|
||||
@@ -228,6 +231,7 @@ DRIVE3_CREATE_ACL_THROW_REASONS = [BAD_REQUEST, INVALID, INVALID_SHARING_REQUEST
|
||||
FILE_ORGANIZER_NOT_YET_ENABLED_FOR_THIS_TEAMDRIVE,
|
||||
FILE_ORGANIZER_ON_FOLDERS_IN_SHARED_DRIVE_ONLY,
|
||||
FILE_ORGANIZER_ON_NON_TEAMDRIVE_NOT_SUPPORTED,
|
||||
CANNOT_MODIFY_INHERITED_PERMISSION,
|
||||
TEAMDRIVES_FOLDER_SHARING_NOT_SUPPORTED, INVALID_LINK_VISIBILITY, ABUSIVE_CONTENT_RESTRICTION]
|
||||
DRIVE3_GET_ACL_REASONS = DRIVE_USER_THROW_REASONS+[FILE_NOT_FOUND, FORBIDDEN, INTERNAL_ERROR,
|
||||
INSUFFICIENT_ADMINISTRATOR_PRIVILEGES, INSUFFICIENT_FILE_PERMISSIONS,
|
||||
@@ -248,10 +252,10 @@ DRIVE3_UPDATE_ACL_THROW_REASONS = [BAD_REQUEST, INVALID_OWNERSHIP_TRANSFER, CANN
|
||||
FILE_ORGANIZER_ON_FOLDERS_IN_SHARED_DRIVE_ONLY,
|
||||
FILE_ORGANIZER_ON_NON_TEAMDRIVE_NOT_SUPPORTED,
|
||||
CANNOT_UPDATE_PERMISSION,
|
||||
CANNOT_MODIFY_INHERITED_TEAMDRIVE_PERMISSION,
|
||||
CANNOT_MODIFY_INHERITED_TEAMDRIVE_PERMISSION, CANNOT_MODIFY_INHERITED_PERMISSION,
|
||||
FIELD_NOT_WRITABLE, PERMISSION_NOT_FOUND]
|
||||
DRIVE3_DELETE_ACL_THROW_REASONS = [BAD_REQUEST, CANNOT_REMOVE_OWNER,
|
||||
CANNOT_MODIFY_INHERITED_TEAMDRIVE_PERMISSION,
|
||||
CANNOT_MODIFY_INHERITED_TEAMDRIVE_PERMISSION, CANNOT_MODIFY_INHERITED_PERMISSION,
|
||||
INSUFFICIENT_ADMINISTRATOR_PRIVILEGES, SHARING_RATE_LIMIT_EXCEEDED,
|
||||
NOT_FOUND, PERMISSION_NOT_FOUND, CANNOT_DELETE_PERMISSION]
|
||||
DRIVE3_MODIFY_LABEL_THROW_REASONS = DRIVE_USER_THROW_REASONS+[FILE_NOT_FOUND, NOT_FOUND, FORBIDDEN, INTERNAL_ERROR,
|
||||
@@ -273,17 +277,18 @@ GROUP_SETTINGS_THROW_REASONS = [NOT_FOUND, GROUP_NOT_FOUND, DOMAIN_NOT_FOUND, DO
|
||||
INVALID, INVALID_ARGUMENT, INVALID_PARAMETER, INVALID_ATTRIBUTE_VALUE, INVALID_INPUT,
|
||||
SERVICE_LIMIT, SERVICE_NOT_AVAILABLE, AUTH_ERROR, REQUIRED]
|
||||
GROUP_SETTINGS_RETRY_REASONS = [INVALID, SERVICE_LIMIT, SERVICE_NOT_AVAILABLE]
|
||||
GROUP_LIST_THROW_REASONS = [RESOURCE_NOT_FOUND, DOMAIN_NOT_FOUND, FORBIDDEN, BAD_REQUEST]
|
||||
GROUP_LIST_THROW_REASONS = [RESOURCE_NOT_FOUND, DOMAIN_NOT_FOUND, FORBIDDEN, BAD_REQUEST, PERMISSION_DENIED]
|
||||
GROUP_LIST_USERKEY_THROW_REASONS = GROUP_LIST_THROW_REASONS+[INVALID_MEMBER, INVALID_INPUT]
|
||||
KEEP_THROW_REASONS = [AUTH_ERROR, BAD_REQUEST, PERMISSION_DENIED, INVALID_ARGUMENT, NOT_FOUND]
|
||||
LOOKERSTUDIO_THROW_REASONS = [INVALID_ARGUMENT, SERVICE_NOT_AVAILABLE, BAD_REQUEST, NOT_FOUND, PERMISSION_DENIED, INTERNAL_ERROR]
|
||||
MEMBERS_THROW_REASONS = [GROUP_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, INVALID, FORBIDDEN, SERVICE_NOT_AVAILABLE]
|
||||
MEMBERS_THROW_REASONS = [GROUP_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, INVALID, FORBIDDEN, SERVICE_NOT_AVAILABLE, PERMISSION_DENIED]
|
||||
MEMBERS_RETRY_REASONS = [SYSTEM_ERROR, SERVICE_NOT_AVAILABLE]
|
||||
ORGUNIT_GET_THROW_REASONS = [INVALID_ORGUNIT, ORGUNIT_NOT_FOUND, BACKEND_ERROR, BAD_REQUEST, INVALID_CUSTOMER_ID, LOGIN_REQUIRED]
|
||||
PEOPLE_ACCESS_THROW_REASONS = [SERVICE_NOT_AVAILABLE, FORBIDDEN, PERMISSION_DENIED, FAILED_PRECONDITION]
|
||||
RESELLER_THROW_REASONS = [BAD_REQUEST, RESOURCE_NOT_FOUND, FORBIDDEN, INVALID]
|
||||
SHEETS_ACCESS_THROW_REASONS = DRIVE_USER_THROW_REASONS+[NOT_FOUND, PERMISSION_DENIED, FORBIDDEN, INTERNAL_ERROR, INSUFFICIENT_FILE_PERMISSIONS,
|
||||
BAD_REQUEST, INVALID, INVALID_ARGUMENT, FAILED_PRECONDITION]
|
||||
TAGMANAGER_THROW_REASONS = [BAD_REQUEST, PERMISSION_DENIED, INVALID, NOT_FOUND, ACCESS_NOT_CONFIGURED]
|
||||
TASK_THROW_REASONS = [BAD_REQUEST, PERMISSION_DENIED, INVALID, NOT_FOUND, ACCESS_NOT_CONFIGURED]
|
||||
TASKLIST_THROW_REASONS = [BAD_REQUEST, PERMISSION_DENIED, INVALID, NOT_FOUND, ACCESS_NOT_CONFIGURED]
|
||||
USER_GET_THROW_REASONS = [USER_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, BAD_REQUEST, SYSTEM_ERROR]
|
||||
@@ -364,6 +369,8 @@ class abusiveContentRestriction(Exception):
|
||||
pass
|
||||
class accessNotConfigured(Exception):
|
||||
pass
|
||||
class adminCannotUnsuspend(Exception):
|
||||
pass
|
||||
class alreadyExists(Exception):
|
||||
pass
|
||||
class applyLabelForbidden(Exception):
|
||||
@@ -398,6 +405,8 @@ class cannotDeletePrimarySendAs(Exception):
|
||||
pass
|
||||
class cannotDeleteResourceWithChildren(Exception):
|
||||
pass
|
||||
class cannotModifyInheritedPermission(Exception):
|
||||
pass
|
||||
class cannotModifyInheritedTeamDrivePermission(Exception):
|
||||
pass
|
||||
class cannotModifyRestrictedLabel(Exception):
|
||||
@@ -574,6 +583,8 @@ class organizerOnNonTeamDriveItemNotSupported(Exception):
|
||||
pass
|
||||
class orgunitNotFound(Exception):
|
||||
pass
|
||||
class outsideDomainMemberCannotChangeTeamDriveRestrictions(Exception):
|
||||
pass
|
||||
class ownerOnTeamDriveItemNotSupported(Exception):
|
||||
pass
|
||||
class ownershipChangeAcrossDomainNotPermitted(Exception):
|
||||
@@ -681,6 +692,7 @@ REASON_EXCEPTION_MAP = {
|
||||
ABORTED: aborted,
|
||||
ABUSIVE_CONTENT_RESTRICTION: abusiveContentRestriction,
|
||||
ACCESS_NOT_CONFIGURED: accessNotConfigured,
|
||||
ADMIN_CANNOT_UNSUSPEND: adminCannotUnsuspend,
|
||||
ALREADY_EXISTS: alreadyExists,
|
||||
APPLY_LABEL_FORBIDDEN: applyLabelForbidden,
|
||||
AUTH_ERROR: authError,
|
||||
@@ -698,6 +710,7 @@ REASON_EXCEPTION_MAP = {
|
||||
CANNOT_DELETE_PRIMARY_CALENDAR: cannotDeletePrimaryCalendar,
|
||||
CANNOT_DELETE_PRIMARY_SENDAS: cannotDeletePrimarySendAs,
|
||||
CANNOT_DELETE_RESOURCE_WITH_CHILDREN: cannotDeleteResourceWithChildren,
|
||||
CANNOT_MODIFY_INHERITED_PERMISSION: cannotModifyInheritedPermission,
|
||||
CANNOT_MODIFY_INHERITED_TEAMDRIVE_PERMISSION: cannotModifyInheritedTeamDrivePermission,
|
||||
CANNOT_MODIFY_RESTRICTED_LABEL: cannotModifyRestrictedLabel,
|
||||
CANNOT_MODIFY_VIEWERS_CAN_COPY_CONTENT: cannotModifyViewersCanCopyContent,
|
||||
@@ -786,6 +799,7 @@ REASON_EXCEPTION_MAP = {
|
||||
ORGANIZER_ON_NON_TEAMDRIVE_NOT_SUPPORTED: organizerOnNonTeamDriveNotSupported,
|
||||
ORGANIZER_ON_NON_TEAMDRIVE_ITEM_NOT_SUPPORTED: organizerOnNonTeamDriveItemNotSupported,
|
||||
ORGUNIT_NOT_FOUND: orgunitNotFound,
|
||||
OUTSIDE_DOMAIN_MEMBER_CANNOT_CHANGE_TEAMDRIVE_RESTRICTIONS: outsideDomainMemberCannotChangeTeamDriveRestrictions,
|
||||
OWNER_ON_TEAMDRIVE_ITEM_NOT_SUPPORTED: ownerOnTeamDriveItemNotSupported,
|
||||
OWNERSHIP_CHANGE_ACROSS_DOMAIN_NOT_PERMITTED: ownershipChangeAcrossDomainNotPermitted,
|
||||
PARTICIPANT_IS_NEITHER_ORGANIZER_NOR_ATTENDEE: participantIsNeitherOrganizerNorAttendee,
|
||||
|
||||
@@ -31,6 +31,8 @@ API_CALLS_RETRY_DATA = 'rtry'
|
||||
CACHE_DIR = 'gacd'
|
||||
# Reset GAM cache directory after discovery
|
||||
CACHE_DISCOVERY_ONLY = 'gcdo'
|
||||
# Classroom owner service object
|
||||
CLASSROOM_OWNER_SA = 'cosa'
|
||||
# Classroom service not available
|
||||
CLASSROOM_SERVICE_NOT_AVAILABLE = 'csna'
|
||||
# Command logging
|
||||
@@ -221,6 +223,7 @@ Globals = {
|
||||
API_CALLS_RETRY_DATA: {},
|
||||
CACHE_DIR: None,
|
||||
CACHE_DISCOVERY_ONLY: True,
|
||||
CLASSROOM_OWNER_SA: {},
|
||||
CLASSROOM_SERVICE_NOT_AVAILABLE: False,
|
||||
CMDLOG_HANDLER: None,
|
||||
CMDLOG_LOGGER: None,
|
||||
|
||||
@@ -53,7 +53,7 @@ Please go to:
|
||||
5. Click "NEXT"
|
||||
6. Under "Audience", choose INTERNAL
|
||||
7. Click "NEXT"
|
||||
8. Under, "Contact Information", enter an email address in "Email addresses *"
|
||||
8. Under, "Contact Information", enter {2} or another value in "Email addresses *"
|
||||
9. Click "NEXT"
|
||||
10. Under "Finish", click "I agree to the Google API Services: User Data Policy."
|
||||
11. Click "CONTINUE"
|
||||
@@ -184,8 +184,8 @@ ALREADY_EXISTS_IN_TARGET_FOLDER = 'Already exists in {0}: {1}'
|
||||
ALREADY_EXISTS_USE_MERGE_ARGUMENT = 'Already exists; use the "merge" argument to merge the labels'
|
||||
API_ACCESS_DENIED = 'API access Denied'
|
||||
API_CALLS_RETRY_DATA = 'API calls retry data\n'
|
||||
API_CHECK_CLIENT_AUTHORIZATION = 'Please make sure the Client ID: {0} is authorized for the appropriate API or scopes:\n{1}\n\nRun: gam oauth create\n'
|
||||
API_CHECK_SVCACCT_AUTHORIZATION = 'Please make sure the Service Account Client ID: {0} is authorized for the appropriate API or scopes:\n{1}\n\nRun: gam user {2} update serviceaccount\n'
|
||||
API_CHECK_CLIENT_AUTHORIZATION = 'Please make sure the Client ID: {0} is authorized for the appropriate API or scopes: {1}\n\nRun: gam oauth create\n'
|
||||
API_CHECK_SVCACCT_AUTHORIZATION = 'Please make sure the Service Account Client ID: {0} is authorized for the appropriate API or scopes: {1}\n\nRun: gam user {2} update serviceaccount\n'
|
||||
API_ERROR_SETTINGS = 'API error, some settings not set'
|
||||
ARE_BOTH_REQUIRED = 'Arguments {0} and {1} are both required'
|
||||
ARE_MUTUALLY_EXCLUSIVE = 'Arguments {0} and {1} are mutually exclusive'
|
||||
@@ -309,6 +309,7 @@ INVALID_ALIAS = 'Invalid Alias'
|
||||
INVALID_ATTENDEE_CHANGE = 'Invalid attendee change "{0}"'
|
||||
INVALID_CHARSET = 'Invalid charset "{0}"'
|
||||
INVALID_DATE_TIME_RANGE = '{0} {1} must be greater than/equal to {2} {3}'
|
||||
INVALID_EMOJI_NAME = '{0} does not match pattern :[0-9a-z_-]:'
|
||||
INVALID_ENTITY = 'Invalid {0}, {1}'
|
||||
INVALID_EVENT_TIMERANGE = '{0} {1} must be less than {2}'
|
||||
INVALID_FILE_SELECTION_WITH_ADMIN_ACCESS = 'Invalid file selection with adminaccess|asadmin'
|
||||
@@ -424,7 +425,7 @@ NO_LABELS_TO_PROCESS = 'No Labels to process'
|
||||
NO_MESSAGES_WITH_LABEL = 'No Messages with Label'
|
||||
NO_PARENTS_TO_CONVERT_TO_SHORTCUTS = 'No parents to convert to shortcuts'
|
||||
NO_REPORT_AVAILABLE = 'No {0} report available.'
|
||||
NO_SCOPES_FOR_API = 'There are no scopes authorized for the {0}'
|
||||
NO_SCOPES_FOR_API = 'There are no scopes authorized for the API(s): {0}'
|
||||
NO_SERIAL_NUMBERS_SPECIFIED = 'No serial numbers specified'
|
||||
NO_SSO_PROFILE_MATCHES = 'No SSO profile matches display name {0}'
|
||||
NO_SSO_PROFILE_ASSIGNED = 'No SSO profile assigned to {0} {1}'
|
||||
@@ -432,6 +433,7 @@ NO_SVCACCT_ACCESS_ALLOWED = 'No Service Account Access allowed'
|
||||
NO_TRANSFER_LACK_OF_DISK_SPACE = 'Transfer not performed due to lack of target drive space.'
|
||||
NO_USAGE_PARAMETERS_DATA_AVAILABLE = 'No usage parameters data available.'
|
||||
NO_USER_COUNTS_DATA_AVAILABLE = 'No User counts data available.'
|
||||
NUM_SELECTED_CLIENT_SCOPES = '\n{0} scopes are selected, if more than {1} scopes are selected, Google will probably generate a "Something went wrong" error\n'
|
||||
OAUTH2_GO_TO_LINK_MESSAGE = """
|
||||
Go to the following link in a browser on this computer or on another computer:
|
||||
|
||||
@@ -463,6 +465,7 @@ PROCESSING_ITEM_N = '{0},0,Processing item {1}\n'
|
||||
PROCESSING_ITEM_N_OF_M = '{0},0,Processing item {1}/{2}\n'
|
||||
PROFILE_PHOTO_NOT_FOUND = 'Profile photo not found'
|
||||
PROFILE_PHOTO_IS_DEFAULT = 'Profile photo is default'
|
||||
QUOTA_EXCEEDED = 'Quota exceeded'
|
||||
REASON_ONLY_VALID_WITH_CONTENTRESTRICTIONS_READONLY_TRUE = 'reason only valid with contentrestrictions readonly true'
|
||||
REAUTHENTICATION_IS_NEEDED = 'Reauthentication is needed, please run\n\ngam oauth create'
|
||||
RECOMMEND_RUNNING_GAM_ROTATE_SAKEY = 'Recommend running "gam rotate sakey" to get a new key\n'
|
||||
@@ -496,6 +499,7 @@ STATISTICS_MOVE_FILE = 'Total: {0}, Moved: {1}, Shortcut created {2}, Shortcut e
|
||||
STATISTICS_MOVE_FOLDER = 'Total: {0}, Moved: {1}, Shortcut created {2}, Shortcut exists {3}, Duplicate: {4}, Merged: {5}, Move Failed: {6}, Not writable: {7}'
|
||||
STATISTICS_USER_NOT_ORGANIZER = 'User not organizer: {0}'
|
||||
STRING_LENGTH = 'string length'
|
||||
STUDENT_NOT_IN_COURSE = 'Student not in course'
|
||||
SUBKEY_FIELD_MISMATCH = 'subkeyfield {0} does not match saved subkeyfield {1}'
|
||||
SUBSCRIPTION_NOT_FOUND = 'Could not find subscription'
|
||||
SUFFIX_NOT_ALLOWED_WITH_CUSTOMLANGUAGE = 'Suffix {0} not allowed with customLanguage {1}'
|
||||
|
||||
@@ -100,13 +100,15 @@ _SKUS = {
|
||||
'1010470003': {
|
||||
'product': '101047', 'aliases': ['geminibiz'], 'displayName': 'Gemini Business'},
|
||||
'1010470004': {
|
||||
'product': '101047', 'aliases': ['geminiedu'], 'displayName': 'Gemini Education'},
|
||||
'product': '101047', 'aliases': ['gaiproedu', 'geminiedu'], 'displayName': 'Google AI Pro for Education'},
|
||||
'1010470005': {
|
||||
'product': '101047', 'aliases': ['geminiedupremium'], 'displayName': 'Gemini Education Premium'},
|
||||
'1010470006': {
|
||||
'product': '101047', 'aliases': ['aisecurity'], 'displayName': 'AI Security'},
|
||||
'1010470007': {
|
||||
'product': '101047', 'aliases': ['aimeetingsandmessaging'], 'displayName': 'AI Meetings and Messaging'},
|
||||
'1010470008': {
|
||||
'product': '101047', 'aliases': ['geminiultra'], 'displayName': 'Google AI Ultra for Business'},
|
||||
'1010490001': {
|
||||
'product': '101049', 'aliases': ['eeu'], 'displayName': 'Endpoint Education Upgrade'},
|
||||
'1010500001': {
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"""
|
||||
|
||||
GAM_VER_LIBS = [
|
||||
'arrow',
|
||||
'chardet',
|
||||
'cryptography',
|
||||
'filelock',
|
||||
@@ -33,6 +34,5 @@ GAM_VER_LIBS = [
|
||||
'passlib',
|
||||
'pathvalidate',
|
||||
'pyscard',
|
||||
'python-dateutil',
|
||||
'yubikey-manager',
|
||||
]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2023 Ross Scroggs All Rights Reserved.
|
||||
# Copyright (C) 2025 Ross Scroggs All Rights Reserved.
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
@@ -19,11 +19,20 @@
|
||||
"""YubiKey"""
|
||||
|
||||
import base64
|
||||
import datetime
|
||||
from secrets import SystemRandom
|
||||
import string
|
||||
import sys
|
||||
|
||||
import arrow
|
||||
|
||||
from gam import mplock
|
||||
|
||||
from gam import systemErrorExit
|
||||
from gam import readStdin
|
||||
from gam import writeStdout
|
||||
|
||||
from gam.gamlib import glmsgs as Msg
|
||||
|
||||
from cryptography.hazmat.primitives import hashes, serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import padding
|
||||
from smartcard.Exceptions import CardConnectionException
|
||||
@@ -49,14 +58,6 @@ YUBIKEY_VALUE_ERROR_RC = 85
|
||||
YUBIKEY_MULTIPLE_CONNECTED_RC = 86
|
||||
YUBIKEY_NOT_FOUND_RC = 87
|
||||
|
||||
from gam import mplock
|
||||
|
||||
from gam import systemErrorExit
|
||||
from gam import readStdin
|
||||
from gam import writeStdout
|
||||
|
||||
from gam.gamlib import glmsgs as Msg
|
||||
|
||||
PIN_PUK_CHARS = string.ascii_letters+string.digits+string.punctuation
|
||||
|
||||
class YubiKey():
|
||||
@@ -155,8 +156,8 @@ class YubiKey():
|
||||
KEY_TYPE.RSA2048,
|
||||
PIN_POLICY.ALWAYS,
|
||||
TOUCH_POLICY.NEVER)
|
||||
now = datetime.datetime.utcnow()
|
||||
valid_to = now + datetime.timedelta(days=36500)
|
||||
now = arrow.utcnow()
|
||||
valid_to = now.shift(days=36500)
|
||||
subject = 'CN=GAM Created Key'
|
||||
piv.authenticate(MANAGEMENT_KEY_TYPE.TDES, DEFAULT_MANAGEMENT_KEY)
|
||||
piv.verify_pin(new_pin)
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
# Copyright 2014 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Set default logging handler to avoid "No handler found" warnings.
|
||||
import logging
|
||||
|
||||
try: # Python 2.7+
|
||||
from logging import NullHandler
|
||||
except ImportError:
|
||||
|
||||
class NullHandler(logging.Handler):
|
||||
def emit(self, record):
|
||||
pass
|
||||
|
||||
|
||||
logging.getLogger(__name__).addHandler(NullHandler())
|
||||
@@ -1,167 +0,0 @@
|
||||
# Copyright 2016 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Helpers for authentication using oauth2client or google-auth."""
|
||||
|
||||
import httplib2
|
||||
|
||||
try:
|
||||
import google.auth
|
||||
import google.auth.credentials
|
||||
|
||||
HAS_GOOGLE_AUTH = True
|
||||
except ImportError: # pragma: NO COVER
|
||||
HAS_GOOGLE_AUTH = False
|
||||
|
||||
try:
|
||||
import google_auth_httplib2
|
||||
except ImportError: # pragma: NO COVER
|
||||
google_auth_httplib2 = None
|
||||
|
||||
try:
|
||||
import oauth2client
|
||||
import oauth2client.client
|
||||
|
||||
HAS_OAUTH2CLIENT = True
|
||||
except ImportError: # pragma: NO COVER
|
||||
HAS_OAUTH2CLIENT = False
|
||||
|
||||
|
||||
def credentials_from_file(filename, scopes=None, quota_project_id=None):
|
||||
"""Returns credentials loaded from a file."""
|
||||
if HAS_GOOGLE_AUTH:
|
||||
credentials, _ = google.auth.load_credentials_from_file(
|
||||
filename, scopes=scopes, quota_project_id=quota_project_id
|
||||
)
|
||||
return credentials
|
||||
else:
|
||||
raise EnvironmentError(
|
||||
"client_options.credentials_file is only supported in google-auth."
|
||||
)
|
||||
|
||||
|
||||
def default_credentials(scopes=None, quota_project_id=None):
|
||||
"""Returns Application Default Credentials."""
|
||||
if HAS_GOOGLE_AUTH:
|
||||
credentials, _ = google.auth.default(
|
||||
scopes=scopes, quota_project_id=quota_project_id
|
||||
)
|
||||
return credentials
|
||||
elif HAS_OAUTH2CLIENT:
|
||||
if scopes is not None or quota_project_id is not None:
|
||||
raise EnvironmentError(
|
||||
"client_options.scopes and client_options.quota_project_id are not supported in oauth2client."
|
||||
"Please install google-auth."
|
||||
)
|
||||
return oauth2client.client.GoogleCredentials.get_application_default()
|
||||
else:
|
||||
raise EnvironmentError(
|
||||
"No authentication library is available. Please install either "
|
||||
"google-auth or oauth2client."
|
||||
)
|
||||
|
||||
|
||||
def with_scopes(credentials, scopes):
|
||||
"""Scopes the credentials if necessary.
|
||||
|
||||
Args:
|
||||
credentials (Union[
|
||||
google.auth.credentials.Credentials,
|
||||
oauth2client.client.Credentials]): The credentials to scope.
|
||||
scopes (Sequence[str]): The list of scopes.
|
||||
|
||||
Returns:
|
||||
Union[google.auth.credentials.Credentials,
|
||||
oauth2client.client.Credentials]: The scoped credentials.
|
||||
"""
|
||||
if HAS_GOOGLE_AUTH and isinstance(credentials, google.auth.credentials.Credentials):
|
||||
return google.auth.credentials.with_scopes_if_required(credentials, scopes)
|
||||
else:
|
||||
try:
|
||||
if credentials.create_scoped_required():
|
||||
return credentials.create_scoped(scopes)
|
||||
else:
|
||||
return credentials
|
||||
except AttributeError:
|
||||
return credentials
|
||||
|
||||
|
||||
def authorized_http(credentials):
|
||||
"""Returns an http client that is authorized with the given credentials.
|
||||
|
||||
Args:
|
||||
credentials (Union[
|
||||
google.auth.credentials.Credentials,
|
||||
oauth2client.client.Credentials]): The credentials to use.
|
||||
|
||||
Returns:
|
||||
Union[httplib2.Http, google_auth_httplib2.AuthorizedHttp]: An
|
||||
authorized http client.
|
||||
"""
|
||||
from googleapiclient.http import build_http
|
||||
|
||||
if HAS_GOOGLE_AUTH and isinstance(credentials, google.auth.credentials.Credentials):
|
||||
if google_auth_httplib2 is None:
|
||||
raise ValueError(
|
||||
"Credentials from google.auth specified, but "
|
||||
"google-api-python-client is unable to use these credentials "
|
||||
"unless google-auth-httplib2 is installed. Please install "
|
||||
"google-auth-httplib2."
|
||||
)
|
||||
return google_auth_httplib2.AuthorizedHttp(credentials, http=build_http())
|
||||
else:
|
||||
return credentials.authorize(build_http())
|
||||
|
||||
|
||||
def refresh_credentials(credentials):
|
||||
# Refresh must use a new http instance, as the one associated with the
|
||||
# credentials could be a AuthorizedHttp or an oauth2client-decorated
|
||||
# Http instance which would cause a weird recursive loop of refreshing
|
||||
# and likely tear a hole in spacetime.
|
||||
refresh_http = httplib2.Http()
|
||||
if HAS_GOOGLE_AUTH and isinstance(credentials, google.auth.credentials.Credentials):
|
||||
request = google_auth_httplib2.Request(refresh_http)
|
||||
return credentials.refresh(request)
|
||||
else:
|
||||
return credentials.refresh(refresh_http)
|
||||
|
||||
|
||||
def apply_credentials(credentials, headers):
|
||||
# oauth2client and google-auth have the same interface for this.
|
||||
if not is_valid(credentials):
|
||||
refresh_credentials(credentials)
|
||||
return credentials.apply(headers)
|
||||
|
||||
|
||||
def is_valid(credentials):
|
||||
if HAS_GOOGLE_AUTH and isinstance(credentials, google.auth.credentials.Credentials):
|
||||
return credentials.valid
|
||||
else:
|
||||
return (
|
||||
credentials.access_token is not None
|
||||
and not credentials.access_token_expired
|
||||
)
|
||||
|
||||
|
||||
def get_credentials_from_http(http):
|
||||
if http is None:
|
||||
return None
|
||||
elif hasattr(http.request, "credentials"):
|
||||
return http.request.credentials
|
||||
elif hasattr(http, "credentials") and not isinstance(
|
||||
http.credentials, httplib2.Credentials
|
||||
):
|
||||
return http.credentials
|
||||
else:
|
||||
return None
|
||||
@@ -1,207 +0,0 @@
|
||||
# Copyright 2015 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Helper functions for commonly used utilities."""
|
||||
|
||||
import functools
|
||||
import inspect
|
||||
import logging
|
||||
import urllib
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
POSITIONAL_WARNING = "WARNING"
|
||||
POSITIONAL_EXCEPTION = "EXCEPTION"
|
||||
POSITIONAL_IGNORE = "IGNORE"
|
||||
POSITIONAL_SET = frozenset(
|
||||
[POSITIONAL_WARNING, POSITIONAL_EXCEPTION, POSITIONAL_IGNORE]
|
||||
)
|
||||
|
||||
positional_parameters_enforcement = POSITIONAL_WARNING
|
||||
|
||||
_SYM_LINK_MESSAGE = "File: {0}: Is a symbolic link."
|
||||
_IS_DIR_MESSAGE = "{0}: Is a directory"
|
||||
_MISSING_FILE_MESSAGE = "Cannot access {0}: No such file or directory"
|
||||
|
||||
|
||||
def positional(max_positional_args):
|
||||
"""A decorator to declare that only the first N arguments may be positional.
|
||||
|
||||
This decorator makes it easy to support Python 3 style keyword-only
|
||||
parameters. For example, in Python 3 it is possible to write::
|
||||
|
||||
def fn(pos1, *, kwonly1=None, kwonly2=None):
|
||||
...
|
||||
|
||||
All named parameters after ``*`` must be a keyword::
|
||||
|
||||
fn(10, 'kw1', 'kw2') # Raises exception.
|
||||
fn(10, kwonly1='kw1') # Ok.
|
||||
|
||||
Example
|
||||
^^^^^^^
|
||||
|
||||
To define a function like above, do::
|
||||
|
||||
@positional(1)
|
||||
def fn(pos1, kwonly1=None, kwonly2=None):
|
||||
...
|
||||
|
||||
If no default value is provided to a keyword argument, it becomes a
|
||||
required keyword argument::
|
||||
|
||||
@positional(0)
|
||||
def fn(required_kw):
|
||||
...
|
||||
|
||||
This must be called with the keyword parameter::
|
||||
|
||||
fn() # Raises exception.
|
||||
fn(10) # Raises exception.
|
||||
fn(required_kw=10) # Ok.
|
||||
|
||||
When defining instance or class methods always remember to account for
|
||||
``self`` and ``cls``::
|
||||
|
||||
class MyClass(object):
|
||||
|
||||
@positional(2)
|
||||
def my_method(self, pos1, kwonly1=None):
|
||||
...
|
||||
|
||||
@classmethod
|
||||
@positional(2)
|
||||
def my_method(cls, pos1, kwonly1=None):
|
||||
...
|
||||
|
||||
The positional decorator behavior is controlled by
|
||||
``_helpers.positional_parameters_enforcement``, which may be set to
|
||||
``POSITIONAL_EXCEPTION``, ``POSITIONAL_WARNING`` or
|
||||
``POSITIONAL_IGNORE`` to raise an exception, log a warning, or do
|
||||
nothing, respectively, if a declaration is violated.
|
||||
|
||||
Args:
|
||||
max_positional_arguments: Maximum number of positional arguments. All
|
||||
parameters after this index must be
|
||||
keyword only.
|
||||
|
||||
Returns:
|
||||
A decorator that prevents using arguments after max_positional_args
|
||||
from being used as positional parameters.
|
||||
|
||||
Raises:
|
||||
TypeError: if a keyword-only argument is provided as a positional
|
||||
parameter, but only if
|
||||
_helpers.positional_parameters_enforcement is set to
|
||||
POSITIONAL_EXCEPTION.
|
||||
"""
|
||||
|
||||
def positional_decorator(wrapped):
|
||||
@functools.wraps(wrapped)
|
||||
def positional_wrapper(*args, **kwargs):
|
||||
if len(args) > max_positional_args:
|
||||
plural_s = ""
|
||||
if max_positional_args != 1:
|
||||
plural_s = "s"
|
||||
message = (
|
||||
"{function}() takes at most {args_max} positional "
|
||||
"argument{plural} ({args_given} given)".format(
|
||||
function=wrapped.__name__,
|
||||
args_max=max_positional_args,
|
||||
args_given=len(args),
|
||||
plural=plural_s,
|
||||
)
|
||||
)
|
||||
if positional_parameters_enforcement == POSITIONAL_EXCEPTION:
|
||||
raise TypeError(message)
|
||||
elif positional_parameters_enforcement == POSITIONAL_WARNING:
|
||||
logger.warning(message)
|
||||
return wrapped(*args, **kwargs)
|
||||
|
||||
return positional_wrapper
|
||||
|
||||
if isinstance(max_positional_args, int):
|
||||
return positional_decorator
|
||||
else:
|
||||
args, _, _, defaults, _, _, _ = inspect.getfullargspec(max_positional_args)
|
||||
return positional(len(args) - len(defaults))(max_positional_args)
|
||||
|
||||
|
||||
def parse_unique_urlencoded(content):
|
||||
"""Parses unique key-value parameters from urlencoded content.
|
||||
|
||||
Args:
|
||||
content: string, URL-encoded key-value pairs.
|
||||
|
||||
Returns:
|
||||
dict, The key-value pairs from ``content``.
|
||||
|
||||
Raises:
|
||||
ValueError: if one of the keys is repeated.
|
||||
"""
|
||||
urlencoded_params = urllib.parse.parse_qs(content)
|
||||
params = {}
|
||||
for key, value in urlencoded_params.items():
|
||||
if len(value) != 1:
|
||||
msg = "URL-encoded content contains a repeated value:" "%s -> %s" % (
|
||||
key,
|
||||
", ".join(value),
|
||||
)
|
||||
raise ValueError(msg)
|
||||
params[key] = value[0]
|
||||
return params
|
||||
|
||||
|
||||
def update_query_params(uri, params):
|
||||
"""Updates a URI with new query parameters.
|
||||
|
||||
If a given key from ``params`` is repeated in the ``uri``, then
|
||||
the URI will be considered invalid and an error will occur.
|
||||
|
||||
If the URI is valid, then each value from ``params`` will
|
||||
replace the corresponding value in the query parameters (if
|
||||
it exists).
|
||||
|
||||
Args:
|
||||
uri: string, A valid URI, with potential existing query parameters.
|
||||
params: dict, A dictionary of query parameters.
|
||||
|
||||
Returns:
|
||||
The same URI but with the new query parameters added.
|
||||
"""
|
||||
parts = urllib.parse.urlparse(uri)
|
||||
query_params = parse_unique_urlencoded(parts.query)
|
||||
query_params.update(params)
|
||||
new_query = urllib.parse.urlencode(query_params)
|
||||
new_parts = parts._replace(query=new_query)
|
||||
return urllib.parse.urlunparse(new_parts)
|
||||
|
||||
|
||||
def _add_query_parameter(url, name, value):
|
||||
"""Adds a query parameter to a url.
|
||||
|
||||
Replaces the current value if it already exists in the URL.
|
||||
|
||||
Args:
|
||||
url: string, url to add the query parameter to.
|
||||
name: string, query parameter name.
|
||||
value: string, query parameter value.
|
||||
|
||||
Returns:
|
||||
Updated query parameter. Does not update the url if value is None.
|
||||
"""
|
||||
if value is None:
|
||||
return url
|
||||
else:
|
||||
return update_query_params(url, {name: value})
|
||||
@@ -1,315 +0,0 @@
|
||||
# Copyright 2014 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Channel notifications support.
|
||||
|
||||
Classes and functions to support channel subscriptions and notifications
|
||||
on those channels.
|
||||
|
||||
Notes:
|
||||
- This code is based on experimental APIs and is subject to change.
|
||||
- Notification does not do deduplication of notification ids, that's up to
|
||||
the receiver.
|
||||
- Storing the Channel between calls is up to the caller.
|
||||
|
||||
|
||||
Example setting up a channel:
|
||||
|
||||
# Create a new channel that gets notifications via webhook.
|
||||
channel = new_webhook_channel("https://example.com/my_web_hook")
|
||||
|
||||
# Store the channel, keyed by 'channel.id'. Store it before calling the
|
||||
# watch method because notifications may start arriving before the watch
|
||||
# method returns.
|
||||
...
|
||||
|
||||
resp = service.objects().watchAll(
|
||||
bucket="some_bucket_id", body=channel.body()).execute()
|
||||
channel.update(resp)
|
||||
|
||||
# Store the channel, keyed by 'channel.id'. Store it after being updated
|
||||
# since the resource_id value will now be correct, and that's needed to
|
||||
# stop a subscription.
|
||||
...
|
||||
|
||||
|
||||
An example Webhook implementation using webapp2. Note that webapp2 puts
|
||||
headers in a case insensitive dictionary, as headers aren't guaranteed to
|
||||
always be upper case.
|
||||
|
||||
id = self.request.headers[X_GOOG_CHANNEL_ID]
|
||||
|
||||
# Retrieve the channel by id.
|
||||
channel = ...
|
||||
|
||||
# Parse notification from the headers, including validating the id.
|
||||
n = notification_from_headers(channel, self.request.headers)
|
||||
|
||||
# Do app specific stuff with the notification here.
|
||||
if n.resource_state == 'sync':
|
||||
# Code to handle sync state.
|
||||
elif n.resource_state == 'exists':
|
||||
# Code to handle the exists state.
|
||||
elif n.resource_state == 'not_exists':
|
||||
# Code to handle the not exists state.
|
||||
|
||||
|
||||
Example of unsubscribing.
|
||||
|
||||
service.channels().stop(channel.body()).execute()
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
from googleapiclient import _helpers as util
|
||||
from googleapiclient import errors
|
||||
|
||||
# The unix time epoch starts at midnight 1970.
|
||||
EPOCH = datetime.datetime(1970, 1, 1)
|
||||
|
||||
# Map the names of the parameters in the JSON channel description to
|
||||
# the parameter names we use in the Channel class.
|
||||
CHANNEL_PARAMS = {
|
||||
"address": "address",
|
||||
"id": "id",
|
||||
"expiration": "expiration",
|
||||
"params": "params",
|
||||
"resourceId": "resource_id",
|
||||
"resourceUri": "resource_uri",
|
||||
"type": "type",
|
||||
"token": "token",
|
||||
}
|
||||
|
||||
X_GOOG_CHANNEL_ID = "X-GOOG-CHANNEL-ID"
|
||||
X_GOOG_MESSAGE_NUMBER = "X-GOOG-MESSAGE-NUMBER"
|
||||
X_GOOG_RESOURCE_STATE = "X-GOOG-RESOURCE-STATE"
|
||||
X_GOOG_RESOURCE_URI = "X-GOOG-RESOURCE-URI"
|
||||
X_GOOG_RESOURCE_ID = "X-GOOG-RESOURCE-ID"
|
||||
|
||||
|
||||
def _upper_header_keys(headers):
|
||||
new_headers = {}
|
||||
for k, v in headers.items():
|
||||
new_headers[k.upper()] = v
|
||||
return new_headers
|
||||
|
||||
|
||||
class Notification(object):
|
||||
"""A Notification from a Channel.
|
||||
|
||||
Notifications are not usually constructed directly, but are returned
|
||||
from functions like notification_from_headers().
|
||||
|
||||
Attributes:
|
||||
message_number: int, The unique id number of this notification.
|
||||
state: str, The state of the resource being monitored.
|
||||
uri: str, The address of the resource being monitored.
|
||||
resource_id: str, The unique identifier of the version of the resource at
|
||||
this event.
|
||||
"""
|
||||
|
||||
@util.positional(5)
|
||||
def __init__(self, message_number, state, resource_uri, resource_id):
|
||||
"""Notification constructor.
|
||||
|
||||
Args:
|
||||
message_number: int, The unique id number of this notification.
|
||||
state: str, The state of the resource being monitored. Can be one
|
||||
of "exists", "not_exists", or "sync".
|
||||
resource_uri: str, The address of the resource being monitored.
|
||||
resource_id: str, The identifier of the watched resource.
|
||||
"""
|
||||
self.message_number = message_number
|
||||
self.state = state
|
||||
self.resource_uri = resource_uri
|
||||
self.resource_id = resource_id
|
||||
|
||||
|
||||
class Channel(object):
|
||||
"""A Channel for notifications.
|
||||
|
||||
Usually not constructed directly, instead it is returned from helper
|
||||
functions like new_webhook_channel().
|
||||
|
||||
Attributes:
|
||||
type: str, The type of delivery mechanism used by this channel. For
|
||||
example, 'web_hook'.
|
||||
id: str, A UUID for the channel.
|
||||
token: str, An arbitrary string associated with the channel that
|
||||
is delivered to the target address with each event delivered
|
||||
over this channel.
|
||||
address: str, The address of the receiving entity where events are
|
||||
delivered. Specific to the channel type.
|
||||
expiration: int, The time, in milliseconds from the epoch, when this
|
||||
channel will expire.
|
||||
params: dict, A dictionary of string to string, with additional parameters
|
||||
controlling delivery channel behavior.
|
||||
resource_id: str, An opaque id that identifies the resource that is
|
||||
being watched. Stable across different API versions.
|
||||
resource_uri: str, The canonicalized ID of the watched resource.
|
||||
"""
|
||||
|
||||
@util.positional(5)
|
||||
def __init__(
|
||||
self,
|
||||
type,
|
||||
id,
|
||||
token,
|
||||
address,
|
||||
expiration=None,
|
||||
params=None,
|
||||
resource_id="",
|
||||
resource_uri="",
|
||||
):
|
||||
"""Create a new Channel.
|
||||
|
||||
In user code, this Channel constructor will not typically be called
|
||||
manually since there are functions for creating channels for each specific
|
||||
type with a more customized set of arguments to pass.
|
||||
|
||||
Args:
|
||||
type: str, The type of delivery mechanism used by this channel. For
|
||||
example, 'web_hook'.
|
||||
id: str, A UUID for the channel.
|
||||
token: str, An arbitrary string associated with the channel that
|
||||
is delivered to the target address with each event delivered
|
||||
over this channel.
|
||||
address: str, The address of the receiving entity where events are
|
||||
delivered. Specific to the channel type.
|
||||
expiration: int, The time, in milliseconds from the epoch, when this
|
||||
channel will expire.
|
||||
params: dict, A dictionary of string to string, with additional parameters
|
||||
controlling delivery channel behavior.
|
||||
resource_id: str, An opaque id that identifies the resource that is
|
||||
being watched. Stable across different API versions.
|
||||
resource_uri: str, The canonicalized ID of the watched resource.
|
||||
"""
|
||||
self.type = type
|
||||
self.id = id
|
||||
self.token = token
|
||||
self.address = address
|
||||
self.expiration = expiration
|
||||
self.params = params
|
||||
self.resource_id = resource_id
|
||||
self.resource_uri = resource_uri
|
||||
|
||||
def body(self):
|
||||
"""Build a body from the Channel.
|
||||
|
||||
Constructs a dictionary that's appropriate for passing into watch()
|
||||
methods as the value of body argument.
|
||||
|
||||
Returns:
|
||||
A dictionary representation of the channel.
|
||||
"""
|
||||
result = {
|
||||
"id": self.id,
|
||||
"token": self.token,
|
||||
"type": self.type,
|
||||
"address": self.address,
|
||||
}
|
||||
if self.params:
|
||||
result["params"] = self.params
|
||||
if self.resource_id:
|
||||
result["resourceId"] = self.resource_id
|
||||
if self.resource_uri:
|
||||
result["resourceUri"] = self.resource_uri
|
||||
if self.expiration:
|
||||
result["expiration"] = self.expiration
|
||||
|
||||
return result
|
||||
|
||||
def update(self, resp):
|
||||
"""Update a channel with information from the response of watch().
|
||||
|
||||
When a request is sent to watch() a resource, the response returned
|
||||
from the watch() request is a dictionary with updated channel information,
|
||||
such as the resource_id, which is needed when stopping a subscription.
|
||||
|
||||
Args:
|
||||
resp: dict, The response from a watch() method.
|
||||
"""
|
||||
for json_name, param_name in CHANNEL_PARAMS.items():
|
||||
value = resp.get(json_name)
|
||||
if value is not None:
|
||||
setattr(self, param_name, value)
|
||||
|
||||
|
||||
def notification_from_headers(channel, headers):
|
||||
"""Parse a notification from the webhook request headers, validate
|
||||
the notification, and return a Notification object.
|
||||
|
||||
Args:
|
||||
channel: Channel, The channel that the notification is associated with.
|
||||
headers: dict, A dictionary like object that contains the request headers
|
||||
from the webhook HTTP request.
|
||||
|
||||
Returns:
|
||||
A Notification object.
|
||||
|
||||
Raises:
|
||||
errors.InvalidNotificationError if the notification is invalid.
|
||||
ValueError if the X-GOOG-MESSAGE-NUMBER can't be converted to an int.
|
||||
"""
|
||||
headers = _upper_header_keys(headers)
|
||||
channel_id = headers[X_GOOG_CHANNEL_ID]
|
||||
if channel.id != channel_id:
|
||||
raise errors.InvalidNotificationError(
|
||||
"Channel id mismatch: %s != %s" % (channel.id, channel_id)
|
||||
)
|
||||
else:
|
||||
message_number = int(headers[X_GOOG_MESSAGE_NUMBER])
|
||||
state = headers[X_GOOG_RESOURCE_STATE]
|
||||
resource_uri = headers[X_GOOG_RESOURCE_URI]
|
||||
resource_id = headers[X_GOOG_RESOURCE_ID]
|
||||
return Notification(message_number, state, resource_uri, resource_id)
|
||||
|
||||
|
||||
@util.positional(2)
|
||||
def new_webhook_channel(url, token=None, expiration=None, params=None):
|
||||
"""Create a new webhook Channel.
|
||||
|
||||
Args:
|
||||
url: str, URL to post notifications to.
|
||||
token: str, An arbitrary string associated with the channel that
|
||||
is delivered to the target address with each notification delivered
|
||||
over this channel.
|
||||
expiration: datetime.datetime, A time in the future when the channel
|
||||
should expire. Can also be None if the subscription should use the
|
||||
default expiration. Note that different services may have different
|
||||
limits on how long a subscription lasts. Check the response from the
|
||||
watch() method to see the value the service has set for an expiration
|
||||
time.
|
||||
params: dict, Extra parameters to pass on channel creation. Currently
|
||||
not used for webhook channels.
|
||||
"""
|
||||
expiration_ms = 0
|
||||
if expiration:
|
||||
delta = expiration - EPOCH
|
||||
expiration_ms = (
|
||||
delta.microseconds / 1000 + (delta.seconds + delta.days * 24 * 3600) * 1000
|
||||
)
|
||||
if expiration_ms < 0:
|
||||
expiration_ms = 0
|
||||
|
||||
return Channel(
|
||||
"web_hook",
|
||||
str(uuid.uuid4()),
|
||||
token,
|
||||
url,
|
||||
expiration=expiration_ms,
|
||||
params=params,
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,78 +0,0 @@
|
||||
# Copyright 2014 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Caching utility for the discovery document."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DISCOVERY_DOC_MAX_AGE = 60 * 60 * 24 # 1 day
|
||||
DISCOVERY_DOC_DIR = os.path.join(
|
||||
os.path.dirname(os.path.realpath(__file__)), "documents"
|
||||
)
|
||||
|
||||
|
||||
def autodetect():
|
||||
"""Detects an appropriate cache module and returns it.
|
||||
|
||||
Returns:
|
||||
googleapiclient.discovery_cache.base.Cache, a cache object which
|
||||
is auto detected, or None if no cache object is available.
|
||||
"""
|
||||
if "GAE_ENV" in os.environ:
|
||||
try:
|
||||
from . import appengine_memcache
|
||||
|
||||
return appengine_memcache.cache
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
from . import file_cache
|
||||
|
||||
return file_cache.cache
|
||||
except Exception:
|
||||
LOGGER.info(
|
||||
"file_cache is only supported with oauth2client<4.0.0", exc_info=False
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
def get_static_doc(serviceName, version):
|
||||
"""Retrieves the discovery document from the directory defined in
|
||||
DISCOVERY_DOC_DIR corresponding to the serviceName and version provided.
|
||||
|
||||
Args:
|
||||
serviceName: string, name of the service.
|
||||
version: string, the version of the service.
|
||||
|
||||
Returns:
|
||||
A string containing the contents of the JSON discovery document,
|
||||
otherwise None if the JSON discovery document was not found.
|
||||
"""
|
||||
|
||||
content = None
|
||||
doc_name = "{}.{}.json".format(serviceName, version)
|
||||
|
||||
try:
|
||||
with open(os.path.join(DISCOVERY_DOC_DIR, doc_name), "r") as f:
|
||||
content = f.read()
|
||||
except FileNotFoundError:
|
||||
# File does not exist. Nothing to do here.
|
||||
pass
|
||||
|
||||
return content
|
||||
@@ -1,55 +0,0 @@
|
||||
# Copyright 2014 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""App Engine memcache based cache for the discovery document."""
|
||||
|
||||
import logging
|
||||
|
||||
# This is only an optional dependency because we only import this
|
||||
# module when google.appengine.api.memcache is available.
|
||||
from google.appengine.api import memcache
|
||||
|
||||
from . import base
|
||||
from ..discovery_cache import DISCOVERY_DOC_MAX_AGE
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
NAMESPACE = "google-api-client"
|
||||
|
||||
|
||||
class Cache(base.Cache):
|
||||
"""A cache with app engine memcache API."""
|
||||
|
||||
def __init__(self, max_age):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
max_age: Cache expiration in seconds.
|
||||
"""
|
||||
self._max_age = max_age
|
||||
|
||||
def get(self, url):
|
||||
try:
|
||||
return memcache.get(url, namespace=NAMESPACE)
|
||||
except Exception as e:
|
||||
LOGGER.warning(e, exc_info=True)
|
||||
|
||||
def set(self, url, content):
|
||||
try:
|
||||
memcache.set(url, content, time=int(self._max_age), namespace=NAMESPACE)
|
||||
except Exception as e:
|
||||
LOGGER.warning(e, exc_info=True)
|
||||
|
||||
|
||||
cache = Cache(max_age=DISCOVERY_DOC_MAX_AGE)
|
||||
@@ -1,46 +0,0 @@
|
||||
# Copyright 2014 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""An abstract class for caching the discovery document."""
|
||||
|
||||
import abc
|
||||
|
||||
|
||||
class Cache(object):
|
||||
"""A base abstract cache class."""
|
||||
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
@abc.abstractmethod
|
||||
def get(self, url):
|
||||
"""Gets the content from the memcache with a given key.
|
||||
|
||||
Args:
|
||||
url: string, the key for the cache.
|
||||
|
||||
Returns:
|
||||
object, the value in the cache for the given key, or None if the key is
|
||||
not in the cache.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
@abc.abstractmethod
|
||||
def set(self, url, content):
|
||||
"""Sets the given key and content in the cache.
|
||||
|
||||
Args:
|
||||
url: string, the key for the cache.
|
||||
content: string, the discovery document.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
@@ -1,145 +0,0 @@
|
||||
# Copyright 2014 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""File based cache for the discovery document.
|
||||
|
||||
The cache is stored in a single file so that multiple processes can
|
||||
share the same cache. It locks the file whenever accessing to the
|
||||
file. When the cache content is corrupted, it will be initialized with
|
||||
an empty cache.
|
||||
"""
|
||||
|
||||
from __future__ import division
|
||||
|
||||
import datetime
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
try:
|
||||
from oauth2client.contrib.locked_file import LockedFile
|
||||
except ImportError:
|
||||
# oauth2client < 2.0.0
|
||||
try:
|
||||
from oauth2client.locked_file import LockedFile
|
||||
except ImportError:
|
||||
# oauth2client > 4.0.0 or google-auth
|
||||
raise ImportError(
|
||||
"file_cache is unavailable when using oauth2client >= 4.0.0 or google-auth"
|
||||
)
|
||||
|
||||
from . import base
|
||||
from ..discovery_cache import DISCOVERY_DOC_MAX_AGE
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
FILENAME = "google-api-python-client-discovery-doc.cache"
|
||||
EPOCH = datetime.datetime(1970, 1, 1)
|
||||
|
||||
|
||||
def _to_timestamp(date):
|
||||
try:
|
||||
return (date - EPOCH).total_seconds()
|
||||
except AttributeError:
|
||||
# The following is the equivalent of total_seconds() in Python2.6.
|
||||
# See also: https://docs.python.org/2/library/datetime.html
|
||||
delta = date - EPOCH
|
||||
return (
|
||||
delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 10**6
|
||||
) / 10**6
|
||||
|
||||
|
||||
def _read_or_initialize_cache(f):
|
||||
f.file_handle().seek(0)
|
||||
try:
|
||||
cache = json.load(f.file_handle())
|
||||
except Exception:
|
||||
# This means it opens the file for the first time, or the cache is
|
||||
# corrupted, so initializing the file with an empty dict.
|
||||
cache = {}
|
||||
f.file_handle().truncate(0)
|
||||
f.file_handle().seek(0)
|
||||
json.dump(cache, f.file_handle())
|
||||
return cache
|
||||
|
||||
|
||||
class Cache(base.Cache):
|
||||
"""A file based cache for the discovery documents."""
|
||||
|
||||
def __init__(self, max_age):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
max_age: Cache expiration in seconds.
|
||||
"""
|
||||
self._max_age = max_age
|
||||
self._file = os.path.join(tempfile.gettempdir(), FILENAME)
|
||||
f = LockedFile(self._file, "a+", "r")
|
||||
try:
|
||||
f.open_and_lock()
|
||||
if f.is_locked():
|
||||
_read_or_initialize_cache(f)
|
||||
# If we can not obtain the lock, other process or thread must
|
||||
# have initialized the file.
|
||||
except Exception as e:
|
||||
LOGGER.warning(e, exc_info=True)
|
||||
finally:
|
||||
f.unlock_and_close()
|
||||
|
||||
def get(self, url):
|
||||
f = LockedFile(self._file, "r+", "r")
|
||||
try:
|
||||
f.open_and_lock()
|
||||
if f.is_locked():
|
||||
cache = _read_or_initialize_cache(f)
|
||||
if url in cache:
|
||||
content, t = cache.get(url, (None, 0))
|
||||
if _to_timestamp(datetime.datetime.now()) < t + self._max_age:
|
||||
return content
|
||||
return None
|
||||
else:
|
||||
LOGGER.debug("Could not obtain a lock for the cache file.")
|
||||
return None
|
||||
except Exception as e:
|
||||
LOGGER.warning(e, exc_info=True)
|
||||
finally:
|
||||
f.unlock_and_close()
|
||||
|
||||
def set(self, url, content):
|
||||
f = LockedFile(self._file, "r+", "r")
|
||||
try:
|
||||
f.open_and_lock()
|
||||
if f.is_locked():
|
||||
cache = _read_or_initialize_cache(f)
|
||||
cache[url] = (content, _to_timestamp(datetime.datetime.now()))
|
||||
# Remove stale cache.
|
||||
for k, (_, timestamp) in list(cache.items()):
|
||||
if (
|
||||
_to_timestamp(datetime.datetime.now())
|
||||
>= timestamp + self._max_age
|
||||
):
|
||||
del cache[k]
|
||||
f.file_handle().truncate(0)
|
||||
f.file_handle().seek(0)
|
||||
json.dump(cache, f.file_handle())
|
||||
else:
|
||||
LOGGER.debug("Could not obtain a lock for the cache file.")
|
||||
except Exception as e:
|
||||
LOGGER.warning(e, exc_info=True)
|
||||
finally:
|
||||
f.unlock_and_close()
|
||||
|
||||
|
||||
cache = Cache(max_age=DISCOVERY_DOC_MAX_AGE)
|
||||
@@ -1,197 +0,0 @@
|
||||
# Copyright 2014 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Errors for the library.
|
||||
|
||||
All exceptions defined by the library
|
||||
should be defined in this file.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
__author__ = "jcgregorio@google.com (Joe Gregorio)"
|
||||
|
||||
import json
|
||||
|
||||
from googleapiclient import _helpers as util
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
"""Base error for this module."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class HttpError(Error):
|
||||
"""HTTP data was invalid or unexpected."""
|
||||
|
||||
@util.positional(3)
|
||||
def __init__(self, resp, content, uri=None):
|
||||
self.resp = resp
|
||||
if not isinstance(content, bytes):
|
||||
raise TypeError("HTTP content should be bytes")
|
||||
self.content = content
|
||||
self.uri = uri
|
||||
self.error_details = ""
|
||||
self.reason = self._get_reason()
|
||||
|
||||
@property
|
||||
def status_code(self):
|
||||
"""Return the HTTP status code from the response content."""
|
||||
return self.resp.status
|
||||
|
||||
def _get_reason(self):
|
||||
"""Calculate the reason for the error from the response content."""
|
||||
reason = self.resp.reason
|
||||
try:
|
||||
try:
|
||||
data = json.loads(self.content.decode("utf-8"))
|
||||
except json.JSONDecodeError:
|
||||
# In case it is not json
|
||||
data = self.content.decode("utf-8")
|
||||
if isinstance(data, dict):
|
||||
reason = data["error"]["message"]
|
||||
error_detail_keyword = next(
|
||||
(
|
||||
kw
|
||||
for kw in ["detail", "details", "errors", "message"]
|
||||
if kw in data["error"]
|
||||
),
|
||||
"",
|
||||
)
|
||||
if error_detail_keyword:
|
||||
self.error_details = data["error"][error_detail_keyword]
|
||||
elif isinstance(data, list) and len(data) > 0:
|
||||
first_error = data[0]
|
||||
reason = first_error["error"]["message"]
|
||||
if "details" in first_error["error"]:
|
||||
self.error_details = first_error["error"]["details"]
|
||||
else:
|
||||
self.error_details = data
|
||||
except (ValueError, KeyError, TypeError):
|
||||
pass
|
||||
if reason is None:
|
||||
reason = ""
|
||||
return reason.strip()
|
||||
|
||||
def __repr__(self):
|
||||
if self.error_details:
|
||||
return '<HttpError %s when requesting %s returned "%s". Details: "%s">' % (
|
||||
self.resp.status,
|
||||
self.uri,
|
||||
self.reason,
|
||||
self.error_details,
|
||||
)
|
||||
elif self.uri:
|
||||
return '<HttpError %s when requesting %s returned "%s">' % (
|
||||
self.resp.status,
|
||||
self.uri,
|
||||
self.reason,
|
||||
)
|
||||
else:
|
||||
return '<HttpError %s "%s">' % (self.resp.status, self.reason)
|
||||
|
||||
__str__ = __repr__
|
||||
|
||||
|
||||
class InvalidJsonError(Error):
|
||||
"""The JSON returned could not be parsed."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class UnknownFileType(Error):
|
||||
"""File type unknown or unexpected."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class UnknownLinkType(Error):
|
||||
"""Link type unknown or unexpected."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class UnknownApiNameOrVersion(Error):
|
||||
"""No API with that name and version exists."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class UnacceptableMimeTypeError(Error):
|
||||
"""That is an unacceptable mimetype for this operation."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class MediaUploadSizeError(Error):
|
||||
"""Media is larger than the method can accept."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ResumableUploadError(HttpError):
|
||||
"""Error occurred during resumable upload."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class InvalidChunkSizeError(Error):
|
||||
"""The given chunksize is not valid."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class InvalidNotificationError(Error):
|
||||
"""The channel Notification is invalid."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class BatchError(HttpError):
|
||||
"""Error occurred during batch operations."""
|
||||
|
||||
@util.positional(2)
|
||||
def __init__(self, reason, resp=None, content=None):
|
||||
self.resp = resp
|
||||
self.content = content
|
||||
self.reason = reason
|
||||
|
||||
def __repr__(self):
|
||||
if getattr(self.resp, "status", None) is None:
|
||||
return '<BatchError "%s">' % (self.reason)
|
||||
else:
|
||||
return '<BatchError %s "%s">' % (self.resp.status, self.reason)
|
||||
|
||||
__str__ = __repr__
|
||||
|
||||
|
||||
class UnexpectedMethodError(Error):
|
||||
"""Exception raised by RequestMockBuilder on unexpected calls."""
|
||||
|
||||
@util.positional(1)
|
||||
def __init__(self, methodId=None):
|
||||
"""Constructor for an UnexpectedMethodError."""
|
||||
super(UnexpectedMethodError, self).__init__(
|
||||
"Received unexpected call %s" % methodId
|
||||
)
|
||||
|
||||
|
||||
class UnexpectedBodyError(Error):
|
||||
"""Exception raised by RequestMockBuilder on unexpected bodies."""
|
||||
|
||||
def __init__(self, expected, provided):
|
||||
"""Constructor for an UnexpectedMethodError."""
|
||||
super(UnexpectedBodyError, self).__init__(
|
||||
"Expected: [%s] - Provided: [%s]" % (expected, provided)
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,183 +0,0 @@
|
||||
# Copyright 2014 Joe Gregorio
|
||||
#
|
||||
# Licensed under the MIT License
|
||||
|
||||
"""MIME-Type Parser
|
||||
|
||||
This module provides basic functions for handling mime-types. It can handle
|
||||
matching mime-types against a list of media-ranges. See section 14.1 of the
|
||||
HTTP specification [RFC 2616] for a complete explanation.
|
||||
|
||||
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
|
||||
|
||||
Contents:
|
||||
- parse_mime_type(): Parses a mime-type into its component parts.
|
||||
- parse_media_range(): Media-ranges are mime-types with wild-cards and a 'q'
|
||||
quality parameter.
|
||||
- quality(): Determines the quality ('q') of a mime-type when
|
||||
compared against a list of media-ranges.
|
||||
- quality_parsed(): Just like quality() except the second parameter must be
|
||||
pre-parsed.
|
||||
- best_match(): Choose the mime-type with the highest quality ('q')
|
||||
from a list of candidates.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
from functools import reduce
|
||||
|
||||
__version__ = "0.1.3"
|
||||
__author__ = "Joe Gregorio"
|
||||
__email__ = "joe@bitworking.org"
|
||||
__license__ = "MIT License"
|
||||
__credits__ = ""
|
||||
|
||||
|
||||
def parse_mime_type(mime_type):
|
||||
"""Parses a mime-type into its component parts.
|
||||
|
||||
Carves up a mime-type and returns a tuple of the (type, subtype, params)
|
||||
where 'params' is a dictionary of all the parameters for the media range.
|
||||
For example, the media range 'application/xhtml;q=0.5' would get parsed
|
||||
into:
|
||||
|
||||
('application', 'xhtml', {'q', '0.5'})
|
||||
"""
|
||||
parts = mime_type.split(";")
|
||||
params = dict(
|
||||
[tuple([s.strip() for s in param.split("=", 1)]) for param in parts[1:]]
|
||||
)
|
||||
full_type = parts[0].strip()
|
||||
# Java URLConnection class sends an Accept header that includes a
|
||||
# single '*'. Turn it into a legal wildcard.
|
||||
if full_type == "*":
|
||||
full_type = "*/*"
|
||||
(type, subtype) = full_type.split("/")
|
||||
|
||||
return (type.strip(), subtype.strip(), params)
|
||||
|
||||
|
||||
def parse_media_range(range):
|
||||
"""Parse a media-range into its component parts.
|
||||
|
||||
Carves up a media range and returns a tuple of the (type, subtype,
|
||||
params) where 'params' is a dictionary of all the parameters for the media
|
||||
range. For example, the media range 'application/*;q=0.5' would get parsed
|
||||
into:
|
||||
|
||||
('application', '*', {'q', '0.5'})
|
||||
|
||||
In addition this function also guarantees that there is a value for 'q'
|
||||
in the params dictionary, filling it in with a proper default if
|
||||
necessary.
|
||||
"""
|
||||
(type, subtype, params) = parse_mime_type(range)
|
||||
if (
|
||||
"q" not in params
|
||||
or not params["q"]
|
||||
or not float(params["q"])
|
||||
or float(params["q"]) > 1
|
||||
or float(params["q"]) < 0
|
||||
):
|
||||
params["q"] = "1"
|
||||
|
||||
return (type, subtype, params)
|
||||
|
||||
|
||||
def fitness_and_quality_parsed(mime_type, parsed_ranges):
|
||||
"""Find the best match for a mime-type amongst parsed media-ranges.
|
||||
|
||||
Find the best match for a given mime-type against a list of media_ranges
|
||||
that have already been parsed by parse_media_range(). Returns a tuple of
|
||||
the fitness value and the value of the 'q' quality parameter of the best
|
||||
match, or (-1, 0) if no match was found. Just as for quality_parsed(),
|
||||
'parsed_ranges' must be a list of parsed media ranges.
|
||||
"""
|
||||
best_fitness = -1
|
||||
best_fit_q = 0
|
||||
(target_type, target_subtype, target_params) = parse_media_range(mime_type)
|
||||
for (type, subtype, params) in parsed_ranges:
|
||||
type_match = type == target_type or type == "*" or target_type == "*"
|
||||
subtype_match = (
|
||||
subtype == target_subtype or subtype == "*" or target_subtype == "*"
|
||||
)
|
||||
if type_match and subtype_match:
|
||||
param_matches = reduce(
|
||||
lambda x, y: x + y,
|
||||
[
|
||||
1
|
||||
for (key, value) in target_params.items()
|
||||
if key != "q" and key in params and value == params[key]
|
||||
],
|
||||
0,
|
||||
)
|
||||
fitness = (type == target_type) and 100 or 0
|
||||
fitness += (subtype == target_subtype) and 10 or 0
|
||||
fitness += param_matches
|
||||
if fitness > best_fitness:
|
||||
best_fitness = fitness
|
||||
best_fit_q = params["q"]
|
||||
|
||||
return best_fitness, float(best_fit_q)
|
||||
|
||||
|
||||
def quality_parsed(mime_type, parsed_ranges):
|
||||
"""Find the best match for a mime-type amongst parsed media-ranges.
|
||||
|
||||
Find the best match for a given mime-type against a list of media_ranges
|
||||
that have already been parsed by parse_media_range(). Returns the 'q'
|
||||
quality parameter of the best match, 0 if no match was found. This function
|
||||
bahaves the same as quality() except that 'parsed_ranges' must be a list of
|
||||
parsed media ranges.
|
||||
"""
|
||||
|
||||
return fitness_and_quality_parsed(mime_type, parsed_ranges)[1]
|
||||
|
||||
|
||||
def quality(mime_type, ranges):
|
||||
"""Return the quality ('q') of a mime-type against a list of media-ranges.
|
||||
|
||||
Returns the quality 'q' of a mime-type when compared against the
|
||||
media-ranges in ranges. For example:
|
||||
|
||||
>>> quality('text/html','text/*;q=0.3, text/html;q=0.7,
|
||||
text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5')
|
||||
0.7
|
||||
|
||||
"""
|
||||
parsed_ranges = [parse_media_range(r) for r in ranges.split(",")]
|
||||
|
||||
return quality_parsed(mime_type, parsed_ranges)
|
||||
|
||||
|
||||
def best_match(supported, header):
|
||||
"""Return mime-type with the highest quality ('q') from list of candidates.
|
||||
|
||||
Takes a list of supported mime-types and finds the best match for all the
|
||||
media-ranges listed in header. The value of header must be a string that
|
||||
conforms to the format of the HTTP Accept: header. The value of 'supported'
|
||||
is a list of mime-types. The list of supported mime-types should be sorted
|
||||
in order of increasing desirability, in case of a situation where there is
|
||||
a tie.
|
||||
|
||||
>>> best_match(['application/xbel+xml', 'text/xml'],
|
||||
'text/*;q=0.5,*/*; q=0.1')
|
||||
'text/xml'
|
||||
"""
|
||||
split_header = _filter_blank(header.split(","))
|
||||
parsed_header = [parse_media_range(r) for r in split_header]
|
||||
weighted_matches = []
|
||||
pos = 0
|
||||
for mime_type in supported:
|
||||
weighted_matches.append(
|
||||
(fitness_and_quality_parsed(mime_type, parsed_header), pos, mime_type)
|
||||
)
|
||||
pos += 1
|
||||
weighted_matches.sort()
|
||||
|
||||
return weighted_matches[-1][0][1] and weighted_matches[-1][2] or ""
|
||||
|
||||
|
||||
def _filter_blank(i):
|
||||
for s in i:
|
||||
if s.strip():
|
||||
yield s
|
||||
@@ -1,429 +0,0 @@
|
||||
# Copyright 2014 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Model objects for requests and responses.
|
||||
|
||||
Each API may support one or more serializations, such
|
||||
as JSON, Atom, etc. The model classes are responsible
|
||||
for converting between the wire format and the Python
|
||||
object representation.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
__author__ = "jcgregorio@google.com (Joe Gregorio)"
|
||||
|
||||
import json
|
||||
import logging
|
||||
import platform
|
||||
import urllib
|
||||
import warnings
|
||||
|
||||
from googleapiclient import version as googleapiclient_version
|
||||
from googleapiclient.errors import HttpError
|
||||
|
||||
try:
|
||||
from google.api_core.version_header import API_VERSION_METADATA_KEY
|
||||
|
||||
HAS_API_VERSION = True
|
||||
except ImportError:
|
||||
HAS_API_VERSION = False
|
||||
|
||||
_LIBRARY_VERSION = googleapiclient_version.__version__
|
||||
_PY_VERSION = platform.python_version()
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
dump_request_response = False
|
||||
|
||||
|
||||
def _abstract():
|
||||
raise NotImplementedError("You need to override this function")
|
||||
|
||||
|
||||
class Model(object):
|
||||
"""Model base class.
|
||||
|
||||
All Model classes should implement this interface.
|
||||
The Model serializes and de-serializes between a wire
|
||||
format such as JSON and a Python object representation.
|
||||
"""
|
||||
|
||||
def request(self, headers, path_params, query_params, body_value):
|
||||
"""Updates outgoing requests with a serialized body.
|
||||
|
||||
Args:
|
||||
headers: dict, request headers
|
||||
path_params: dict, parameters that appear in the request path
|
||||
query_params: dict, parameters that appear in the query
|
||||
body_value: object, the request body as a Python object, which must be
|
||||
serializable.
|
||||
Returns:
|
||||
A tuple of (headers, path_params, query, body)
|
||||
|
||||
headers: dict, request headers
|
||||
path_params: dict, parameters that appear in the request path
|
||||
query: string, query part of the request URI
|
||||
body: string, the body serialized in the desired wire format.
|
||||
"""
|
||||
_abstract()
|
||||
|
||||
def response(self, resp, content):
|
||||
"""Convert the response wire format into a Python object.
|
||||
|
||||
Args:
|
||||
resp: httplib2.Response, the HTTP response headers and status
|
||||
content: string, the body of the HTTP response
|
||||
|
||||
Returns:
|
||||
The body de-serialized as a Python object.
|
||||
|
||||
Raises:
|
||||
googleapiclient.errors.HttpError if a non 2xx response is received.
|
||||
"""
|
||||
_abstract()
|
||||
|
||||
|
||||
class BaseModel(Model):
|
||||
"""Base model class.
|
||||
|
||||
Subclasses should provide implementations for the "serialize" and
|
||||
"deserialize" methods, as well as values for the following class attributes.
|
||||
|
||||
Attributes:
|
||||
accept: The value to use for the HTTP Accept header.
|
||||
content_type: The value to use for the HTTP Content-type header.
|
||||
no_content_response: The value to return when deserializing a 204 "No
|
||||
Content" response.
|
||||
alt_param: The value to supply as the "alt" query parameter for requests.
|
||||
"""
|
||||
|
||||
accept = None
|
||||
content_type = None
|
||||
no_content_response = None
|
||||
alt_param = None
|
||||
|
||||
def _log_request(self, headers, path_params, query, body):
|
||||
"""Logs debugging information about the request if requested."""
|
||||
if dump_request_response:
|
||||
LOGGER.info("--request-start--")
|
||||
LOGGER.info("-headers-start-")
|
||||
for h, v in headers.items():
|
||||
LOGGER.info("%s: %s", h, v)
|
||||
LOGGER.info("-headers-end-")
|
||||
LOGGER.info("-path-parameters-start-")
|
||||
for h, v in path_params.items():
|
||||
LOGGER.info("%s: %s", h, v)
|
||||
LOGGER.info("-path-parameters-end-")
|
||||
LOGGER.info("body: %s", body)
|
||||
LOGGER.info("query: %s", query)
|
||||
LOGGER.info("--request-end--")
|
||||
|
||||
def request(self, headers, path_params, query_params, body_value, api_version=None):
|
||||
"""Updates outgoing requests with a serialized body.
|
||||
|
||||
Args:
|
||||
headers: dict, request headers
|
||||
path_params: dict, parameters that appear in the request path
|
||||
query_params: dict, parameters that appear in the query
|
||||
body_value: object, the request body as a Python object, which must be
|
||||
serializable by json.
|
||||
api_version: str, The precise API version represented by this request,
|
||||
which will result in an API Version header being sent along with the
|
||||
HTTP request.
|
||||
Returns:
|
||||
A tuple of (headers, path_params, query, body)
|
||||
|
||||
headers: dict, request headers
|
||||
path_params: dict, parameters that appear in the request path
|
||||
query: string, query part of the request URI
|
||||
body: string, the body serialized as JSON
|
||||
"""
|
||||
query = self._build_query(query_params)
|
||||
headers["accept"] = self.accept
|
||||
headers["accept-encoding"] = "gzip, deflate"
|
||||
if "user-agent" in headers:
|
||||
headers["user-agent"] += " "
|
||||
else:
|
||||
headers["user-agent"] = ""
|
||||
headers["user-agent"] += "(gzip)"
|
||||
if "x-goog-api-client" in headers:
|
||||
headers["x-goog-api-client"] += " "
|
||||
else:
|
||||
headers["x-goog-api-client"] = ""
|
||||
headers["x-goog-api-client"] += "gdcl/%s gl-python/%s" % (
|
||||
_LIBRARY_VERSION,
|
||||
_PY_VERSION,
|
||||
)
|
||||
|
||||
if api_version and HAS_API_VERSION:
|
||||
headers[API_VERSION_METADATA_KEY] = api_version
|
||||
elif api_version:
|
||||
warnings.warn(
|
||||
"The `api_version` argument is ignored as a newer version of "
|
||||
"`google-api-core` is required to use this feature."
|
||||
"Please upgrade `google-api-core` to 2.19.0 or newer."
|
||||
)
|
||||
|
||||
if body_value is not None:
|
||||
headers["content-type"] = self.content_type
|
||||
body_value = self.serialize(body_value)
|
||||
self._log_request(headers, path_params, query, body_value)
|
||||
return (headers, path_params, query, body_value)
|
||||
|
||||
def _build_query(self, params):
|
||||
"""Builds a query string.
|
||||
|
||||
Args:
|
||||
params: dict, the query parameters
|
||||
|
||||
Returns:
|
||||
The query parameters properly encoded into an HTTP URI query string.
|
||||
"""
|
||||
if self.alt_param is not None:
|
||||
params.update({"alt": self.alt_param})
|
||||
astuples = []
|
||||
for key, value in params.items():
|
||||
if type(value) == type([]):
|
||||
for x in value:
|
||||
x = x.encode("utf-8")
|
||||
astuples.append((key, x))
|
||||
else:
|
||||
if isinstance(value, str) and callable(value.encode):
|
||||
value = value.encode("utf-8")
|
||||
astuples.append((key, value))
|
||||
return "?" + urllib.parse.urlencode(astuples)
|
||||
|
||||
def _log_response(self, resp, content):
|
||||
"""Logs debugging information about the response if requested."""
|
||||
if dump_request_response:
|
||||
LOGGER.info("--response-start--")
|
||||
for h, v in resp.items():
|
||||
LOGGER.info("%s: %s", h, v)
|
||||
if content:
|
||||
LOGGER.info(content)
|
||||
LOGGER.info("--response-end--")
|
||||
|
||||
def response(self, resp, content):
|
||||
"""Convert the response wire format into a Python object.
|
||||
|
||||
Args:
|
||||
resp: httplib2.Response, the HTTP response headers and status
|
||||
content: string, the body of the HTTP response
|
||||
|
||||
Returns:
|
||||
The body de-serialized as a Python object.
|
||||
|
||||
Raises:
|
||||
googleapiclient.errors.HttpError if a non 2xx response is received.
|
||||
"""
|
||||
self._log_response(resp, content)
|
||||
# Error handling is TBD, for example, do we retry
|
||||
# for some operation/error combinations?
|
||||
if resp.status < 300:
|
||||
if resp.status == 204:
|
||||
# A 204: No Content response should be treated differently
|
||||
# to all the other success states
|
||||
return self.no_content_response
|
||||
return self.deserialize(content)
|
||||
else:
|
||||
LOGGER.debug("Content from bad request was: %r" % content)
|
||||
raise HttpError(resp, content)
|
||||
|
||||
def serialize(self, body_value):
|
||||
"""Perform the actual Python object serialization.
|
||||
|
||||
Args:
|
||||
body_value: object, the request body as a Python object.
|
||||
|
||||
Returns:
|
||||
string, the body in serialized form.
|
||||
"""
|
||||
_abstract()
|
||||
|
||||
def deserialize(self, content):
|
||||
"""Perform the actual deserialization from response string to Python
|
||||
object.
|
||||
|
||||
Args:
|
||||
content: string, the body of the HTTP response
|
||||
|
||||
Returns:
|
||||
The body de-serialized as a Python object.
|
||||
"""
|
||||
_abstract()
|
||||
|
||||
|
||||
class JsonModel(BaseModel):
|
||||
"""Model class for JSON.
|
||||
|
||||
Serializes and de-serializes between JSON and the Python
|
||||
object representation of HTTP request and response bodies.
|
||||
"""
|
||||
|
||||
accept = "application/json"
|
||||
content_type = "application/json"
|
||||
alt_param = "json"
|
||||
|
||||
def __init__(self, data_wrapper=False):
|
||||
"""Construct a JsonModel.
|
||||
|
||||
Args:
|
||||
data_wrapper: boolean, wrap requests and responses in a data wrapper
|
||||
"""
|
||||
self._data_wrapper = data_wrapper
|
||||
|
||||
def serialize(self, body_value):
|
||||
if (
|
||||
isinstance(body_value, dict)
|
||||
and "data" not in body_value
|
||||
and self._data_wrapper
|
||||
):
|
||||
body_value = {"data": body_value}
|
||||
return json.dumps(body_value)
|
||||
|
||||
def deserialize(self, content):
|
||||
try:
|
||||
content = content.decode("utf-8")
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
body = json.loads(content)
|
||||
except json.decoder.JSONDecodeError:
|
||||
body = content
|
||||
else:
|
||||
if self._data_wrapper and "data" in body:
|
||||
body = body["data"]
|
||||
return body
|
||||
|
||||
@property
|
||||
def no_content_response(self):
|
||||
return {}
|
||||
|
||||
|
||||
class RawModel(JsonModel):
|
||||
"""Model class for requests that don't return JSON.
|
||||
|
||||
Serializes and de-serializes between JSON and the Python
|
||||
object representation of HTTP request, and returns the raw bytes
|
||||
of the response body.
|
||||
"""
|
||||
|
||||
accept = "*/*"
|
||||
content_type = "application/json"
|
||||
alt_param = None
|
||||
|
||||
def deserialize(self, content):
|
||||
return content
|
||||
|
||||
@property
|
||||
def no_content_response(self):
|
||||
return ""
|
||||
|
||||
|
||||
class MediaModel(JsonModel):
|
||||
"""Model class for requests that return Media.
|
||||
|
||||
Serializes and de-serializes between JSON and the Python
|
||||
object representation of HTTP request, and returns the raw bytes
|
||||
of the response body.
|
||||
"""
|
||||
|
||||
accept = "*/*"
|
||||
content_type = "application/json"
|
||||
alt_param = "media"
|
||||
|
||||
def deserialize(self, content):
|
||||
return content
|
||||
|
||||
@property
|
||||
def no_content_response(self):
|
||||
return ""
|
||||
|
||||
|
||||
class ProtocolBufferModel(BaseModel):
|
||||
"""Model class for protocol buffers.
|
||||
|
||||
Serializes and de-serializes the binary protocol buffer sent in the HTTP
|
||||
request and response bodies.
|
||||
"""
|
||||
|
||||
accept = "application/x-protobuf"
|
||||
content_type = "application/x-protobuf"
|
||||
alt_param = "proto"
|
||||
|
||||
def __init__(self, protocol_buffer):
|
||||
"""Constructs a ProtocolBufferModel.
|
||||
|
||||
The serialized protocol buffer returned in an HTTP response will be
|
||||
de-serialized using the given protocol buffer class.
|
||||
|
||||
Args:
|
||||
protocol_buffer: The protocol buffer class used to de-serialize a
|
||||
response from the API.
|
||||
"""
|
||||
self._protocol_buffer = protocol_buffer
|
||||
|
||||
def serialize(self, body_value):
|
||||
return body_value.SerializeToString()
|
||||
|
||||
def deserialize(self, content):
|
||||
return self._protocol_buffer.FromString(content)
|
||||
|
||||
@property
|
||||
def no_content_response(self):
|
||||
return self._protocol_buffer()
|
||||
|
||||
|
||||
def makepatch(original, modified):
|
||||
"""Create a patch object.
|
||||
|
||||
Some methods support PATCH, an efficient way to send updates to a resource.
|
||||
This method allows the easy construction of patch bodies by looking at the
|
||||
differences between a resource before and after it was modified.
|
||||
|
||||
Args:
|
||||
original: object, the original deserialized resource
|
||||
modified: object, the modified deserialized resource
|
||||
Returns:
|
||||
An object that contains only the changes from original to modified, in a
|
||||
form suitable to pass to a PATCH method.
|
||||
|
||||
Example usage:
|
||||
item = service.activities().get(postid=postid, userid=userid).execute()
|
||||
original = copy.deepcopy(item)
|
||||
item['object']['content'] = 'This is updated.'
|
||||
service.activities.patch(postid=postid, userid=userid,
|
||||
body=makepatch(original, item)).execute()
|
||||
"""
|
||||
patch = {}
|
||||
for key, original_value in original.items():
|
||||
modified_value = modified.get(key, None)
|
||||
if modified_value is None:
|
||||
# Use None to signal that the element is deleted
|
||||
patch[key] = None
|
||||
elif original_value != modified_value:
|
||||
if type(original_value) == type({}):
|
||||
# Recursively descend objects
|
||||
patch[key] = makepatch(original_value, modified_value)
|
||||
else:
|
||||
# In the case of simple types or arrays we just replace
|
||||
patch[key] = modified_value
|
||||
else:
|
||||
# Don't add anything to patch if there's no change
|
||||
pass
|
||||
for key in modified:
|
||||
if key not in original:
|
||||
patch[key] = modified[key]
|
||||
|
||||
return patch
|
||||
@@ -1,317 +0,0 @@
|
||||
# Copyright 2014 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Schema processing for discovery based APIs
|
||||
|
||||
Schemas holds an APIs discovery schemas. It can return those schema as
|
||||
deserialized JSON objects, or pretty print them as prototype objects that
|
||||
conform to the schema.
|
||||
|
||||
For example, given the schema:
|
||||
|
||||
schema = \"\"\"{
|
||||
"Foo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"etag": {
|
||||
"type": "string",
|
||||
"description": "ETag of the collection."
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"description": "Type of the collection ('calendar#acl').",
|
||||
"default": "calendar#acl"
|
||||
},
|
||||
"nextPageToken": {
|
||||
"type": "string",
|
||||
"description": "Token used to access the next
|
||||
page of this result. Omitted if no further results are available."
|
||||
}
|
||||
}
|
||||
}
|
||||
}\"\"\"
|
||||
|
||||
s = Schemas(schema)
|
||||
print s.prettyPrintByName('Foo')
|
||||
|
||||
Produces the following output:
|
||||
|
||||
{
|
||||
"nextPageToken": "A String", # Token used to access the
|
||||
# next page of this result. Omitted if no further results are available.
|
||||
"kind": "A String", # Type of the collection ('calendar#acl').
|
||||
"etag": "A String", # ETag of the collection.
|
||||
},
|
||||
|
||||
The constructor takes a discovery document in which to look up named schema.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
# TODO(jcgregorio) support format, enum, minimum, maximum
|
||||
|
||||
__author__ = "jcgregorio@google.com (Joe Gregorio)"
|
||||
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from googleapiclient import _helpers as util
|
||||
|
||||
|
||||
class Schemas(object):
|
||||
"""Schemas for an API."""
|
||||
|
||||
def __init__(self, discovery):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
discovery: object, Deserialized discovery document from which we pull
|
||||
out the named schema.
|
||||
"""
|
||||
self.schemas = discovery.get("schemas", {})
|
||||
|
||||
# Cache of pretty printed schemas.
|
||||
self.pretty = {}
|
||||
|
||||
@util.positional(2)
|
||||
def _prettyPrintByName(self, name, seen=None, dent=0):
|
||||
"""Get pretty printed object prototype from the schema name.
|
||||
|
||||
Args:
|
||||
name: string, Name of schema in the discovery document.
|
||||
seen: list of string, Names of schema already seen. Used to handle
|
||||
recursive definitions.
|
||||
|
||||
Returns:
|
||||
string, A string that contains a prototype object with
|
||||
comments that conforms to the given schema.
|
||||
"""
|
||||
if seen is None:
|
||||
seen = []
|
||||
|
||||
if name in seen:
|
||||
# Do not fall into an infinite loop over recursive definitions.
|
||||
return "# Object with schema name: %s" % name
|
||||
seen.append(name)
|
||||
|
||||
if name not in self.pretty:
|
||||
self.pretty[name] = _SchemaToStruct(
|
||||
self.schemas[name], seen, dent=dent
|
||||
).to_str(self._prettyPrintByName)
|
||||
|
||||
seen.pop()
|
||||
|
||||
return self.pretty[name]
|
||||
|
||||
def prettyPrintByName(self, name):
|
||||
"""Get pretty printed object prototype from the schema name.
|
||||
|
||||
Args:
|
||||
name: string, Name of schema in the discovery document.
|
||||
|
||||
Returns:
|
||||
string, A string that contains a prototype object with
|
||||
comments that conforms to the given schema.
|
||||
"""
|
||||
# Return with trailing comma and newline removed.
|
||||
return self._prettyPrintByName(name, seen=[], dent=0)[:-2]
|
||||
|
||||
@util.positional(2)
|
||||
def _prettyPrintSchema(self, schema, seen=None, dent=0):
|
||||
"""Get pretty printed object prototype of schema.
|
||||
|
||||
Args:
|
||||
schema: object, Parsed JSON schema.
|
||||
seen: list of string, Names of schema already seen. Used to handle
|
||||
recursive definitions.
|
||||
|
||||
Returns:
|
||||
string, A string that contains a prototype object with
|
||||
comments that conforms to the given schema.
|
||||
"""
|
||||
if seen is None:
|
||||
seen = []
|
||||
|
||||
return _SchemaToStruct(schema, seen, dent=dent).to_str(self._prettyPrintByName)
|
||||
|
||||
def prettyPrintSchema(self, schema):
|
||||
"""Get pretty printed object prototype of schema.
|
||||
|
||||
Args:
|
||||
schema: object, Parsed JSON schema.
|
||||
|
||||
Returns:
|
||||
string, A string that contains a prototype object with
|
||||
comments that conforms to the given schema.
|
||||
"""
|
||||
# Return with trailing comma and newline removed.
|
||||
return self._prettyPrintSchema(schema, dent=0)[:-2]
|
||||
|
||||
def get(self, name, default=None):
|
||||
"""Get deserialized JSON schema from the schema name.
|
||||
|
||||
Args:
|
||||
name: string, Schema name.
|
||||
default: object, return value if name not found.
|
||||
"""
|
||||
return self.schemas.get(name, default)
|
||||
|
||||
|
||||
class _SchemaToStruct(object):
|
||||
"""Convert schema to a prototype object."""
|
||||
|
||||
@util.positional(3)
|
||||
def __init__(self, schema, seen, dent=0):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
schema: object, Parsed JSON schema.
|
||||
seen: list, List of names of schema already seen while parsing. Used to
|
||||
handle recursive definitions.
|
||||
dent: int, Initial indentation depth.
|
||||
"""
|
||||
# The result of this parsing kept as list of strings.
|
||||
self.value = []
|
||||
|
||||
# The final value of the parsing.
|
||||
self.string = None
|
||||
|
||||
# The parsed JSON schema.
|
||||
self.schema = schema
|
||||
|
||||
# Indentation level.
|
||||
self.dent = dent
|
||||
|
||||
# Method that when called returns a prototype object for the schema with
|
||||
# the given name.
|
||||
self.from_cache = None
|
||||
|
||||
# List of names of schema already seen while parsing.
|
||||
self.seen = seen
|
||||
|
||||
def emit(self, text):
|
||||
"""Add text as a line to the output.
|
||||
|
||||
Args:
|
||||
text: string, Text to output.
|
||||
"""
|
||||
self.value.extend([" " * self.dent, text, "\n"])
|
||||
|
||||
def emitBegin(self, text):
|
||||
"""Add text to the output, but with no line terminator.
|
||||
|
||||
Args:
|
||||
text: string, Text to output.
|
||||
"""
|
||||
self.value.extend([" " * self.dent, text])
|
||||
|
||||
def emitEnd(self, text, comment):
|
||||
"""Add text and comment to the output with line terminator.
|
||||
|
||||
Args:
|
||||
text: string, Text to output.
|
||||
comment: string, Python comment.
|
||||
"""
|
||||
if comment:
|
||||
divider = "\n" + " " * (self.dent + 2) + "# "
|
||||
lines = comment.splitlines()
|
||||
lines = [x.rstrip() for x in lines]
|
||||
comment = divider.join(lines)
|
||||
self.value.extend([text, " # ", comment, "\n"])
|
||||
else:
|
||||
self.value.extend([text, "\n"])
|
||||
|
||||
def indent(self):
|
||||
"""Increase indentation level."""
|
||||
self.dent += 1
|
||||
|
||||
def undent(self):
|
||||
"""Decrease indentation level."""
|
||||
self.dent -= 1
|
||||
|
||||
def _to_str_impl(self, schema):
|
||||
"""Prototype object based on the schema, in Python code with comments.
|
||||
|
||||
Args:
|
||||
schema: object, Parsed JSON schema file.
|
||||
|
||||
Returns:
|
||||
Prototype object based on the schema, in Python code with comments.
|
||||
"""
|
||||
stype = schema.get("type")
|
||||
if stype == "object":
|
||||
self.emitEnd("{", schema.get("description", ""))
|
||||
self.indent()
|
||||
if "properties" in schema:
|
||||
properties = schema.get("properties", {})
|
||||
sorted_properties = OrderedDict(sorted(properties.items()))
|
||||
for pname, pschema in sorted_properties.items():
|
||||
self.emitBegin('"%s": ' % pname)
|
||||
self._to_str_impl(pschema)
|
||||
elif "additionalProperties" in schema:
|
||||
self.emitBegin('"a_key": ')
|
||||
self._to_str_impl(schema["additionalProperties"])
|
||||
self.undent()
|
||||
self.emit("},")
|
||||
elif "$ref" in schema:
|
||||
schemaName = schema["$ref"]
|
||||
description = schema.get("description", "")
|
||||
s = self.from_cache(schemaName, seen=self.seen)
|
||||
parts = s.splitlines()
|
||||
self.emitEnd(parts[0], description)
|
||||
for line in parts[1:]:
|
||||
self.emit(line.rstrip())
|
||||
elif stype == "boolean":
|
||||
value = schema.get("default", "True or False")
|
||||
self.emitEnd("%s," % str(value), schema.get("description", ""))
|
||||
elif stype == "string":
|
||||
value = schema.get("default", "A String")
|
||||
self.emitEnd('"%s",' % str(value), schema.get("description", ""))
|
||||
elif stype == "integer":
|
||||
value = schema.get("default", "42")
|
||||
self.emitEnd("%s," % str(value), schema.get("description", ""))
|
||||
elif stype == "number":
|
||||
value = schema.get("default", "3.14")
|
||||
self.emitEnd("%s," % str(value), schema.get("description", ""))
|
||||
elif stype == "null":
|
||||
self.emitEnd("None,", schema.get("description", ""))
|
||||
elif stype == "any":
|
||||
self.emitEnd('"",', schema.get("description", ""))
|
||||
elif stype == "array":
|
||||
self.emitEnd("[", schema.get("description"))
|
||||
self.indent()
|
||||
self.emitBegin("")
|
||||
self._to_str_impl(schema["items"])
|
||||
self.undent()
|
||||
self.emit("],")
|
||||
else:
|
||||
self.emit("Unknown type! %s" % stype)
|
||||
self.emitEnd("", "")
|
||||
|
||||
self.string = "".join(self.value)
|
||||
return self.string
|
||||
|
||||
def to_str(self, from_cache):
|
||||
"""Prototype object based on the schema, in Python code with comments.
|
||||
|
||||
Args:
|
||||
from_cache: callable(name, seen), Callable that retrieves an object
|
||||
prototype for a schema with the given name. Seen is a list of schema
|
||||
names already seen as we recursively descend the schema definition.
|
||||
|
||||
Returns:
|
||||
Prototype object based on the schema, in Python code with comments.
|
||||
The lines of the code will all be properly indented.
|
||||
"""
|
||||
self.from_cache = from_cache
|
||||
return self._to_str_impl(self.schema)
|
||||
@@ -1,15 +0,0 @@
|
||||
# Copyright 2021 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "2.164.0"
|
||||
@@ -1,28 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2007 - 2015 Michael Twomey
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||
# copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
"""ISO 8601 date time string parsing
|
||||
|
||||
"""
|
||||
|
||||
__all__ = ["parse_date", "ParseError", "UTC"]
|
||||
@@ -1,160 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""ISO 8601 date time string parsing
|
||||
|
||||
"""
|
||||
|
||||
from datetime import (datetime, timedelta, tzinfo)
|
||||
import time as _time
|
||||
import re
|
||||
|
||||
ISO8601_REGEX = re.compile(r'^(?P<year>[0-9]{4})-(?P<month>[0-9]{2})-(?P<day>[0-9]{2})(?P<separator>[ T])(?P<hour>[0-9]{2}):(?P<minute>[0-9]{2}):(?P<second>[0-9]{2})([.,](?P<second_fraction>[0-9]+)){0,1}(?P<timezone>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9]{2}):(?P<tz_minute>[0-9]{2}))$')
|
||||
ISO8601_TZ_REGEX = re.compile(r'^(?P<timezone>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9]{2}):(?P<tz_minute>[0-9]{2}))$')
|
||||
|
||||
class ParseError(Exception):
|
||||
"""Raised when there is a problem parsing a date string"""
|
||||
|
||||
# Yoinked from python docs
|
||||
ZERO = timedelta(0)
|
||||
class Utc(tzinfo):
|
||||
"""UTC Timezone
|
||||
|
||||
"""
|
||||
def utcoffset(self, dt):
|
||||
return ZERO
|
||||
|
||||
def tzname(self, dt):
|
||||
return "UTC"
|
||||
|
||||
def dst(self, dt):
|
||||
return ZERO
|
||||
|
||||
def __repr__(self):
|
||||
return "<iso8601.Utc>"
|
||||
|
||||
UTC = Utc()
|
||||
|
||||
class FixedOffset(tzinfo):
|
||||
"""Fixed offset in hours and minutes from UTC
|
||||
|
||||
"""
|
||||
def __init__(self, offset_hours, offset_minutes, name):
|
||||
self.__offset_hours = offset_hours # Keep for later __getinitargs__
|
||||
self.__offset_minutes = offset_minutes # Keep for later __getinitargs__
|
||||
self.__offset = timedelta(hours=offset_hours, minutes=offset_minutes)
|
||||
self.__name = name
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, FixedOffset):
|
||||
return (other.__offset == self.__offset) and (other.__name == self.__name)
|
||||
if isinstance(other, tzinfo):
|
||||
return other == self
|
||||
return False
|
||||
|
||||
def __getinitargs__(self):
|
||||
return (self.__offset_hours, self.__offset_minutes, self.__name)
|
||||
|
||||
def utcoffset(self, dt):
|
||||
return self.__offset
|
||||
|
||||
def tzname(self, dt):
|
||||
return self.__name
|
||||
|
||||
def dst(self, dt):
|
||||
return ZERO
|
||||
|
||||
def __repr__(self):
|
||||
return "<FixedOffset %r %r>" % (self.__name, self.__offset)
|
||||
|
||||
# A class capturing the platform's idea of local time.
|
||||
|
||||
STDOFFSET = timedelta(seconds = -_time.timezone)
|
||||
if _time.daylight:
|
||||
DSTOFFSET = timedelta(seconds = -_time.altzone)
|
||||
else:
|
||||
DSTOFFSET = STDOFFSET
|
||||
|
||||
DSTDIFF = DSTOFFSET - STDOFFSET
|
||||
|
||||
class LocalTimezone(tzinfo):
|
||||
"""Local time zone
|
||||
|
||||
"""
|
||||
|
||||
def utcoffset(self, dt):
|
||||
if self._isdst(dt):
|
||||
return DSTOFFSET
|
||||
else:
|
||||
return STDOFFSET
|
||||
|
||||
def dst(self, dt):
|
||||
if self._isdst(dt):
|
||||
return DSTDIFF
|
||||
else:
|
||||
return ZERO
|
||||
|
||||
def tzname(self, dt):
|
||||
return _time.tzname[self._isdst(dt)]
|
||||
|
||||
def _isdst(self, dt):
|
||||
tt = (dt.year, dt.month, dt.day,
|
||||
dt.hour, dt.minute, dt.second,
|
||||
dt.weekday(), 0, 0)
|
||||
stamp = _time.mktime(tt)
|
||||
tt = _time.localtime(stamp)
|
||||
return tt.tm_isdst > 0
|
||||
|
||||
Local = LocalTimezone()
|
||||
|
||||
def parse_timezone(matches):
|
||||
"""Parses ISO 8601 time zone specs into tzinfo offsets
|
||||
|
||||
"""
|
||||
|
||||
if matches["timezone"] == "Z":
|
||||
return UTC
|
||||
sign = matches["tz_sign"]
|
||||
hours = int(matches['tz_hour'])
|
||||
minutes = int(matches['tz_minute'])
|
||||
description = "%s%02d:%02d" % (sign, hours, minutes)
|
||||
if sign == "-":
|
||||
hours = -hours
|
||||
minutes = -minutes
|
||||
return FixedOffset(hours, minutes, description)
|
||||
|
||||
def parse_timezone_str(tzstring):
|
||||
m = ISO8601_TZ_REGEX.match(tzstring)
|
||||
if not m:
|
||||
raise ParseError("Unable to parse timezone string %r" % tzstring)
|
||||
groups = m.groupdict()
|
||||
return parse_timezone(groups)
|
||||
|
||||
def parse_date(datestring):
|
||||
"""Parses ISO 8601 dates into datetime objects
|
||||
|
||||
The timezone is parsed from the date string. However it is quite common to
|
||||
have dates without a timezone (not strictly correct). In this case the
|
||||
default timezone specified in default_timezone is used. This is UTC by
|
||||
default.
|
||||
|
||||
:param datestring: The date to parse as a string
|
||||
:returns: A datetime.datetime instance
|
||||
:raises: ParseError when there is a problem parsing the date or
|
||||
constructing the datetime instance.
|
||||
|
||||
"""
|
||||
m = ISO8601_REGEX.match(datestring)
|
||||
if not m:
|
||||
raise ParseError("Unable to parse date string %r" % datestring)
|
||||
groups = m.groupdict()
|
||||
tz = parse_timezone(groups)
|
||||
try:
|
||||
return (datetime(year=int(groups['year']),
|
||||
month=int(groups['month']),
|
||||
day=int(groups['day']),
|
||||
hour=int(groups['hour']),
|
||||
minute=int(groups['minute']),
|
||||
second=int(groups['second']),
|
||||
tzinfo=tz),
|
||||
tz)
|
||||
except Exception as e:
|
||||
raise ParseError(e)
|
||||
982
src/gam/six.py
982
src/gam/six.py
@@ -1,982 +0,0 @@
|
||||
# Copyright (c) 2010-2020 Benjamin Peterson
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
"""Utilities for writing code that runs on Python 2 and 3"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import functools
|
||||
import itertools
|
||||
import operator
|
||||
import sys
|
||||
import types
|
||||
|
||||
__author__ = "Benjamin Peterson <benjamin@python.org>"
|
||||
__version__ = "1.15.0"
|
||||
|
||||
|
||||
# Useful for very coarse version differentiation.
|
||||
PY2 = sys.version_info[0] == 2
|
||||
PY3 = sys.version_info[0] == 3
|
||||
PY34 = sys.version_info[0:2] >= (3, 4)
|
||||
|
||||
if PY3:
|
||||
string_types = str,
|
||||
integer_types = int,
|
||||
class_types = type,
|
||||
text_type = str
|
||||
binary_type = bytes
|
||||
|
||||
MAXSIZE = sys.maxsize
|
||||
else:
|
||||
string_types = basestring,
|
||||
integer_types = (int, long)
|
||||
class_types = (type, types.ClassType)
|
||||
text_type = unicode
|
||||
binary_type = str
|
||||
|
||||
if sys.platform.startswith("java"):
|
||||
# Jython always uses 32 bits.
|
||||
MAXSIZE = int((1 << 31) - 1)
|
||||
else:
|
||||
# It's possible to have sizeof(long) != sizeof(Py_ssize_t).
|
||||
class X(object):
|
||||
|
||||
def __len__(self):
|
||||
return 1 << 31
|
||||
try:
|
||||
len(X())
|
||||
except OverflowError:
|
||||
# 32-bit
|
||||
MAXSIZE = int((1 << 31) - 1)
|
||||
else:
|
||||
# 64-bit
|
||||
MAXSIZE = int((1 << 63) - 1)
|
||||
del X
|
||||
|
||||
|
||||
def _add_doc(func, doc):
|
||||
"""Add documentation to a function."""
|
||||
func.__doc__ = doc
|
||||
|
||||
|
||||
def _import_module(name):
|
||||
"""Import module, returning the module after the last dot."""
|
||||
__import__(name)
|
||||
return sys.modules[name]
|
||||
|
||||
|
||||
class _LazyDescr(object):
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __get__(self, obj, tp):
|
||||
result = self._resolve()
|
||||
setattr(obj, self.name, result) # Invokes __set__.
|
||||
try:
|
||||
# This is a bit ugly, but it avoids running this again by
|
||||
# removing this descriptor.
|
||||
delattr(obj.__class__, self.name)
|
||||
except AttributeError:
|
||||
pass
|
||||
return result
|
||||
|
||||
|
||||
class MovedModule(_LazyDescr):
|
||||
|
||||
def __init__(self, name, old, new=None):
|
||||
super(MovedModule, self).__init__(name)
|
||||
if PY3:
|
||||
if new is None:
|
||||
new = name
|
||||
self.mod = new
|
||||
else:
|
||||
self.mod = old
|
||||
|
||||
def _resolve(self):
|
||||
return _import_module(self.mod)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
_module = self._resolve()
|
||||
value = getattr(_module, attr)
|
||||
setattr(self, attr, value)
|
||||
return value
|
||||
|
||||
|
||||
class _LazyModule(types.ModuleType):
|
||||
|
||||
def __init__(self, name):
|
||||
super(_LazyModule, self).__init__(name)
|
||||
self.__doc__ = self.__class__.__doc__
|
||||
|
||||
def __dir__(self):
|
||||
attrs = ["__doc__", "__name__"]
|
||||
attrs += [attr.name for attr in self._moved_attributes]
|
||||
return attrs
|
||||
|
||||
# Subclasses should override this
|
||||
_moved_attributes = []
|
||||
|
||||
|
||||
class MovedAttribute(_LazyDescr):
|
||||
|
||||
def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
|
||||
super(MovedAttribute, self).__init__(name)
|
||||
if PY3:
|
||||
if new_mod is None:
|
||||
new_mod = name
|
||||
self.mod = new_mod
|
||||
if new_attr is None:
|
||||
if old_attr is None:
|
||||
new_attr = name
|
||||
else:
|
||||
new_attr = old_attr
|
||||
self.attr = new_attr
|
||||
else:
|
||||
self.mod = old_mod
|
||||
if old_attr is None:
|
||||
old_attr = name
|
||||
self.attr = old_attr
|
||||
|
||||
def _resolve(self):
|
||||
module = _import_module(self.mod)
|
||||
return getattr(module, self.attr)
|
||||
|
||||
|
||||
class _SixMetaPathImporter(object):
|
||||
|
||||
"""
|
||||
A meta path importer to import six.moves and its submodules.
|
||||
|
||||
This class implements a PEP302 finder and loader. It should be compatible
|
||||
with Python 2.5 and all existing versions of Python3
|
||||
"""
|
||||
|
||||
def __init__(self, six_module_name):
|
||||
self.name = six_module_name
|
||||
self.known_modules = {}
|
||||
|
||||
def _add_module(self, mod, *fullnames):
|
||||
for fullname in fullnames:
|
||||
self.known_modules[self.name + "." + fullname] = mod
|
||||
|
||||
def _get_module(self, fullname):
|
||||
return self.known_modules[self.name + "." + fullname]
|
||||
|
||||
def find_module(self, fullname, path=None):
|
||||
if fullname in self.known_modules:
|
||||
return self
|
||||
return None
|
||||
|
||||
def __get_module(self, fullname):
|
||||
try:
|
||||
return self.known_modules[fullname]
|
||||
except KeyError:
|
||||
raise ImportError("This loader does not know module " + fullname)
|
||||
|
||||
def load_module(self, fullname):
|
||||
try:
|
||||
# in case of a reload
|
||||
return sys.modules[fullname]
|
||||
except KeyError:
|
||||
pass
|
||||
mod = self.__get_module(fullname)
|
||||
if isinstance(mod, MovedModule):
|
||||
mod = mod._resolve()
|
||||
else:
|
||||
mod.__loader__ = self
|
||||
sys.modules[fullname] = mod
|
||||
return mod
|
||||
|
||||
def is_package(self, fullname):
|
||||
"""
|
||||
Return true, if the named module is a package.
|
||||
|
||||
We need this method to get correct spec objects with
|
||||
Python 3.4 (see PEP451)
|
||||
"""
|
||||
return hasattr(self.__get_module(fullname), "__path__")
|
||||
|
||||
def get_code(self, fullname):
|
||||
"""Return None
|
||||
|
||||
Required, if is_package is implemented"""
|
||||
self.__get_module(fullname) # eventually raises ImportError
|
||||
return None
|
||||
get_source = get_code # same as get_code
|
||||
|
||||
_importer = _SixMetaPathImporter(__name__)
|
||||
|
||||
|
||||
class _MovedItems(_LazyModule):
|
||||
|
||||
"""Lazy loading of moved objects"""
|
||||
__path__ = [] # mark as package
|
||||
|
||||
|
||||
_moved_attributes = [
|
||||
MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
|
||||
MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
|
||||
MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
|
||||
MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
|
||||
MovedAttribute("intern", "__builtin__", "sys"),
|
||||
MovedAttribute("map", "itertools", "builtins", "imap", "map"),
|
||||
MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
|
||||
MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
|
||||
MovedAttribute("getoutput", "commands", "subprocess"),
|
||||
MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
|
||||
MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"),
|
||||
MovedAttribute("reduce", "__builtin__", "functools"),
|
||||
MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
|
||||
MovedAttribute("StringIO", "StringIO", "io"),
|
||||
MovedAttribute("UserDict", "UserDict", "collections"),
|
||||
MovedAttribute("UserList", "UserList", "collections"),
|
||||
MovedAttribute("UserString", "UserString", "collections"),
|
||||
MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
|
||||
MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
|
||||
MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
|
||||
MovedModule("builtins", "__builtin__"),
|
||||
MovedModule("configparser", "ConfigParser"),
|
||||
MovedModule("collections_abc", "collections", "collections.abc" if sys.version_info >= (3, 3) else "collections"),
|
||||
MovedModule("copyreg", "copy_reg"),
|
||||
MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
|
||||
MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"),
|
||||
MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread" if sys.version_info < (3, 9) else "_thread"),
|
||||
MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
|
||||
MovedModule("http_cookies", "Cookie", "http.cookies"),
|
||||
MovedModule("html_entities", "htmlentitydefs", "html.entities"),
|
||||
MovedModule("html_parser", "HTMLParser", "html.parser"),
|
||||
MovedModule("http_client", "httplib", "http.client"),
|
||||
MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
|
||||
MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"),
|
||||
MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
|
||||
MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"),
|
||||
MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
|
||||
MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
|
||||
MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
|
||||
MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
|
||||
MovedModule("cPickle", "cPickle", "pickle"),
|
||||
MovedModule("queue", "Queue"),
|
||||
MovedModule("reprlib", "repr"),
|
||||
MovedModule("socketserver", "SocketServer"),
|
||||
MovedModule("_thread", "thread", "_thread"),
|
||||
MovedModule("tkinter", "Tkinter"),
|
||||
MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
|
||||
MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
|
||||
MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
|
||||
MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
|
||||
MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
|
||||
MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
|
||||
MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
|
||||
MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
|
||||
MovedModule("tkinter_colorchooser", "tkColorChooser",
|
||||
"tkinter.colorchooser"),
|
||||
MovedModule("tkinter_commondialog", "tkCommonDialog",
|
||||
"tkinter.commondialog"),
|
||||
MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
|
||||
MovedModule("tkinter_font", "tkFont", "tkinter.font"),
|
||||
MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
|
||||
MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
|
||||
"tkinter.simpledialog"),
|
||||
MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
|
||||
MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
|
||||
MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
|
||||
MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
|
||||
MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
|
||||
MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
|
||||
]
|
||||
# Add windows specific modules.
|
||||
if sys.platform == "win32":
|
||||
_moved_attributes += [
|
||||
MovedModule("winreg", "_winreg"),
|
||||
]
|
||||
|
||||
for attr in _moved_attributes:
|
||||
setattr(_MovedItems, attr.name, attr)
|
||||
if isinstance(attr, MovedModule):
|
||||
_importer._add_module(attr, "moves." + attr.name)
|
||||
del attr
|
||||
|
||||
_MovedItems._moved_attributes = _moved_attributes
|
||||
|
||||
moves = _MovedItems(__name__ + ".moves")
|
||||
_importer._add_module(moves, "moves")
|
||||
|
||||
|
||||
class Module_six_moves_urllib_parse(_LazyModule):
|
||||
|
||||
"""Lazy loading of moved objects in six.moves.urllib_parse"""
|
||||
|
||||
|
||||
_urllib_parse_moved_attributes = [
|
||||
MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("SplitResult", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("urljoin", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("urlparse", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("urlsplit", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("urlunparse", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("urlunsplit", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("quote", "urllib", "urllib.parse"),
|
||||
MovedAttribute("quote_plus", "urllib", "urllib.parse"),
|
||||
MovedAttribute("unquote", "urllib", "urllib.parse"),
|
||||
MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
|
||||
MovedAttribute("unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"),
|
||||
MovedAttribute("urlencode", "urllib", "urllib.parse"),
|
||||
MovedAttribute("splitquery", "urllib", "urllib.parse"),
|
||||
MovedAttribute("splittag", "urllib", "urllib.parse"),
|
||||
MovedAttribute("splituser", "urllib", "urllib.parse"),
|
||||
MovedAttribute("splitvalue", "urllib", "urllib.parse"),
|
||||
MovedAttribute("uses_fragment", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("uses_netloc", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("uses_params", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("uses_query", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("uses_relative", "urlparse", "urllib.parse"),
|
||||
]
|
||||
for attr in _urllib_parse_moved_attributes:
|
||||
setattr(Module_six_moves_urllib_parse, attr.name, attr)
|
||||
del attr
|
||||
|
||||
Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
|
||||
|
||||
_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"),
|
||||
"moves.urllib_parse", "moves.urllib.parse")
|
||||
|
||||
|
||||
class Module_six_moves_urllib_error(_LazyModule):
|
||||
|
||||
"""Lazy loading of moved objects in six.moves.urllib_error"""
|
||||
|
||||
|
||||
_urllib_error_moved_attributes = [
|
||||
MovedAttribute("URLError", "urllib2", "urllib.error"),
|
||||
MovedAttribute("HTTPError", "urllib2", "urllib.error"),
|
||||
MovedAttribute("ContentTooShortError", "urllib", "urllib.error"),
|
||||
]
|
||||
for attr in _urllib_error_moved_attributes:
|
||||
setattr(Module_six_moves_urllib_error, attr.name, attr)
|
||||
del attr
|
||||
|
||||
Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
|
||||
|
||||
_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"),
|
||||
"moves.urllib_error", "moves.urllib.error")
|
||||
|
||||
|
||||
class Module_six_moves_urllib_request(_LazyModule):
|
||||
|
||||
"""Lazy loading of moved objects in six.moves.urllib_request"""
|
||||
|
||||
|
||||
_urllib_request_moved_attributes = [
|
||||
MovedAttribute("urlopen", "urllib2", "urllib.request"),
|
||||
MovedAttribute("install_opener", "urllib2", "urllib.request"),
|
||||
MovedAttribute("build_opener", "urllib2", "urllib.request"),
|
||||
MovedAttribute("pathname2url", "urllib", "urllib.request"),
|
||||
MovedAttribute("url2pathname", "urllib", "urllib.request"),
|
||||
MovedAttribute("getproxies", "urllib", "urllib.request"),
|
||||
MovedAttribute("Request", "urllib2", "urllib.request"),
|
||||
MovedAttribute("OpenerDirector", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"),
|
||||
MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
|
||||
MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("FileHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("FTPHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("UnknownHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"),
|
||||
MovedAttribute("urlretrieve", "urllib", "urllib.request"),
|
||||
MovedAttribute("urlcleanup", "urllib", "urllib.request"),
|
||||
MovedAttribute("URLopener", "urllib", "urllib.request"),
|
||||
MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
|
||||
MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
|
||||
MovedAttribute("parse_http_list", "urllib2", "urllib.request"),
|
||||
MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"),
|
||||
]
|
||||
for attr in _urllib_request_moved_attributes:
|
||||
setattr(Module_six_moves_urllib_request, attr.name, attr)
|
||||
del attr
|
||||
|
||||
Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
|
||||
|
||||
_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"),
|
||||
"moves.urllib_request", "moves.urllib.request")
|
||||
|
||||
|
||||
class Module_six_moves_urllib_response(_LazyModule):
|
||||
|
||||
"""Lazy loading of moved objects in six.moves.urllib_response"""
|
||||
|
||||
|
||||
_urllib_response_moved_attributes = [
|
||||
MovedAttribute("addbase", "urllib", "urllib.response"),
|
||||
MovedAttribute("addclosehook", "urllib", "urllib.response"),
|
||||
MovedAttribute("addinfo", "urllib", "urllib.response"),
|
||||
MovedAttribute("addinfourl", "urllib", "urllib.response"),
|
||||
]
|
||||
for attr in _urllib_response_moved_attributes:
|
||||
setattr(Module_six_moves_urllib_response, attr.name, attr)
|
||||
del attr
|
||||
|
||||
Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
|
||||
|
||||
_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"),
|
||||
"moves.urllib_response", "moves.urllib.response")
|
||||
|
||||
|
||||
class Module_six_moves_urllib_robotparser(_LazyModule):
|
||||
|
||||
"""Lazy loading of moved objects in six.moves.urllib_robotparser"""
|
||||
|
||||
|
||||
_urllib_robotparser_moved_attributes = [
|
||||
MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"),
|
||||
]
|
||||
for attr in _urllib_robotparser_moved_attributes:
|
||||
setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
|
||||
del attr
|
||||
|
||||
Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
|
||||
|
||||
_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
|
||||
"moves.urllib_robotparser", "moves.urllib.robotparser")
|
||||
|
||||
|
||||
class Module_six_moves_urllib(types.ModuleType):
|
||||
|
||||
"""Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
|
||||
__path__ = [] # mark as package
|
||||
parse = _importer._get_module("moves.urllib_parse")
|
||||
error = _importer._get_module("moves.urllib_error")
|
||||
request = _importer._get_module("moves.urllib_request")
|
||||
response = _importer._get_module("moves.urllib_response")
|
||||
robotparser = _importer._get_module("moves.urllib_robotparser")
|
||||
|
||||
def __dir__(self):
|
||||
return ['parse', 'error', 'request', 'response', 'robotparser']
|
||||
|
||||
_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"),
|
||||
"moves.urllib")
|
||||
|
||||
|
||||
def add_move(move):
|
||||
"""Add an item to six.moves."""
|
||||
setattr(_MovedItems, move.name, move)
|
||||
|
||||
|
||||
def remove_move(name):
|
||||
"""Remove item from six.moves."""
|
||||
try:
|
||||
delattr(_MovedItems, name)
|
||||
except AttributeError:
|
||||
try:
|
||||
del moves.__dict__[name]
|
||||
except KeyError:
|
||||
raise AttributeError("no such move, %r" % (name,))
|
||||
|
||||
|
||||
if PY3:
|
||||
_meth_func = "__func__"
|
||||
_meth_self = "__self__"
|
||||
|
||||
_func_closure = "__closure__"
|
||||
_func_code = "__code__"
|
||||
_func_defaults = "__defaults__"
|
||||
_func_globals = "__globals__"
|
||||
else:
|
||||
_meth_func = "im_func"
|
||||
_meth_self = "im_self"
|
||||
|
||||
_func_closure = "func_closure"
|
||||
_func_code = "func_code"
|
||||
_func_defaults = "func_defaults"
|
||||
_func_globals = "func_globals"
|
||||
|
||||
|
||||
try:
|
||||
advance_iterator = next
|
||||
except NameError:
|
||||
def advance_iterator(it):
|
||||
return it.next()
|
||||
next = advance_iterator
|
||||
|
||||
|
||||
try:
|
||||
callable = callable
|
||||
except NameError:
|
||||
def callable(obj):
|
||||
return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
|
||||
|
||||
|
||||
if PY3:
|
||||
def get_unbound_function(unbound):
|
||||
return unbound
|
||||
|
||||
create_bound_method = types.MethodType
|
||||
|
||||
def create_unbound_method(func, cls):
|
||||
return func
|
||||
|
||||
Iterator = object
|
||||
else:
|
||||
def get_unbound_function(unbound):
|
||||
return unbound.im_func
|
||||
|
||||
def create_bound_method(func, obj):
|
||||
return types.MethodType(func, obj, obj.__class__)
|
||||
|
||||
def create_unbound_method(func, cls):
|
||||
return types.MethodType(func, None, cls)
|
||||
|
||||
class Iterator(object):
|
||||
|
||||
def next(self):
|
||||
return type(self).__next__(self)
|
||||
|
||||
callable = callable
|
||||
_add_doc(get_unbound_function,
|
||||
"""Get the function out of a possibly unbound function""")
|
||||
|
||||
|
||||
get_method_function = operator.attrgetter(_meth_func)
|
||||
get_method_self = operator.attrgetter(_meth_self)
|
||||
get_function_closure = operator.attrgetter(_func_closure)
|
||||
get_function_code = operator.attrgetter(_func_code)
|
||||
get_function_defaults = operator.attrgetter(_func_defaults)
|
||||
get_function_globals = operator.attrgetter(_func_globals)
|
||||
|
||||
|
||||
if PY3:
|
||||
def iterkeys(d, **kw):
|
||||
return iter(d.keys(**kw))
|
||||
|
||||
def itervalues(d, **kw):
|
||||
return iter(d.values(**kw))
|
||||
|
||||
def iteritems(d, **kw):
|
||||
return iter(d.items(**kw))
|
||||
|
||||
def iterlists(d, **kw):
|
||||
return iter(d.lists(**kw))
|
||||
|
||||
viewkeys = operator.methodcaller("keys")
|
||||
|
||||
viewvalues = operator.methodcaller("values")
|
||||
|
||||
viewitems = operator.methodcaller("items")
|
||||
else:
|
||||
def iterkeys(d, **kw):
|
||||
return d.iterkeys(**kw)
|
||||
|
||||
def itervalues(d, **kw):
|
||||
return d.itervalues(**kw)
|
||||
|
||||
def iteritems(d, **kw):
|
||||
return d.iteritems(**kw)
|
||||
|
||||
def iterlists(d, **kw):
|
||||
return d.iterlists(**kw)
|
||||
|
||||
viewkeys = operator.methodcaller("viewkeys")
|
||||
|
||||
viewvalues = operator.methodcaller("viewvalues")
|
||||
|
||||
viewitems = operator.methodcaller("viewitems")
|
||||
|
||||
_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
|
||||
_add_doc(itervalues, "Return an iterator over the values of a dictionary.")
|
||||
_add_doc(iteritems,
|
||||
"Return an iterator over the (key, value) pairs of a dictionary.")
|
||||
_add_doc(iterlists,
|
||||
"Return an iterator over the (key, [values]) pairs of a dictionary.")
|
||||
|
||||
|
||||
if PY3:
|
||||
def b(s):
|
||||
return s.encode("latin-1")
|
||||
|
||||
def u(s):
|
||||
return s
|
||||
unichr = chr
|
||||
import struct
|
||||
int2byte = struct.Struct(">B").pack
|
||||
del struct
|
||||
byte2int = operator.itemgetter(0)
|
||||
indexbytes = operator.getitem
|
||||
iterbytes = iter
|
||||
import io
|
||||
StringIO = io.StringIO
|
||||
BytesIO = io.BytesIO
|
||||
del io
|
||||
_assertCountEqual = "assertCountEqual"
|
||||
if sys.version_info[1] <= 1:
|
||||
_assertRaisesRegex = "assertRaisesRegexp"
|
||||
_assertRegex = "assertRegexpMatches"
|
||||
_assertNotRegex = "assertNotRegexpMatches"
|
||||
else:
|
||||
_assertRaisesRegex = "assertRaisesRegex"
|
||||
_assertRegex = "assertRegex"
|
||||
_assertNotRegex = "assertNotRegex"
|
||||
else:
|
||||
def b(s):
|
||||
return s
|
||||
# Workaround for standalone backslash
|
||||
|
||||
def u(s):
|
||||
return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
|
||||
unichr = unichr
|
||||
int2byte = chr
|
||||
|
||||
def byte2int(bs):
|
||||
return ord(bs[0])
|
||||
|
||||
def indexbytes(buf, i):
|
||||
return ord(buf[i])
|
||||
iterbytes = functools.partial(itertools.imap, ord)
|
||||
import StringIO
|
||||
StringIO = BytesIO = StringIO.StringIO
|
||||
_assertCountEqual = "assertItemsEqual"
|
||||
_assertRaisesRegex = "assertRaisesRegexp"
|
||||
_assertRegex = "assertRegexpMatches"
|
||||
_assertNotRegex = "assertNotRegexpMatches"
|
||||
_add_doc(b, """Byte literal""")
|
||||
_add_doc(u, """Text literal""")
|
||||
|
||||
|
||||
def assertCountEqual(self, *args, **kwargs):
|
||||
return getattr(self, _assertCountEqual)(*args, **kwargs)
|
||||
|
||||
|
||||
def assertRaisesRegex(self, *args, **kwargs):
|
||||
return getattr(self, _assertRaisesRegex)(*args, **kwargs)
|
||||
|
||||
|
||||
def assertRegex(self, *args, **kwargs):
|
||||
return getattr(self, _assertRegex)(*args, **kwargs)
|
||||
|
||||
|
||||
def assertNotRegex(self, *args, **kwargs):
|
||||
return getattr(self, _assertNotRegex)(*args, **kwargs)
|
||||
|
||||
|
||||
if PY3:
|
||||
exec_ = getattr(moves.builtins, "exec")
|
||||
|
||||
def reraise(tp, value, tb=None):
|
||||
try:
|
||||
if value is None:
|
||||
value = tp()
|
||||
if value.__traceback__ is not tb:
|
||||
raise value.with_traceback(tb)
|
||||
raise value
|
||||
finally:
|
||||
value = None
|
||||
tb = None
|
||||
|
||||
else:
|
||||
def exec_(_code_, _globs_=None, _locs_=None):
|
||||
"""Execute code in a namespace."""
|
||||
if _globs_ is None:
|
||||
frame = sys._getframe(1)
|
||||
_globs_ = frame.f_globals
|
||||
if _locs_ is None:
|
||||
_locs_ = frame.f_locals
|
||||
del frame
|
||||
elif _locs_ is None:
|
||||
_locs_ = _globs_
|
||||
exec("""exec _code_ in _globs_, _locs_""")
|
||||
|
||||
exec_("""def reraise(tp, value, tb=None):
|
||||
try:
|
||||
raise tp, value, tb
|
||||
finally:
|
||||
tb = None
|
||||
""")
|
||||
|
||||
|
||||
if sys.version_info[:2] > (3,):
|
||||
exec_("""def raise_from(value, from_value):
|
||||
try:
|
||||
raise value from from_value
|
||||
finally:
|
||||
value = None
|
||||
""")
|
||||
else:
|
||||
def raise_from(value, from_value):
|
||||
raise value
|
||||
|
||||
|
||||
print_ = getattr(moves.builtins, "print", None)
|
||||
if print_ is None:
|
||||
def print_(*args, **kwargs):
|
||||
"""The new-style print function for Python 2.4 and 2.5."""
|
||||
fp = kwargs.pop("file", sys.stdout)
|
||||
if fp is None:
|
||||
return
|
||||
|
||||
def write(data):
|
||||
if not isinstance(data, basestring):
|
||||
data = str(data)
|
||||
# If the file has an encoding, encode unicode with it.
|
||||
if (isinstance(fp, file) and
|
||||
isinstance(data, unicode) and
|
||||
fp.encoding is not None):
|
||||
errors = getattr(fp, "errors", None)
|
||||
if errors is None:
|
||||
errors = "strict"
|
||||
data = data.encode(fp.encoding, errors)
|
||||
fp.write(data)
|
||||
want_unicode = False
|
||||
sep = kwargs.pop("sep", None)
|
||||
if sep is not None:
|
||||
if isinstance(sep, unicode):
|
||||
want_unicode = True
|
||||
elif not isinstance(sep, str):
|
||||
raise TypeError("sep must be None or a string")
|
||||
end = kwargs.pop("end", None)
|
||||
if end is not None:
|
||||
if isinstance(end, unicode):
|
||||
want_unicode = True
|
||||
elif not isinstance(end, str):
|
||||
raise TypeError("end must be None or a string")
|
||||
if kwargs:
|
||||
raise TypeError("invalid keyword arguments to print()")
|
||||
if not want_unicode:
|
||||
for arg in args:
|
||||
if isinstance(arg, unicode):
|
||||
want_unicode = True
|
||||
break
|
||||
if want_unicode:
|
||||
newline = unicode("\n")
|
||||
space = unicode(" ")
|
||||
else:
|
||||
newline = "\n"
|
||||
space = " "
|
||||
if sep is None:
|
||||
sep = space
|
||||
if end is None:
|
||||
end = newline
|
||||
for i, arg in enumerate(args):
|
||||
if i:
|
||||
write(sep)
|
||||
write(arg)
|
||||
write(end)
|
||||
if sys.version_info[:2] < (3, 3):
|
||||
_print = print_
|
||||
|
||||
def print_(*args, **kwargs):
|
||||
fp = kwargs.get("file", sys.stdout)
|
||||
flush = kwargs.pop("flush", False)
|
||||
_print(*args, **kwargs)
|
||||
if flush and fp is not None:
|
||||
fp.flush()
|
||||
|
||||
_add_doc(reraise, """Reraise an exception.""")
|
||||
|
||||
if sys.version_info[0:2] < (3, 4):
|
||||
# This does exactly the same what the :func:`py3:functools.update_wrapper`
|
||||
# function does on Python versions after 3.2. It sets the ``__wrapped__``
|
||||
# attribute on ``wrapper`` object and it doesn't raise an error if any of
|
||||
# the attributes mentioned in ``assigned`` and ``updated`` are missing on
|
||||
# ``wrapped`` object.
|
||||
def _update_wrapper(wrapper, wrapped,
|
||||
assigned=functools.WRAPPER_ASSIGNMENTS,
|
||||
updated=functools.WRAPPER_UPDATES):
|
||||
for attr in assigned:
|
||||
try:
|
||||
value = getattr(wrapped, attr)
|
||||
except AttributeError:
|
||||
continue
|
||||
else:
|
||||
setattr(wrapper, attr, value)
|
||||
for attr in updated:
|
||||
getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
|
||||
wrapper.__wrapped__ = wrapped
|
||||
return wrapper
|
||||
_update_wrapper.__doc__ = functools.update_wrapper.__doc__
|
||||
|
||||
def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
|
||||
updated=functools.WRAPPER_UPDATES):
|
||||
return functools.partial(_update_wrapper, wrapped=wrapped,
|
||||
assigned=assigned, updated=updated)
|
||||
wraps.__doc__ = functools.wraps.__doc__
|
||||
|
||||
else:
|
||||
wraps = functools.wraps
|
||||
|
||||
|
||||
def with_metaclass(meta, *bases):
|
||||
"""Create a base class with a metaclass."""
|
||||
# This requires a bit of explanation: the basic idea is to make a dummy
|
||||
# metaclass for one level of class instantiation that replaces itself with
|
||||
# the actual metaclass.
|
||||
class metaclass(type):
|
||||
|
||||
def __new__(cls, name, this_bases, d):
|
||||
if sys.version_info[:2] >= (3, 7):
|
||||
# This version introduced PEP 560 that requires a bit
|
||||
# of extra care (we mimic what is done by __build_class__).
|
||||
resolved_bases = types.resolve_bases(bases)
|
||||
if resolved_bases is not bases:
|
||||
d['__orig_bases__'] = bases
|
||||
else:
|
||||
resolved_bases = bases
|
||||
return meta(name, resolved_bases, d)
|
||||
|
||||
@classmethod
|
||||
def __prepare__(cls, name, this_bases):
|
||||
return meta.__prepare__(name, bases)
|
||||
return type.__new__(metaclass, 'temporary_class', (), {})
|
||||
|
||||
|
||||
def add_metaclass(metaclass):
|
||||
"""Class decorator for creating a class with a metaclass."""
|
||||
def wrapper(cls):
|
||||
orig_vars = cls.__dict__.copy()
|
||||
slots = orig_vars.get('__slots__')
|
||||
if slots is not None:
|
||||
if isinstance(slots, str):
|
||||
slots = [slots]
|
||||
for slots_var in slots:
|
||||
orig_vars.pop(slots_var)
|
||||
orig_vars.pop('__dict__', None)
|
||||
orig_vars.pop('__weakref__', None)
|
||||
if hasattr(cls, '__qualname__'):
|
||||
orig_vars['__qualname__'] = cls.__qualname__
|
||||
return metaclass(cls.__name__, cls.__bases__, orig_vars)
|
||||
return wrapper
|
||||
|
||||
|
||||
def ensure_binary(s, encoding='utf-8', errors='strict'):
|
||||
"""Coerce **s** to six.binary_type.
|
||||
|
||||
For Python 2:
|
||||
- `unicode` -> encoded to `str`
|
||||
- `str` -> `str`
|
||||
|
||||
For Python 3:
|
||||
- `str` -> encoded to `bytes`
|
||||
- `bytes` -> `bytes`
|
||||
"""
|
||||
if isinstance(s, binary_type):
|
||||
return s
|
||||
if isinstance(s, text_type):
|
||||
return s.encode(encoding, errors)
|
||||
raise TypeError("not expecting type '%s'" % type(s))
|
||||
|
||||
|
||||
def ensure_str(s, encoding='utf-8', errors='strict'):
|
||||
"""Coerce *s* to `str`.
|
||||
|
||||
For Python 2:
|
||||
- `unicode` -> encoded to `str`
|
||||
- `str` -> `str`
|
||||
|
||||
For Python 3:
|
||||
- `str` -> `str`
|
||||
- `bytes` -> decoded to `str`
|
||||
"""
|
||||
# Optimization: Fast return for the common case.
|
||||
if type(s) is str:
|
||||
return s
|
||||
if PY2 and isinstance(s, text_type):
|
||||
return s.encode(encoding, errors)
|
||||
elif PY3 and isinstance(s, binary_type):
|
||||
return s.decode(encoding, errors)
|
||||
elif not isinstance(s, (text_type, binary_type)):
|
||||
raise TypeError("not expecting type '%s'" % type(s))
|
||||
return s
|
||||
|
||||
|
||||
def ensure_text(s, encoding='utf-8', errors='strict'):
|
||||
"""Coerce *s* to six.text_type.
|
||||
|
||||
For Python 2:
|
||||
- `unicode` -> `unicode`
|
||||
- `str` -> `unicode`
|
||||
|
||||
For Python 3:
|
||||
- `str` -> `str`
|
||||
- `bytes` -> decoded to `str`
|
||||
"""
|
||||
if isinstance(s, binary_type):
|
||||
return s.decode(encoding, errors)
|
||||
elif isinstance(s, text_type):
|
||||
return s
|
||||
else:
|
||||
raise TypeError("not expecting type '%s'" % type(s))
|
||||
|
||||
|
||||
def python_2_unicode_compatible(klass):
|
||||
"""
|
||||
A class decorator that defines __unicode__ and __str__ methods under Python 2.
|
||||
Under Python 3 it does nothing.
|
||||
|
||||
To support Python 2 and 3 with a single code base, define a __str__ method
|
||||
returning text and apply this decorator to the class.
|
||||
"""
|
||||
if PY2:
|
||||
if '__str__' not in klass.__dict__:
|
||||
raise ValueError("@python_2_unicode_compatible cannot be applied "
|
||||
"to %s because it doesn't define __str__()." %
|
||||
klass.__name__)
|
||||
klass.__unicode__ = klass.__str__
|
||||
klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
|
||||
return klass
|
||||
|
||||
|
||||
# Complete the moves implementation.
|
||||
# This code is at the end of this module to speed up module loading.
|
||||
# Turn this module into a package.
|
||||
__path__ = [] # required for PEP 302 and PEP 451
|
||||
__package__ = __name__ # see PEP 366 @ReservedAssignment
|
||||
if globals().get("__spec__") is not None:
|
||||
__spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable
|
||||
# Remove other six meta path importers, since they cause problems. This can
|
||||
# happen if six is removed from sys.modules and then reloaded. (Setuptools does
|
||||
# this for some reason.)
|
||||
if sys.meta_path:
|
||||
for i, importer in enumerate(sys.meta_path):
|
||||
# Here's some real nastiness: Another "instance" of the six module might
|
||||
# be floating around. Therefore, we can't use isinstance() to check for
|
||||
# the six meta path importer, since the other six instance will have
|
||||
# inserted an importer with different class.
|
||||
if (type(importer).__name__ == "_SixMetaPathImporter" and
|
||||
importer.name == __name__):
|
||||
del sys.meta_path[i]
|
||||
break
|
||||
del i, importer
|
||||
# Finally, add the importer to the meta path import hook.
|
||||
sys.meta_path.append(_importer)
|
||||
@@ -1,7 +0,0 @@
|
||||
# This file contains all requirements needed for GAM development work
|
||||
|
||||
# Include all build requirements
|
||||
-r requirements.txt
|
||||
|
||||
# Dev-specific requirements
|
||||
pre-commit
|
||||
@@ -1,14 +0,0 @@
|
||||
chardet>=5.2.0
|
||||
cryptography>=44.0.2
|
||||
distro; sys_platform=='linux'
|
||||
filelock>=3.18.0
|
||||
google-api-python-client>=2.167.0
|
||||
google-auth-httplib2>=0.2.0
|
||||
google-auth-oauthlib>=1.2.2
|
||||
google-auth>=2.39.0
|
||||
httplib2>=0.22.0
|
||||
lxml>=5.4.0
|
||||
passlib>=1.7.4
|
||||
pathvalidate>=3.2.3
|
||||
python-dateutil
|
||||
yubikey-manager>=5.6.1
|
||||
@@ -1,55 +0,0 @@
|
||||
[metadata]
|
||||
name = GAM for Google Workspace
|
||||
version = attr: gam.var.GAM_VERSION
|
||||
description = Command line management for Google Workspaces
|
||||
long_description = file: readme.md
|
||||
long_description_content_type = text/markdown
|
||||
url = https://github.com/GAM-team/GAM
|
||||
author = GAM Team
|
||||
author_email = google-apps-manager@googlegroups.com
|
||||
license = Apache
|
||||
license_files = LICENSE
|
||||
keywords = google, oauth2, gsuite, google-apps, google-admin-sdk, google-drive, google-cloud, google-calendar, gam, google-api, oauth2-client, google-workspace
|
||||
classifiers =
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3 :: Only
|
||||
Programming Language :: Python :: 3.9
|
||||
Programming Language :: Python :: 3.10
|
||||
Programming Language :: Python :: 3.11
|
||||
Programming Language :: Python :: 3.12
|
||||
Programming Language :: Python :: 3.13
|
||||
License :: OSI Approved :: Apache License
|
||||
|
||||
[options]
|
||||
packages = find:
|
||||
python_requires = >= 3.9
|
||||
# The following files should be edited to match: pyproject.toml, requirements.txt
|
||||
install_requires =
|
||||
chardet >= 5.2.0
|
||||
cryptography >= 44.0.2
|
||||
distro; sys_platform == 'linux'
|
||||
filelock >= 3.18.0
|
||||
google-api-python-client >= 2.167.0
|
||||
google-auth-httplib2 >= 0.2.0
|
||||
google-auth-oauthlib >= 1.2.2
|
||||
google-auth >= 2.39.0
|
||||
httplib2 >= 0.22.0
|
||||
lxml >= 5.4.0
|
||||
passlib >= 1.7.4
|
||||
pathvalidate >= 3.2.3
|
||||
python-dateutil
|
||||
yubikey-manager >= 5.6.1
|
||||
|
||||
[options.package_data]
|
||||
* = *.pem
|
||||
|
||||
# used during pip install .[test]
|
||||
[options.extras_require]
|
||||
test = pre-commit
|
||||
|
||||
[options.entry_points]
|
||||
console_scripts =
|
||||
gam = gam.__main__:main
|
||||
|
||||
[bdist_wheel]
|
||||
universal = True
|
||||
@@ -1,3 +0,0 @@
|
||||
from setuptools import setup
|
||||
|
||||
setup()
|
||||
21
src/tools/hooks/hook-googleapiclient.model.py
Normal file
21
src/tools/hooks/hook-googleapiclient.model.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# ------------------------------------------------------------------
|
||||
# Copyright (c) 2021 PyInstaller Development Team.
|
||||
#
|
||||
# This file is distributed under the terms of the GNU General Public
|
||||
# License (version 2.0 or later).
|
||||
#
|
||||
# The full license is available in LICENSE, distributed with
|
||||
# this software.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
from PyInstaller.utils.hooks import copy_metadata
|
||||
from PyInstaller.utils.hooks import collect_data_files
|
||||
|
||||
# googleapiclient.model queries the library version via
|
||||
# pkg_resources.get_distribution("google-api-python-client").version,
|
||||
# so we need to collect that package's metadata
|
||||
datas = copy_metadata('google_api_python_client')
|
||||
# we don't want these cached discovery files and they make the binary HUUUGEEEE
|
||||
#datas += collect_data_files('googleapiclient.discovery_cache', excludes=['*.txt', '**/__pycache__'])
|
||||
19
src/tools/hooks/hook-httplib2.py
Normal file
19
src/tools/hooks/hook-httplib2.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# ------------------------------------------------------------------
|
||||
# Copyright (c) 2020 PyInstaller Development Team.
|
||||
#
|
||||
# This file is distributed under the terms of the GNU General Public
|
||||
# License (version 2.0 or later).
|
||||
#
|
||||
# The full license is available in LICENSE, distributed with
|
||||
# this software.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
# This is needed to bundle cacerts.txt that comes with httplib2 module
|
||||
|
||||
# WE DON'T NEED httplib2/cacerts.txt since we get our own
|
||||
|
||||
#from PyInstaller.utils.hooks import collect_data_files
|
||||
|
||||
#datas = collect_data_files('httplib2')
|
||||
128
src/tools/ssd.mjs
Normal file
128
src/tools/ssd.mjs
Normal file
@@ -0,0 +1,128 @@
|
||||
// Node.js script that implements an Appium client which will launch
|
||||
// Simply Sign Desktop app and log a user in. Once logged in it should
|
||||
// be possible to use tools like signtool.exe to sign Windows EXE/MSI files
|
||||
// with the Certum certificate.
|
||||
|
||||
import { Key, remote } from 'webdriverio';
|
||||
import { exec } from 'child_process';
|
||||
import { TOTP } from 'totp-generator';
|
||||
|
||||
async function screenshot(driver, filename) {
|
||||
// uncomment to save .png screenshots
|
||||
//await driver.saveScreenshot(filename);
|
||||
return
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function executeCommand(command) {
|
||||
try {
|
||||
let { stdout, stderr } = await exec(command);
|
||||
return stdout;
|
||||
} catch (error) {
|
||||
console.error(`Error executing command: ${command}`);
|
||||
console.error(`Error details: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function runSSD() {
|
||||
const opts = {
|
||||
port: 4723,
|
||||
logLevel: "silent",
|
||||
capabilities: {
|
||||
platformName: "Windows",
|
||||
"appium:app": "C:\\Program Files\\Certum\\SimplySign Desktop\\SimplySignDesktop.exe",
|
||||
"appium:automationName": "Windows",
|
||||
},
|
||||
};
|
||||
|
||||
let driver;
|
||||
try {
|
||||
driver = await remote(opts);
|
||||
|
||||
// Github Actions Win ARM64 is stuck on a OOB screen that steals focus
|
||||
// These enter / escapes should dismiss it.
|
||||
const runner_arch = process.env.RUNNER_ARCH;
|
||||
if ( runner_arch === "ARM64" ) {
|
||||
console.log('Running on ARM64...');
|
||||
await sleep(3000); // Pause execution for 3 seconds
|
||||
await screenshot(driver, 'oob1.png');
|
||||
await driver.sendKeys([Key.Enter]);
|
||||
await sleep(3000); // Pause execution for 3 seconds
|
||||
await screenshot(driver, 'oob2.png');
|
||||
await driver.sendKeys([Key.Enter]);
|
||||
await sleep(3000); // Pause execution for 3 seconds
|
||||
await screenshot(driver, 'oob3.png');
|
||||
await driver.sendKeys([Key.Escape]);
|
||||
await screenshot(driver, 'oob6.png');
|
||||
} else {
|
||||
console.log('NOT running on ARM64');
|
||||
}
|
||||
|
||||
// Execute SSD again to open login dialog
|
||||
exec('"C:\\Program Files\\Certum\\SimplySign Desktop\\SimplySignDesktop.exe"', (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.error(`exec error: ${error}`);
|
||||
return;
|
||||
}
|
||||
});
|
||||
await sleep(3000);
|
||||
|
||||
// Login
|
||||
const windows = await driver.getWindowHandles();
|
||||
const login_window = windows[0]
|
||||
await driver.switchWindow(login_window);
|
||||
await screenshot(driver, 'login01.png');
|
||||
const id_value = 'jay0lee@gmail.com';
|
||||
const id_arr = [...id_value];
|
||||
await driver.sendKeys(id_arr);
|
||||
await screenshot(driver, 'login02.png');
|
||||
await driver.sendKeys([Key.Tab]);
|
||||
console.log('Our secret is ' + process.env.TOTP_SECRET.length + ' characters.');
|
||||
// We wait until the last possible second to generate
|
||||
// our TOTP to ensure it's still valid.
|
||||
const { otp } = await TOTP.generate(process.env.TOTP_SECRET, {algorithm: 'SHA-256'});
|
||||
console.log('Our token is ' + otp.length + ' characters.');
|
||||
const otp_arr = [...otp];
|
||||
await driver.sendKeys(otp_arr);
|
||||
await screenshot(driver, 'login03.png');
|
||||
await driver.sendKeys([Key.Enter]);
|
||||
|
||||
// TODO: it's expected that on successful login the window
|
||||
// will close and these screenshots will error out. Figure
|
||||
// out how to handle that gracefully.
|
||||
await screenshot(driver, 'login04.png');
|
||||
await sleep(500);
|
||||
await screenshot(driver, 'login05.png');
|
||||
await sleep(500);
|
||||
await screenshot(driver, 'login06.png');
|
||||
await sleep(500);
|
||||
await screenshot(driver, 'login07.png');
|
||||
await sleep(500);
|
||||
await screenshot(driver, 'login08.png');
|
||||
await sleep(500);
|
||||
await screenshot(driver, 'login09.png');
|
||||
await sleep(500);
|
||||
await screenshot(driver, 'login10.png');
|
||||
await sleep(500);
|
||||
await screenshot(driver, 'login11.png');
|
||||
await sleep(500);
|
||||
await screenshot(driver, 'login12.png');
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
//console.error("Error during Appium run:");
|
||||
}
|
||||
|
||||
// INTENTIONAL Keep driver open so tray icon for Certum doesn't close
|
||||
// finally {
|
||||
// if (driver) {
|
||||
// await driver.deleteSession(); // Close the Appium session
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
runSSD();
|
||||
@@ -9,6 +9,7 @@
|
||||
- [Display administrators](#display-administrators)
|
||||
- [Copy privileges from one role to a new role](#copy-privileges-from-one-role-to-a-new-role)
|
||||
- [Copy roles from one administrator to another](#copy-roles-from-one-administrator-to-another)
|
||||
- [Copy non-system admin roles from a source workspace to a target workspace](#copy-non-system-admin-roles-from-a-source-workspace-to-a-target-workspace)
|
||||
|
||||
## API documentation
|
||||
* [About Administrator roles](https://support.google.com/a/answer/33325?ref_topic=4514341)
|
||||
@@ -21,13 +22,16 @@
|
||||
<DomainName> ::= <String>(.<String>)+
|
||||
<EmailAddress> ::= <String>@<DomainName>
|
||||
<GroupItem> ::= <EmailAddress>|<UniqueID>|<String>
|
||||
<JSONData> ::= (json [charset <Charset>] <String>) | (json file <FileName> [charset <Charset>]) |
|
||||
<OrgUnitID> ::= id:<String>
|
||||
<OrgUnitPath> ::= /|(/<String)+
|
||||
<OrgUnitItem> ::= <OrgUnitID>|<OrgUnitPath>
|
||||
<Privilege> ::= <String>
|
||||
<PrivilegeList> ::= "<Privilege>(,<Privilege)*"
|
||||
<RoleAssignmentID> ::= <String>
|
||||
<RoleItem> ::= id:<String>|uid:<String>|<String>
|
||||
<RoleID> ::= <String>
|
||||
<RoleName> ::= <String>
|
||||
<RoleItem> ::= id:<RoleID>|<RoleName>
|
||||
<UniqueID> ::= id:<String>
|
||||
<UserItem> ::= <EmailAddress>|<UniqueID>|<String>
|
||||
```
|
||||
@@ -1383,9 +1387,11 @@ Show 111 Privileges
|
||||
## Manage administrative roles
|
||||
```
|
||||
gam create adminrole <String> [description <String>]
|
||||
privileges all|all_ou|<PrivilegeList>|(select <FileSelector>|<CSVFileSelector>>)
|
||||
privileges all|all_ou|<PrivilegeList>|(select <FileSelector>|<CSVFileSelector>>)|<JSONData>
|
||||
[csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]] (addcsvdata <FieldName> <String>)*]
|
||||
gam update adminrole <RoleItem> [name <String>] [description <String>]
|
||||
[privileges all|all_ou|<PrivilegeList>|(select <FileSelector>|<CSVFileSelector>>)]
|
||||
[privileges all|all_ou|<PrivilegeList>|(select <FileSelector>|<CSVFileSelector>>)|<JSONData>]
|
||||
[csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]] (addcsvdata <FieldName> <String>)*]
|
||||
gam delete adminrole <RoleItem>
|
||||
```
|
||||
* `privileges all` - All defined privileges
|
||||
@@ -1393,24 +1399,61 @@ gam delete adminrole <RoleItem>
|
||||
* `privileges <PrivilegeList>` - A specific list of privileges
|
||||
* `privileges select <FileSelector>|<CSVFileSelector>>` - A collection of privileges from a flat or CSV file
|
||||
|
||||
By default, when an admin role is created|update, GAM displays `<RoleName>(<RoleID>) created|updated`.
|
||||
* `csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]]` - Output the admin roledetails in CSV format.
|
||||
|
||||
When `csv` is uused, Add additional columns of data from the command line to the output.
|
||||
* `addcsvdata <FieldName> <String>`
|
||||
|
||||
## Display administrative roles
|
||||
```
|
||||
gam info adminrole <RoleItem> [privileges]
|
||||
[formatjson]
|
||||
```
|
||||
* `privileges` - Display privileges associated with role
|
||||
|
||||
By default, Gam displays the information as an indented list of keys and values.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
|
||||
```
|
||||
gam show adminroles|roles
|
||||
[role <RoleItem>] [privileges]
|
||||
[nosystemroles]
|
||||
[formatjson]
|
||||
```
|
||||
* `privileges` - Display privileges associated with each role
|
||||
|
||||
By default, all roles are displayed:
|
||||
* `role <RoleItem>` - Display a specific role.
|
||||
* `nosystemroles` - Display onnly non-system roles.
|
||||
|
||||
By default, Gam displays the information as an indented list of keys and values.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
|
||||
```
|
||||
gam print adminroles|roles [todrive <ToDriveAttribute>*]
|
||||
[role <RoleItem>] [privileges] [oneitemperrow]
|
||||
gam show adminroles|roles
|
||||
[role <RoleItem>] [privileges]
|
||||
[nosystemroles]
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
By default, all roles are displayed, use `role <RoleItem>` to display a specific role.
|
||||
|
||||
* `privileges` - Display privileges associated with each role
|
||||
|
||||
By default, with `print`, all privileges for a role are shown on one row as a repeating item.
|
||||
By default, all privileges for a role are shown on one row as a repeating item.
|
||||
When `oneitemperrow` is specified, each privilege is output on a separate row/line with the other role fields.
|
||||
|
||||
By default, all roles are displayed:
|
||||
* `role <RoleItem>` - Display a specific role.
|
||||
* `nosystemroles` - Display onnly non-system roles.
|
||||
|
||||
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.
|
||||
|
||||
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
|
||||
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
|
||||
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.
|
||||
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
|
||||
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
|
||||
|
||||
## Create an administrator
|
||||
Add an administrator role to an administrator.
|
||||
```
|
||||
@@ -1469,3 +1512,15 @@ gam config csv_input_row_filter "scopeType:regex:CUSTOMER" redirect stdout ./Upd
|
||||
gam config csv_input_row_filter "scopeType:regex:ORG_UNIT" redirect stdout ./UpdateNewAdminOrgUnitRoles.txt multiprocess redirect stderr stdout csv CurrentAdminRoles.csv gam create admin newadmin@domain.com "id:~~roleId~~" org_unit "id:~~orgUnitId~~"
|
||||
```
|
||||
|
||||
## Copy non-system admin roles from a source workspace to a target workspace
|
||||
This requires GAM version 7.18.01 or higher.
|
||||
|
||||
In the source workspace to the following:
|
||||
```
|
||||
gam redirect csv ./SourceNonSystemRoles.csv print adminroles privileges nosystemroles formatjson quotechar "'"
|
||||
```
|
||||
|
||||
In the target workspacce do the following:
|
||||
```
|
||||
gam redirect csv ./TargetNonSystemRoles.csv multiprocess quotechar "'" redirect stderr - multiprocess csv SourceNonSystemRoles.csv quotechar "'" gam create adminrole "~roleName" description "~roleDescription" privileges json "~JSON" csv addcsvdata oldRoleId "~roleId" formatjson
|
||||
```
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
- [Display alerts](#display-alerts)
|
||||
- [Manage alert feedback](#manage-alert-feedback)
|
||||
- [Display alert feedback](#display-alert-feedback)
|
||||
- [Configuring settings](#configuring-settings)
|
||||
|
||||
## API documentation
|
||||
* [Alert Center API](https://developers.google.com/admin-sdk/alertcenter/reference/rest/)
|
||||
@@ -18,6 +19,7 @@
|
||||
## Definitions
|
||||
```
|
||||
<AlertID> ::= <String>
|
||||
<PubSubTopicName> ::= <String>
|
||||
<QueryAlert> ::= <String> See: https://developers.google.com/admin-sdk/alertcenter/guides/query-filters
|
||||
```
|
||||
## Introduction
|
||||
@@ -95,3 +97,15 @@ the quote character itself, the column delimiter (comma by default) and new-line
|
||||
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.
|
||||
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
|
||||
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
|
||||
|
||||
## Configuring settings
|
||||
|
||||
Alert Center can be configured to send notifications to a Google Cloud Pub/Sub topic, but it first requires configuration.
|
||||
* See https://developers.google.com/workspace/admin/alertcenter/guides/notifications for information.
|
||||
|
||||
Gam can be used to display or modify the settings:
|
||||
```
|
||||
gam show alertsettings
|
||||
gam update alertsettings <PubSubTopicName>
|
||||
gam clear alertsettings
|
||||
```
|
||||
@@ -103,7 +103,7 @@ gam print aliases [todrive <ToDriveAttribute>*]
|
||||
[limittoou <OrgUnitItem>])
|
||||
[user|users <EmailAddressList>] [group|groups <EmailAddressList>]
|
||||
[select <UserTypeEntity>]
|
||||
[aliasmatchpattern <REMatchPattern>]
|
||||
[issuspended <Boolean>] [isarchived <Boolean>] [aliasmatchpattern <REMatchPattern>]
|
||||
[shownoneditable] [nogroups] [nousers]
|
||||
[onerowpertarget] [delimiter <Character>]
|
||||
[suppressnoaliasrows]
|
||||
@@ -117,6 +117,8 @@ By default, group and user aliases in all domains in the account are selected; t
|
||||
* `user|users <EmailAddressList>` - Print aliases for users in `<EmailAddressList`
|
||||
* `select <UserTypeEntity>` - Print aliases for users in `<UserTypeEntity>`
|
||||
* `group|groups <EmailAddressList>` - Print aliases for groups in `<EmailAddressList`
|
||||
* `issuspended <Boolean>` - Limit users based on their status
|
||||
* `isarchived <Boolean>` - Limit users based on their status
|
||||
* `aliasmatchpattern <REMatchPattern>` - Print aliases that match a pattern
|
||||
* `nogroups` - Print only user aliases
|
||||
* `nousers` - Print only group aliases
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
- [Python Regular Expressions](Python-Regular-Expressions)
|
||||
- [Definitions](#definitions)
|
||||
- [Manage Projects](#manage-projects)
|
||||
- [Authorize a super admin to create projects](#authorize-a-super-admin-to-create-projects)
|
||||
- [Authorize a user to create projects](#authorize-a-user-to-create-projects)
|
||||
- [Authorize Service Account Key Uploads](#authorize-service-account-key-uploads)
|
||||
- [Authorize GAM to create projects](#authorize-gam-to-create-projects)
|
||||
- [Create a new GCP project folder](#create-a-new-gcp-project-folder)
|
||||
@@ -74,11 +74,6 @@ Verify that all scopes are available:
|
||||
* Select "ON for everyone"
|
||||
* Click "SAVE"
|
||||
|
||||
Verify that internal apps are trusted.
|
||||
* Access the admin console and go to Security -> Access and data control -> API Controls
|
||||
* Check that "Trust internal, domain-owned apps" is present in the **Settings** section
|
||||
* Click "SAVE"
|
||||
|
||||
If you run a Google Workspace Education SKU, verify that Classroom API is enabled if required.
|
||||
* Access the admin console and go to Apps -> Google Workspace - Classroom
|
||||
* Expand "Data access"
|
||||
@@ -110,12 +105,13 @@ Verify whether the super admin you'll be using is in an OU where reauthenticatio
|
||||
* Access the admin console and go to Security -> Overview
|
||||
* Scroll down and open Google Cloud session control section
|
||||
* Select the OU containing the super admin
|
||||
* If Require reauthentication is selected and Exempt Trusted apps is not checked, you'll have to do `gam oauth create` at whatever frequency is specified
|
||||
* If that sounds unappealing, check Exempt Trusted apps
|
||||
* Click "OVERRIDE"
|
||||
* If Require reauthentication is selected, you'll need either:
|
||||
* uncheck Google Cloud Storage and any other GCP APIs that you selected on `gam oauth create` (reauth is only necessary for GCP APIs)
|
||||
* enable "Exempt Trusted apps"
|
||||
* rerun `gam oauth create` at whatever frequency is specified
|
||||
|
||||
Additional steps may be required if errors are encountered.
|
||||
* [Authorize a super admin to create projects](#authorize-a-super-admin-to-create-projects)
|
||||
* [Authorize a user to create projects](#authorize-a-user-to-create-projects)
|
||||
* [Authorize Service Account Key Uploads](#authorize-service-account-key-uploads)
|
||||
* [Authorize GAM to create projects](#authorize-gam-to-create-projects)
|
||||
|
||||
@@ -169,8 +165,8 @@ For `print|show projects`, you can eliminate the password prompt and authenticat
|
||||
gam print projects admin admin@domain.com
|
||||
```
|
||||
|
||||
## Authorize a super admin to create projects
|
||||
If you try to create a project and get an error saying that the admin you specified is not authorized to create projects,
|
||||
## Authorize a user to create projects
|
||||
If you try to create a project and get an error saying that the user you specified is not authorized to create projects,
|
||||
perform these steps and then retry the create project command.
|
||||
|
||||
* Login as an existing super admin at console.cloud.google.com
|
||||
@@ -184,13 +180,12 @@ perform these steps and then retry the create project command.
|
||||
* Click in the Select a role box
|
||||
* Type project creator in the Filter box
|
||||
* Click Project Creator
|
||||
* Click + Add Another Role
|
||||
* Type orgpolicy.policyAdmin in the Filter box
|
||||
* Click Organization Policy Administrator
|
||||
* Click Save
|
||||
|
||||
## Authorize Service Account Key Uploads
|
||||
|
||||
*IMPORTANT:* Google best practice is to NOT use service account keys. Rather than overriding Google's default policy please consider [Running GAM7 securely on a Google Compute Engine](https://github.com/GAM-team/GAM/wiki/Running-GAM7-securely-on-a-Google-Compute-Engine) (if running in Google Cloud) or [Workload Identity Federation](https://github.com/GAM-team/GAM/wiki/Using-GAM7-with-keyless-authentication-Workload-Identity-Federation) (if running outside Google Cloud) so that service account keys are not necessary.
|
||||
|
||||
If you try to create a project and get an error saying that Constraint `constraints/iam.disableServiceAccountKeyUpload violated for service account projects/gam-project-xxxxx`,
|
||||
perform these steps and then you should be able to authorize and use your project.
|
||||
|
||||
@@ -331,7 +326,7 @@ Use an existing project to create and download two files: `client_secrets.json`
|
||||
Use an existing uninitialized/uncredentialed project and configure it to be a GAM project; this typically used when
|
||||
the GCP administrators have created a basic project because project creation is not available for most users.
|
||||
|
||||
See Jay's notes about how to do this: https://github.com/GAM-team/GAM/wiki/GAM-with--minimal-GCP-rights
|
||||
See Jay's notes about how to do this: https://github.com/GAM-team/GAM/wiki/GAM-with-minimal-GCP-rights
|
||||
|
||||
```
|
||||
gam use project [<EmailAddress>] [project <ProjectID>]
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
banana|basil|blueberry|flamingo|graphite|grape|
|
||||
lavender|peacock|sage|tangerine|tomato
|
||||
<FileFormat> ::=
|
||||
csv|doc|dot|docx|dotx|epub|html|jpeg|jpg|mht|odp|ods|odt|
|
||||
csv|doc|dot|docx|dotx|epub|html|jpeg|jpg|json|mht|odp|ods|odt|
|
||||
pdf|png|ppt|pot|potx|pptx|rtf|svg|tsv|txt|xls|xlt|xlsx|xltx|zip|
|
||||
ms|microsoft|openoffice|
|
||||
<LabelColorHex> ::=
|
||||
@@ -278,10 +278,15 @@
|
||||
domain:<DomainName>|domain|default
|
||||
<CalendarItem> ::= <EmailAddress>
|
||||
<ChannelCustomerID> ::= <String>
|
||||
<ChatEmojiName> ::= :[0-9a-z_-]+:
|
||||
<ChatEmoji> ::= emojiname <ChatEmojiName> | customemojis/<String>
|
||||
<ChatMember> ::= spaces/<String>/members/<String>
|
||||
<ChatMessage> ::= spaces/<String>/messages/<String>
|
||||
<ChatSpace> ::= spaces/<String> | space <String> | space spaces/<String>
|
||||
<ChatThread> ::= spaces/<String>/threads/<String>
|
||||
<ChromeProfilePermanentID> ::= <String>
|
||||
<ChromeProfileName> ::= customers/<CustomerID>/profiles/<ChromeProfilePermanentID> | <ChromeProfilePermanentID>
|
||||
<ChromeProfileCommandName> ::= <ChomeProfileName>/commands/<String>
|
||||
<GIGroupAlias> ::= <EmailAddress>
|
||||
<GIGroupItem> ::= <EmailAddress>|<UniqueID>|groups/<String>
|
||||
<CIGroupMemberType> ::= cbcmbrowser|chromeosdevice|customer|group|other|serviceaccount|user
|
||||
@@ -300,6 +305,11 @@
|
||||
<ContactGroupItem> ::= <ContactGroupID>|<ContactGroupName>
|
||||
<CorporaAttribute> ::= alldrives|allteamdrives|domain|onlyteamdrives|user
|
||||
<CourseAlias> ::= <String>
|
||||
<CourseAnnouncementContent> ::=
|
||||
((text <String>)|
|
||||
(textfile <FileName> [charset <Charset>])|
|
||||
(gdoc <UserGoogleDoc>)|
|
||||
(gcsdoc <StorageBucketObjectName>))
|
||||
<CourseAnnouncementID> ::= <Number>
|
||||
<CourseAnnouncementState> ::= draft|published|deleted
|
||||
<CourseID> ::= <Number>|d:<CourseAlias>
|
||||
@@ -315,6 +325,8 @@
|
||||
<CourseWorkState> ::= draft|published|deleted
|
||||
<CrOSID> ::= <String>
|
||||
<CustomerID> ::= <String>
|
||||
<DateTimeFormat> ::= <String>
|
||||
See: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes
|
||||
<DeliverySetting> ::=
|
||||
allmail|
|
||||
abridged|daily|
|
||||
@@ -426,6 +438,7 @@
|
||||
Must match this Python Regular Expression: [a-zA-Z0-9 '"!-]{4,30}
|
||||
<PropertyKey> ::= <String>
|
||||
<PropertyValue> ::= <String>
|
||||
<PubSubTopicName> ::= <String>
|
||||
<QueryAlert> ::= <String>
|
||||
See: https://developers.google.com/admin-sdk/alertcenter/guides/query-filters
|
||||
<QueryBrowser> ::= <String>
|
||||
@@ -449,6 +462,7 @@
|
||||
See: https://support.google.com/mail/answer/7190
|
||||
<QueryGroup> ::= <String>
|
||||
See: https://developers.google.com/admin-sdk/directory/v1/guides/search-groups
|
||||
<QueryItem> ::= <UniqueID>|<String>
|
||||
<QueryMemberRestrictions> ::= <String>
|
||||
See: https://cloud.google.com/identity/docs/reference/rest/v1beta1/SecuritySettings#MemberRestriction
|
||||
<QueryMobile> ::= <String>
|
||||
@@ -492,6 +506,7 @@
|
||||
<SiteItem> ::= [<DomainName>/]<SiteName>
|
||||
<S/MIMEID> ::= <String>
|
||||
<SMTPHostName> ::= <String>
|
||||
<StudentGroupID> ::= <Number>
|
||||
<StudentItem> ::= <EmailAddress>|<UniqueID>|<String>
|
||||
<SharedDriveACLRole> ::=
|
||||
commenter|
|
||||
@@ -509,6 +524,14 @@
|
||||
gs://<StorageBucketName>/<StorageObjectName>|
|
||||
<StorageBucketName>/<StorageObjectName>
|
||||
<Tag> ::= <String>
|
||||
<TagManagerAccountID> ::= <String>
|
||||
<TagManagerAccountPath> ::= accounts/<TagManagerAccountID>
|
||||
<TagManagerContainerID> ::= <String>
|
||||
<TagManagerContainerPath> ::= accounts/<TagManagerAccountID>/containers/<TagManagerContainerID>
|
||||
<TagManagerWorkspaceID> ::= <String>
|
||||
<TagManagerWorkspacePath> ::= accounts/<TagManagerAccountID>/containers/<TagManagerContainerID>/workspaces/<TagManagerWorkspaceID>
|
||||
<TagManagerTagID> ::= <String>
|
||||
<TagManagerTagPath> ::= accounts/<TagManagerAccountID>/containers/<TagManagerContainerID>/workspaces/<TagManagerWorkspaceID>/tags/<TagManagerTagID>
|
||||
<TakeoutBucketName> ::= takeout-export-[a-f,0-9,-]*
|
||||
<TaskID> ::= <String>
|
||||
<TaskListID> ::= <String>
|
||||
|
||||
@@ -18,6 +18,9 @@ The variables `num_threads`, `num_tbatch_threads` and `auto_batch_min` in `gam.c
|
||||
* [Command data from Google Docs/Sheets/Storage](Command-Data-From-Google-Docs-Sheets-Storage)
|
||||
`gdoc <UserGoogleDoc>` and `gsheet <UserGoogleSheet>`
|
||||
|
||||
<DateTimeFormat> ::= <String>
|
||||
See: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes
|
||||
|
||||
## Batch files
|
||||
There are two types of batch processing, one that uses processes and one that uses threads. Using processes is higher performance but `gam csv` commands are not supported.
|
||||
* `gam batch` - gam commands are run as processes, gam csv commands are not allowed in the batch file
|
||||
@@ -45,6 +48,9 @@ Batch files can contain the following types of lines:
|
||||
* sleep \<Integer\> - Batch processing will suspend for \<Integer\> seconds before the next command line is processed
|
||||
* To be effective, this should immediately follow commit-batch
|
||||
* print \<String\> - Print \<String\> on stderr
|
||||
* datetime \<DateTimeFormat\>
|
||||
* The current time is formatted with \<DateTimeFormat\> and subsequent lines will have `%datetime%` replaced with the formatted time value.
|
||||
* See: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes
|
||||
* set \<KeywordString\> \<ValueString\>
|
||||
* Subsequent lines will have %\<KeywordString\>% replaced with \<ValueString\>
|
||||
* clear \<KeywordString\>
|
||||
|
||||
36
wiki/Business-Account-Management.md
Normal file
36
wiki/Business-Account-Management.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Users - Business Account Management
|
||||
- [API documentation](#api-documentation)
|
||||
- [Introduction](#introduction)
|
||||
- [Definitions](#definitions)
|
||||
- [Display Business Profile Accounts](#display-business-profile-accounts)
|
||||
|
||||
## API documentation
|
||||
* [Business Account Management](https://developers.google.com/my-business/reference/accountmanagement/rest)
|
||||
|
||||
|
||||
## Introduction
|
||||
These features were added in version 7.18.00.
|
||||
|
||||
To use these commands you add the 'Business Account Management API' to your project and update client authorization.
|
||||
```
|
||||
gam update project
|
||||
gam oauth create
|
||||
...
|
||||
[*] 0) Business Account Management API
|
||||
|
||||
```
|
||||
## Definitions
|
||||
* [`<UserTypeEntity>`](Collections-of-Users)
|
||||
|
||||
## Display Business Profile Accounts
|
||||
```
|
||||
gam <UserItem> show businessprofileaccounts
|
||||
[type locationgroup|organization|personal|usergroup]
|
||||
```
|
||||
Gam displays the information as an indented list of keys and values.
|
||||
|
||||
```
|
||||
gam <UserItem> print businessprofileaccounts [todrive <ToDriveAttribute>*]
|
||||
[type locationgroup|organization|personal|usergroup]
|
||||
```
|
||||
Gam displays the information as columns of fields.
|
||||
@@ -1,4 +1,4 @@
|
||||
# Chat Bot
|
||||
# Chat Bot Setup and Use
|
||||
- [Introduction](#introduction)
|
||||
- [Set up a Chat Bot](#set-up-a-chat-bot)
|
||||
- [API documentation](#api-documentation)
|
||||
@@ -40,6 +40,7 @@ GAM is capable of acting as a Chat Bot and sending messages to Chat Rooms or dir
|
||||
Even if you're not going to use GAM as a Chat Bot, you have to configure a Chat Bot as it is required by the Chat API in [Users - Chat](Users-Chat).
|
||||
|
||||
* Run the command `gam setup chat`; it will point you to a URL to configure your Chat Bot.
|
||||
* Uncheck "Build this Chat app as a Workspace add-on."
|
||||
* Enter an App name and Description of your choosing.
|
||||
* For the Avatar URL you can use `https://dummyimage.com/384x256/4d4d4d/0011ff.png&text=+GAM` or a public URL to an image of your own choosing.
|
||||
* In Functionality, uncheck both "Receive 1:1 messages" and "Join spaces and group conversations"
|
||||
@@ -239,6 +239,10 @@ bookmarks.json
|
||||
|
||||
gam update chromepolicy chrome.users.ManagedBookmarksSetting json file bookmarks.json orgunit "/Students/
|
||||
```
|
||||
Allowlist the Google Translate extension for the Students OrgUnit
|
||||
```
|
||||
gam update chromepolicy chrome.users.apps.InstallType appInstallType ALLOWED app_id chrome:aapbdbdomjkkjkaonfhkkikfgjllcleb ou "/Students"
|
||||
```
|
||||
|
||||
## Delete Chrome policy
|
||||
You can delete a policy for all devices/users within an OU, users with a group or for a specific printer or application within an OU.
|
||||
@@ -603,8 +607,7 @@ chrome.devices.DeviceAllowEnterpriseRemoteAccessConnections: Enterprise remote a
|
||||
false: Prevent remote access connections from enterprise admins.
|
||||
|
||||
chrome.devices.DeviceAuthenticationFlowAutoReloadInterval: Automatic online sign-in / lock screen refresh.
|
||||
deviceAuthenticationFlowAutoReloadInterval
|
||||
duration: TYPE_INT64
|
||||
deviceAuthenticationFlowAutoReloadInterval: TYPE_INT64
|
||||
|
||||
chrome.devices.DeviceAuthenticationUrlAllowlist: Blocked URL exceptions on the sign-in / lock screens.
|
||||
deviceAuthenticationUrlAllowlist: TYPE_LIST
|
||||
@@ -846,10 +849,8 @@ chrome.devices.DeviceScreensaverLoginScreenEnabled: Screen saver.
|
||||
false: Don't display screen saver when idle.
|
||||
deviceScreensaverLoginScreenImages: TYPE_LIST
|
||||
Screen saver image URLs. Enter one URL per line. Images must be in JPG format(.jpg or .jpeg files.
|
||||
deviceScreensaverLoginScreenIdleTimeoutSeconds
|
||||
duration: TYPE_INT64
|
||||
deviceScreensaverLoginScreenImageDisplayIntervalSeconds
|
||||
duration: TYPE_INT64
|
||||
deviceScreensaverLoginScreenIdleTimeoutSeconds: TYPE_INT64
|
||||
deviceScreensaverLoginScreenImageDisplayIntervalSeconds: TYPE_INT64
|
||||
|
||||
chrome.devices.DeviceScreenSettings: Screen settings.
|
||||
allowUserDisplayChanges: TYPE_BOOL
|
||||
@@ -1042,16 +1043,13 @@ chrome.devices.EnableReportDeviceUsers: Report device user tracking.
|
||||
false: Disable tracking recent users.
|
||||
|
||||
chrome.devices.EnableReportUploadFrequency: Device status report upload frequency.
|
||||
reportDeviceUploadFrequency
|
||||
duration: TYPE_STRING
|
||||
reportDeviceUploadFrequency: TYPE_INT64
|
||||
|
||||
chrome.devices.EnableReportUploadFrequencyV2: Device status report upload frequency.
|
||||
reportDeviceUploadFrequency
|
||||
duration: TYPE_INT64
|
||||
reportDeviceUploadFrequency: TYPE_INT64
|
||||
|
||||
chrome.devices.ExtensionCacheSize: Apps and extensions cache size.
|
||||
extensionCacheSize
|
||||
value: TYPE_INT64
|
||||
extensionCacheSize: TYPE_INT64
|
||||
|
||||
chrome.devices.ForcedReenrollment: Forced re-enrollment.
|
||||
reenrollmentMode: TYPE_ENUM
|
||||
@@ -1101,34 +1099,26 @@ chrome.devices.kiosk.AccessibilityShortcutsEnabled: Kiosk accessibility shortcut
|
||||
ACCESSIBILITY_ENABLED: Enable accessibility shortcuts.
|
||||
|
||||
chrome.devices.kiosk.AcPowerSettings: AC Kiosk power settings.
|
||||
acIdleTimeout
|
||||
duration: TYPE_STRING
|
||||
acWarningTimeout
|
||||
duration: TYPE_STRING
|
||||
acIdleTimeout: TYPE_INT64
|
||||
acWarningTimeout: TYPE_INT64
|
||||
acIdleAction: TYPE_ENUM
|
||||
IDLE_ACTION_SUSPEND: Sleep.
|
||||
IDLE_ACTION_LOGOUT: Logout.
|
||||
IDLE_ACTION_SHUTDOWN: Shutdown.
|
||||
IDLE_ACTION_DO_NOTHING: Do nothing.
|
||||
acDimTimeout
|
||||
duration: TYPE_STRING
|
||||
acScreenOffTimeout
|
||||
duration: TYPE_STRING
|
||||
acDimTimeout: TYPE_INT64
|
||||
acScreenOffTimeout: TYPE_INT64
|
||||
|
||||
chrome.devices.kiosk.AcPowerSettingsV2: AC Kiosk power settings.
|
||||
acIdleTimeout
|
||||
duration: TYPE_INT64
|
||||
acWarningTimeout
|
||||
duration: TYPE_INT64
|
||||
acIdleTimeout: TYPE_INT64
|
||||
acWarningTimeout: TYPE_INT64
|
||||
acIdleAction: TYPE_ENUM
|
||||
IDLE_ACTION_SUSPEND: Sleep.
|
||||
IDLE_ACTION_LOGOUT: Logout.
|
||||
IDLE_ACTION_SHUTDOWN: Shutdown.
|
||||
IDLE_ACTION_DO_NOTHING: Do nothing.
|
||||
acDimTimeout
|
||||
duration: TYPE_INT64
|
||||
acScreenOffTimeout
|
||||
duration: TYPE_INT64
|
||||
acDimTimeout: TYPE_INT64
|
||||
acScreenOffTimeout: TYPE_INT64
|
||||
|
||||
chrome.devices.kiosk.Alerting: Kiosk device status alerting delivery.
|
||||
deviceStatusAlertDeliveryModes: TYPE_LIST
|
||||
@@ -1217,34 +1207,26 @@ chrome.devices.kiosk.AutoclickEnabled: Kiosk auto-click enabled.
|
||||
ACCESSIBILITY_ENABLED: Enable auto-click.
|
||||
|
||||
chrome.devices.kiosk.BatteryPowerSettings: Battery Kiosk power settings.
|
||||
batteryIdleTimeout
|
||||
duration: TYPE_STRING
|
||||
batteryWarningTimeout
|
||||
duration: TYPE_STRING
|
||||
batteryIdleTimeout: TYPE_INT64
|
||||
batteryWarningTimeout: TYPE_INT64
|
||||
batteryIdleAction: TYPE_ENUM
|
||||
IDLE_ACTION_SUSPEND: Sleep.
|
||||
IDLE_ACTION_LOGOUT: Logout.
|
||||
IDLE_ACTION_SHUTDOWN: Shutdown.
|
||||
IDLE_ACTION_DO_NOTHING: Do nothing.
|
||||
batteryDimTimeout
|
||||
duration: TYPE_STRING
|
||||
batteryScreenOffTimeout
|
||||
duration: TYPE_STRING
|
||||
batteryDimTimeout: TYPE_INT64
|
||||
batteryScreenOffTimeout: TYPE_INT64
|
||||
|
||||
chrome.devices.kiosk.BatteryPowerSettingsV2: Battery Kiosk power settings.
|
||||
batteryIdleTimeout
|
||||
duration: TYPE_INT64
|
||||
batteryWarningTimeout
|
||||
duration: TYPE_INT64
|
||||
batteryIdleTimeout: TYPE_INT64
|
||||
batteryWarningTimeout: TYPE_INT64
|
||||
batteryIdleAction: TYPE_ENUM
|
||||
IDLE_ACTION_SUSPEND: Sleep.
|
||||
IDLE_ACTION_LOGOUT: Logout.
|
||||
IDLE_ACTION_SHUTDOWN: Shutdown.
|
||||
IDLE_ACTION_DO_NOTHING: Do nothing.
|
||||
batteryDimTimeout
|
||||
duration: TYPE_INT64
|
||||
batteryScreenOffTimeout
|
||||
duration: TYPE_INT64
|
||||
batteryDimTimeout: TYPE_INT64
|
||||
batteryScreenOffTimeout: TYPE_INT64
|
||||
|
||||
chrome.devices.kiosk.CaretHighlightEnabled: Kiosk caret highlight.
|
||||
caretHighlightEnabled: TYPE_ENUM
|
||||
@@ -2481,40 +2463,24 @@ chrome.devices.managedguest.BrowserHistory: Browser history.
|
||||
false: Always save browser history.
|
||||
|
||||
chrome.devices.managedguest.BrowsingDataLifetime: Browsing Data Lifetime.
|
||||
browsingHistoryTtl
|
||||
duration: TYPE_STRING
|
||||
downloadHistoryTtl
|
||||
duration: TYPE_STRING
|
||||
cookiesAndOtherSiteDataTtl
|
||||
duration: TYPE_STRING
|
||||
cachedImagesAndFilesTtl
|
||||
duration: TYPE_STRING
|
||||
passwordSigninTtl
|
||||
duration: TYPE_STRING
|
||||
autofillTtl
|
||||
duration: TYPE_STRING
|
||||
siteSettingsTtl
|
||||
duration: TYPE_STRING
|
||||
hostedAppDataTtl
|
||||
duration: TYPE_STRING
|
||||
browsingHistoryTtl: TYPE_INT64
|
||||
downloadHistoryTtl: TYPE_INT64
|
||||
cookiesAndOtherSiteDataTtl: TYPE_INT64
|
||||
cachedImagesAndFilesTtl: TYPE_INT64
|
||||
passwordSigninTtl: TYPE_INT64
|
||||
autofillTtl: TYPE_INT64
|
||||
siteSettingsTtl: TYPE_INT64
|
||||
hostedAppDataTtl: TYPE_INT64
|
||||
|
||||
chrome.devices.managedguest.BrowsingDataLifetimeV2: Browsing Data Lifetime.
|
||||
browsingHistoryTtl
|
||||
duration: TYPE_INT64
|
||||
downloadHistoryTtl
|
||||
duration: TYPE_INT64
|
||||
cookiesAndOtherSiteDataTtl
|
||||
duration: TYPE_INT64
|
||||
cachedImagesAndFilesTtl
|
||||
duration: TYPE_INT64
|
||||
passwordSigninTtl
|
||||
duration: TYPE_INT64
|
||||
autofillTtl
|
||||
duration: TYPE_INT64
|
||||
siteSettingsTtl
|
||||
duration: TYPE_INT64
|
||||
hostedAppDataTtl
|
||||
duration: TYPE_INT64
|
||||
browsingHistoryTtl: TYPE_INT64
|
||||
downloadHistoryTtl: TYPE_INT64
|
||||
cookiesAndOtherSiteDataTtl: TYPE_INT64
|
||||
cachedImagesAndFilesTtl: TYPE_INT64
|
||||
passwordSigninTtl: TYPE_INT64
|
||||
autofillTtl: TYPE_INT64
|
||||
siteSettingsTtl: TYPE_INT64
|
||||
hostedAppDataTtl: TYPE_INT64
|
||||
|
||||
chrome.devices.managedguest.BuiltInDnsClientEnabled: Built-in DNS client.
|
||||
builtInDnsClientEnabled: TYPE_ENUM
|
||||
@@ -3009,36 +2975,26 @@ chrome.devices.managedguest.IdleSettingsExtended: Idle settings.
|
||||
LOGOUT: Logout.
|
||||
SHUTDOWN: Shutdown.
|
||||
DO_NOTHING: Do nothing.
|
||||
idleDelayAc
|
||||
duration: TYPE_INT64
|
||||
idleWarningDelayAc
|
||||
duration: TYPE_INT64
|
||||
idleDelayAc: TYPE_INT64
|
||||
idleWarningDelayAc: TYPE_INT64
|
||||
idleActionAc: TYPE_ENUM
|
||||
SLEEP: Sleep.
|
||||
LOGOUT: Logout.
|
||||
SHUTDOWN: Shut down.
|
||||
DO_NOTHING: Do nothing.
|
||||
screenDimDelayAc
|
||||
duration: TYPE_INT64
|
||||
screenOffDelayAc
|
||||
duration: TYPE_INT64
|
||||
screenLockDelayAc
|
||||
duration: TYPE_INT64
|
||||
idleDelayBattery
|
||||
duration: TYPE_INT64
|
||||
idleWarningDelayBattery
|
||||
duration: TYPE_INT64
|
||||
screenDimDelayAc: TYPE_INT64
|
||||
screenOffDelayAc: TYPE_INT64
|
||||
screenLockDelayAc: TYPE_INT64
|
||||
idleDelayBattery: TYPE_INT64
|
||||
idleWarningDelayBattery: TYPE_INT64
|
||||
idleActionBattery: TYPE_ENUM
|
||||
SLEEP: Sleep.
|
||||
LOGOUT: Logout.
|
||||
SHUTDOWN: Shut down.
|
||||
DO_NOTHING: Do nothing.
|
||||
screenDimDelayBattery
|
||||
duration: TYPE_INT64
|
||||
screenOffDelayBattery
|
||||
duration: TYPE_INT64
|
||||
screenLockDelayBattery
|
||||
duration: TYPE_INT64
|
||||
screenDimDelayBattery: TYPE_INT64
|
||||
screenOffDelayBattery: TYPE_INT64
|
||||
screenLockDelayBattery: TYPE_INT64
|
||||
lockOnSleepOrLidClose: TYPE_ENUM
|
||||
UNSET: Allow user to configure.
|
||||
FALSE: Don't lock screen.
|
||||
@@ -3238,12 +3194,10 @@ chrome.devices.managedguest.ManagedGuestSessionV2: Managed guest session.
|
||||
ROTATE_270: 270 degrees.
|
||||
|
||||
chrome.devices.managedguest.MaxInvalidationFetchDelay: Policy fetch delay.
|
||||
maxInvalidationFetchDelay
|
||||
duration: TYPE_STRING
|
||||
maxInvalidationFetchDelay: TYPE_INT64
|
||||
|
||||
chrome.devices.managedguest.MaxInvalidationFetchDelayV2: Policy fetch delay.
|
||||
maxInvalidationFetchDelay
|
||||
duration: TYPE_INT64
|
||||
maxInvalidationFetchDelay: TYPE_INT64
|
||||
|
||||
chrome.devices.managedguest.MemorySaverModeSavings: Memory saver.
|
||||
memorySaverModeSavings: TYPE_ENUM
|
||||
@@ -3451,8 +3405,7 @@ chrome.devices.managedguest.PrintingBackgroundGraphicsDefault: Background graphi
|
||||
ENABLED: Enable background graphics printing mode by default.
|
||||
|
||||
chrome.devices.managedguest.PrintingMaxSheetsAllowed: Maximum sheets.
|
||||
printingMaxSheetsAllowedNullable
|
||||
value: TYPE_INT64
|
||||
printingMaxSheetsAllowedNullable: TYPE_INT64
|
||||
|
||||
chrome.devices.managedguest.PrintingPaperSizeDefault: Default printing page size.
|
||||
printingPaperSizeEnum: TYPE_ENUM
|
||||
@@ -3474,19 +3427,16 @@ chrome.devices.managedguest.PrintingPinDefault: Default PIN printing mode.
|
||||
DEFAULT_TO_NOT_PIN_PRINTING: Without PIN.
|
||||
|
||||
chrome.devices.managedguest.PrintJobHistoryExpirationPeriodNew: Print job history retention period.
|
||||
printJobHistoryExpirationPeriodDaysNew
|
||||
duration: TYPE_STRING
|
||||
printJobHistoryExpirationPeriodDaysNew: TYPE_INT64
|
||||
|
||||
chrome.devices.managedguest.PrintJobHistoryExpirationPeriodNewV2: Print job history retention period.
|
||||
printJobHistoryExpirationPeriodDaysNew
|
||||
duration: TYPE_INT64
|
||||
printJobHistoryExpirationPeriodDaysNew: TYPE_INT64
|
||||
|
||||
chrome.devices.managedguest.PrintPdfAsImage: Print PDF as image.
|
||||
printPdfAsImageAvailability: TYPE_BOOL
|
||||
true: Allow users to print PDF documents as images.
|
||||
false: Do not allow users to print PDF documents as images.
|
||||
printRasterizePdfDpi
|
||||
value: TYPE_INT64
|
||||
printRasterizePdfDpi: TYPE_INT64
|
||||
printPdfAsImageDefault: TYPE_BOOL
|
||||
true: Default to printing PDFs as images when available.
|
||||
false: Default to printing PDFs without being rasterized.
|
||||
@@ -3547,8 +3497,7 @@ chrome.devices.managedguest.RemoteAccessHostClientDomainList: Remote access clie
|
||||
Remote access client domain. Configure the required domain names for remote access clients.
|
||||
|
||||
chrome.devices.managedguest.RemoteAccessHostClipboardSizeBytes: Clipboard sync max size.
|
||||
remoteAccessHostClipboardSizeBytes
|
||||
value: TYPE_INT64
|
||||
remoteAccessHostClipboardSizeBytes: TYPE_INT64
|
||||
|
||||
chrome.devices.managedguest.RemoteAccessHostDomainList: Remote access hosts.
|
||||
remoteAccessHostDomainList: TYPE_LIST
|
||||
@@ -3658,10 +3607,8 @@ chrome.devices.managedguest.ScreensaverLockScreenEnabled: Screen saver.
|
||||
screensaverLockScreenEnabled: TYPE_BOOL
|
||||
true: Display screen saver on lock screen when idle.
|
||||
false: Don't display screen saver on lock screen when idle.
|
||||
screensaverLockScreenIdleTimeoutSeconds
|
||||
duration: TYPE_INT64
|
||||
screensaverLockScreenImageDisplayIntervalSeconds
|
||||
duration: TYPE_INT64
|
||||
screensaverLockScreenIdleTimeoutSeconds: TYPE_INT64
|
||||
screensaverLockScreenImageDisplayIntervalSeconds: TYPE_INT64
|
||||
screensaverLockScreenImages: TYPE_LIST
|
||||
Screen saver image URLs. Enter one URL per line. Images must be in JPG format(.jpg or .jpeg files.
|
||||
|
||||
@@ -3689,16 +3636,14 @@ chrome.devices.managedguest.SecurityTokenSessionSettings: Security token removal
|
||||
IGNORE: Nothing.
|
||||
LOGOUT: Log the user out.
|
||||
LOCK: Lock the current session.
|
||||
securityTokenSessionNotificationSeconds
|
||||
duration: TYPE_STRING
|
||||
securityTokenSessionNotificationSeconds: TYPE_INT64
|
||||
|
||||
chrome.devices.managedguest.SecurityTokenSessionSettingsV2: Security token removal.
|
||||
securityTokenSessionBehavior: TYPE_ENUM
|
||||
IGNORE: Nothing.
|
||||
LOGOUT: Log the user out.
|
||||
LOCK: Lock the current session.
|
||||
securityTokenSessionNotificationSeconds
|
||||
duration: TYPE_INT64
|
||||
securityTokenSessionNotificationSeconds: TYPE_INT64
|
||||
|
||||
chrome.devices.managedguest.SelectToSpeakEnabled: Select to speak.
|
||||
selectToSpeakEnabled: TYPE_ENUM
|
||||
@@ -3723,12 +3668,10 @@ chrome.devices.managedguest.ServiceWorkerToControlSrcdocIframeEnabled: Service w
|
||||
false: Block service workers from controlling srcdoc iframes.
|
||||
|
||||
chrome.devices.managedguest.SessionLength: Maximum user session length.
|
||||
sessionDurationLimit
|
||||
duration: TYPE_STRING
|
||||
sessionDurationLimit: TYPE_INT64
|
||||
|
||||
chrome.devices.managedguest.SessionLengthV2: Maximum user session length.
|
||||
sessionDurationLimit
|
||||
duration: TYPE_INT64
|
||||
sessionDurationLimit: TYPE_INT64
|
||||
|
||||
chrome.devices.managedguest.SessionLocale: Session locale.
|
||||
sessionLocalesRepeatedString: TYPE_LIST
|
||||
@@ -4327,6 +4270,13 @@ chrome.devices.MobileDataRoaming: Mobile data roaming.
|
||||
true: Allow mobile data roaming.
|
||||
false: Do not allow mobile data roaming.
|
||||
|
||||
chrome.devices.PartnerAccess: Allow EMM partners access to device management.
|
||||
chromeDeviceManagementApiEnabled: TYPE_BOOL
|
||||
true: Enable Chrome management - partner access.
|
||||
false: Disable Chrome management - partner access.
|
||||
ackNoticeForChromeDeviceManagementApiEnabledSetToTrue: TYPE_BOOL
|
||||
This field must be set to true to acknowledge the notice message associated with the field 'chrome_device_management_api_enabled' set to value 'true'. Please sse the notices listed with this policy for more information.
|
||||
|
||||
chrome.devices.PowerManagement: Power management.
|
||||
loginScreenPowerManagement: TYPE_BOOL
|
||||
true: Allow device to sleep/shut down when idle on the sign-in screen.
|
||||
@@ -4361,12 +4311,10 @@ chrome.devices.RestrictedManagedGuestSessionExtensionCleanupExemptList: Shared a
|
||||
Extension IDs. Enter a list of extension IDs. Each extension ID must be exactly 32 characters.
|
||||
|
||||
chrome.devices.ScheduledRebootDuration: Reboot after uptime limit.
|
||||
uptimeLimitDuration
|
||||
duration: TYPE_STRING
|
||||
uptimeLimitDuration: TYPE_INT64
|
||||
|
||||
chrome.devices.ScheduledRebootDurationV2: Reboot after uptime limit.
|
||||
uptimeLimitDuration
|
||||
duration: TYPE_INT64
|
||||
uptimeLimitDuration: TYPE_INT64
|
||||
|
||||
chrome.devices.ShowLowDiskSpaceNotification: Low disk space notification.
|
||||
showLowDiskSpaceNotification: TYPE_BOOL
|
||||
@@ -4519,8 +4467,7 @@ chrome.devices.ThrottleDeviceBandwidth: Throttle device bandwidth.
|
||||
Upload rate (kbits). Sets the maximum upload rate if network bandwidth throttling is enabled on a ChromeOS device.
|
||||
|
||||
chrome.devices.Timezone: Timezone.
|
||||
systemTimezone
|
||||
value: TYPE_STRING
|
||||
systemTimezone: TYPE_STRING
|
||||
timezoneDetectionType: TYPE_ENUM
|
||||
USERS_DECIDE: Let users decide.
|
||||
DISABLED: Never auto-detect timezone.
|
||||
@@ -6043,6 +5990,9 @@ chrome.users.appsconfig.AllowedAppTypes: Allowed types of apps and extensions.
|
||||
platform_app: Chrome packaged app.
|
||||
|
||||
chrome.users.appsconfig.AllowedInstallSources: Allows setting of the allowed install sources for apps. Note these must be set together.
|
||||
playStoreInstallSources: TYPE_ENUM
|
||||
ALLOW_ALL_APPS: All apps allowed, admin manages blocklist.
|
||||
BLOCK_ALL_APPS: All apps blocked, admin manages allowlist.
|
||||
chromeWebStoreInstallSources: TYPE_ENUM
|
||||
ALLOW_ALL_APPS: All apps allowed, admin manages blocklist.
|
||||
BLOCK_ALL_APPS: All apps blocked, admin manages allowlist.
|
||||
@@ -6518,12 +6468,10 @@ chrome.users.AutoplayAllowlist: Autoplay video.
|
||||
Allowed URLs. URL patterns allowed to autoplay. Prefix domain with [*.] to include all subdomains. Use * to allow all domains.
|
||||
|
||||
chrome.users.AutoUpdateCheckPeriodNew: Auto-update check period.
|
||||
autoUpdateCheckPeriodMinutesNew
|
||||
duration: TYPE_STRING
|
||||
autoUpdateCheckPeriodMinutesNew: TYPE_INT64
|
||||
|
||||
chrome.users.AutoUpdateCheckPeriodNewV2: Auto-update check period.
|
||||
autoUpdateCheckPeriodMinutesNew
|
||||
duration: TYPE_INT64
|
||||
autoUpdateCheckPeriodMinutesNew: TYPE_INT64
|
||||
|
||||
chrome.users.Avatar: Custom avatar.
|
||||
userAvatarImage
|
||||
@@ -6608,8 +6556,7 @@ chrome.users.BrowserHistory: Browser history.
|
||||
false: Always save browser history.
|
||||
|
||||
chrome.users.BrowserIdleTimeout: Browser idle timeout.
|
||||
idleTimeout
|
||||
duration: TYPE_INT64
|
||||
idleTimeout: TYPE_INT64
|
||||
idleTimeoutActions: TYPE_LIST
|
||||
close_browsers: Close Browsers.
|
||||
show_profile_picker: Show Profile Picker.
|
||||
@@ -6658,12 +6605,10 @@ chrome.users.BrowserSwitcherChromePath: Chrome path.
|
||||
Path to the Chrome executable. Windows-only. Path to the Chrome executable to launch when switching from the alternative browser to Chrome. If unset, the alternative browser will auto-detect the path to Chrome.
|
||||
|
||||
chrome.users.BrowserSwitcherDelayDuration: Delay before launching alternative browser.
|
||||
browserSwitcherDelayDuration
|
||||
duration: TYPE_STRING
|
||||
browserSwitcherDelayDuration: TYPE_INT64
|
||||
|
||||
chrome.users.BrowserSwitcherDelayDurationV2: Delay before launching alternative browser.
|
||||
browserSwitcherDelayDuration
|
||||
duration: TYPE_INT64
|
||||
browserSwitcherDelayDuration: TYPE_INT64
|
||||
|
||||
chrome.users.BrowserSwitcherExternalGreylistUrl: URL to list of websites to open in either browser.
|
||||
browserSwitcherExternalGreylistUrl: TYPE_STRING
|
||||
@@ -6701,40 +6646,24 @@ chrome.users.BrowserThemeColor: Custom theme color.
|
||||
Hex color. Enter a valid hex color, for instance #FFFFFF.
|
||||
|
||||
chrome.users.BrowsingDataLifetime: Browsing Data Lifetime.
|
||||
browsingHistoryTtl
|
||||
duration: TYPE_STRING
|
||||
downloadHistoryTtl
|
||||
duration: TYPE_STRING
|
||||
cookiesAndOtherSiteDataTtl
|
||||
duration: TYPE_STRING
|
||||
cachedImagesAndFilesTtl
|
||||
duration: TYPE_STRING
|
||||
passwordSigninTtl
|
||||
duration: TYPE_STRING
|
||||
autofillTtl
|
||||
duration: TYPE_STRING
|
||||
siteSettingsTtl
|
||||
duration: TYPE_STRING
|
||||
hostedAppDataTtl
|
||||
duration: TYPE_STRING
|
||||
browsingHistoryTtl: TYPE_INT64
|
||||
downloadHistoryTtl: TYPE_INT64
|
||||
cookiesAndOtherSiteDataTtl: TYPE_INT64
|
||||
cachedImagesAndFilesTtl: TYPE_INT64
|
||||
passwordSigninTtl: TYPE_INT64
|
||||
autofillTtl: TYPE_INT64
|
||||
siteSettingsTtl: TYPE_INT64
|
||||
hostedAppDataTtl: TYPE_INT64
|
||||
|
||||
chrome.users.BrowsingDataLifetimeV2: Browsing Data Lifetime.
|
||||
browsingHistoryTtl
|
||||
duration: TYPE_INT64
|
||||
downloadHistoryTtl
|
||||
duration: TYPE_INT64
|
||||
cookiesAndOtherSiteDataTtl
|
||||
duration: TYPE_INT64
|
||||
cachedImagesAndFilesTtl
|
||||
duration: TYPE_INT64
|
||||
passwordSigninTtl
|
||||
duration: TYPE_INT64
|
||||
autofillTtl
|
||||
duration: TYPE_INT64
|
||||
siteSettingsTtl
|
||||
duration: TYPE_INT64
|
||||
hostedAppDataTtl
|
||||
duration: TYPE_INT64
|
||||
browsingHistoryTtl: TYPE_INT64
|
||||
downloadHistoryTtl: TYPE_INT64
|
||||
cookiesAndOtherSiteDataTtl: TYPE_INT64
|
||||
cachedImagesAndFilesTtl: TYPE_INT64
|
||||
passwordSigninTtl: TYPE_INT64
|
||||
autofillTtl: TYPE_INT64
|
||||
siteSettingsTtl: TYPE_INT64
|
||||
hostedAppDataTtl: TYPE_INT64
|
||||
|
||||
chrome.users.BuiltInDnsClientEnabled: Built-in DNS client.
|
||||
builtInDnsClientEnabled: TYPE_ENUM
|
||||
@@ -6890,12 +6819,10 @@ chrome.users.CloudReporting: Managed browser reporting.
|
||||
false: Disable managed browser cloud reporting.
|
||||
|
||||
chrome.users.CloudReportingUploadFrequency: Managed browser reporting upload frequency.
|
||||
cloudReportingUploadFrequency
|
||||
duration: TYPE_STRING
|
||||
cloudReportingUploadFrequency: TYPE_INT64
|
||||
|
||||
chrome.users.CloudReportingUploadFrequencyV2: Managed browser reporting upload frequency.
|
||||
cloudReportingUploadFrequency
|
||||
duration: TYPE_INT64
|
||||
cloudReportingUploadFrequency: TYPE_INT64
|
||||
|
||||
chrome.users.CloudUserPolicyMerge: User cloud policy merge.
|
||||
cloudUserPolicyMerge: TYPE_BOOL
|
||||
@@ -7374,12 +7301,10 @@ chrome.users.FElevenKeyModifier: Control the shortcut used to trigger F11.
|
||||
RECOMMENDED: Allow users to override.
|
||||
|
||||
chrome.users.FetchKeepaliveDurationSecondsOnShutdown: Keepalive duration.
|
||||
fetchKeepaliveDurationSecondsOnShutdown
|
||||
duration: TYPE_STRING
|
||||
fetchKeepaliveDurationSecondsOnShutdown: TYPE_INT64
|
||||
|
||||
chrome.users.FetchKeepaliveDurationSecondsOnShutdownV2: Keepalive duration.
|
||||
fetchKeepaliveDurationSecondsOnShutdown
|
||||
duration: TYPE_INT64
|
||||
fetchKeepaliveDurationSecondsOnShutdown: TYPE_INT64
|
||||
|
||||
chrome.users.FileOrDirectoryPickerWithoutGestureAllowedForOrigins: File/directory picker without user gesture.
|
||||
fileOrDirectoryPickerWithoutGestureAllowedForOrigins: TYPE_LIST
|
||||
@@ -7639,12 +7564,10 @@ chrome.users.FullscreenAllowed: Fullscreen mode.
|
||||
false: Do not allow fullscreen mode.
|
||||
|
||||
chrome.users.GaiaLockScreenOfflineSigninTimeLimitDays: Google online unlock frequency.
|
||||
gaiaLockScreenOfflineSigninTimeLimitDays
|
||||
value: TYPE_INT64
|
||||
gaiaLockScreenOfflineSigninTimeLimitDays: TYPE_INT64
|
||||
|
||||
chrome.users.GaiaOfflineSigninTimeLimitDays: Google online login frequency.
|
||||
gaiaOfflineSigninTimeLimitDays
|
||||
value: TYPE_INT64
|
||||
gaiaOfflineSigninTimeLimitDays: TYPE_INT64
|
||||
|
||||
chrome.users.GeminiSettings: Gemini integration.
|
||||
geminiSettings: TYPE_ENUM
|
||||
@@ -7812,36 +7735,26 @@ chrome.users.IdleSettingsExtended: Idle settings.
|
||||
LOGOUT: Logout.
|
||||
SHUTDOWN: Shutdown.
|
||||
DO_NOTHING: Do nothing.
|
||||
idleDelayAc
|
||||
duration: TYPE_INT64
|
||||
idleWarningDelayAc
|
||||
duration: TYPE_INT64
|
||||
idleDelayAc: TYPE_INT64
|
||||
idleWarningDelayAc: TYPE_INT64
|
||||
idleActionAc: TYPE_ENUM
|
||||
SLEEP: Sleep.
|
||||
LOGOUT: Logout.
|
||||
SHUTDOWN: Shut down.
|
||||
DO_NOTHING: Do nothing.
|
||||
screenDimDelayAc
|
||||
duration: TYPE_INT64
|
||||
screenOffDelayAc
|
||||
duration: TYPE_INT64
|
||||
screenLockDelayAc
|
||||
duration: TYPE_INT64
|
||||
idleDelayBattery
|
||||
duration: TYPE_INT64
|
||||
idleWarningDelayBattery
|
||||
duration: TYPE_INT64
|
||||
screenDimDelayAc: TYPE_INT64
|
||||
screenOffDelayAc: TYPE_INT64
|
||||
screenLockDelayAc: TYPE_INT64
|
||||
idleDelayBattery: TYPE_INT64
|
||||
idleWarningDelayBattery: TYPE_INT64
|
||||
idleActionBattery: TYPE_ENUM
|
||||
SLEEP: Sleep.
|
||||
LOGOUT: Logout.
|
||||
SHUTDOWN: Shut down.
|
||||
DO_NOTHING: Do nothing.
|
||||
screenDimDelayBattery
|
||||
duration: TYPE_INT64
|
||||
screenOffDelayBattery
|
||||
duration: TYPE_INT64
|
||||
screenLockDelayBattery
|
||||
duration: TYPE_INT64
|
||||
screenDimDelayBattery: TYPE_INT64
|
||||
screenOffDelayBattery: TYPE_INT64
|
||||
screenLockDelayBattery: TYPE_INT64
|
||||
lockOnSleepOrLidClose: TYPE_ENUM
|
||||
UNSET: Allow user to configure.
|
||||
FALSE: Don't lock screen.
|
||||
@@ -7956,6 +7869,11 @@ chrome.users.InsertKeyModifier: Control the shortcut used to trigger the Insert
|
||||
MANDATORY: Do not allow users to override.
|
||||
RECOMMENDED: Allow users to override.
|
||||
|
||||
chrome.users.InstantTetheringAllowed: Instant Tethering.
|
||||
instantTetheringAllowed: TYPE_BOOL
|
||||
true: Allow users to use Instant Tethering.
|
||||
false: Do not allow users to use Instant Tethering.
|
||||
|
||||
chrome.users.IntegratedWebAuthenticationAllowed: Login credentials for network authentication.
|
||||
integratedWebAuthenticationAllowed: TYPE_BOOL
|
||||
true: Use login credentials for network authentication to a managed proxy.
|
||||
@@ -8199,12 +8117,10 @@ chrome.users.MaxConnectionsPerProxy: Max connections per proxy.
|
||||
Maximum number of concurrent connections to the proxy server. Specifies the maximal number of simultaneous connections to the proxy server. The value of this policy should be lower than 100 and higher than 6 and the default value is 32.
|
||||
|
||||
chrome.users.MaxInvalidationFetchDelay: Policy fetch delay.
|
||||
maxInvalidationFetchDelay
|
||||
duration: TYPE_STRING
|
||||
maxInvalidationFetchDelay: TYPE_INT64
|
||||
|
||||
chrome.users.MaxInvalidationFetchDelayV2: Policy fetch delay.
|
||||
maxInvalidationFetchDelay
|
||||
duration: TYPE_INT64
|
||||
maxInvalidationFetchDelay: TYPE_INT64
|
||||
|
||||
chrome.users.MediaRecommendationsEnabled: Media Recommendations.
|
||||
mediaRecommendationsEnabled: TYPE_BOOL
|
||||
@@ -8678,8 +8594,7 @@ chrome.users.PrintingLpacSandboxEnabled: Printing LPAC Sandbox.
|
||||
false: Run printing services in a less secure sandbox.
|
||||
|
||||
chrome.users.PrintingMaxSheetsAllowed: Maximum sheets.
|
||||
printingMaxSheetsAllowedNullable
|
||||
value: TYPE_INT64
|
||||
printingMaxSheetsAllowedNullable: TYPE_INT64
|
||||
|
||||
chrome.users.PrintingPaperSizeDefault: Default printing page size.
|
||||
printingPaperSizeEnum: TYPE_ENUM
|
||||
@@ -8706,19 +8621,16 @@ chrome.users.PrintingSendUsernameAndFilenameEnabled: CUPS Print job information.
|
||||
false: Do not include user account and filename in print job.
|
||||
|
||||
chrome.users.PrintJobHistoryExpirationPeriodNew: Print job history retention period.
|
||||
printJobHistoryExpirationPeriodDaysNew
|
||||
duration: TYPE_STRING
|
||||
printJobHistoryExpirationPeriodDaysNew: TYPE_INT64
|
||||
|
||||
chrome.users.PrintJobHistoryExpirationPeriodNewV2: Print job history retention period.
|
||||
printJobHistoryExpirationPeriodDaysNew
|
||||
duration: TYPE_INT64
|
||||
printJobHistoryExpirationPeriodDaysNew: TYPE_INT64
|
||||
|
||||
chrome.users.PrintPdfAsImage: Print PDF as image.
|
||||
printPdfAsImageAvailability: TYPE_BOOL
|
||||
true: Allow users to print PDF documents as images.
|
||||
false: Do not allow users to print PDF documents as images.
|
||||
printRasterizePdfDpi
|
||||
value: TYPE_INT64
|
||||
printRasterizePdfDpi: TYPE_INT64
|
||||
printPdfAsImageDefault: TYPE_BOOL
|
||||
true: Default to printing PDFs as images when available.
|
||||
false: Default to printing PDFs without being rasterized.
|
||||
@@ -8861,36 +8773,30 @@ chrome.users.RelaunchNotificationWithDuration: Relaunch notification.
|
||||
NO_NOTIFICATION: No relaunch notification.
|
||||
RECOMMENDED: Show notification recommending relaunch.
|
||||
REQUIRED: Force relaunch after a period.
|
||||
relaunchNotificationPeriodDuration
|
||||
duration: TYPE_STRING
|
||||
relaunchInitialQuietPeriodDuration
|
||||
duration: TYPE_STRING
|
||||
relaunchNotificationPeriodDuration: TYPE_INT64
|
||||
relaunchInitialQuietPeriodDuration: TYPE_INT64
|
||||
relaunchWindowStartTime
|
||||
timeOfDay
|
||||
hours: TYPE_INT32
|
||||
minutes: TYPE_INT32
|
||||
seconds: TYPE_INT32
|
||||
nanos: TYPE_INT32
|
||||
relaunchWindowDurationMin
|
||||
duration: TYPE_STRING
|
||||
relaunchWindowDurationMin: TYPE_INT64
|
||||
|
||||
chrome.users.RelaunchNotificationWithDurationV2: Relaunch notification.
|
||||
relaunchNotificationEnum: TYPE_ENUM
|
||||
NO_NOTIFICATION: No relaunch notification.
|
||||
RECOMMENDED: Show notification recommending relaunch.
|
||||
REQUIRED: Force relaunch after a period.
|
||||
relaunchNotificationPeriodDuration
|
||||
duration: TYPE_INT64
|
||||
relaunchInitialQuietPeriodDuration
|
||||
duration: TYPE_INT64
|
||||
relaunchNotificationPeriodDuration: TYPE_INT64
|
||||
relaunchInitialQuietPeriodDuration: TYPE_INT64
|
||||
relaunchWindowStartTime
|
||||
timeOfDay
|
||||
hours: TYPE_INT32
|
||||
minutes: TYPE_INT32
|
||||
seconds: TYPE_INT32
|
||||
nanos: TYPE_INT32
|
||||
relaunchWindowDurationMin
|
||||
duration: TYPE_INT64
|
||||
relaunchWindowDurationMin: TYPE_INT64
|
||||
|
||||
chrome.users.RemoteAccessHostAllowEnterpriseRemoteSupportConnections: Enterprise remote support connections.
|
||||
remoteAccessHostAllowEnterpriseRemoteSupportConnections: TYPE_BOOL
|
||||
@@ -8907,8 +8813,7 @@ chrome.users.RemoteAccessHostClientDomainList: Remote access clients.
|
||||
Remote access client domain. Configure the required domain names for remote access clients.
|
||||
|
||||
chrome.users.RemoteAccessHostClipboardSizeBytes: Clipboard sync max size.
|
||||
remoteAccessHostClipboardSizeBytes
|
||||
value: TYPE_INT64
|
||||
remoteAccessHostClipboardSizeBytes: TYPE_INT64
|
||||
|
||||
chrome.users.RemoteAccessHostDomainList: Remote access hosts.
|
||||
remoteAccessHostDomainList: TYPE_LIST
|
||||
@@ -9033,8 +8938,7 @@ chrome.users.SafeSitesFilterBehavior: SafeSites URL filter.
|
||||
SAFE_SITES_FILTER_ENABLED: Filter sites for adult content.
|
||||
|
||||
chrome.users.SamlLockScreenOfflineSigninTimeLimitDays: SAML single sign-on unlock frequency.
|
||||
samlLockScreenOfflineSigninTimeLimitDays
|
||||
value: TYPE_INT64
|
||||
samlLockScreenOfflineSigninTimeLimitDays: TYPE_INT64
|
||||
|
||||
chrome.users.SamlLockScreenReauthenticationEnabled: SAML single sign-on password synchronization flows.
|
||||
samlLockScreenReauthenticationEnabled: TYPE_BOOL
|
||||
@@ -9106,6 +9010,11 @@ chrome.users.SecondaryGoogleAccountSignin: Sign-in to secondary accounts.
|
||||
allowedDomainsForApps: TYPE_LIST
|
||||
Whether the OS version updates will be set to a version defined in the manifest of a kiosk app.
|
||||
|
||||
chrome.users.SecondaryGoogleAccountUsage: Managed account as secondary account.
|
||||
secondaryGoogleAccountUsage: TYPE_ENUM
|
||||
ALL: All usages of managed accounts are allowed.
|
||||
PRIMARY_ACCOUNT_SIGNIN: Block addition of a managed account as secondary account (in-session).
|
||||
|
||||
chrome.users.SecurityKeyAttestation: Security key attestation.
|
||||
securityKeyPermitAttestation: TYPE_LIST
|
||||
Enter URL or domain. Specifies URLs and domains for which no prompt will be shown when attestation certificates from security keys are requested. Additionally, a signal will be sent to the security key indicating that individual attestation may be used. Without this, users will be prompted in Chrome 65+ when sites request attestation of security keys. URLs (like "https://example.com/some/path") will only match as U2F AppIDs. Domains (like "example.com") only match as WebAuthn RP IDs. Thus, to cover both U2F and WebAuthn APIs for a given site, both the AppID URL and domain would need to be listed.
|
||||
@@ -9115,16 +9024,14 @@ chrome.users.SecurityTokenSessionSettings: Security token removal.
|
||||
IGNORE: Nothing.
|
||||
LOGOUT: Log the user out.
|
||||
LOCK: Lock the current session.
|
||||
securityTokenSessionNotificationSeconds
|
||||
duration: TYPE_STRING
|
||||
securityTokenSessionNotificationSeconds: TYPE_INT64
|
||||
|
||||
chrome.users.SecurityTokenSessionSettingsV2: Security token removal.
|
||||
securityTokenSessionBehavior: TYPE_ENUM
|
||||
IGNORE: Nothing.
|
||||
LOGOUT: Log the user out.
|
||||
LOCK: Lock the current session.
|
||||
securityTokenSessionNotificationSeconds
|
||||
duration: TYPE_INT64
|
||||
securityTokenSessionNotificationSeconds: TYPE_INT64
|
||||
|
||||
chrome.users.SelectToSpeakEnabled: Select to speak.
|
||||
selectToSpeakEnabled: TYPE_ENUM
|
||||
@@ -9149,12 +9056,10 @@ chrome.users.ServiceWorkerToControlSrcdocIframeEnabled: Service worker control o
|
||||
false: Block service workers from controlling srcdoc iframes.
|
||||
|
||||
chrome.users.SessionLength: Maximum user session length.
|
||||
sessionDurationLimit
|
||||
duration: TYPE_STRING
|
||||
sessionDurationLimit: TYPE_INT64
|
||||
|
||||
chrome.users.SessionLengthV2: Maximum user session length.
|
||||
sessionDurationLimit
|
||||
duration: TYPE_INT64
|
||||
sessionDurationLimit: TYPE_INT64
|
||||
|
||||
chrome.users.SetTimeoutWithoutOneMsClampEnabled: Javascript setTimeout() minimum.
|
||||
setTimeoutWithoutOneMsClampEnabled: TYPE_ENUM
|
||||
@@ -9330,6 +9235,7 @@ chrome.users.SiteSearchSettings: Site search.
|
||||
name: TYPE_STRING
|
||||
shortcut: TYPE_STRING
|
||||
url: TYPE_STRING
|
||||
allowUserOverride: TYPE_BOOL
|
||||
|
||||
chrome.users.SmartLockAllowed: Smart Lock.
|
||||
smartLockAllowed: TYPE_BOOL
|
||||
@@ -9345,6 +9251,11 @@ chrome.users.SmartScreenDimDelay: Delay screen dim on user activity.
|
||||
true: Enable smart dim model.
|
||||
false: Disable smart dim model.
|
||||
|
||||
chrome.users.SmsMessagesAllowed: Messages.
|
||||
smsMessagesAllowed: TYPE_BOOL
|
||||
true: Allow users to sync SMS messages between their phone and Chromebook.
|
||||
false: Do not allow users to sync SMS messages between their phone and Chromebook.
|
||||
|
||||
chrome.users.SpellcheckEnabled: Spell check.
|
||||
spellcheckEnabled: TYPE_ENUM
|
||||
UNSET: Allow the user to decide.
|
||||
@@ -10038,4 +9949,5 @@ chrome.users.ZstdContentEncodingEnabled: Zstd compression.
|
||||
true: Allow zstd-compressed web content.
|
||||
false: Do not allow zstd-compressed web content.
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
- [API documentation](#api-documentation)
|
||||
- [Introduction](#introduction)
|
||||
- [Definitions](#definitions)
|
||||
- [Delete Chrome profiles](#delete-chrome-profiles)
|
||||
- [Display Chrome profiles](#display-chrome-profiles)
|
||||
- [Delete Chrome Profiles](#delete-chrome-profiles)
|
||||
- [Display Chrome Profiles](#display-chrome-profiles)
|
||||
- [Profile Query Searchable Fields](#profile-query-searchable-fields)
|
||||
- [Collections of Chrome Profile names for commands](#collections-of-chrome-profile-names-for-commands)
|
||||
- [Create a Chrome Profile command](#create-a-chrome-profile-command)
|
||||
- [Display Chrome Profile commands](#display-chrome-profile-commands)
|
||||
|
||||
## Introduction
|
||||
These features were added in version 7.01.00.
|
||||
@@ -21,13 +24,24 @@ Follow instructions at: Turn on managed profile reporting
|
||||
|
||||
## API documentation
|
||||
* [Chrome Management API - Profiles](https://developers.google.com/chrome/management/reference/rest/v1/customers.profiles)
|
||||
* [Chrome Management API - Profile Commands](https://developers.google.com/chrome/management/reference/rest/v1/customers.profiles.commands)
|
||||
* [Turn on Chrome Browser and Profile Reporting](https://support.google.com/chrome/a/answer/9301421)
|
||||
|
||||
## Definitions
|
||||
* [`<FileSelector> | <CSVFileSelector>`](Collections-of-Items)
|
||||
|
||||
```
|
||||
<CustomerID> ::= <String>
|
||||
<ChromeProfilePermanentID> ::= <String>
|
||||
<ChromeProfileName> ::= customers/<CustomerID>/profiles/<ChromeProfilePermanentID>
|
||||
<ChromeProfileName> ::= customers/<CustomerID>/profiles/<ChromeProfilePermanentID> | <ChromeProfilePermanentID>
|
||||
<ChromeProfileNameList> ::= "<ChromeProfileName>(,<ChromeProfileName>)*"
|
||||
<ChromeProfileCommandName> ::= <ChomeProfileName>/commands/<String>
|
||||
<ChromeProfileCommandNameList> ::= "<ChromeProfileCommandName>(,<ChromeProfileCommandName>)*"
|
||||
<ChromeProfileNameEntity> ::=
|
||||
<ChromeProfileNameList> |
|
||||
(select <FileSelector>|<CSVFileSelector>) |
|
||||
(filter <String> (filtertime<String> <Time>)* [orderby <ChromeProfileOrderByFieldName> [ascending|descending]]) |
|
||||
(commands <ChromeProfileCommandNameList>|<FileSelector>|<CSVFileSelector>)
|
||||
|
||||
<ChromeProfileFieldName> ::=
|
||||
affiliationstate|
|
||||
@@ -89,11 +103,11 @@ Select the fields to be displayed:
|
||||
* `<ChromeProfileFieldName>* [fields <ChromeProfileFieldNameList>]` - Display a selected list of fields
|
||||
|
||||
By default, Gam displays the information as an indented list of keys and values:
|
||||
- `formatjson` - Display the fields in JSON format.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
|
||||
```
|
||||
gam show chromeprofiles
|
||||
[filtertime.* <Time>] [filter <String>]
|
||||
[filter <String> (filtertime<String> <Time>)*]
|
||||
[orderby <ChromeProfileOrderByFieldName> [ascending|descending]]
|
||||
<ChromeProfileFieldName>* [fields <ChromeProfileFieldNameList>]
|
||||
[formatjson]
|
||||
@@ -106,18 +120,18 @@ Select the fields to be displayed:
|
||||
* `<ChromeProfileFieldName>* [fields <ChromeProfileFieldNameList>]` - Display a selected list of fields
|
||||
|
||||
Use the `filtertime<String> <Time>` option to allow times, usually relative, to be substituted into the `filter <String>` option.
|
||||
The `filtertime<String> <Time>` value replaces the string `#fiktertime<String>#` in the `filter <String>`.
|
||||
The `filtertime<String> <Time>` value replaces the string `#filtertime<String>#` in the `filter <String>`.
|
||||
The characters following `filtertime` can be any combination of lowercase letters and numbers.
|
||||
|
||||
By default, Gam displays the information as an indented list of keys and values:
|
||||
- `formatjson` - Display the fields in JSON format.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
|
||||
```
|
||||
gam print chromeprofiles [todrive <ToDriveAttribute>*]
|
||||
[filtertime.* <Time>] [filter <String>]
|
||||
[filter <String> (filtertime<String> <Time>)*]
|
||||
[orderby <ChromeProfileOrderByFieldName> [ascending|descending]]
|
||||
<ChromeProfileFieldName>* [fields <ChromeProfileFieldNameList>]
|
||||
[[formatjson [quotechar <Character>]]
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
|
||||
Use these options to select Chrome profiles; if none are chosen, all Chrome profiles in the account are selected:
|
||||
@@ -192,4 +206,111 @@ gam print chromeprofiles filter "lastPolicySyncTime >= \"#filtertime1#\" lastPol
|
||||
Print information about Chrome profiles on Windows.
|
||||
```
|
||||
gam print chromeprofiles filter "osPlatformType=WINDOWS"
|
||||
```
|
||||
```
|
||||
## Collections of Chrome Profile names for commands
|
||||
```
|
||||
<ChromeProfileNameEntity> ::=
|
||||
<ChromeProfileNameList> |
|
||||
(select <ChromeProfileNameList>|<FileSelector>|<CSVFileSelector>) |
|
||||
(filter <String> (filtertime<String> <Time>)* [orderby <ChromeProfileOrderByFieldName> [ascending|descending]]) |
|
||||
(commands <ChromeProfileCommandNameList>|<FileSelector>|<CSVFileSelector>)
|
||||
```
|
||||
* `<ChromeProfileNameList>` - A list of Chrome profile names
|
||||
* `select <ChromeProfileNameList>` - A list of Chrome profile names
|
||||
* `select <FileSelector>|<CSVFileSelector>` - A flat or CSV file containing Chrome profile names
|
||||
* `filter <String> (filtertime<String> <Time>)*` - A filter to select Chrome profiles
|
||||
* `commands <ChromeProfileCommandNameList>` - A list of Chrome profile command names
|
||||
* `commands <FileSelector>|<CSVFileSelector>` - A flat or CSV file containing Chrome profile command names
|
||||
|
||||
Use the `filtertime<String> <Time>` option to allow times, usually relative, to be substituted into the `filter <String>` option.
|
||||
The `filtertime<String> <Time>` value replaces the string `#filtertime<String>#` in the `filter <String>`.
|
||||
The characters following `filtertime` can be any combination of lowercase letters and numbers.
|
||||
|
||||
## Create a Chrome Profile command
|
||||
Clear a Chrome Browser profile cache and/or cookies.
|
||||
```
|
||||
gam create chromeprofilecommand <ChromeProfileNameEntity>
|
||||
[clearcache [<Boolean>]] [clearcookies [<Boolean>]]
|
||||
[csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]]]
|
||||
```
|
||||
By default, when a Chrome profile command is created, GAM outputs details of the command as indented keywords and values.
|
||||
* `formatjson` - Display the details in JSON format.
|
||||
* `csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]]` - Output the details in CSV format.
|
||||
|
||||
## Display Chrome Profile commands
|
||||
Display the status of a specific Chrome Browser profile command.
|
||||
```
|
||||
gam info chromeprofilecommand <ChromeProfileCommandName>
|
||||
[formatjson]
|
||||
```
|
||||
By default, Gam displays the information as an indented list of keys and values:
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
|
||||
Display the status of selected Chrome Browser profile commands.
|
||||
```
|
||||
gam show chromeprofilecommands <ChromeProfileNameEntity>
|
||||
[formatjson]
|
||||
```
|
||||
|
||||
By default, Gam displays the information as an indented list of keys and values:
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
```
|
||||
gam print chromeprofilecommands <ChromeProfileNameEntity> [todrive <ToDriveAttribute>*]
|
||||
[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.
|
||||
|
||||
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
|
||||
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
|
||||
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.
|
||||
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
|
||||
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
|
||||
|
||||
### Examples
|
||||
|
||||
For Windows PowerShell, replace `\"` with ``` `" ```.
|
||||
|
||||
Clear cache and cookies for two specific Chrome profiles:
|
||||
```
|
||||
gam create chromeprofilecommand 4c6c0a9f-de78-4285-be86-713fca8cffff,aa03151c-7c1d-41fe-b793-5753e167ffff clearcache clearcookies
|
||||
```
|
||||
|
||||
Display the command status for those Chrome profiles:
|
||||
```
|
||||
gam show chromeprofilecommand 4c6c0a9f-de78-4285-be86-713fca8cffff,aa03151c-7c1d-41fe-b793-5753e167ffff
|
||||
gam print chromeprofilecommand 4c6c0a9f-de78-4285-be86-713fca8cffff,aa03151c-7c1d-41fe-b793-5753e167ffff
|
||||
```
|
||||
|
||||
Clear cache and cookies for Chrome profiles in a CSV file named `ChromeProfiles.csv` with a column `name`:
|
||||
```
|
||||
gam create chromeprofilecommand select csvfile ChromeProfiles.csv:name clearcache clearcookies
|
||||
```
|
||||
|
||||
Display the command status for those Chrome profiles:
|
||||
```
|
||||
gam show chromeprofilecommand select csvfile ChromeProfiles.csv:name
|
||||
gam print chromeprofilecommand select csvfile ChromeProfiles.csv:name
|
||||
```
|
||||
|
||||
Clear cache and cookies for Chrome profiles with last activity more that 60 days ago:
|
||||
```
|
||||
gam create chromeprofilecommand filter "lastActivityTime < \"#filtertime1#\"" filtertime1 -60d clearcache clearcookies
|
||||
```
|
||||
|
||||
Display the command status for those Chrome profiles:
|
||||
```
|
||||
gam show chromeprofilecommand filter "lastActivityTime < \"#filtertime1#\"" filtertime1 -60d
|
||||
gam print chromeprofilecommand filter "lastActivityTime < \"#filtertime1#\"" filtertime1 -60d
|
||||
```
|
||||
|
||||
Clear cache and cookies for Chrome profiles with last activity more that 60 days ago:
|
||||
```
|
||||
gam redirect csv ./ChromeProfileCmds.csv create chromeprofilecommand filter "lastActivityTime < \"#filtertime1#\"" filtertime1 -60d clearcache clearcookies csv
|
||||
```
|
||||
|
||||
Display the command status for those Chrome profile commands
|
||||
```
|
||||
gam show chromeprofilecommand commands ChromeProfileCmds.csv:name
|
||||
gam print chromeprofilecommand commands ChromeProfileCmds.csv:name
|
||||
```
|
||||
|
||||
@@ -62,15 +62,6 @@ To use the `crostelemetry` commands you must authorize an additional scope:
|
||||
gam oauth create
|
||||
```
|
||||
|
||||
Many commands come in two forms:
|
||||
```
|
||||
gam <CrOSTypeEntity> <Command> ...
|
||||
gam <Command> cros <CrOSEntity> ...
|
||||
```
|
||||
The first form allows more powerful selection of devices with `<CrOSTypeEntity>`.
|
||||
|
||||
The second form is backwards compatible with Legacy GAM and selection with `<CrOSEntity>` is limited.
|
||||
|
||||
## Definitions
|
||||
* [`<CrOSTypeEntity>`](Collections-of-ChromeOS-Devices)
|
||||
|
||||
@@ -332,7 +323,6 @@ gam select default config update_cros_ou_with_id true save
|
||||
|
||||
```
|
||||
gam <CrOSTypeEntity> update <CrOSAttribute>+ [quickcrosmove [<Boolean>]] [nobatchupdate]
|
||||
gam update cros <CrOSEntity> <CrOSAttribute>+ [quickcrosmove [<Boolean>]] [nobatchupdate]
|
||||
```
|
||||
|
||||
Google has introduced a new, faster method for moving CrOS devices to a new OU. The `quickcrosmove` option controls which method Gam uses.
|
||||
@@ -419,8 +409,6 @@ gam update ou csvkmd cros.csv keyfield OU datafield deviceId add croscsvdata dev
|
||||
|
||||
gam <CrOSTypeEntity> update action <CrOSAction> [acknowledge_device_touch_requirement]
|
||||
[actionbatchsize <Integer>]
|
||||
gam update cros <CrOSEntity> action <CrOSAction> [acknowledge_device_touch_requirement]
|
||||
[actionbatchsize <Integer>]
|
||||
```
|
||||
As of GAM version `6.67.00`, the new API function `batchChangeStatus` replaces the old API function `action`; ChromeOS devices are now processed in batches.
|
||||
The batch size defaults to 10, the `actionbatchsize <Integer>` option can be used to set a batch size between 10 and 250.
|
||||
@@ -457,21 +445,18 @@ is configurable from 0 to some large number. If the status reaches `EXPIRED`, `C
|
||||
wipe_users|
|
||||
take_a_screenshot
|
||||
|
||||
gam cros <CrOSTypeEntity> issuecommand command <CrOSCommand> [times_to_check_status <Integer>] [doit]
|
||||
gam issuecommand cros <CrOSEntity> command <CrOSCommand> [times_to_check_status <Integer>] [doit]
|
||||
gam <CrOSTypeEntity> issuecommand command <CrOSCommand> [times_to_check_status <Integer>] [doit]
|
||||
```
|
||||
If the final status is not reached before GAM exits, you can issue the following commands to continue checking the status.
|
||||
```
|
||||
gam cros <CrOSTypeEntity> getcommand commandid <CommandID> [times_to_check_status <Integer>]
|
||||
gam getcommand cros <CrOSEntity> commandid <CommandID> [times_to_check_status <Integer>]
|
||||
gam <CrOSTypeEntity> getcommand commandid <CommandID> [times_to_check_status <Integer>]
|
||||
```
|
||||
|
||||
### Action Examples
|
||||
Remove user profile data from the device; the device will remain enrolled and connected.
|
||||
User data not synced to the Cloud including Downloads, Android app data and Crostini Linux VMs will be permanently lost.
|
||||
Commands with issuecommand directly after gam will work with Legacy GAM & GAM7, whereas commands where the issuecommand is after the cros <CrOSTypeEntity> will work only with GAM7.
|
||||
```
|
||||
gam issuecommand cros dd1d659a-0ea4-4e94-905e-4726c7a5f1e9 command wipe_users doit
|
||||
gam cros dd1d659a-0ea4-4e94-905e-4726c7a5f1e9 issuecommand command wipe_users doit
|
||||
```
|
||||
Remove profiles using the annotatedAssetID, which is a user editable field, in this example the device has an asset ID of CB1234.
|
||||
```
|
||||
@@ -483,14 +468,12 @@ gam cros_queries "asset_id:CB1234,asset_id:CB5678" issuecommand command wipe_use
|
||||
```
|
||||
Powerwash the device with serial number 143040348.
|
||||
```
|
||||
gam issuecommand cros query:id:143040348 command remote_powerwash times_to_check_status 10 doit
|
||||
gam cros_sn 143040348 issuecommand command remote_powerwash times_to_check_status 10 doit
|
||||
```
|
||||
|
||||
Powerwash all devices in the /StudentCarts OrgUnit. Devices will need to be manually reconnected to WiFi which may mean entering a PSK.
|
||||
Use `wipe_users` if that's going to create too much work for you.
|
||||
```
|
||||
gam issuecommand cros "query:orgunitpath:/StudentCarts" command remote_powerwash times_to_check_status 0 doit
|
||||
gam cros_ou /StudentCarts issuecommand command remote_powerwash times_to_check_status 0 doit
|
||||
```
|
||||
## ChromeOS device lists
|
||||
@@ -829,7 +812,6 @@ The `quotechar <Character>` option allows you to choose an alternate quote chara
|
||||
|
||||
```
|
||||
gam <CrOSTypeEntity> info downloadfile latest|<Time> [targetfolder <FilePath>]
|
||||
gam info cros <CrOSEntity> downloadfile latest|<Time> [targetfolder <FilePath>]
|
||||
```
|
||||
|
||||
Select the device file to download by its timestamp.
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
- [Create and update courses](#create-and-update-courses)
|
||||
- [Delete courses](#delete-courses)
|
||||
- [Manage course aliases](#manage-course-aliases)
|
||||
- [Manage course announcements](#manage-course-announcements)
|
||||
- [Manage course topics](#manage-course-topics)
|
||||
- [Display courses](#display-courses)
|
||||
- [Display course counts](#display-course-counts)
|
||||
@@ -55,6 +56,11 @@ gam user user@domain.com check|update serviceaccount
|
||||
<CourseAliasEntity> ::=
|
||||
<CourseAliasList>|<FileSelector>|<CSVFileSelector>|<CSVkmdSelector>|<CSVDataSelector>
|
||||
See: https://github.com/GAM-team/GAM/wiki/Collections-of-Items
|
||||
<CourseAnnouncementContent> ::=
|
||||
((text <String>)|
|
||||
(textfile <FileName> [charset <Charset>])|
|
||||
(gdoc <UserGoogleDoc>)|
|
||||
(gcsdoc <StorageBucketObjectName>))
|
||||
<CourseAnnouncementID> ::= <Number>
|
||||
<CourseAnnouncementIDList> ::= "<CourseAnnouncementID>(,<CourseAnnouncementID>)*"
|
||||
<CourseAnnouncementIDEntity> ::=
|
||||
@@ -389,17 +395,40 @@ These commands can process multiple courses.
|
||||
gam courses <CourseEntity> add alias <CourseAliasEntity>
|
||||
gam courses <CourseEntity> delete alias <CourseAliasEntity>
|
||||
```
|
||||
|
||||
## Manage course announcements
|
||||
These commands can process a single course.
|
||||
```
|
||||
gam course <CourseID> add announcement
|
||||
<CourseAnnouncementContent> [scheduledtime <Time>] [state draft|published]
|
||||
gam course <CourseID> delete announcement <CourseAnnouncementID>
|
||||
gam course <CourseID> update announcement <CourseAnnouncementID>
|
||||
[<CourseAnnouncementContent>] [scheduledtime <Time>] [state published]
|
||||
```
|
||||
These commands can process multiple courses.
|
||||
```
|
||||
gam courses <CourseEntity> add announcement
|
||||
<CourseAnnouncementContent> [scheduledtime <Time>] [state draft|published]
|
||||
gam courses <CourseEntity> delete announcement <CourseAnnouncementIDEntity>
|
||||
gam courses <CourseEntity> update announcement <CourseAnnouncementIDEntity>
|
||||
[<CourseAnnouncementContent>] [scheduledtime <Time>] [state published]
|
||||
```
|
||||
|
||||
## Manage course topics
|
||||
These commands can process a single course.
|
||||
```
|
||||
gam course <CourseID> add topic <CourseTopic>
|
||||
gam course <CourseID> delete topic <CourseTopicID>
|
||||
gam course <CourseID> update topic <CourseTopicID> <CourseTopic>
|
||||
|
||||
```
|
||||
These commands can process multiple courses.
|
||||
```
|
||||
gam courses <CourseEntity> add topic <CourseTopicEntity>
|
||||
gam courses <CourseEntity> delete topic <CourseTopicIDEntity>
|
||||
gam courses <CourseEntity> update topic <CourseTopicIDEntity> <CourseTopic>
|
||||
```
|
||||
|
||||
## Display courses
|
||||
```
|
||||
gam info course <CourseID> [owneremail] [alias|aliases] [show all|students|teachers] [countsonly]
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
* [Google Classroom API](https://developers.google.com/classroom/reference/rest)
|
||||
* [Google Classroom API - Courses Students](https://developers.google.com/classroom/reference/rest/v1/courses.students)
|
||||
* [Google Classroom API - Courses Teachers](https://developers.google.com/classroom/reference/rest/v1/courses.teachers)
|
||||
* [Classroom Membership Limits](https://support.google.com/edu/classroom/answer/7300976)
|
||||
|
||||
## Definitions
|
||||
```
|
||||
|
||||
273
wiki/Classroom-StudentGroups.md
Normal file
273
wiki/Classroom-StudentGroups.md
Normal file
@@ -0,0 +1,273 @@
|
||||
# Classroom - Student Groups
|
||||
- [Notes](#notes)
|
||||
- [API documentation](#api-documentation)
|
||||
- [Definitions](#definitions)
|
||||
- [Special quoting for course aliases](#special-quoting-for-course-aliases)
|
||||
- [Special quoting for lists of titles](#special-quoting-for-lists-of-titles)
|
||||
- [Manage student groups](#manage-student-groups)
|
||||
- [Display student groups](#display-student-groups)
|
||||
- [Display student group counts](#display-student-group-counts)
|
||||
- [Manage student group membership](#manage-student-group-membership)
|
||||
- [Display student group membership](#display-student-group-membership)
|
||||
- [Display student group membership counts](#display-student-group-membership-counts)
|
||||
|
||||
## Notes
|
||||
These commands wera added in version 7.20.00.
|
||||
|
||||
To use these commands your project must be enrolled the Developer Preview program.
|
||||
* https://developers.google.com/workspace/preview
|
||||
|
||||
You will need your GAM project number.
|
||||
* Login as an existing super admin at console.cloud.google.com
|
||||
* In the upper left click the three lines to the left of Google Cloud and select IAM & Admin
|
||||
* Under IAM & Admin select IAM
|
||||
* Click in the box to the right of Google Cloud
|
||||
* Click the three dots at the right and select Manage Resources
|
||||
* Click the three dots at the end of the line for your GAM project
|
||||
* Click Settings
|
||||
* You will see the Project number; save it
|
||||
|
||||
You will need an API key
|
||||
* In the upper left click the three lines to the left of Google Cloud and select APIs & Services
|
||||
* Under APIs & Services select Credentials
|
||||
* If you already have an API key, click Show key at the end of the line and save the value
|
||||
* If you don't have an API key, click +Credentials and select API key
|
||||
* Save the displayed API key
|
||||
* Click close
|
||||
|
||||
Issue the following GAM command:
|
||||
`gam config developer_preview_api_key <API Key Value> save`
|
||||
|
||||
Once you get an email from Google saying that your project has been registered you can use these commands.
|
||||
|
||||
## API documentation
|
||||
* [Google Classroom API](https://developers.google.com/classroom/reference/rest)
|
||||
* [Google Classroom Student Groups](https://developers.google.com/workspace/classroom/reference/rest/v1/courses.studentGroups)
|
||||
* [Google Classroom Student Group Members](https://developers.google.com/workspace/classroom/reference/rest/v1/courses.studentGroups.studentGroupMembers)
|
||||
|
||||
## Definitions
|
||||
```
|
||||
<DomainName> ::= <String>(.<String>)+
|
||||
<EmailAddress> ::= <String>@<DomainName>
|
||||
<UniqueID> ::= id:<String>
|
||||
<UserItem> ::= <EmailAddress>|<UniqueID>|<String>
|
||||
|
||||
<CourseAlias> ::= <String>
|
||||
<CourseID> ::= <Number>|d:<CourseAlias>
|
||||
<CourseIDList> ::= "<CourseID>(,<CourseID>)*"
|
||||
<CourseEntity> ::=
|
||||
<CourseIDList> | <FileSelector> | <CSVFileSelector | <CSVkmdSelector>
|
||||
See: https://github.com/GAM-team/GAM/wiki/Collections-of-Items
|
||||
<CourseState> ::= active|archived|provisioned|declined|suspended
|
||||
<CourseStateList> ::= all|"<CourseState>(,<CourseState>)*"
|
||||
|
||||
<StringList> ::= "<String>(,<String>)*"
|
||||
<StringEntity> ::=
|
||||
<StringList> | <FileSelector> | <CSVFileSelector>
|
||||
See: https://github.com/GAM-team/GAM/wiki/Collections-of-Items
|
||||
|
||||
<StudentGroupID> ::= <Number>
|
||||
<StudentGroupIDList> ::= "<StudentGroupID>(,<StudentGroupID>)*"
|
||||
<StudentGroupEntity> ::=
|
||||
<StudentGroupIDList> | <FileSelector> | <CSVFileSelector> | <CSVkmdSelector>
|
||||
```
|
||||
## Special quoting for course aliases
|
||||
As course aliases can contain spaces, some care must be used when entering `<CourseAliasList>`, `<CourseID>`, `<CourseIDList>` and `<CourseEntity>`.
|
||||
|
||||
Suppose you have a course with the alias `Math Class`. To get information about it you enter the command: `gam info course "d:Math Class"`
|
||||
|
||||
The shell strips the `"` leaving a single argument `d:Math Class`; gam correctly processes the argument as it is expecting a single course.
|
||||
|
||||
Suppose you enter the command: `gam info courses "d:Math Class"`
|
||||
|
||||
The shell strips the `"` leaving a single argument `d:Math Class`; as gam is expecting a list, it splits the argument on space leaving two items and then tries to process `d:Math` and `Class`, not what you want.
|
||||
|
||||
You must enter: `gam info courses "'d:Math Class'"`
|
||||
|
||||
The shell strips the `"` leaving a single argument `'d:Math Class'`; as gam is expecting a list, it splits the argument on space while honoring the `'` leaving one item `d:Math Class` and correctly processes the item.
|
||||
|
||||
For multiple aliases you must enter: `gam info courses "'d:Math Class','d:Science Class'"`
|
||||
|
||||
## Special quoting for lists of titles
|
||||
As student group titles can contain spaces, some care must be used when entering `selevct <StringList>`.
|
||||
|
||||
Suppose you want to create a student group `Advanced Students`. `gam create course-studentgroups course <CourseID> title "Advanced Students"`
|
||||
|
||||
The shell strips the `"` leaving a single argument `Advanced Math`; gam correctly processes the argument as it is expecting a single title.
|
||||
|
||||
Suppose you enter the command: `gam create course-studentgroups course <CourseID> select "Advanced Students"`
|
||||
|
||||
The shell strips the `"` leaving a single argument `Advanced Students`; as gam is expecting a list, it splits the argument on space leaving two items and then tries to process `Advanced` and `Students`, not what you want.
|
||||
|
||||
You must enter: `gam create course-studentgroups course <CourseID> select "'Advanced Students'"`
|
||||
|
||||
The shell strips the `"` leaving a single argument `'Advanced Students'`; as gam is expecting a list, it splits the argument on space while honoring the `'` leaving one item `Advanced Students` and correctly processes the item.
|
||||
|
||||
For multiple titles you can enter either of the following:
|
||||
* `gam create course-studentgroups course <CourseID> select "'Advanced Students','Beginner Students'"`
|
||||
* `gam create course-studentgroups course <CourseID> title"Advanced Students" title "Beginner Students"`
|
||||
|
||||
See: [Lists and Collections](Lists-and-Collections)
|
||||
|
||||
## Manage student groups
|
||||
|
||||
```
|
||||
gam create course-studentgroups
|
||||
(course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
||||
((title <String>)|(select <StringEntity))+
|
||||
[csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]]]
|
||||
gam update course-studentgroups <CourseID> <StudentGroupID> title <String>
|
||||
gam delete course-studentgroups <CourseID> <StudentGroupIDEntity>
|
||||
gam clear course-studentgroups
|
||||
(course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
||||
```
|
||||
|
||||
When creating student groups, the API does not check for duplicate titles; you can have multiple student grpups
|
||||
with the same title; they will have unique `<StudentGroupID>s`.
|
||||
|
||||
The `update|delete course-studentgroups` commands manage a specific course.
|
||||
|
||||
By default, the `create|clear course-studentgroups` commands manage student group information about all courses.
|
||||
|
||||
To manage student group information for a specific set of courses, use the following option; it can be repeated to select multiple courses.
|
||||
* `(course|class <CourseID>)*` - Display courses with the specified `<CourseID>`.
|
||||
|
||||
To manage student group information for courses based on their having a particular participant, use the following options. Both options can be specified.
|
||||
* `teacher <UserItem>` - Display courses with the specified teacher.
|
||||
* `student <UserItem>` - Display courses with the specified student.
|
||||
|
||||
To manage student group information for courses based on their state, use the following option. This option can be combined with the `teacher` and `student` options.
|
||||
By default, all course states are selected.
|
||||
* `states <CourseStateList>` - Display courses with any of the specified states.
|
||||
|
||||
By default, when a student group is created, you will get output like this:
|
||||
```
|
||||
Course: <CourseID>, Course Student Group: <Title>(<StudentGroupId>), Added
|
||||
```
|
||||
If you use the `csv` option, you will get output like this:
|
||||
```
|
||||
courseId,courseName,studentGroupId,studentGroupTitle
|
||||
<CourseID>,<CourseName>,<StudentGroupID>,<Title>
|
||||
```
|
||||
This gives you a record the the student group IDs.
|
||||
|
||||
### Example
|
||||
```
|
||||
$ more titles.csv
|
||||
title
|
||||
Advanced Students
|
||||
Middle Students
|
||||
Beginner Students
|
||||
|
||||
$ gam redirect csv ./StudentGroups.csv add coursestudentgroups course <CourseID> select csvfile titles.csv:title csv
|
||||
Course: <CourseID>, Add 3 Course Student Groups
|
||||
|
||||
$ more StudentGroups.csv
|
||||
courseId,courseName,studentGroupId,studentGroupTitle
|
||||
<CourseID>,<CourseName>,796177544247,Advanced Students
|
||||
<CourseID>,<CourseName>,796177718666,Middle Students
|
||||
<CourseID>,<CourseName>,796177727901,Beginner Students
|
||||
```
|
||||
|
||||
## Display student groups
|
||||
```
|
||||
gam print course-studentgroups [todrive <ToDriveAttribute>*]
|
||||
(course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
By default, the `print course-studentgroups` command displays student group information about all courses.
|
||||
|
||||
To display student group information for a specific set of courses, use the following option; it can be repeated to select multiple courses.
|
||||
* `(course|class <CourseID>)*` - Display courses with the specified `<CourseID>`.
|
||||
|
||||
To display student group information for courses based on their having a particular participant, use the following options. Both options can be specified.
|
||||
* `teacher <UserItem>` - Display courses with the specified teacher.
|
||||
* `student <UserItem>` - Display courses with the specified student.
|
||||
|
||||
To display student group information for courses based on their state, use the following option. This option can be combined with the `teacher` and `student` options.
|
||||
By default, all course states are selected.
|
||||
* `states <CourseStateList>` - Display courses with any of the specified states.
|
||||
|
||||
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.
|
||||
|
||||
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
|
||||
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
|
||||
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.
|
||||
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
|
||||
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
|
||||
|
||||
## Display student group counts
|
||||
Display the number of student groups
|
||||
```
|
||||
gam print course-studentgroup [todrive <ToDriveAttribute>*]
|
||||
(course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
||||
showitemcountonly
|
||||
```
|
||||
|
||||
## Manage student group membership
|
||||
```
|
||||
gam create course-studentgroup-members <CourseID> <StudentGroupID> <UserTypeEntity>
|
||||
gam delete course-studentgroup-members <CourseID> <StudentGroupID> <UserTypeEntity>
|
||||
gam sync course-studentgroup-members <CourseID> <StudentGroupID> <UserTypeEntity>
|
||||
gam clear course-studentgroupmembers <CourseID> <StudentGroupID>
|
||||
```
|
||||
|
||||
# Display student group membership
|
||||
```
|
||||
gam print course-studentgroup-members [todrive <ToDriveAttribute>*]
|
||||
(course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
By default, the `print course-studentgroup-members` command displays student group member information about all courses.
|
||||
|
||||
To display student group member information for a specific set of courses, use the following option; it can be repeated to select multiple courses.
|
||||
* `(course|class <CourseID>)*` - Display courses with the specified `<CourseID>`.
|
||||
|
||||
To display student group member information for courses based on their having a particular participant, use the following options. Both options can be specified.
|
||||
* `teacher <UserItem>` - Display courses with the specified teacher.
|
||||
* `student <UserItem>` - Display courses with the specified student.
|
||||
|
||||
To display student group member information for courses based on their state, use the following option. This option can be combined with the `teacher` and `student` options.
|
||||
By default, all course states are selected.
|
||||
* `states <CourseStateList>` - Display courses with any of the specified states.
|
||||
|
||||
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.
|
||||
|
||||
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
|
||||
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
|
||||
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.
|
||||
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
|
||||
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
|
||||
|
||||
## Display student group membership counts
|
||||
Display the number of student group members
|
||||
```
|
||||
gam print course-studentgroup-members [todrive <ToDriveAttribute>*]
|
||||
(course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
||||
showitemcountonly
|
||||
```
|
||||
Example
|
||||
```
|
||||
$ gam print course-participants teacher asmith states active show students showitemcountonly
|
||||
Getting all Courses that match query (Teacher: asmith@domain.com, Course State: ACTIVE), may take some time on a large Google Workspace Account...
|
||||
Got 3 Courses...
|
||||
Getting Students for Course: 636981507234 (1/3)
|
||||
Got 30 Students...
|
||||
Got 43 Students...
|
||||
Getting Students for Course: 589346784341 (2/3)
|
||||
Got 22 Students...
|
||||
Getting Students for Course: 589345535881 (3/3)
|
||||
Got 23 Students...
|
||||
88
|
||||
```
|
||||
The `Getting` and `Got` messages are written to stderr, the count is writtem to stdout.
|
||||
|
||||
To retrieve the count with `showitemcountonly`:
|
||||
```
|
||||
Linux/MacOS
|
||||
count=$(gam print course-participants teacher asmith states active show students showitemcountonly)
|
||||
Windows PowerShell
|
||||
count = & gam print course-participants teacher asmith states active show students showitemcountonly
|
||||
```
|
||||
@@ -211,6 +211,7 @@ gam print devices [todrive <ToDriveAttribute>*]
|
||||
[orderby <DeviceOrderByFieldName> [ascending|descending]]
|
||||
[all|company|personal|nocompanydevices|nopersonaldevices]
|
||||
[nodeviceusers|oneuserperrow]
|
||||
[clientstates]
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
By default, all devices are displayed; use the query options to limit the display.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Cloud Identity Groups - Membership
|
||||
- [API documentation](#api-documentation)
|
||||
- [Query documentation](#query-documentation)
|
||||
- [Python Regular Expressions](Python-Regular-Expressions) Match function
|
||||
- [Definitions](#definitions)
|
||||
- [Notes](#Notes)
|
||||
@@ -22,10 +21,6 @@
|
||||
* [Cloud Identity Groups](https://gsuiteupdates.googleblog.com/2020/08/new-api-cloud-identity-groups-google.html)
|
||||
* [Security Groups](https://gsuiteupdates.googleblog.com/2020/09/security-groups-beta.html)
|
||||
|
||||
## Query documentation
|
||||
* [Cloud Identity Groups API - Search Dynamic Groups](https://cloud.google.com/identity/docs/reference/rest/v1/groups#dynamicgroupquery)
|
||||
* [Member Restrictions](https://cloud.google.com/identity/docs/reference/rest/v1/SecuritySettings#MemberRestriction)
|
||||
|
||||
## Notes
|
||||
|
||||
In the Admin Directory API a group has the following characteristics:
|
||||
@@ -45,7 +40,7 @@ Dynamic Groups require Cloud Identity Premium accounts.
|
||||
* https://cloud.google.com/identity/docs/how-to/create-dynamic-groups
|
||||
|
||||
The `cimember <UserItem>` option of `gam print|show cigroup-members` requires a Google Workspace Enterprise Standard, Enterprise Plus, and Enterprise for Education;
|
||||
and Cloud Identity Premium accounts. Unfortunately, even if you have the required account, the API call that supports the query doesn't work.
|
||||
and Cloud Identity Premium accounts.
|
||||
|
||||
* https://cloud.google.com/identity/docs/reference/rest/v1/groups.memberships/searchTransitiveGroups
|
||||
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
* [Security Groups](https://gsuiteupdates.googleblog.com/2020/09/security-groups-beta.html)
|
||||
|
||||
## Query documentation
|
||||
* [Cloud Identity Groups API - Search Dynamic Groups](https://cloud.google.com/identity/docs/reference/rest/v1/groups#dynamicgroupquery)
|
||||
* [Member REstrictions](https://cloud.google.com/identity/docs/reference/rest/v1/SecuritySettings#MemberRestriction)
|
||||
* [Cloud Identity Groups API - Search](https://cloud.google.com/identity/docs/reference/rest/v1/groups/search)
|
||||
* [Cloud Identity Groups API - Dynamic Group Query](https://cloud.google.com/identity/docs/reference/rest/v1/groups#dynamicgroupquery)
|
||||
* [Dynamic Groups Member Attributes](https://cloud.google.com/identity/docs/how-to/dynamic-groups-attributes)
|
||||
* [Member Restrictions](https://cloud.google.com/identity/docs/reference/rest/v1/SecuritySettings#MemberRestriction)
|
||||
|
||||
## Notes
|
||||
|
||||
@@ -50,7 +52,7 @@ Dynamic Groups require Cloud Identity Premium accounts.
|
||||
* https://cloud.google.com/identity/docs/how-to/create-dynamic-groups
|
||||
|
||||
The `cimember <UserItem>` option of `gam print cigroups` requires a Google Workspace Enterprise Standard, Enterprise Plus, and Enterprise for Education;
|
||||
and Cloud Identity Premium accounts. Unfortunately, even if you have the required account, the API call that supports the query doesn't work.
|
||||
and Cloud Identity Premium accounts.
|
||||
|
||||
* https://cloud.google.com/identity/docs/reference/rest/v1/groups.memberships/searchTransitiveGroups
|
||||
|
||||
|
||||
@@ -12,14 +12,28 @@
|
||||
|
||||
## Notes
|
||||
To use these commands you must update your client access authentication.
|
||||
You'll enter 19R to turn on the Cloud Identity Policy scope; then continue
|
||||
You'll enter 20r to turn on the Cloud Identity Policy scope; then continue
|
||||
with authentication.
|
||||
```
|
||||
gam oauth delete
|
||||
gam oauth create
|
||||
...
|
||||
[R] 19) Cloud Identity - Policy
|
||||
[R] 20) Cloud Identity - Policy (supports readonly)
|
||||
```
|
||||
You must enable access to policies in the GCP cloud console.
|
||||
|
||||
* Login at console.cloud.google.com
|
||||
* In the upper left click the three lines to the left of Google Cloud and select IAM & Admin
|
||||
* Under IAM & Admin select IAM
|
||||
* Click in the box to the right of Google Cloud
|
||||
* Click the three dots at the right and select IAM/Permissions
|
||||
* Now you should be at "Permissions for organization ..."
|
||||
* Click on Grant Access
|
||||
* Enter the GAM project creator address in Principals
|
||||
* Click in the Select a role box
|
||||
* Type orgpolicy.policyAdmin in the Filter box
|
||||
* Click Organization Policy Administrator
|
||||
* Click Save
|
||||
|
||||
## Definitions
|
||||
```
|
||||
|
||||
@@ -144,6 +144,11 @@ Data fields identified in a `csvkmd` argument.
|
||||
<CalendarACLScopeList> | <FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVDataSelector>
|
||||
<CalendarEntity> ::=
|
||||
<CalendarList> | <FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVDataSelector>
|
||||
<ChromeProfileNameEntity> ::=
|
||||
<ChromeProfileNameList> |
|
||||
(select <FileSelector>|<CSVFileSelector>) |
|
||||
(filter <String> (filtertime<String> <Time>)* [orderby <ChromeProfileOrderByFieldName> [ascending|descending]]) |
|
||||
(commands <ChromeProfileCommandNameList>|<FileSelector>|<CSVFileSelector>)
|
||||
<CIPolicyNameEntity> ::=
|
||||
<CIPolicyNameList> | <FileSelector> | <CSVFileSelector>
|
||||
<ClassificationLabelNameEntity> ::=
|
||||
@@ -206,6 +211,7 @@ Data fields identified in a `csvkmd` argument.
|
||||
all_shortcuts |
|
||||
all_3p_shortcuts |
|
||||
all_items |
|
||||
my_commentable_items |
|
||||
my_docs |
|
||||
my_files |
|
||||
my_folders |
|
||||
@@ -231,6 +237,7 @@ Data fields identified in a `csvkmd` argument.
|
||||
others_3p_shortcuts |
|
||||
others_items |
|
||||
writable_files
|
||||
|
||||
<DriveFileEntityShortcut> ::=
|
||||
alldrives |
|
||||
mydrive_any |
|
||||
@@ -246,6 +253,7 @@ Data fields identified in a `csvkmd` argument.
|
||||
sharedwithme_all |
|
||||
sharedwithme_mydrive |
|
||||
sharedwithme_notmydrive
|
||||
|
||||
<DriveFileEntity> ::=
|
||||
<DriveFileIDEntity> |
|
||||
<DriveFileNameEntity> |
|
||||
@@ -343,6 +351,19 @@ Data fields identified in a `csvkmd` argument.
|
||||
<SiteACLScopeList> | <FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVDataSelector>
|
||||
<SiteEntity> ::=
|
||||
<SiteList> | <FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVDataSelector>
|
||||
<StringEntity> ::=
|
||||
<StringList> | <FileSelector> | <CSVFileSelector>
|
||||
<StudentGroupEntity> ::=
|
||||
<StudentGroupIDList> | <FileSelector> | <CSVFileSelector> | <CSVkmdSelector>
|
||||
<TagManagerAccountPathEntity> ::=
|
||||
<TagManagerAccountPathList> |
|
||||
(select <FileSelector>|<CSVFileSelector>) |
|
||||
<TagManagerContainerPathEntity> ::=
|
||||
<TagManagerContainerPathList> |
|
||||
(select <FileSelector>|<CSVFileSelector>) |
|
||||
<TagManagerWorkspacePathEntity> ::=
|
||||
<TagManagerWorkspacePathList> |
|
||||
(select <FileSelector>|<CSVFileSelector>) |
|
||||
<TasklistEntity> ::=
|
||||
<TasklistIDList> | <TaskListTitleList> | <FileSelector> | <CSVFileSelector>
|
||||
<TasklistIDTaskIDEntity> ::=
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Collections of Users
|
||||
- [Python Regular Expressions](Python-Regular-Expressions) Search function
|
||||
- [Notes](#notes)
|
||||
- [Definitions](#definitions)
|
||||
- [User Type Entity](#user-type-entity)
|
||||
- [All non-suspended Users](#all-non-suspended-users)
|
||||
@@ -37,6 +38,37 @@
|
||||
- [Examples using CSV files to print users from groups](#examples-using-CSV-files-to-print-users-from-groups)
|
||||
- [Examples using multiple queries](#examples-using-multiple-queries)
|
||||
|
||||
## Notes
|
||||
|
||||
The followig items referencing non-archived/archived users were added to `<UserTypeEntity>` in version 7.22.00.
|
||||
```
|
||||
all users_na
|
||||
all users_arch
|
||||
all users_na_ns
|
||||
all users_arch_or_susp
|
||||
domains_na
|
||||
domains_arch
|
||||
domains_na_ns
|
||||
groups_na
|
||||
groups_arch
|
||||
groups_na_ns
|
||||
group_users_na
|
||||
group_users_arch
|
||||
group_users_na_ns
|
||||
ou_na
|
||||
ou_arch
|
||||
ou_na_ns
|
||||
ou_and_children_na
|
||||
ou_and_children_arch
|
||||
ou_and_children_na_ns
|
||||
ous_na
|
||||
ous_arch
|
||||
ous_na_ns
|
||||
ous_and_children_na
|
||||
ous_and_children_arch
|
||||
ous_and_children_na_ns
|
||||
```
|
||||
|
||||
## Definitions
|
||||
* [Basic Items](Basic-Items)
|
||||
|
||||
@@ -90,25 +122,25 @@
|
||||
<SharedDriveNameEntity>
|
||||
|
||||
<UserTypeEntity> ::=
|
||||
(all users|users_ns|users_susp|users_ns_susp)|
|
||||
(all users|users_na|users_arch|users_ns|users_susp|users_ns_susp|users_arch_or_susp|users_na_ns)|
|
||||
(user <UserItem>)|
|
||||
(users <UserList>)|
|
||||
(oauthuser)
|
||||
(domains|domains_ns|domains_susp <DomainNameList>)|
|
||||
(group|group_ns|group_susp|group_inde <GroupItem>)|
|
||||
(groups|groups_ns|groups_susp|groups_inde <GroupList>)|
|
||||
(domains|domains_na|domains_arch|domains_ns|domains_susp|domains_na_ns <DomainNameListList>)|
|
||||
(group|group_na|group_arch|group_ns|group_susp|group_na_ns|group_inde <GroupItem>)|
|
||||
(groups|groups_na|groups_arch|groups_ns|groups_susp|groups_na_ns|groups_inde <GroupList>)|
|
||||
(group_inde <GroupItem>)|(groups_inde <GroupList>)|
|
||||
(group_users|group_users_ns|group_users_susp <GroupList>
|
||||
(group_users|group_users_na|group_users_arch|group_users_ns|group_users_susp|group_users_na_ns <GroupList>
|
||||
[members] [managers] [owners]
|
||||
[primarydomain] [domains <DomainNameList>] [recursive|includederivedmembership] end)|
|
||||
(group_users_select <GroupList>
|
||||
[members] [managers] [owners]
|
||||
[notsuspended|suspended] [notarchived|archived]
|
||||
[primarydomain] [domains <DomainNameList>] [recursive|includederivedmembership] end)|
|
||||
(ou|ou_ns|ou_susp <OrgUnitItem>)|
|
||||
(ou_and_children|ou_and_children_ns|ou_and_children_susp <OrgUnitItem>)|
|
||||
(ous|ous_ns|ous_susp <OrgUnitList>)|
|
||||
(ous_and_children|ous_and_children_ns|ous_and_children_susp <OrgUnitList>)|
|
||||
(ou|ou_na|ou_arch|ou_ns|ou_susp|ou_na_ns <OrgUnitItem>)|
|
||||
(ou_and_children|ou_and_children_na|ou_and_children_arch|ou_and_children_ns|ou_and_children_susp|ou_and_children_na_ns <OrgUnitItem>)|
|
||||
(ous|ous_na|ous_arch|ous_ns|ous_susp|ous_na_ns <OrgUnitList>)|
|
||||
(ous_and_children|ous_and_children_na|ous_and_children_arch|ous_and_children_ns|ous_and_children_susp|ous_and_children_na_ns <OrgUnitList>)|
|
||||
(courseparticipants <CourseIDList>)|
|
||||
(students <CourseIDList>)|
|
||||
(teachers <CourseIDList>)|
|
||||
@@ -126,41 +158,47 @@
|
||||
(gdoc(:<FieldName>)+ <UserGoogleDoc>)|
|
||||
(gcscsv(:<FieldName>)+ <StorageBucketObjectName>)|
|
||||
(gcsdoc(:<FieldName>)+ <StorageBucketObjectName>))
|
||||
[warnifnodata] [columndelimiter <Character>] [noescapechar <Boolean>][quotechar <Character>]
|
||||
[warnifnodata] [columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
|
||||
[endcsv|(fields <FieldNameList>)]
|
||||
(matchfield|skipfield <FieldName> <RESearchPattern>)*
|
||||
[delimiter <Character>])|
|
||||
(datafile
|
||||
users|groups|groups_ns|groups_susp|groups_inde|ous|ous_ns|ous_susp|
|
||||
ous_and_children|ous_and_children_ns|ous_and_children_susp|
|
||||
courseparticipants|students|teachers
|
||||
users|
|
||||
groups|groups_na|groups_arch|groups_ns|groups_susp|groups_na_ns|groups_inde|
|
||||
ous|ous_na|ous_arch|ous_ns|ous_susps|ous_na_ns|
|
||||
ous_and_children|ous_and_children_na|ous_and_children_arch|ous_and_children_ns|ous_and_children_susp|ous_and_children_na_ns|
|
||||
courseparticipants|students|teachers
|
||||
((<FileName> [charset <Charset>])|
|
||||
(gdoc <UserGoogleDoc>)|
|
||||
(gcsdoc <StorageBucketObjectName>))
|
||||
[delimiter <Character>])|
|
||||
(csvdatafile
|
||||
users|groups|groups_ns|groups_susp|groups_inde|ous|ous_ns|ous_susp|
|
||||
ous_and_children|ous_and_children_ns|ous_and_children_susp|
|
||||
courseparticipants|students|teachers
|
||||
users|
|
||||
groups|groups_na|groups_arch|groups_ns|groups_susp|groups_na_ns|groups_inde|
|
||||
ous|ous_na|ous_arch|ous_ns|ous_susps|ous_na_ns|
|
||||
ous_and_children|ous_and_children_na|ous_and_children_arch|ous_and_children_ns|ous_and_children_susp|ous_and_children_na_ns|
|
||||
courseparticipants|students|teachers
|
||||
((<FileName>(:<FieldName>)+ [charset <Charset>] )|
|
||||
(gsheet(:<FieldName>)+ <UserGoogleSheet>)|
|
||||
(gdoc(:<FieldName>)+ <UserGoogleDoc>)|
|
||||
(gcscsv(:<FieldName>)+ <StorageBucketObjectName>)|
|
||||
(gcsdoc(:<FieldName>)+ <StorageBucketObjectName>))
|
||||
[warnifnodata] [columndelimiter <Character>] [noescapechar <Boolean>][quotechar <Character>]
|
||||
[warnifnodata] [columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
|
||||
[endcsv|(fields <FieldNameList>)]
|
||||
(matchfield|skipfield <FieldName> <RESearchPattern>)*
|
||||
[delimiter <Character>])|
|
||||
(csvkmd
|
||||
users|groups|groups_ns|groups_susp|groups_inde|ous|ous_ns|ous_susp|
|
||||
ous_and_children|ous_and_children_ns|ous_and_children_susp|
|
||||
courseparticipants|students|teachers
|
||||
users|
|
||||
groups|groups_na|groups_arch|groups_ns|groups_susp|groups_na_ns|groups_inde|
|
||||
ous|ous_na|ous_arch|ous_ns|ous_susps|ous_na_ns|
|
||||
ous_and_children|ous_and_children_na|ous_and_children_arch|ous_and_children_ns|ous_and_children_susp|ous_and_children_na_ns|
|
||||
courseparticipants|students|teachers
|
||||
((<FileName>|
|
||||
(gsheet <UserGoogleSheet>)|
|
||||
(gdoc <UserGoogleDoc>)|
|
||||
(gcscsv <StorageBucketObjectName>)|
|
||||
(gcsdoc <StorageBucketObjectName>))
|
||||
[charset <Charset>] [columndelimiter <Character>] [noescapechar <Boolean>][quotechar <Character>] [fields <FieldNameList>])
|
||||
[charset <Charset>] [columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>] [fields <FieldNameList>])
|
||||
keyfield <FieldName> [keypattern <RESearchPattern>] [keyvalue <RESubstitution>] [delimiter <Character>]
|
||||
subkeyfield <FieldName> [keypattern <RESearchPattern>] [keyvalue <RESubstitution>] [delimiter <Character>]
|
||||
(matchfield|skipfield <FieldName> <RESearchPattern>)*
|
||||
@@ -172,6 +210,12 @@
|
||||
|
||||
Use these options to select users for GAM commands.
|
||||
|
||||
## All non-archived Users
|
||||
* `all users_na`
|
||||
|
||||
## All archived Users
|
||||
* `all users_arch`
|
||||
|
||||
## All non-suspended Users
|
||||
* `all users`
|
||||
* `all users_ns`
|
||||
@@ -179,6 +223,12 @@ Use these options to select users for GAM commands.
|
||||
## All suspended Users
|
||||
* `all users_susp`
|
||||
|
||||
## All archived or suspended Users
|
||||
* `all users_arch_or_susp`
|
||||
|
||||
## All non-archived and non-suspended Users
|
||||
* `all users_na_ns`
|
||||
|
||||
## All non-suspended and suspended Users
|
||||
* `all users_ns_susp`
|
||||
|
||||
@@ -192,22 +242,31 @@ Use these options to select users for GAM commands.
|
||||
* `oauthuser`
|
||||
|
||||
## Users in the domains `<DomainNameList>`
|
||||
* `domains|domains_ns|domains_susp <DomainNameList>`
|
||||
* `domains|domains_na|domains_arch|domains_ns|domains_susp|domains_na_ns <DomainNameList>`
|
||||
* `domains` - All users
|
||||
* `domains_na` - Non-archived users
|
||||
* `domains_arch` - Archived users
|
||||
* `domains_ns` - Non-suspended users
|
||||
* `domains_susp` - Suspended users
|
||||
* `domains_na_ns` - Non-archived and non-suspended users
|
||||
|
||||
## Users directly in the group `<GroupItem>`
|
||||
* `group|group_ns|group_susp <GroupItem>`
|
||||
* `group|group_na|group_arch|group_ns|group_susp|group_na_ns <GroupItem>`
|
||||
* `group` - All user members
|
||||
* `group_na` - Non-archived user members
|
||||
* `group_arch` - Archived user members
|
||||
* `group_ns` - Non-suspended user members
|
||||
* `group_susp` - Suspended user members
|
||||
* `group_na_ns` - Non-archived and non-suspended user members
|
||||
|
||||
## Users directly in the groups `<GroupList>`
|
||||
* `groups|groups_ns|groups_susp <GroupList>`
|
||||
* `groups|groups_na|groups_arch|groups_ns|groups_susp|groups_na_ns <GroupList>`
|
||||
* `groups` - All user members
|
||||
* `groups_na` - Non-archived user members
|
||||
* `groups_arch` - Archived user members
|
||||
* `groups_ns` - Non-suspended user members
|
||||
* `groups_susp` - Suspended user members
|
||||
* `groups_na_ns` - Non-archived and non-suspended user members
|
||||
|
||||
## Users directly and indirectly in the group `<GroupItem>`
|
||||
* `group_inde` - All user members including those from all subgroups
|
||||
@@ -216,10 +275,13 @@ Use these options to select users for GAM commands.
|
||||
* `groups_inde` - All user members including those from all subgroups
|
||||
|
||||
## Selected Users from groups
|
||||
* `group_users|group_users_ns|group_users_susp <GroupList> [members] [managers] [owners] [primarydomain] [domains <DomainNameList>] [recursive|includederivedmembership] end`
|
||||
* `group_users|group_users_na|group_users_arch|group_users_ns|group_users_susp|group_users_na_ns <GroupList> [members] [managers] [owners] [primarydomain] [domains <DomainNameList>] [recursive|includederivedmembership] end`
|
||||
* `group_users` - All user members
|
||||
* `group_users_na` - Non-archived user members
|
||||
* `group_users_arch` - Archived user members
|
||||
* `group_users_ns` - Non-suspended user members
|
||||
* `group_users_susp` - Suspended user members
|
||||
* `group_users_na_ns` - Non-archived and non-suspended user members
|
||||
* `[members] [managers] [owners]` - The desired roles; if roles are not specified, all roles are included
|
||||
* `primarydomain` - Select Users from the primary domain
|
||||
* `domains <DomainNameList>` - Select Users from the list of domains
|
||||
@@ -259,30 +321,41 @@ Use these options to select users for GAM commands.
|
||||
* `end` - Terminate the selection
|
||||
|
||||
## Users directly in the Organization Unit `<OrgUnitItem>`
|
||||
* `ou|ou_ns|ou_susp <OrgUnitItem>`
|
||||
* `ou|ou_na|ou_arch|ou_ns|ou_susp|ou_na_ns <OrgUnitItem>`
|
||||
* `ou` - All users
|
||||
* `ou_ns` - Non-Suspended users
|
||||
* `ou_na` - Non-archived users
|
||||
* `ou_arch` - Archived users
|
||||
* `ou_ns` - Non-suspended users
|
||||
* `ou_susp` - Suspended users
|
||||
* `ou_na_ns` - Non-archived and nn-suspended users
|
||||
|
||||
## Users in the Organization Unit `<OrgUnitItem>` and all of its sub Organization Units
|
||||
* `ou_and_children|ou_and_children_ns|ou_and_children_susp <OrgUnitItem>`
|
||||
* `ou_and_children|ou_and_children_na|ou_and_children_arch|ou_and_children_ns|ou_and_children_susp|ou_and_children_na_ns <OrgUnitItem>`
|
||||
* `ou_and_children` - All users
|
||||
* `ou_and_children_na` - Non-archived users
|
||||
* `ou_and_children_arch` - Archived users
|
||||
* `ou_and_children_ns` - Non-suspended users
|
||||
* `ou_and_children_susp` - Suspended users
|
||||
* `ou_and_children_na_ns` - Non-archived and nn-suspended users
|
||||
|
||||
## Users directly in the Organization Units `<OrgUnitList>`
|
||||
* `ous|ous_ns|ous_susp <OrgUnitList>` - Users directly in the Organization Units `<OrgUnitList>`
|
||||
* `ous|ous_na|ous_arch|ous_ns|ous_susp|ous_na_ns <OrgUnitList>` - Users directly in the Organization Units `<OrgUnitList>`
|
||||
* `ous` - All users
|
||||
* `ous_na` - Non-archived users
|
||||
* `ous_arch` - Archived users
|
||||
* `ous_ns` - Non-suspended users
|
||||
* `ous_susp` - Suspended users
|
||||
* `ous_na_ns` - Non-archived and nn-suspended users
|
||||
|
||||
`<OrgUnitList>` may require special quoting based on whether the OUs contain spaces, commas or single quotes.
|
||||
|
||||
For quoting rules, see: [List Quoting Rules](Command-Line-Parsing)
|
||||
|
||||
## Users in the Organization Units `<OrgUnitList>` and all of their sub Organization Units
|
||||
* `ous_and_children|ous_and_children_ns|ous_and_children_susp <OrgUnitList>` - Users in the Organization Units `<OrgUnitList>` and all of their sub Organization Units
|
||||
* `ous_and_children|ous_and_children_na|ous_and_children_arch|ous_and_children_ns|ous_and_children_susp|ous_and_children_na_ns <OrgUnitList>` - Users in the Organization Units `<OrgUnitList>` and all of their sub Organization Units
|
||||
* `ous_and_children` - All users
|
||||
* `ous_and_children_na` - Non-archived users
|
||||
* `ous_and_children_arch` - Archived users
|
||||
* `ous_and_children_ns` - Non-suspended users
|
||||
* `ous_and_children_susp` - Suspended users
|
||||
|
||||
@@ -363,15 +436,21 @@ csvfile
|
||||
## Users from groups/OUs/courses in a flat file/Google Doc/Google Cloud Storage Object
|
||||
```
|
||||
datafile
|
||||
users|groups|groups_ns|groups_susp|groups_inde|ous|ous_ns|ous_susp|
|
||||
ous_and_children|ous_and_children_ns|ous_and_children_susp|
|
||||
courseparticipants|students|teachers
|
||||
users|
|
||||
groups|groups_na|groups_arch|groups_ns|groups_susp|groups_na_ns|groups_inde|
|
||||
ous|ous_na|ous_arch|ous_ns|ous_susp|ous_na_ns|
|
||||
ous_and_children|ous_and_children_na|ous_and_children_arch|ous_and_children_ns|ous_and_children_susp|ous_and_children_na_ns|
|
||||
courseparticipants|students|teachers
|
||||
((<FileName> [charset <Charset>])|
|
||||
(gdoc <UserGoogleDoc>)|
|
||||
(gcsdoc <StorageBucketObjectName>))
|
||||
[delimiter <Character>]
|
||||
```
|
||||
* `users|groups|groups_ns|groups_susp|groups_inde|ous|ous_ns|ous_susp|ous_and_children|ous_and_children_ns|ous_and_children_susp|courseparticipants|students|teachers` - The type of item in the file
|
||||
* `users|`
|
||||
* `groups|groups_na|groups_arch|groups_ns_|groups_susp|groups_na_ns|groups_inde|`
|
||||
* `ous|ous_na|ous_arch|ous_ns|ous_susp|ous_na_ns|`
|
||||
* `ous_and_children|ous_and_children_na|ous_and_children_arch|ous_and_children_ns|ous_and_children_susp|ous_and_children_na_ns|`
|
||||
* `courseparticipants|students|teachers` - The type of item in the file
|
||||
* `<FileName>` - A flat file containing rows of the type of item specified
|
||||
* `charset <Charset>` - The character aset of the file if it isn't UTF-8
|
||||
* `gdoc <UserGoogleDoc>` - A Google Doc containing rows of the type of item specified
|
||||
@@ -381,9 +460,11 @@ datafile
|
||||
## Users from groups/OUs/courses in a CSV file/Google Sheet/Google Doc/Google Cloud Storage Object
|
||||
```
|
||||
csvdatafile
|
||||
users|groups|groups_ns|groups_susp|groups_inde|ous|ous_ns|ous_susp|
|
||||
ous_and_children|ous_and_children_ns|ous_and_children_susp|
|
||||
courseparticipants|students|teachers
|
||||
users|
|
||||
groups|groups_na|groups_arch|groups_ns|groups_susp|groups_na_ns|groups_inde|
|
||||
ous|ous_na|ous_arch|ous_ns|ous_susp|ous_na_ns|
|
||||
ous_and_children|ous_and_children_na|ous_and_children_arch|ous_and_children_ns|ous_and_children_susp|ous_and_children_na_ns|
|
||||
courseparticipants|students|teachers
|
||||
((<FileName>(:<FieldName>)+ [charset <Charset>] )|
|
||||
(gsheet(:<FieldName>)+ <UserGoogleSheet>)|
|
||||
(gdoc(:<FieldName>)+ <UserGoogleDoc>)|
|
||||
@@ -394,9 +475,13 @@ csvdatafile
|
||||
(matchfield|skipfield <FieldName> <RESearchPattern>)*
|
||||
[delimiter <Character>]
|
||||
```
|
||||
* `users|groups|groups_ns|groups_susp|groups_inde|ous|ous_ns|ous_susp|ous_and_children|ous_and_children_ns|ous_and_children_susp|courseparticipants|students|teachers` - The type of item in the file
|
||||
* `users|`
|
||||
* `groups|groups_na|groups_arch|groups_ns_|groups_susp|groups_na_ns|groups_inde|`
|
||||
* `ous|ous_na|ous_arch|ous_ns|ous_susp|ous_na_ns|`
|
||||
* `ous_and_children|ous_and_children_na|ous_and_children_arch|ous_and_children_ns|ous_and_children_susp|ous_and_children_na_ns|`
|
||||
* `courseparticipants|students|teachers` - The type of item in the file
|
||||
* `<FileName>(:<FieldName>)+` - A CSV file and the one or more columns contain the type of item specified
|
||||
* `charset <Charset>` - The character aset of the file if it isn't UTF-8
|
||||
* `charset <Charset>` - The character set of the file if it isn't UTF-8
|
||||
* `gsheet(:<FieldName>)+ <UserGoogleSheet>` - A Google Sheet and the one or more columns contain the type of item specified
|
||||
* `gdoc(:<FieldName>)+ <UserGoogleDoc>` - A Google Doc and the one or more columns contain the type of item specified
|
||||
* `gcscsv(:<FieldName>)+ <StorageBucketObjectName>` - A Google Cloud Storage Bucket Object and the one or more columns contain the type of item specified
|
||||
@@ -413,9 +498,11 @@ csvdatafile
|
||||
## Users directly in or from groups/OUs/courses in a CSV file/Google Sheet/Google Doc/Google Cloud Storage Object
|
||||
```
|
||||
csvkmd
|
||||
users|groups|groups_ns|groups_susp|groups_inde|ous|ous_ns|ous_susp|
|
||||
ous_and_children|ous_and_children_ns|ous_and_children_susp|
|
||||
courseparticipants|students|teachers
|
||||
users|
|
||||
groups|groups_na|groups_arch|groups_ns|groups_susp|groups_na_ns|groups_inde|
|
||||
ous|ous_na|ous_arch|ous_ns|ous_susp|ous_na_ns|
|
||||
ous_and_children|ous_and_children_na|ous_and_children_arch|ous_and_children_ns|ous_and_children_susp|ous_and_children_na_ns|
|
||||
courseparticipants|students|teachers
|
||||
((<FileName>|
|
||||
(gsheet <UserGoogleSheet>)|
|
||||
(gdoc <UserGoogleDoc>)|
|
||||
@@ -427,9 +514,13 @@ csvkmd
|
||||
(matchfield|skipfield <FieldName> <RESearchPattern>)*
|
||||
[datafield <FieldName>(:<FieldName>)* [delimiter <Character>]]
|
||||
```
|
||||
* `users|groups|groups_ns_|groups_susp|groups_inde|ous|ous_ns|ous_susp|ous_and_children|ous_and_children_ns|ous_and_children_susp|courseparticipants|students|teachers` - The type of item in the file
|
||||
* `users|`
|
||||
* `groups|groups_na|groups_arch|groups_ns_|groups_susp|groups_na_ns|groups_inde|`
|
||||
* `ous|ous_na|ous_arch|ous_ns|ous_susp|ous_na_ns|`
|
||||
* `ous_and_children|ous_and_children_na|ous_and_children_arch|ous_and_children_ns|ous_and_children_susp|ous_and_children_na_ns|`
|
||||
* `courseparticipants|students|teachers` - The type of item in the file
|
||||
* `<FileName>` - A CSV file containing rows with columns of the type of item specified
|
||||
* `charset <Charset>` - The character aset of the file if it isn't UTF-8
|
||||
* `charset <Charset>` - The character set of the file if it isn't UTF-8
|
||||
* `gsheet <UserGoogleSheet>` - A Google Sheet containing rows with columns of the type of item specified
|
||||
* `gdoc <UserGoogleDoc>` - A Google Doc containing rows with columns of the type of item specified
|
||||
* `gcscsv <StorageBucketObjectName>` - A Google Cloud Storage Bucket Object with columns of the type of item specified
|
||||
|
||||
@@ -308,12 +308,3 @@ the quote character itself, the column delimiter (comma by default) and new-line
|
||||
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.
|
||||
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
|
||||
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
|
||||
|
||||
## Display global address list
|
||||
As of mid-October 2024, Google deprecated the API that retrieved the Global Address List.
|
||||
|
||||
These commands are a work-around.
|
||||
```
|
||||
gam config csv_output_row_filter "includeInGlobalAddressList:boolean:true" redirect csv ./UserGAL.csv print users fields name,gal
|
||||
gam config csv_output_row_filter "includeInGlobalAddressList:boolean:true" batch_size 25 redirect csv ./GroupGAL.csv print groups fields name,gal
|
||||
```
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
!All Google Drive API calls have been converted from v2 to v3, see: https://developers.google.com/drive/v3/web/migration
|
||||
Many of the changes are internal to Gam and have no visible effect. Google has modified/renamed many field names and these will affect scripts that parse the output from `gam print/show drivesettings/drivefileacls/fileinfo/filelist/filerevisions`. Additionally, Google has dropped some fields and their values are no longer available. On input, Gam accepts both the old and new field names.
|
||||
Legacy GAM used Drive API v2, GAM7 uses Drive API v3. See: https://developers.google.com/drive/v3/web/migration
|
||||
Many of the changes are internal to GAM7 and have no visible effect.
|
||||
Google has modified/renamed many field names and these will affect scripts that parse the output from `gam print/show drivesettings/drivefileacls/fileinfo/filelist/filerevisions`.
|
||||
Additionally, Google has dropped some fields and their values are no longer available. On input, GAM7 accepts both the old and new field names where applicable.
|
||||
|
||||
A variable, `drive_v3_native_names` (default value is True), has been added to `gam.cfg` to control the field names on output: when True, the v3 native field names are used; when False, the v3 native field names are mapped to the v2 field names.
|
||||
|
||||
If you have scripts that process the output from these print commands, you may have to make modifications to your scripts.
|
||||
Run your print/show commands with a version of Legacy Gam and save the output.
|
||||
With drive_v3_native_names = False, run your print/show commands with this version of Gam and compare the output to that saved in the previous run;
|
||||
If you use Legacy GAM and have scripts that process the output from these print commands, you may have to make modifications to your scripts when you upgrade to GAM7.
|
||||
Run your print/show commands with a version of Legacy GAM and save the output.
|
||||
Run your print/show commands with GAM7 and compare the output to that saved in the previous run;
|
||||
modify your scripts that process the output as appropriate.
|
||||
|
||||
There is a cost to mapping the v3 field names back to the v2 field names; you can avoid this cost by setting drive_v3_native_names = True,
|
||||
running your print/show commands, comparing the output and making the appropriate script modifications.
|
||||
```
|
||||
print/show drivesettings
|
||||
Dropped fields:
|
||||
@@ -30,7 +28,7 @@ Dropped fields:
|
||||
authKey
|
||||
Renamed fields (Old->New):
|
||||
name->displayName
|
||||
withLink->allowFileDiscovery
|
||||
withLink->allowFileDiscovery - value is complemented
|
||||
|
||||
print/show fileinfo/filelist
|
||||
Dropped fields:
|
||||
@@ -40,19 +38,20 @@ Dropped fields:
|
||||
labels(hidden)
|
||||
markedViewedByMeDate
|
||||
openWithLinks
|
||||
selfLink
|
||||
ownerNames
|
||||
parents(isRoot)
|
||||
parents(parentLink)
|
||||
parents(selfLink)
|
||||
permissions(selfLink)
|
||||
selfLink
|
||||
userPermission(selfLink)
|
||||
userPermission
|
||||
Renamed fields (Old->New):
|
||||
alternateLink->webViewLink
|
||||
capabilities(canChangeRestrictedDownload)->capabilities(canChangeViewersCanCopyContent)
|
||||
createdDate->createdTime
|
||||
expirationDate->expirationTime
|
||||
fileSize->size
|
||||
lastModifyingUserName->lastModifyingUser(displayName)
|
||||
lastViewedByMeDate->viewedByMeTime
|
||||
modified->modifiedByMe
|
||||
modifiedByMeDate->modifiedByMeTime
|
||||
@@ -76,18 +75,3 @@ Renamed fields (Old->New):
|
||||
picture.url->photoLink
|
||||
pinned->keepForever
|
||||
```
|
||||
The parents field of a file has undergone the most change. In Drive v2 it was a list of compound items with three sub-fields per item: id, isRoot, parentLink.
|
||||
In Drive v3 the parents field is a list of simple items, the parent ids. The following examples show how the parents field is output in a CSV file for a file with two parents.
|
||||
```
|
||||
Previous versions of Gam:
|
||||
Owner,title,parents,parents.0.isRoot,parents.0.id,parents.0.parentLink,parents.1.isRoot,parents.1.id,parents.1.parentLink
|
||||
testuser@domain.com,TestFile,2,True,PPPP1111,https://www.googleapis.com/drive/v2/files/PPPP1111,False,PPPP2222,https://www.googleapis.com/drive/v2/files/PPPP2222
|
||||
|
||||
Current version of Gam with drive_v3_name_names = false
|
||||
Owner,title,parents,parents.0.id,parents.1.id
|
||||
testuser@domain.com,TestFile,2,PPPP1111,PPPP2222
|
||||
|
||||
Current version of Gam with drive_v3_name_names = true
|
||||
Owner,name,parents
|
||||
testuser@domain.com,TestFile,PPPP1111 PPPP2222
|
||||
```
|
||||
|
||||
21
wiki/GAM-Release-Process.md
Normal file
21
wiki/GAM-Release-Process.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Steps to release a new GAM version
|
||||
1. In a final commit before release:
|
||||
- [src/gam/__init.py](https://github.com/GAM-team/GAM/blob/main/src/gam/__init__.py) `__version___` value should be updated to the new version.
|
||||
- [src/GamUpdate.txt](https://github.com/GAM-team/GAM/blob/main/src/GamUpdate.txt) should be updated with a high-level changelog.
|
||||
- [wiki/GamUpdates.md](https://github.com/GAM-team/GAM/blob/main/wiki/GamUpdates.md) should be updated with same high-level changelog.
|
||||
- [wiki/Version-and-Help.md](https://github.com/GAM-team/GAM/blob/main/wiki/Version-and-Help.md) should be updated with current version N.NN.NN
|
||||
- [wiki/How-to-Upgrade-Legacy-GAM-to-GAM7.md](https://github.com/GAM-team/GAM/blob/main/wiki/How-to-Upgrade-Legacy-GAM-to-GAM7.md) should be updated with current version N.NN.NN
|
||||
2. The [build.yaml](https://github.com/GAM-team/GAM/blob/main/.github/workflows/build.yml) Github Action for final commit should complete successfully and creating a new dated Draft release.
|
||||
- We should *NEVER* upload release files manually. Only release files automatically created and [attested](https://github.com/GAM-team/GAM/wiki/Verifying-a-GAM7-Build-is-Legitimate-and-Official#github-attestation-linuxmacoswindows) as created by the Github Action should be used.
|
||||
3. Edit the Draft release:
|
||||
- Create a new tag with the format: `vN.NN.NN` where N.NN.NN is the GAM release version.
|
||||
- name the release "GAM N.NN.NN" where N.NN.NN is the GAM release version.
|
||||
- Include the changelog details for the new version in details.
|
||||
- leave "Set as pre-release" unchecked and "Set as the latest release" checked.
|
||||
- Publish the release.
|
||||
|
||||
# TODO: Release Process Improvements
|
||||
- copying changelog between GamUpdate.txt, GamUpdates.md and release description is manual and tedious. Automate it.
|
||||
- copying version string from gam/__init__.py, changelogs and release details and tag in manual and tedious. Automate it.
|
||||
- See if we can block releases with binaries not uploaded by GitHub Actions to further secure release pipelines.
|
||||
|
||||
@@ -33,6 +33,7 @@ ENTITY_IS_A_GROUP_RC = 22
|
||||
ENTITY_IS_A_GROUP_ALIAS_RC = 23
|
||||
ENTITY_IS_AN_UNMANAGED_ACCOUNT_RC = 24
|
||||
ORGUNIT_NOT_EMPTY_RC = 25
|
||||
USER_SUSPENDED_RC = 26
|
||||
CHECK_USER_GROUPS_ERROR_RC = 29
|
||||
ORPHANS_COLLECTED_RC = 30
|
||||
# Warnings/Errors
|
||||
|
||||
@@ -15,7 +15,7 @@ The 27ft RV Jay drove his family to Niagara Falls this summer. They’re all sti
|
||||
some in full sentences 🙂
|
||||
|
||||
# Has something changed with Ross?
|
||||
He’s just older, 75 and counting.
|
||||
He’s just older, 76 and counting.
|
||||
|
||||
(Jay here, this is all I could get from Ross but he’s his usual awesome self helping admins in Chat and Groups forums as I write this and adding new features. Because some have asked, Ross is a real person. He is not an Advanced GenAI as rumours have claimed. 🙂)
|
||||
|
||||
@@ -49,8 +49,8 @@ Both GAM7 and GAM-ADV versions use the same configuration file (gam.cfg), and cr
|
||||
# Help!!! Something went wrong!
|
||||
Well that’s not really a question but as ever, please reach out to either the GAM email support group:
|
||||
|
||||
[git.io/gam-group](http://git.io/gam-group)
|
||||
[GAM Discussion Forum](https://groups.google.com/forum/#!forum/google-apps-manager)
|
||||
|
||||
Or the Google Chat Space:
|
||||
|
||||
[git.io/gam-chat](http://git.io/gam-chat)
|
||||
[GAM Public Chat Room](GAM-Public-Chat-Room)
|
||||
@@ -10,6 +10,550 @@ 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.22.07
|
||||
|
||||
Added options `showdetails` and `returnidonly` to `gam create|copy vaultquery`.
|
||||
|
||||
Added option `<JSONData>` to `gam create vaultexport|vaultquery and `gam print vaultcounts``.
|
||||
|
||||
### 7.22.06
|
||||
|
||||
Added commands to create, copy and delete Vault saved queries.
|
||||
```
|
||||
gam create vaultquery <MatterItem> [name <String>]
|
||||
corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
|
||||
[scope all_data|held_data|unprocessed_data]
|
||||
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
(documentids (<DriveFileIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
(shareddrives|teamdrives (<SharedDriveIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
[(includeshareddrives <Boolean>)|(shareddrivesoption included|included_if_account_is_not_a_member|not_included)]
|
||||
(sitesurl (<URLList>||(select <FileSelector>|<CSVFileSelector>)))
|
||||
[driveversiondate <Date>|<Time>]
|
||||
[includerooms <Boolean>]
|
||||
(rooms (<ChatSpaceList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
|
||||
[locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
|
||||
[responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
|
||||
(covereddata calllogs|textmessages|voicemails)*
|
||||
[shownames] [formatjson]
|
||||
|
||||
gam copy vaultquery <MatterItem> <QueryItem> [targetmatter <MatterItem"] [name <String>]
|
||||
[shownames] [formatjson]
|
||||
|
||||
gam delete vaultquery <QueryItem> matter <MatterItem>
|
||||
gam delete vaultquery <MatterItem> <QueryItem>
|
||||
```
|
||||
|
||||
Added a variant of `gam print vaultcounts` that gets its query parameters from a saved Vault query.
|
||||
```
|
||||
gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
matter <MatterItem> <QueryItem>
|
||||
[wait <Integer>]
|
||||
```
|
||||
|
||||
### 7.22.05
|
||||
|
||||
Added a variant of `gam create vaultexport` that gets its query parameters from a saved Vault query.
|
||||
|
||||
```
|
||||
gam create vaultexport|export matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[driveclientsideencryption any|encrypted|unencrypted]
|
||||
[includeaccessinfo <Boolean>]
|
||||
[excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
|
||||
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
[format ics|mbox|pst|xml]
|
||||
[region any|europe|us] [showdetails|returnidonly]
|
||||
```
|
||||
|
||||
### 7.22.04
|
||||
|
||||
Added a variant of `gam create vaulthold` that gets its parameters from a saved Vault query.
|
||||
```
|
||||
gam create vaulthold matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[showdetails|returnidonly]
|
||||
```
|
||||
|
||||
### 7.22.03
|
||||
|
||||
Fix backwards compatability bug introduced in 7.22.00 for `gam print users` that changed `suspended`
|
||||
from a field name to a query option; it is now correctly interpreted as a field name.
|
||||
|
||||
### 7.22.02
|
||||
|
||||
An update to the httplib2 library caused GAM proxy connections to fail; this has been fixed
|
||||
by including the pysocks library needed by the latest httplib2 library.
|
||||
|
||||
### 7.22.00
|
||||
|
||||
Expanded `<UserTypeEntity>` to allow specification of non-archived/archived users.
|
||||
* See [Collections of Users](Collections-of-Users)
|
||||
|
||||
These commands have also been updated to deal with archived users:
|
||||
* `gam print aliases`
|
||||
* `gam update groups`
|
||||
* `gam info orgs`
|
||||
* `gam print orgs`
|
||||
* `gam print users`
|
||||
|
||||
Added `datetime <DateTimeFormat>` command that can be embedded in Gam batch files.
|
||||
The current time is formatted with `<DateTimeFormat>` and subsequent lines in `<BatchContent>`
|
||||
will have `%datetime%` replaced with the formatted time value.
|
||||
|
||||
See: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes
|
||||
|
||||
### 7.21.03
|
||||
|
||||
Added option `notifyrecoveryemail` to `gam create user` and `gam <UserTypeEntity> update user password <String>`
|
||||
that sends the passsword notification email to the user's recovery email address (if defined).
|
||||
|
||||
### 7.21.02
|
||||
|
||||
GAM now builds on macOS 26 Tahoe and properly identifies the OS.
|
||||
|
||||
A custom build of the cryptography library is no longer needed for Windows arm64 builds as the project now releases their own build for the OS.
|
||||
|
||||
Upgrade to OpenSSL 3.5.3 latest
|
||||
|
||||
### 7.21.01
|
||||
|
||||
Replaced datetime, dateutil, calendar and iso8601 Python libraries with arrow library.
|
||||
This should have no performance impact; report any problems.
|
||||
|
||||
You can now use timezone names when setting `timezone` in `gam.cfg`.
|
||||
* See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||
```
|
||||
gam config timezone America/Los_Angeles save
|
||||
```
|
||||
|
||||
### 7.20.04
|
||||
|
||||
Cleaned up Python library imports: googleapiclient, iso8601
|
||||
|
||||
### 7.20.03
|
||||
|
||||
Rebranded license SKU `1010470004` from `Gemini Education` to `Google AI Pro for Education`.
|
||||
|
||||
Additional updates to student groups in Google Classroom.
|
||||
|
||||
### 7.20.02
|
||||
|
||||
Upgraded `gam create course-studentgroups` to allow specification of multiple student group titles;
|
||||
multiple student groups can be created in a single command.
|
||||
* `((title <String>)|(select <StringEntity))+`
|
||||
|
||||
### 7.20.01
|
||||
|
||||
Added option `showaccesssettings` to `gam [<UserTypeEntity>] print|show chatspaces`. When listing
|
||||
Chat Spaces, the Chat API does not return the `accessSettings` field; if you need to see this field,
|
||||
add `showaccesssettings` to the command. This requires an additional Chat API call per chat space of type `SPACE`
|
||||
to get the `accessSettings` field.
|
||||
|
||||
### 7.20.00
|
||||
|
||||
Added initial support for student groups in Google Classroom. This is a work in progress and requires Developer Preview membership.
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Classroom-StudentGroups#notes
|
||||
|
||||
### 7.19.03
|
||||
|
||||
Fixed bug where specifying a `<UserItem>` as `id:1234567890` could lead to errors like this:
|
||||
```
|
||||
ERROR: 400: invalidArgument - Resource name has invalid email.
|
||||
```
|
||||
|
||||
### 7.19.02
|
||||
|
||||
Update `gam info user <UserItem>` to eliminate 5 second delay when getting license info.
|
||||
|
||||
Additional information:
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Licenses#info-user-performance
|
||||
|
||||
### 7.19.01
|
||||
|
||||
Updated `gam <UserTypeEntity> print|show signature` to handle the following error
|
||||
that occurs when an alias is specified.
|
||||
```
|
||||
ERROR: 404: notFound - Requested entity was not found.
|
||||
```
|
||||
|
||||
### 7.19.00
|
||||
|
||||
Eliminated `drive_v3_beta` and `meet_v2_beta` from `gam.cfg` as the API betas are no longer used.
|
||||
|
||||
Updated `Meet API` scopes so that GAM can read metadata about additional Meet spaces.
|
||||
```
|
||||
[*] 34) Meet API - Manage/Display Meeting Spaces
|
||||
[*] 35) Meet API - Read Meeting Spaces metadata
|
||||
```
|
||||
|
||||
### 7.18.07
|
||||
|
||||
Updated `gam <UserTypeEntity> print drivelastmodification` to put `addcsvdata` columns
|
||||
after `User,id,name` rather than after the last column.
|
||||
|
||||
### 7.18.06
|
||||
|
||||
Updated `gam <UserTypeEntity> delete|modify messages` to improve the handling
|
||||
of the following error.
|
||||
```
|
||||
quotaExceeded - User-rate limit exceeded
|
||||
```
|
||||
|
||||
### 7.18.05
|
||||
|
||||
Added support for Inbound SSO OIDC profiles.
|
||||
|
||||
Currently, if you enter `gam select <SectionName>` and nothing else on the command line,
|
||||
GAM performs no action. Now, it will be treated as if you entered:
|
||||
`gam select <SectionName> save`
|
||||
|
||||
Updated to Python 3.13.7.
|
||||
|
||||
### 7.18.04
|
||||
|
||||
Added commands to display/manage Alert Center Pub/Sub notifications.
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Alert-Center#configuring-settings
|
||||
|
||||
### 7.18.03
|
||||
|
||||
Updated `gam oauth create` to give a warning if the number of selected scopes will
|
||||
probably cause Google to generate a "Something went wrong" error.
|
||||
|
||||
### 7.18.02
|
||||
|
||||
Upgraded to OpenSSL 3.5.2.
|
||||
|
||||
### 7.18.01
|
||||
|
||||
Added option `nosystemroles` to `gam print|show adminroles` that causes GAM
|
||||
to only display non-system roles.
|
||||
|
||||
Added option `formatjson` to `gam info|print|show adminroles`; this will be most useful
|
||||
when the `privileges` option is used.
|
||||
|
||||
Updated `gam create|update adminrole` to allow specification of privileges with
|
||||
JSON data: `privileges <JSONData>`. These two updates make it easier to copy admin roles.
|
||||
|
||||
Updated `gam create|update adminrole` to allow output of the created/updated
|
||||
role data in CSV format; by default, GAM displays `<RoleName>(<RoleID>) created|updated`.
|
||||
```
|
||||
csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]] (addcsvdata <FieldName> <String>)*
|
||||
```
|
||||
|
||||
### 7.18.00
|
||||
|
||||
Added commands to display Business Profile Accounts.
|
||||
These are special purpose commands and will not generally be used.
|
||||
```
|
||||
gam show businessprofileaccounts
|
||||
gam print businessprofileaccounts [todrive <ToDriveAttribute>*]
|
||||
```
|
||||
|
||||
### 7.17.03
|
||||
|
||||
Fixed bug in `gam <UserItem> print|show chatspaces asadmin fields <ChatSpaceFieldNameList>` that caused a trap
|
||||
when `displayname` was not in `<ChatSpaceFieldNameList>`.
|
||||
|
||||
### 7.17.02
|
||||
|
||||
Updated `gam <UserTypeEntity> print|show webmastersites` to handle the following error
|
||||
that occurs if you haven't updated your project to include the Google Search Console API.
|
||||
```
|
||||
ERROR: 403: permissionDenied - Google Search Console API has not been used in project 111055363999 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/searchconsole.googleapis.com/overview?project=111055363999 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
|
||||
```
|
||||
|
||||
### 7.17.01
|
||||
|
||||
Fixed bug in `gam <UserTypeEntity> show webmastersites` that caused a trap.
|
||||
|
||||
### 7.17.00
|
||||
|
||||
Added commands to discover Sites and WebResources that managed users (previously unmanaged) may have access to for better governance and visibility.
|
||||
These are special purpose commands and will not generally be used.
|
||||
```
|
||||
gam <UserTypeEntity> show webresources
|
||||
gam <UserTypeEntity> print webresources [todrive <ToDriveAttribute>*]
|
||||
gam <UserTypeEntity> show webmastersites
|
||||
gam <UserTypeEntity> print webmastersites [todrive <ToDriveAttribute>*]
|
||||
```
|
||||
|
||||
### 7.16.01
|
||||
|
||||
The Drive API now supports setting download restrictions on individual files.
|
||||
|
||||
Added `downloadrestictions` and `<DriveDownloadRestrictionsSubfieldName>` to `<DriveFieldName>`.
|
||||
```
|
||||
<DriveDownloadRestrictionsSubfieldName> ::=
|
||||
downloadrestrictions.itemdownloadrestriction|
|
||||
downloadrestrictions.effectivedownloadrestrictionwithcontext
|
||||
```
|
||||
|
||||
Added `itemdownloadrestriction (restrictedforreaders [<Boolean>]) (restrictedforwriters [<Boolean>])`
|
||||
to `<DriveFileAttribute>`.
|
||||
|
||||
From the Drive API documentation:
|
||||
```
|
||||
itemDownloadRestriction - The download restriction of the file applied directly by the owner or organizer. This does not take into account shared drive settings or DLP rules.
|
||||
effectiveDownloadRestrictionWithContext - Output only. The effective download restriction applied to this file. This considers all restriction settings and DLP rules.
|
||||
restrictedForReaders - Whether download and copy is restricted for readers.
|
||||
restrictedForWriters - Whether download and copy is restricted for writers. If true, download is also restricted for readers.
|
||||
```
|
||||
|
||||
### 7.16.00
|
||||
|
||||
Removed `drive_v3_native_names` from `gam.cfg`; GAM now only uses Drive API v3 fields names on output.
|
||||
If you had `drive_v3_native_names = False` in `gam.cfg` or are updating from Legacy GAM:
|
||||
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Drive-REST-API-v3
|
||||
|
||||
### 7.15.01
|
||||
|
||||
Added `downloadrestrictions.restrictedforreaders` and `downloadrestrictions.restrictedforwriters`
|
||||
to `<SharedDriveRestrictionsSubfieldName>`; previously, only the abbreviations `downloadrestrictedforreaders`
|
||||
and `downloadrestrictedforwriters` were supported (they are still supported).
|
||||
|
||||
Updated `gam <UserTypeEntity> copy drivefile` to handle unexpected data returned by Google that caused a trap.
|
||||
|
||||
### 7.15.00
|
||||
|
||||
Updated `gam print shareddriveorganizers` to make `shownoorganizerdrives` default to `True`
|
||||
as documented; it was defaulting to `False`.
|
||||
|
||||
Cleaned up code for processing Python dictionary structures; this should have no noticable effect.
|
||||
|
||||
### 7.14.04
|
||||
|
||||
Fixed bug in `gam print|show cigroups cimember <UserItem>` that generated the following error:
|
||||
```
|
||||
ERROR: Cloud Identity Group: groups/-, Print Failed: Error(4013): Insufficient permissions to retrieve memberships.
|
||||
```
|
||||
|
||||
Updated `gam <UserTypeEntity> update user suspended off` and `gam <UserTypeEntity> unsuspend users`
|
||||
to handle the following error that occurs when trying to unsuspend a user that has been suspended for abuse.
|
||||
```
|
||||
ERROR: 412: adminCannotUnsuspend - Cannot restore a user suspended for abuse.
|
||||
```
|
||||
|
||||
* See: https://support.google.com/a/answer/1110339
|
||||
|
||||
### 7.14.03
|
||||
|
||||
Fixed bug in `gam print cigroup-members includederivedmembership` that caused a trap.
|
||||
|
||||
### 7.14.02
|
||||
|
||||
Fixed bug in `gam print|show cigroups|cigroups-members cimember <UserItem>` that generated the following error:
|
||||
```
|
||||
Cloud Identity Group Print Failed: Request contains an invalid argument.
|
||||
```
|
||||
|
||||
### 7.14.01
|
||||
|
||||
Don't install yubikey library via pip by default. To install with yubikey support use pip install gam7[yubikey]
|
||||
|
||||
### 7.14.00
|
||||
|
||||
Added commands to display Google Tag Manager accounts, containers, workspaces, tags and user permissions.
|
||||
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Users-Tag-Manager
|
||||
|
||||
### 7.13.03
|
||||
|
||||
Added option `csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]]]`
|
||||
to `gam create chromeprofilecommand` so that command details are displayed in CSV format.
|
||||
|
||||
Added option `commands <ChromeProfileCommandNameList>|<FileSelector>|<CSVFileSelector>` to `<ChromeProfileNameEntity>`
|
||||
so that `gam print|show chromeprofilecommands` can directly display the commands generated by
|
||||
`gam create chromeprofilecommand` with the `csv` option.
|
||||
|
||||
### 7.13.02
|
||||
|
||||
Fixed bug in `gam create chromeprofilecommand` where `select|filter` were not recognized.
|
||||
|
||||
Updated `gam create datatransfer <OldOwnerID> datastudio <NewOwnerID>` that generated the following
|
||||
error due to an unhandled API change.
|
||||
```
|
||||
ERROR: Invalid choice (google data studio): Expected <calendar|looker studio|drive and docs>
|
||||
```
|
||||
|
||||
### 7.13.01
|
||||
|
||||
Enhanced `gam create|print|show chromeprofilecommand` to allow specification
|
||||
of multiple Chrome browser profiles rather than just one.
|
||||
```
|
||||
<ChromeProfilePermanentID> ::= <String>
|
||||
<ChromeProfileName> ::= customers/<CustomerID>/profiles/<ChromeProfilePermanentID> | <ChromeProfilePermanentID>
|
||||
<ChromeProfileNameList> ::= "<ChromeProfileName>(,<ChromeProfileName>)*"
|
||||
<ChromeProfileNameEntity> ::=
|
||||
<ChromeProfileNameEntity> ::=
|
||||
<ChromeProfileNameList> |
|
||||
(select <FileSelector>|<CSVFileSelector>) |
|
||||
(filter <String> (filtertime<String> <Time>)* [orderby <ChromeProfileOrderByFieldName> [ascending|descending]])
|
||||
|
||||
gam create|print_show chromeprofilecommand <ChromeProfileNameEntity>
|
||||
```
|
||||
|
||||
### 7.13.00
|
||||
|
||||
Added commands that send remote commands to Chrome browser profiles and display the results;
|
||||
at the moment, these commands can clear the browser cache and cookies.
|
||||
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Chrome-Profile-Management#create-a-chrome-profile-command
|
||||
|
||||
### 7.12.02
|
||||
|
||||
Updated `gam print users` to handle the following error:
|
||||
```
|
||||
ERROR: 503: serviceNotAvailable - The service is currently unavailable
|
||||
```
|
||||
|
||||
### 7.12.01
|
||||
|
||||
Added support for `plan free` in `gam create resoldsubscription`.
|
||||
|
||||
* The free plan is exclusive to the Cloud Identity SKU and does not incur any billing.
|
||||
|
||||
### 7.12.00
|
||||
|
||||
Started updated handling of missing scopes messages in client access commands;
|
||||
this is a work in progress.
|
||||
|
||||
Updated `gam info|show shareddrive` to handle changes in the Drive API that caused traps.
|
||||
|
||||
Added `downloadrestrictedforreaders` and `downloadrestrictedforwriters` to
|
||||
`<SharedDriveRestrictionsSubfieldName>` to support new Shared Drive restrictions.
|
||||
|
||||
Updated `gam course <CourseID> create|update announcement` to accept input from
|
||||
a literal string, a file or a Google Doc.
|
||||
```
|
||||
<CourseAnnouncementContent> ::=
|
||||
((text <String>)|
|
||||
(textfile <FileName> [charset <Charset>])|
|
||||
(gdoc <UserGoogleDoc>)|
|
||||
(gcsdoc <StorageBucketObjectName>))
|
||||
```
|
||||
|
||||
Added command `gam check suspended <UserItem>` that checks the suspension status of a user
|
||||
and sets the return code to 0 if the user is not suspended or 26 if it is.
|
||||
```
|
||||
$ gam check suspended testok@domain.com
|
||||
User: testok@domain.com, Account Suspended: False
|
||||
$ echo $?
|
||||
0
|
||||
|
||||
$ gam check suspended testsusp@domain.com
|
||||
User: testsusp@domain.com, Account Suspended: True, Suspension Reason: ADMIN
|
||||
$ echo $?
|
||||
26
|
||||
```
|
||||
|
||||
Updated `gam <UserTypeEntity> sendemail` to verify that one of `recipient|to|from`
|
||||
immediately follows `sendemail`.
|
||||
|
||||
### 7.11.00
|
||||
|
||||
Added commands to manage classroom/course announcements.
|
||||
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Classroom-Courses#manage-course-announcements
|
||||
|
||||
Upgraded to OpenSSL 3.5.1.
|
||||
|
||||
### 7.10.10
|
||||
|
||||
Added choices `text` and `hyperlink` to option `showwebviewlink` in `gam [<UserTypeEntity>] print|show shareddrives`.
|
||||
* `showwebviewlink text` - Displays `https://drive.google.com/drive/folders/<SharedDriveID>`
|
||||
* `showwebviewlink hyperlink` - Displays `=HYPERLINK("https://drive.google.com/drive/folders/<SharedDriveID>", "<SharedDriveName>")`
|
||||
|
||||
### 7.10.09
|
||||
|
||||
Added option `showwebviewlink` to `gam [<UserTypeEntity>] print|show shareddrives` that
|
||||
displays the web view link for the Shared Drive: `https://drive.google.com/drive/folders/<SharedDriveID>`.
|
||||
|
||||
### 7.10.08
|
||||
|
||||
Fixed bug in commands that modify messages where the `labelids <LabelIdList>` option
|
||||
could not be used unless one of these options was also specified: `query`, `matchlabel`, `ids`;
|
||||
it can be now be used by itself.
|
||||
|
||||
### 7.10.07
|
||||
|
||||
Updated `gam <UserTypeEntity> copy|move drivefile` to hanndle additional instances of
|
||||
the `cannotModifyInheritedPermission` error.
|
||||
|
||||
Added license SKU `Google AI Ultra for Business`
|
||||
* ProductID - 101047
|
||||
* SKUID - 1010470008 | geminiultra
|
||||
|
||||
### 7.10.06
|
||||
|
||||
Added option `clientstates` to `gam print devices` to include client states in device output.
|
||||
|
||||
### 7.10.05
|
||||
|
||||
Google renamed an error: `cannotModifyInheritedTeamDrivePermission` became `cannotModifyInheritedPermission`.
|
||||
GAM will now handle the new error.
|
||||
|
||||
### 7.10.04
|
||||
|
||||
Updated `gam report <ActivityApplicationName>` to accept accept application names as defined
|
||||
in the Reports API discovery document; this means that GAM does not have to be updated when
|
||||
Google defines a new application name.
|
||||
|
||||
`gemini_in_workspace_apps` is now available in `gam report`.
|
||||
|
||||
### 7.10.03
|
||||
|
||||
Fixed bug in commands that modify messages where the `labelids <LabelIdList>` option
|
||||
was not being applied.
|
||||
|
||||
### 7.10.02
|
||||
|
||||
Added option `labelids <LabelIdList>` to all commands that process messages;
|
||||
this option causes GAM to only return messages with labels that match all of the specified label IDs.
|
||||
|
||||
Updated `gam <UserTypeEntity> print|show forms` to always display `isPublished` and
|
||||
`isAcceptingResponses` in `publishSettings/publishState` regardless of their value;
|
||||
the API doesn't return these values when they are False.
|
||||
|
||||
### 7.10.01
|
||||
|
||||
Added options `ispublished [<Boolean>]` and `isacceptingresponses [<Boolean>]` to
|
||||
`gam <UserTypeEntity> create|update form`.
|
||||
|
||||
### 7.10.00
|
||||
|
||||
Added commands to manage/display Chat Custom Emojis.
|
||||
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Users-Chat#manage-chat-emojis
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Users-Chat#display-chat-emojis
|
||||
|
||||
Updated `gam <UserItem> print|show chatspaces|chatmembers asadmin` to display
|
||||
the spaces in ascending display name order.
|
||||
|
||||
### 7.09.07
|
||||
|
||||
Added `webviewlink` to `<FileTreeFieldName>` for use in `gam <UserTypeEntity> print|show filetree`.
|
||||
|
||||
### 7.09.06
|
||||
|
||||
Upddated `gam print|show shareddrives`, `gam print|show shareddriveacls`, `gam print shareddriveorganizers`
|
||||
to display the Shared Drives in ascending name order; the API returns them in an unidentifiable order.
|
||||
|
||||
### 7.09.05
|
||||
|
||||
Improved output of `gam info|show chromeschemas [std]` to more accurately display the schemas.
|
||||
|
||||
Fixed bugs in `gam update chromepolicy` that caused invalid error messaages.
|
||||
|
||||
### 7.09.04
|
||||
|
||||
Fixed bug in `gam whatis <EmailItem>` where the check for an invitable user always failed.
|
||||
|
||||
Fixed bug in `gam print shareddriveorganizers` where no organizers were displayed when `domain` in `gam.cfg` was blank.
|
||||
|
||||
Updated to Python 3.13.5
|
||||
|
||||
### 7.09.03
|
||||
|
||||
Updated `gam <UserTypeEntity> create focustime|outofoffice ... timerange <Time> <Time>` to check
|
||||
@@ -1466,7 +2010,7 @@ number of domain aliasess on stdout; no CSV file is written.
|
||||
|
||||
Added option `showitemcountonly` to `gam print domains` that causes GAM to display the
|
||||
number of domains on stdout; no CSV file is written.
|
||||
|
||||
|
||||
### 6.77.16
|
||||
|
||||
Fixed bug in `gam <UserTypeEntity> print filelist` that caused a trap.
|
||||
@@ -2230,7 +2774,7 @@ Batch processing will suspend for `<Integer>` seconds before the next command li
|
||||
|
||||
Added the following options to `<PermissionMatch>` that allow more powerful matching.
|
||||
```
|
||||
nottype <DriveFileACLType>
|
||||
nottype <DriveFileACLType>
|
||||
typelist <DriveFileACLTypeList>
|
||||
nottypelist <DriveFileACLTypeList>
|
||||
rolelist <DriveFileACLRoleList>
|
||||
@@ -2882,7 +3426,7 @@ Added support for Google Workspace Labs license.
|
||||
|
||||
### 6.64.10
|
||||
|
||||
Fixed bug introduced in 6.64.09 that caused a trap when `gam redirect csv <FileName> multiprocess` was used.
|
||||
Fixed bug introduced in 6.64.09 that caused a trap when `gam redirect csv <FileName> multiprocess` was used.
|
||||
|
||||
### 6.64.09
|
||||
|
||||
|
||||
17
wiki/Global-Address-List.md
Normal file
17
wiki/Global-Address-List.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Global Address List
|
||||
|
||||
As of mid-October 2024, Google deprecated the API that retrieved the Global Address List.
|
||||
|
||||
These commands are a work-around.
|
||||
|
||||
Display users/groups in GAL.
|
||||
```
|
||||
gam config csv_output_row_filter "includeInGlobalAddressList:boolean:true" redirect csv ./UserGAL.csv print users fields name,gal
|
||||
gam config csv_output_row_filter "includeInGlobalAddressList:boolean:true" batch_size 25 redirect csv ./GroupGAL.csv print groups fields name,gal
|
||||
```
|
||||
|
||||
Display users/groups not in GAL.
|
||||
```
|
||||
gam config csv_output_row_filter "includeInGlobalAddressList:boolean:false" redirect csv ./UserNotGAL.csv print users fields name,gal
|
||||
gam config csv_output_row_filter "includeInGlobalAddressList:boolean:false" batch_size 25 redirect csv ./GroupNotGAL.csv print groups fields name,gal
|
||||
```
|
||||
@@ -13,8 +13,7 @@
|
||||
```
|
||||
<DataTransferService> ::=
|
||||
calendar|
|
||||
currents|
|
||||
datastudio|lookerstudio|"google data studio"|
|
||||
datastudio|lookerstudio|"looker studio"|
|
||||
drive|gdrive|googledrive|"drive and docs"
|
||||
<DataTransferServiceList> ::= "<DataTransferService>(,<DataTransferService>)*"
|
||||
|
||||
@@ -38,7 +37,7 @@ gam create|add datatransfer|transfer <OldOwnerID> <DataTransferServiceList> <New
|
||||
(<ParameterKey> <ParameterValue>)*
|
||||
[wait <Integer> <Integer>]
|
||||
```
|
||||
For`datastudio` and `drive`, there are options to control the privacy level of the files to be transferred.
|
||||
For`lookerstudio` and `drive`, there are options to control the privacy level of the files to be transferred.
|
||||
* `private` or `privacy_level private` - Transfer files that are not shared with anyone
|
||||
* `shared` or `privacy_level shared` - Transfer files shared with at least one other user; this is the **default**
|
||||
* `all` or `privacy_level private,shared` - Transfer all files
|
||||
|
||||
@@ -92,6 +92,38 @@ See [Collections of Items](Collections-of-Items)
|
||||
Group membership commands involve specifying collections of users;
|
||||
for `<UserTypeEntity>`, see: [Collections of Users](Collections-of-Users)
|
||||
|
||||
### Select users based on archived state
|
||||
When adding, deleting or synchronizing group members, to select only archived or non-archived users, use the following`<UserTypeEntity>`:
|
||||
```
|
||||
(all users_na|users_arch)|
|
||||
(domains_na|domains_arch <DomainNameList>)|
|
||||
(group_na|group_arch <GroupItem>)|
|
||||
(groups_na|groups_arch <GroupList>)|
|
||||
(group_users_na|group_users_arch <GroupList>
|
||||
[members] [managers] [owners]
|
||||
[primarydomain] [domains <DomainNameList>] [recursive|includederivedmembership] end)|
|
||||
(ou_na|ou_arch <OrgUnitItem>)|
|
||||
(ou_and_children_na|ou_and_children_arch <OrgUnitItem>)|
|
||||
(ous_na|ous_arch <OrgUnitList>)|
|
||||
(ous_and_children_na|ous_and_children_arch <OrgUnitList>)
|
||||
```
|
||||
|
||||
When adding, deleting or synchronizing group members, the `notarchived|archived` option can be used to select
|
||||
users in a particular archived state. This option can be used with the following `<UserTypeEntity>`:
|
||||
```
|
||||
(all users)|
|
||||
(domains <DomainNameList>)|
|
||||
(group <GroupItem>)|
|
||||
(groups <GroupList>)|
|
||||
(group_users <GroupList>
|
||||
[members] [managers] [owners]
|
||||
[primarydomain] [domains <DomainNameList>] [recursive|includederivedmembership] end)|
|
||||
(ou <OrgUnitItem>)|
|
||||
(ou_and_children <OrgUnitItem>)|
|
||||
(ous <OrgUnitList>)|
|
||||
(ous_and_children <OrgUnitList>)
|
||||
```
|
||||
|
||||
### Select users based on suspension state
|
||||
When adding, deleting or synchronizing group members, to select only suspended or non-suspended users, use the following`<UserTypeEntity>`:
|
||||
```
|
||||
@@ -124,25 +156,6 @@ users in a particular suspension state. This option can be used with the followi
|
||||
(ous_and_children <OrgUnitList>)
|
||||
```
|
||||
|
||||
### Select users based on archived state
|
||||
When adding, deleting or synchronizing group members, the `notarchived|archived` option can be used to select
|
||||
users in a particular archived state. This option can be used with the following `<UserTypeEntity>`:
|
||||
```
|
||||
(all users|users_ns|users_susp|users_ns_susp)|
|
||||
(domains|domains_ns|domains_susp <DomainNameList>)|
|
||||
(group|group_ns|group_susp <GroupItem>)|
|
||||
(groups|groups_ns|groups_susp <GroupList>)|
|
||||
(group_users|group_users_ns|group_users_susp <GroupList>
|
||||
[members] [managers] [owners]
|
||||
[primarydomain] [domains <DomainNameList>] [recursive|includederivedmembership] end)|
|
||||
(ou|ou_ns|ou_susp <OrgUnitItem>)|
|
||||
(ou_and_children|ou_and_children_ns|ou_and_children_susp <OrgUnitItem>)|
|
||||
(ous|ous_ns|ous_susp <OrgUnitList>)|
|
||||
(ous_and_children|ous_and_children_ns|ous_and_children_susp <OrgUnitList>)|
|
||||
(query <QueryUser>)|
|
||||
(queries <QueryUserList>)
|
||||
```
|
||||
|
||||
## Add members to a group
|
||||
```
|
||||
gam update group|groups <GroupEntity> create|add [<GroupRole>]
|
||||
@@ -275,6 +288,11 @@ For `notarchived|archived`, see: [Select users based on archived state](#select-
|
||||
|
||||
The `notsuspended|suspended` and `notarchived|archived` not only control what users are selected from `<UserTypeEntity>`
|
||||
but they also control what users are selected from `<GroupEntity>`.
|
||||
* `notsuspended` - Select only non-suspended members
|
||||
* `suspended` - Select only suspended members
|
||||
* `notarchived` - Select only non-archived members
|
||||
* `archived` - Select only archived users
|
||||
* `notsuspended notarchived` - Select non-suspended and non-archived members
|
||||
|
||||
The `remove_domain_nostatus_members` option is used to remove members from the group that are in your domain but have no status.
|
||||
These members were added to the group before the user or group that they represent was created.
|
||||
@@ -373,10 +391,7 @@ By default, when clearing members from a group, all members, whether suspended/a
|
||||
* `suspended` - Clear only suspended members
|
||||
* `notarchived` - Clear only non-archived members
|
||||
* `archived` - Clear only archived users
|
||||
* `notsuspended notarchived` - Do not clear suspended and archived members
|
||||
* `suspended archived` - Clear suspended and archived members
|
||||
* `notsuspended archived` - Do not clear archived members
|
||||
* `suspended notarchived` - Do not clear suspended members
|
||||
* `notsuspended notarchived` - Clear non-suspended and non-archived members
|
||||
|
||||
Members that have met the above qualifications to be cleared can be further qualifed by their email address.
|
||||
* `emailclearpattern <REMatchPattern>` - Members with email addresses that match `<REMatchPattern>` will be cleared; others will be retained
|
||||
@@ -417,19 +432,12 @@ When `<UserTypeEntity>` specifies a group or groups:
|
||||
* `usersonly` - Only the user members from the specified groups are added
|
||||
* `groupsonly` - Only the group members from the specified groups are added
|
||||
|
||||
By default, when updating members from organization units, all users, whether suspended or not, are included.
|
||||
* `notsuspended` - Do not include suspended users
|
||||
* `suspended` - Only include suspended users
|
||||
|
||||
By default, when updating members from groups, all users, whether suspended/archived or not, are included.
|
||||
* `notsuspended` - Do not include suspended users
|
||||
* `suspended` - Only include suspended users
|
||||
* `notarchived` - Do not include archived users
|
||||
* `archived` - Only include archived users
|
||||
* `notsuspended notarchived` - Do not include suspended and archived users
|
||||
* `suspended archived` - Include only suspended or archived users
|
||||
* `notsuspended archived` - Only include archived users
|
||||
* `suspended notarchived` - Only include suspended users
|
||||
By default, when updating members from groups/organization units, all users, whether suspended/archived or not, are included.
|
||||
* `notsuspended` - Update only non-suspended members
|
||||
* `suspended` - Update only suspended members
|
||||
* `notarchived` - Update only non-archived members
|
||||
* `archived` - Update only archived users
|
||||
* `notsuspended notarchived` - Update non-suspended and non-archived members
|
||||
|
||||
You can set the `delivery` option for the updated members:
|
||||
* `allmail` - All messages, delivered as soon as they arrive
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Use these steps if you have used any version of GAM in your domain. They will update your GAM project
|
||||
and all necessary authentications.
|
||||
|
||||
- [Drive API v2 to Drive API v3](Drive-REST-v3)
|
||||
- [Downloads-Installs](Downloads-Installs)
|
||||
- [Linux and MacOS and Google Cloud Shell](#linux-and-mac-os-and-google-cloud-shell)
|
||||
- [Windows](#windows)
|
||||
@@ -251,10 +252,10 @@ 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.09.03 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.22.07 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.4 64-bit final
|
||||
MacOS Sequoia 15.5 x86_64
|
||||
Python 3.13.7 64-bit final
|
||||
MacOS Sequoia 15.6.1 x86_64
|
||||
Path: /Users/admin/bin/gam7
|
||||
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
|
||||
|
||||
@@ -989,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.09.03 - https://github.com/GAM-team/GAM - pythonsource
|
||||
GAM 7.22.00 - https://github.com/GAM-team/GAM - pythonsource
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.4 64-bit final
|
||||
Python 3.13.7 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
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
# Inbound SSO
|
||||
- [Admin Console](#admin-console)
|
||||
- [Setup SSO](https://support.google.com/a/answer/12032922)
|
||||
- [Admin Console](https://admin.google.com/ac/security/sso)
|
||||
- [API documentation](#api-documentation)
|
||||
- [Definitions](#definitions)
|
||||
- [Setup SSO](#setupsso)
|
||||
- [Manage profiles](#manage-profiles)
|
||||
- [Display profiles](#display-profiles)
|
||||
- [Manage credentials](#manage-credentials)
|
||||
@@ -9,12 +11,10 @@
|
||||
- [Manage assignments](#manage-assignments)
|
||||
- [Display assignments](#display-assignments)
|
||||
|
||||
## Admin Console
|
||||
* https://admin.google.com/ac/security/sso
|
||||
|
||||
## API documentation
|
||||
* [Cloud Identity API - Inbound SAML SSO Profiles](https://cloud.google.com/identity/docs/reference/rest/v1beta1/inboundSamlSsoProfiles)
|
||||
* [Cloud Identity API - Inbound SAML SSO Profiles idp Credentials](https://cloud.google.com/identity/docs/reference/rest/v1beta1/inboundSamlSsoProfiles.idpCredentials)
|
||||
* [Cloud Identity API - Inbound OIDC SSO Profiles](https://cloud.google.com/identity/docs/reference/rest/v1beta1/inboundOidcSsoProfiles)
|
||||
* [Cloud Identity API - Inbound SSO Assignments](https://cloud.google.com/identity/docs/reference/rest/v1beta1/inboundSsoAssignments)
|
||||
|
||||
## Definitions
|
||||
@@ -41,46 +41,68 @@
|
||||
```
|
||||
## Manage profiles
|
||||
```
|
||||
gam create inboundssoprofile [name <SSOProfileDisplayName>]
|
||||
gam create inboundssoprofile [saml|oidc] [name <SSOProfileDisplayName>]
|
||||
[entityid <String>] [loginurl <URL>] [logouturl <URL>] [changepasswordurl <URL>]
|
||||
[returnnameonly]
|
||||
gam update inboundssoprofile <SSOProfileItem>
|
||||
gam update inboundssoprofile [saml|oidc] <SSOProfileItem>
|
||||
[entityid <String>] [loginurl <URL>] [logouturl <URL>] [changepasswordurl <URL>]
|
||||
[returnnameonly]
|
||||
```
|
||||
Select type of profile:
|
||||
* `saml` - SAML profile; this is the default
|
||||
* `oidc` - OIDC profile
|
||||
|
||||
By default, all fields of the created|updated profile are displayed;
|
||||
use the `returnnameonly` option to have GAM display just the profile name of the created|updated profile.
|
||||
This will be useful in scripts that create|update a profile and then want to perform subsequent GAM commands that
|
||||
reference the profile.
|
||||
|
||||
If `returnnameonly is specified, `inProgress` is returned if the API does not return a complete result.
|
||||
If `returnnameonly` is specified, `inProgress` is returned if the API does not return a complete result.
|
||||
|
||||
```
|
||||
gam delete inboundssoprofile <SSOProfileItem>
|
||||
gam delete inboundssoprofile [saml|oidc] <SSOProfileItem>
|
||||
```
|
||||
Select type of profile:
|
||||
* `saml` - SAML profile; this is the default
|
||||
* `oidc` - OIDC profile
|
||||
|
||||
## Display profiles
|
||||
Display a specific profile.
|
||||
```
|
||||
gam info inboundssoprofile <SSOProfileItem>
|
||||
gam info inboundssoprofile [all|saml|oidc] <SSOProfileItem>
|
||||
[formatjson]
|
||||
```
|
||||
Select type of profile:
|
||||
* `all` - All profiles are displayed; this is the default
|
||||
* `saml` - SAML profile
|
||||
* `oidc` - OIDC profile
|
||||
|
||||
By default, Gam displays the information as an indented list of keys and values.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
|
||||
Display all profiles.
|
||||
Display profiles.
|
||||
```
|
||||
gam show inboundssoprofiles
|
||||
gam show inboundssoprofiles [all|saml|oidc]
|
||||
[formatjson]
|
||||
```
|
||||
Select profiles to display:
|
||||
* `all` - All profiles are displayed; this is the default
|
||||
* `saml` - Display SAML profiles
|
||||
* `oidc` - Display OIDC profiles
|
||||
|
||||
By default, Gam displays the information as an indented list of keys and values.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
|
||||
Display all profiles in a CSV file.
|
||||
Display profiles in a CSV file.
|
||||
```
|
||||
gam print inboundssoprofiles [todrive <ToDriveAttribute>*]
|
||||
gam print inboundssoprofiles [all|saml|oidc] [todrive <ToDriveAttribute>*]
|
||||
[[formatjson [quotechar <Character>]]
|
||||
```
|
||||
Select profiles to display:
|
||||
* `all` - All profiles are displayed; this is the default
|
||||
* `saml` - Display SAML profiles
|
||||
* `oidc` - Display OIDC profiles
|
||||
|
||||
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.
|
||||
|
||||
@@ -130,10 +152,14 @@ The `quotechar <Character>` option allows you to choose an alternate quote chara
|
||||
|
||||
## Manage assignments
|
||||
```
|
||||
gam create inboundssoassignment (group <GroupItem> rank <Number>)|(ou|org|orgunit <OrgUnitItem>)
|
||||
(mode sso_off)|(mode saml_sso profile <SSOProfileItem>)(mode domain_wide_saml_if_enabled) [neverredirect]
|
||||
gam update inboundssoassignment [(group <GroupItem> rank <Number>)|(ou|org|orgunit <OrgUnitItem>)]
|
||||
[(mode sso_off)|(mode saml_sso profile <SSOProfileItem>)(mode domain_wide_saml_if_enabled)] [neverredirect]
|
||||
gam create inboundssoassignment
|
||||
(group <GroupItem> rank <Number>)|(ou|org|orgunit <OrgUnitItem>)
|
||||
(mode sso_off)|(mode saml_sso profile <SSOProfileItem>)(mode domain_wide_saml_if_enabled)
|
||||
[neverredirect]
|
||||
gam update inboundssoassignment <SSOAssignmentName>
|
||||
[(group <GroupItem> rank <Number>)|(ou|org|orgunit <OrgUnitItem>)]
|
||||
[(mode sso_off)|(mode saml_sso profile <SSOProfileItem>)(mode domain_wide_saml_if_enabled)]
|
||||
[neverredirect]
|
||||
gam delete inboundssoassignment <SSOAssignmentSelector>
|
||||
```
|
||||
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
# Install GAM as Python Library
|
||||
|
||||
Thanks to Jay Lee for showing me how to do this.
|
||||
|
||||
On Windows, you need to install Git to use the pip command.
|
||||
* See: https://pythoninoffice.com/python-pip-install-from-github/
|
||||
|
||||
Scroll down to Install Git
|
||||
|
||||
You can install GAM as a Python library with pip.
|
||||
```
|
||||
pip install git+https://github.com/GAM-team/GAM.git#subdirectory=src
|
||||
pip install gam7
|
||||
```
|
||||
|
||||
Or as a PEP 508 Requirement Specifier, e.g. in requirements.txt file:
|
||||
```
|
||||
advanced-gam-for-google-workspace @ git+https://github.com/GAM-team/GAM.git#subdirectory=src
|
||||
gam7
|
||||
```
|
||||
|
||||
Or a pyproject.toml file:
|
||||
@@ -23,13 +17,13 @@ Or a pyproject.toml file:
|
||||
name = "your-project"
|
||||
# ...
|
||||
dependencies = [
|
||||
"advanced-gam-for-google-workspace @ git+https://github.com/GAM-team/GAM.git#subdirectory=src"
|
||||
"gam7"
|
||||
]
|
||||
```
|
||||
|
||||
Target a specific revision or tag:
|
||||
Target a specific version:
|
||||
```
|
||||
advanced-gam-for-google-workspace @ git+https://github.com/GAM-team/GAM.git@v6.76.01#subdirectory=src
|
||||
gam7==/7.13.3
|
||||
```
|
||||
|
||||
## Using the library
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
- [License Products and SKUs](#license-products-and-skus)
|
||||
- [Definitions](#definitions)
|
||||
- [Notes](#Notes)
|
||||
- [Info User Performance](#info-user-performance)
|
||||
- [Display license counts](#display-license-counts)
|
||||
- [Display licenses](#display-licenses)
|
||||
- [Add licenses](#add-licenses)
|
||||
@@ -11,7 +12,7 @@
|
||||
- [Synchronize licenses](#synchronize-licenses)
|
||||
|
||||
## API documentation
|
||||
* [License Manager API](https://developers.google.com/admin-sdk/licensing/rest/v1/licenseAssignments)
|
||||
* [License Manager API](https://developers.google.com/workspace/admin/licensing/reference/rest/v1/licenseAssignments)
|
||||
|
||||
## License Products and SKUs
|
||||
* [Product and SKU IDs](https://developers.google.com/admin-sdk/licensing/v1/how-tos/products)
|
||||
@@ -59,9 +60,10 @@
|
||||
| G Suite Legacy | Google-Apps | standard |
|
||||
| G Suite Lite | Google-Apps-Lite | gsuitelite |
|
||||
| Gemini Business | 1010470003 | geminibiz
|
||||
| Gemini Education | 1010470004 | geminiedu |
|
||||
| Gemini Education Premium | 1010470005 | geminiedupremium |
|
||||
| Gemini Enterprise | 1010470001 | geminient | duetai |
|
||||
| Google AI Pro for Education | 1010470004 | gaiproedu |
|
||||
| Google AI Ultra for Business | 1010470008 | geminiultra |
|
||||
| Google Apps Message Security | Google-Apps-For-Postini | postini |
|
||||
| Google Chrome Device Management | Google-Chrome-Device-Management | cdm |
|
||||
| Google Drive Storage 16TB | Google-Drive-storage-16TB | 16tb |
|
||||
@@ -159,18 +161,17 @@
|
||||
assuredcontrolsplus | 1010390002 | Assured Controls Plus |
|
||||
bce | beyondcorp | beyondcorpenterprise | cep | chromeenterprisepremium | 1010400001 | Chrome Enterprise Premium |
|
||||
cdm | chrome | googlechromedevicemanagement | Google-Chrome-Device-Management |
|
||||
bce | beyondcorp | beyondcorpenterprise | cep | chromeenterprisepremium | 1010400001 | Chrome Enterprise Premium |
|
||||
cdm | chrome | googlechromedevicemanagement | Google-Chrome-Device-Management |
|
||||
cloudidentity | identity | 1010010001 | Cloud Identity |
|
||||
cloudidentitypremium | identitypremium | 1010050001 | Cloud Identity Premium |
|
||||
cloudsearch | 1010350001 | Cloud Search |
|
||||
colabpro | 1010500001 | Colab Pro |
|
||||
colabpro+ | colabproplus | 1010500002 | Colab Pro+ |
|
||||
eeu | 1010490001 | SKU Endpoint Education Upgrade |
|
||||
gaiproedu | geminiedu | 1010470004 | Google AI Pro for Education |
|
||||
geminibiz | 1010470003 | Gemini Business |
|
||||
geminiedu | 1010470004 | Gemini Education |
|
||||
geminiedupremium| 1010470005 | Gemini Education Premium |
|
||||
geminient| duetai | 1010470001 | Gemini Enterprise |
|
||||
geminiultra | 1010470008 | Google AI Ultra for Business |
|
||||
gsuitebasic | gafb | gafw | basic | Google-Apps-For-Business |
|
||||
gsuitebusiness | gau | gsb | unlimited | Google-Apps-Unlimited |
|
||||
gsuitebusinessarchived | gsbau | businessarchived | 1010340002 | Google Workspace Business - Archived User |
|
||||
@@ -214,7 +215,8 @@
|
||||
wsess | workspaceesentials | gsuiteessentials | essentials | d4e | driveenterprise | drive4enterprise | 1010060001 | Google Workspace Essentials (formerly G Suite Essentials) |
|
||||
wsessplus | workspaceessentialsplus | 1010060005 | Google Workspace Enterprise Essentials Plus |
|
||||
wsflw | workspacefrontline | workspacefrontlineworker | 1010020030 | Google Workspace Frontline Starter |
|
||||
wsflwstan | workspacefrontlinestan | workspacefrontlineworkerstan | 1010020031 | Google Workspace Frontline Standard
|
||||
wsflwstan | workspacefrontlinestan | workspacefrontlineworkerstan | 1010020031 | Google Workspace Frontline Standard |
|
||||
wsflwplus | workspacefrontlineplus | workspacefrontlineworkerplus | 1010020034 | Google Workspace Frontline Plus
|
||||
<SKUIDList> ::= "<SKUID>(,<SKUID>)*"
|
||||
```
|
||||
## Notes
|
||||
@@ -232,6 +234,42 @@ nv:<String>:<String>
|
||||
```
|
||||
The first `<String>` is a Product and the second `<String>` is a SKU.
|
||||
|
||||
## Info User Performance
|
||||
|
||||
In GAM versions prior 7.18.05, when you did `gam info user`, GAM would make one attempt to get the user's licenses.
|
||||
If something went wrong, you might not get the complete list.
|
||||
|
||||
The License Manager API doesn't have a call that returns the list of licenses that a user has; you have to ask:
|
||||
```
|
||||
Does user have license SKU 1?
|
||||
Does user have license SKU 2?
|
||||
Does user have license SKU 3?
|
||||
...
|
||||
Does user have license SKU 73?
|
||||
```
|
||||
If you do a couple of info user commands back to back, you start to run into quota issues.
|
||||
|
||||
You can help yourself in the following way: generate a list of all of the license SKUs that exist in your workspace.
|
||||
```
|
||||
gam config csv_output_row_filter "licenses:count>0" print license countsonly allskus
|
||||
Got 0 Licenses for 1010010001 (Cloud Identity)...
|
||||
Got 0 Licenses for 1010050001 (Cloud Identity Premium)...
|
||||
...
|
||||
Got 0 Licenses for Google-Vault (Google Vault)...
|
||||
Got 0 Licenses for Google-Vault-Former-Employee (Google Vault - Former Employee)...
|
||||
productId,productDisplay,skuId,skuDisplay,licenses
|
||||
101031,Google Workspace for Education,1010310008,Google Workspace for Education Plus,410
|
||||
101031,Google Workspace for Education,1010310009,Google Workspace for Education Plus (Staff),103
|
||||
101033,Google Voice,1010330004,Google Voice Standard,3
|
||||
Google-Apps,Google Workspace,1010070001,Google Workspace for Education Fundamentals,1453
|
||||
```
|
||||
|
||||
Then do (example, use your actual list):
|
||||
`gam config license_skus 1010310008,1010310009,1010330004,1010070001 save`
|
||||
|
||||
Now, rather that asking 73 questions per user, GAM will only ask about the license SKUs in the list.
|
||||
It is much less likely that quota issues will occur,
|
||||
|
||||
## Display license counts
|
||||
```
|
||||
gam show licenses
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
<CalendarACLScopeList> ::= "<CalendarACLScope>(,<CalendarACLScope>)*"
|
||||
<CalendarList> ::= "<CalendarItem>(,<CalendarItem>)*"
|
||||
<ChatSpaceList> ::= "<ChatSpace>(,<ChatSpace>)*"
|
||||
<ChromeProfileNameList> ::= "<ChromeProfileName>(,<ChromeProfileName>)*"
|
||||
<ChromeProfileCommandNameList> ::= "<ChromeProfileCommandName>(,<ChromeProfileCommandName>)*"
|
||||
<CIGroupAliasList> ::= "<CIGroupAlias>(,<CIGroupAlias>)*"
|
||||
<CIGroupMemberTypeList> ::= "<CIGroupMemberType>(,<CIGroupMemberType>)*"
|
||||
<CIPolicyNameList> ::= "<CIPolicyName>(,<CIPolicyName>)*"
|
||||
@@ -41,6 +43,7 @@
|
||||
<DomainNameList> ::= "<DomainName>(,<DomainName>)*"
|
||||
<DriveFileACLRoleList> ::= "<DriveFileACLRole>(,<DriveFileACLRole>)*"
|
||||
<DriveFileACLTypeList> ::= "<DriveFileACLType>(,<DriveFileACLType>)*"
|
||||
<DriveFileIDList> ::= "<DriveFileID>(,<DriveFileID>)*"
|
||||
<DriveFileList> ::= "<DriveFileItem>(,<DriveFileItem>)*"
|
||||
<DriveFilePermissionList> ::= "<DriveFilePermission>(,<DriveFilePermission>)*"
|
||||
<DriveFilePermissionIDList> ::= "<DriveFilePermissionID>(,<DriveFilePermissionID>)*"
|
||||
@@ -96,6 +99,10 @@
|
||||
<SharedDriveACLRoleList> ::= "<SharedDriveACLRole>(,<SharedDriveACLRole>)*"
|
||||
<SharedDriveIDList> ::= "<SharedDriveID>(,<SharedDriveID>)*"
|
||||
<StringList> ::= "<String>(,<String>)*"
|
||||
<StudentGroupIDList> ::= "<StudentGroupID>(,<StudentGroupID>)*"
|
||||
<TagManagerAccountPathList> ::= "<TagManagerAccountPath>(,<TagManagerAccountPath>)*"
|
||||
<TagManagerContainerPathList> ::= "<TagManagerContainerPath>(,<TagManagerContainerPath>)*"
|
||||
<TagManagerWorkspacePathList> ::= "<TagManagerWorkspacePath>(,<TagManagerWorkspacePath>)*"
|
||||
<TasklistIDList> ::= "<TasklistID>(,<TasklistID>)*"
|
||||
<TasklistTitleList> ::= "'<TasklistTitle>'(,'<TasklistTitle>')*"
|
||||
<TasklistIDTaskIDList> ::= "<TasklistIDTaskID>(,<TasklistIDTaskID>)*"
|
||||
|
||||
@@ -35,6 +35,9 @@ Select a section from gam.cfg and process a GAM command using values from that s
|
||||
- Print the variable values for the selected section
|
||||
- Values are determined in this order: Selected section, DEFAULT section, Program default
|
||||
|
||||
If you enter `gam select <SectionName>` and nothing else on the command line,
|
||||
it will be treated as if you entered: `gam select <SectionName> save`
|
||||
|
||||
### Display sections
|
||||
Display all of the sections in gam.cfg and mark the currently selected section with a *.
|
||||
```
|
||||
|
||||
@@ -187,11 +187,15 @@ given if invalid CrOS deviceIds are specified.
|
||||
## Display organizational units
|
||||
These commands display information as an indented list of keys and values.
|
||||
```
|
||||
gam info org|ou <OrgUnitPath> [nousers|notsuspended|suspended] [children|child]
|
||||
gam info orgs|ous <OrgUnitEntity> [nousers|notsuspended|suspended] [children|child]
|
||||
gam info org|ou <OrgUnitPath> [nousers|notarchived|archived|notsuspended|suspended] [children|child]
|
||||
[nousers | ([notarchived|archived] [notsuspended|suspended])] [children|child]
|
||||
gam info orgs|ous <OrgUnitEntity> [nousers|notarchived|archived|notsuspended|suspended] [children|child]
|
||||
[nousers | ([notarchived|archived] [notsuspended|suspended])] [children|child]
|
||||
```
|
||||
By default, all users of the org units are displayed:
|
||||
* `nousers` - Don't display users of the org units
|
||||
* `notarchived` - Display non-archived users of the org units
|
||||
* `archived` - Display archived users of the org units
|
||||
* `notsuspended` - Display non-suspended users of the org units
|
||||
* `suspended` - Display suspended users of the org units
|
||||
* `children|child` - Display users in any child org unit
|
||||
@@ -214,7 +218,7 @@ By default, Gam prints all child org units of /.
|
||||
* `convertcrnl` - In the description field, convert carriage return to \r and new line to \n.
|
||||
|
||||
Options `parentselector <OrgUnitSelector>` and `childselector <OrgUnitSelector>` add an additional column `orgUnitSelector` to the output.
|
||||
This column value can be used in subsequent `gam csv` commands to appropriateley select members without duplication.
|
||||
This column value can be used in subsequent `gam csv` commands to appropriately select members without duplication.
|
||||
|
||||
By default, all OUs are displayed. You can limit the display of OUs to those where the number
|
||||
of ChromeOS devices/users falls within a range. Gathering this data requires additional API calls
|
||||
|
||||
223
wiki/Reports.md
223
wiki/Reports.md
@@ -12,6 +12,8 @@
|
||||
- [User reports](#user-reports)
|
||||
|
||||
## API documentation
|
||||
These pages show event/parameter names; scroll down in the left column to: Reports.
|
||||
|
||||
* [Reports API - Activities](https://developers.google.com/admin-sdk/reports/v1/reference/activities)
|
||||
* [Reports API - Customer Usage](https://developers.google.com/admin-sdk/reports/v1/reference/customerUsageReports)
|
||||
* [Reports API - User Usage](https://developers.google.com/admin-sdk/reports/v1/reference/userUsageReport)
|
||||
@@ -39,19 +41,18 @@ config csv_output_row_filter "'\"accounts:used_quota_in_mb\":count>15000'"
|
||||
## Activity reports
|
||||
```
|
||||
<ActivityApplicationName> ::=
|
||||
access|accesstransparency|
|
||||
accesstransparency|access|
|
||||
admin|
|
||||
calendar|calendars|
|
||||
chat|
|
||||
chrome|
|
||||
classroom|
|
||||
contextawareaccess|
|
||||
currents|gplus|google+|
|
||||
gplus|currents|google+|
|
||||
datastudio|
|
||||
devices|mobile|
|
||||
domain|
|
||||
drive|doc|docs|
|
||||
gcp|
|
||||
gemini|geminiforworkspace|
|
||||
gcp|cloud|
|
||||
geminiinworkspaceapps|gemini|geminiforworkspace|
|
||||
groups|group|
|
||||
groupsenterprise|enterprisegroups|
|
||||
jamboard|
|
||||
@@ -69,7 +70,7 @@ gam report <ActivityApplicationName> [todrive <ToDriveAttribute>*]
|
||||
[(user all|<UserItem>)|(orgunit|org|ou <OrgUnitPath> [showorgunit])|(select <UserTypeEntity>)]
|
||||
[([start <Time>] [end <Time>])|(range <Time> <Time>)|
|
||||
yesterday|today|thismonth|(previousmonths <Integer>)]
|
||||
[filtertime<String> <Time>] [filter|filters <String>]
|
||||
[filter <String> (filtertime<String> <Time>)*]
|
||||
[event|events <EventNameList>] [ip <String>]
|
||||
[groupidfilter <String>]
|
||||
[maxactivities <Number>] [maxevents <Number>] [maxresults <Number>]
|
||||
@@ -178,8 +179,8 @@ Example output from SharedDrivesActivity.csv:
|
||||
|
||||
name,id.time,shared_drive_id,shared_drive_name
|
||||
NoActivities,,0AERPpMc23znvUkPXYZ,Shared Drive 1
|
||||
view,2023-10-18T21:27:51-07:00,0AMhgLk82dhsuUkPXYZ,Shared Drive 2
|
||||
edit,2023-09-05T15:27:01-07:00,0AM8lpdkkJaKYUkPXYZ,Shared Drive 3
|
||||
view,2025-10-18T21:27:51-07:00,0AMhgLk82dhsuUkPXYZ,Shared Drive 2
|
||||
edit,2025-09-05T15:27:01-07:00,0AM8lpdkkJaKYUkPXYZ,Shared Drive 3
|
||||
```
|
||||
|
||||
Get activities with full activty data.
|
||||
@@ -190,8 +191,8 @@ Example output from SharedDrivesActivity.csv:
|
||||
|
||||
name,actor.callerType,actor.email,actor.key,actor.profileId,actor_is_collaborator_account,added_role,billable,destination_folder_id,destination_folder_title,doc_id,doc_title,doc_type,id.applicationName,id.customerId,id.time,id.uniqueQualifier,ipAddress,is_encrypted,membership_change_type,new_settings_state,old_settings_state,originating_app_id,owner,owner_is_shared_drive,owner_is_team_drive,owner_team_drive_id,primary_event,removed_role,shared_drive_id,shared_drive_name,shared_drive_settings_change_type,target,team_drive_id,team_drive_settings_change_type,type,visibility
|
||||
NoActivities,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0AERPpMc23znvUkPXYZ,Shared Drive 1,,,,,,
|
||||
view,,user1@domain.com,,100016760394505151666,False,,True,,,1SDNu-yzDapqjdJq4y4xKDUATJlOPRIBodpGGeGt1n4I,Digital Poetry Journal,document,drive,C03kt1z99,2023-10-18T21:27:51-07:00,-2856812962461786835,2600:1700:9580:f4b0:2127:3b2:dd21:3806,False,,,,263492796725,Shared Drive 2,True,True,0AMhgLk82dhsuUkPXYZ,True,,0AMhgLk82dhsuUkPXYZ,Shared Drive 2,,,0AMhgLk82dhsuUkPXYZ,,access,people_with_link
|
||||
edit,,user2@domain.com,,104066776037911136666,False,,True,,,1ZwHi_v-JVXH8W6zwgb7QYoUHrZD6NzIshJEqoTCaDD0,High School Scavenger Hunt,form,drive,C03kt1z99,2023-09-05T15:27:01-07:00,-1272095408714453395,50.204.178.246,False,,,,,Shared Drive 3,True,True,0AM8lpdkkJaKYUkPXYZ,True,,0AM8lpdkkJaKYUkPXYZ,Shared Drive 3,,,0AM8lpdkkJaKYUkPXYZ,,access,shared_internally
|
||||
view,,user1@domain.com,,100016760394505151666,False,,True,,,1SDNu-yzDapqjdJq4y4xKDUATJlOPRIBodpGGeGt1n4I,Digital Poetry Journal,document,drive,C03kt1z99,2025-10-18T21:27:51-07:00,-2856812962461786835,2600:1700:9580:f4b0:2127:3b2:dd21:3806,False,,,,263492796725,Shared Drive 2,True,True,0AMhgLk82dhsuUkPXYZ,True,,0AMhgLk82dhsuUkPXYZ,Shared Drive 2,,,0AMhgLk82dhsuUkPXYZ,,access,people_with_link
|
||||
edit,,user2@domain.com,,104066776037911136666,False,,True,,,1ZwHi_v-JVXH8W6zwgb7QYoUHrZD6NzIshJEqoTCaDD0,High School Scavenger Hunt,form,drive,C03kt1z99,2025-09-05T15:27:01-07:00,-1272095408714453395,50.204.178.246,False,,,,,Shared Drive 3,True,True,0AM8lpdkkJaKYUkPXYZ,True,,0AM8lpdkkJaKYUkPXYZ,Shared Drive 3,,,0AM8lpdkkJaKYUkPXYZ,,access,shared_internally
|
||||
```
|
||||
|
||||
## Customer and user reports parameters
|
||||
@@ -364,7 +365,7 @@ gam report users|user [todrive <ToDriveAttribute>*]
|
||||
[(date <Date>)|(range <Date> <Date>)|
|
||||
yesterday|today|thismonth|(previousmonths <Integer>)]
|
||||
[(nodatechange | limitdatechanges <Integer>) | (fulldatarequired all|<UserServiceNameList>)]
|
||||
[filtertime<String> <Time>] [filter|filters <String>]
|
||||
[filter <String> (filtertime<String> <Time>)*]
|
||||
[(fields|parameters <String>)|(services <UserServiceNameList>)]
|
||||
[aggregatebydate|aggregatebyuser [Boolean]]
|
||||
[maxresults <Number>]
|
||||
@@ -377,7 +378,7 @@ Select the users for whom information is desired.
|
||||
* `showorgunit` - Add a column labelled `orgUnitPath` to the output; an additional API call is made to get the email addresses of the users in `<OrgUnitPath>`
|
||||
* `select <UserTypeEntity>` - A selected collection of users, e.g., `select group staff@domain.com`; there is one API call per user
|
||||
|
||||
By default, when `user all` is specified (or no user specification in supplied), GAM backs up looking for data with a (basically) random user. If the randaom
|
||||
By default, when `user all` is specified (or no user specification in supplied), GAM backs up looking for data with a (basically) random user. If the random
|
||||
doesn't have any data, the command reports that no data was found. Use `allverifyuser <UserItem>` to specify a specific user to use to search for data.
|
||||
|
||||
Specify the report date; the default is today's date.
|
||||
@@ -414,7 +415,7 @@ where you can specify a relative date without having to change the script.
|
||||
|
||||
For example, filter for last logins more that 60 days ago.
|
||||
```
|
||||
filtertime60d -60d filters "accounts:last_login_time<#filtertime60d#"
|
||||
filters "accounts:last_login_time<#filtertime60d#" filtertime60d -60d
|
||||
```
|
||||
|
||||
Select the fields/parameters to display.
|
||||
@@ -449,117 +450,117 @@ gam report users parameters accounts:drive_used_quota_in_mb,accounts:gmail_used_
|
||||
```
|
||||
Report on email activity for individual users.
|
||||
```
|
||||
$ gam report users select users testuser1,testuser2,testuser3 fields gmail:num_emails_received,gmail:num_emails_sent range 2023-07-01 2023-07-07
|
||||
$ gam report users select users testuser1,testuser2,testuser3 fields gmail:num_emails_received,gmail:num_emails_sent range 2025-07-01 2025-07-07
|
||||
Getting Reports for testuser1@rdschool.org (1/3)
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-01...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-02...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-03...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-04...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-05...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-06...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-07...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-01...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-02...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-03...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-04...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-05...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-06...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-07...
|
||||
Getting Reports for testuser2@domain.com (2/3)
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-01...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-02...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-03...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-04...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-05...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-06...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-07...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-01...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-02...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-03...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-04...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-05...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-06...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-07...
|
||||
Getting Reports for testuser3@domain.com (3/3)
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-01...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-02...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-03...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-04...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-05...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-06...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-07...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-01...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-02...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-03...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-04...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-05...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-06...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-07...
|
||||
email,date,gmail:num_emails_received,gmail:num_emails_sent
|
||||
testuser1@domain.com,2023-07-01,10,1
|
||||
testuser1@domain.com,2023-07-02,5,1
|
||||
testuser1@domain.com,2023-07-03,14,3
|
||||
testuser1@domain.com,2023-07-04,3,0
|
||||
testuser1@domain.com,2023-07-05,35,4
|
||||
testuser1@domain.com,2023-07-06,30,2
|
||||
testuser1@domain.com,2023-07-07,20,0
|
||||
testuser2@domain.com,2023-07-01,3,1
|
||||
testuser2@domain.com,2023-07-02,1,0
|
||||
testuser2@domain.com,2023-07-03,4,0
|
||||
testuser2@domain.com,2023-07-04,1,0
|
||||
testuser2@domain.com,2023-07-05,15,0
|
||||
testuser2@domain.com,2023-07-06,14,0
|
||||
testuser2@domain.com,2023-07-07,9,1
|
||||
testuser3@domain.com,2023-07-01,14,0
|
||||
testuser3@domain.com,2023-07-02,14,0
|
||||
testuser3@domain.com,2023-07-03,20,0
|
||||
testuser3@domain.com,2023-07-04,12,0
|
||||
testuser3@domain.com,2023-07-05,37,2
|
||||
testuser3@domain.com,2023-07-06,42,0
|
||||
testuser3@domain.com,2023-07-07,20,0
|
||||
testuser1@domain.com,2025-07-01,10,1
|
||||
testuser1@domain.com,2025-07-02,5,1
|
||||
testuser1@domain.com,2025-07-03,14,3
|
||||
testuser1@domain.com,2025-07-04,3,0
|
||||
testuser1@domain.com,2025-07-05,35,4
|
||||
testuser1@domain.com,2025-07-06,30,2
|
||||
testuser1@domain.com,2025-07-07,20,0
|
||||
testuser2@domain.com,2025-07-01,3,1
|
||||
testuser2@domain.com,2025-07-02,1,0
|
||||
testuser2@domain.com,2025-07-03,4,0
|
||||
testuser2@domain.com,2025-07-04,1,0
|
||||
testuser2@domain.com,2025-07-05,15,0
|
||||
testuser2@domain.com,2025-07-06,14,0
|
||||
testuser2@domain.com,2025-07-07,9,1
|
||||
testuser3@domain.com,2025-07-01,14,0
|
||||
testuser3@domain.com,2025-07-02,14,0
|
||||
testuser3@domain.com,2025-07-03,20,0
|
||||
testuser3@domain.com,2025-07-04,12,0
|
||||
testuser3@domain.com,2025-07-05,37,2
|
||||
testuser3@domain.com,2025-07-06,42,0
|
||||
testuser3@domain.com,2025-07-07,20,0
|
||||
```
|
||||
Report on email activity for individual users, aggregate by date across users.
|
||||
```
|
||||
$ gam report users select users testuser1,testuser2,testuser3@domain.com fields gmail:num_emails_received,gmail:num_emails_sent range 2023-07-01 2023-07-07 aggregatebydate
|
||||
$ gam report users select users testuser1,testuser2,testuser3@domain.com fields gmail:num_emails_received,gmail:num_emails_sent range 2025-07-01 2025-07-07 aggregatebydate
|
||||
Getting Reports for testuser1@domain.com (1/3)
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-01...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-02...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-03...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-04...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-05...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-06...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-07...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-01...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-02...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-03...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-04...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-05...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-06...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-07...
|
||||
Getting Reports for testuser2@domain.com (2/3)
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-01...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-02...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-03...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-04...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-05...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-06...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-07...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-01...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-02...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-03...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-04...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-05...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-06...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-07...
|
||||
Getting Reports for testuser3@domain.com (3/3)
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-01...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-02...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-03...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-04...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-05...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-06...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-07...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-01...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-02...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-03...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-04...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-05...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-06...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-07...
|
||||
date,gmail:num_emails_received,gmail:num_emails_sent
|
||||
2023-07-01,27,2
|
||||
2023-07-02,20,1
|
||||
2023-07-03,38,3
|
||||
2023-07-04,16,0
|
||||
2023-07-05,87,6
|
||||
2023-07-06,86,2
|
||||
2023-07-07,49,1
|
||||
2025-07-01,27,2
|
||||
2025-07-02,20,1
|
||||
2025-07-03,38,3
|
||||
2025-07-04,16,0
|
||||
2025-07-05,87,6
|
||||
2025-07-06,86,2
|
||||
2025-07-07,49,1
|
||||
```
|
||||
Report on email activity for individual users, aggregate by user across dates.
|
||||
```
|
||||
$ gam report users select users testuser1,testuser2,testuser3@domain.com fields gmail:num_emails_received,gmail:num_emails_sent range 2023-07-01 2023-07-07 aggregatebyuser
|
||||
$ gam report users select users testuser1,testuser2,testuser3@domain.com fields gmail:num_emails_received,gmail:num_emails_sent range 2025-07-01 2025-07-07 aggregatebyuser
|
||||
Getting Reports for testuser1@domain.com (1/3)
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-01...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-02...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-03...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-04...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-05...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-06...
|
||||
Got 1 Report for testuser1@domain.com on 2023-07-07...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-01...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-02...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-03...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-04...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-05...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-06...
|
||||
Got 1 Report for testuser1@domain.com on 2025-07-07...
|
||||
Getting Reports for testuser2@domain.com (2/3)
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-01...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-02...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-03...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-04...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-05...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-06...
|
||||
Got 1 Report for testuser2@domain.com on 2023-07-07...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-01...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-02...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-03...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-04...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-05...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-06...
|
||||
Got 1 Report for testuser2@domain.com on 2025-07-07...
|
||||
Getting Reports for testuser3@domain.com (3/3)
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-01...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-02...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-03...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-04...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-05...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-06...
|
||||
Got 1 Report for testuser3@domain.com on 2023-07-07...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-01...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-02...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-03...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-04...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-05...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-06...
|
||||
Got 1 Report for testuser3@domain.com on 2025-07-07...
|
||||
email,gmail:num_emails_received,gmail:num_emails_sent
|
||||
testuser1@domain.com,117,11
|
||||
testuser2@domain.com,47,2
|
||||
@@ -567,7 +568,7 @@ testuser3@domain.com,159,2
|
||||
```
|
||||
|
||||
## Monthly Report
|
||||
### An example, running this on 3rd December 2020;-
|
||||
### An example, running this on 3rd December 2025.
|
||||
If combined with a scheduled task or cron job, this will produce an ongoing report with a new tab/sheet for each month.
|
||||
```
|
||||
$ gam report usage customer parameters meet:total_call_minutes,meet:total_meeting_minutes skipdaysofweek sat,sun previousmonths 1 todrive tdfileid <File ID> tdtitle "Meet Usage" tdtimeformat %Y-%m-%d tdaddsheet tdsheet "" tdsheettimeformat "%B %Y" tdsheetdaysoffset 6
|
||||
@@ -576,9 +577,9 @@ $ gam report usage customer parameters meet:total_call_minutes,meet:total_meetin
|
||||
* **gam report usage customer parameters meet:total_call_minutes,meet:total_meeting_minutes** - The GAM command
|
||||
* **skipdaysofweek sat,sun** - exclude Sat & Sun, so only working days
|
||||
* **previousmonths 1** - run against the previous months date range (regardless of how many days in the month, leap year etc)
|
||||
* **todrive tdfileid <File ID> tdtitle "Meet Usage" tdtimeformat %Y-%m-%d** - write the data to an existing Google Sheet and append with current date, so it will be called "Meet Usage - 2020-12-03"
|
||||
* **todrive tdfileid <File ID> tdtitle "Meet Usage" tdtimeformat %Y-%m-%d** - write the data to an existing Google Sheet and append with current date, so it will be called "Meet Usage - 2025-12-03"
|
||||
* **tdaddsheet tdsheet ""** - Add a new tab/sheet with no name
|
||||
* **tdsheettimeformat "%B %Y" tdsheetdaysoffset 6** - give the new tab/sheet a time stamp backdated by 6 days of 'Month Year', so for this example "November 2020", which will become the name of the new tab/sheet. The offset number must take you back in time into the previous month.
|
||||
* **tdsheettimeformat "%B %Y" tdsheetdaysoffset 6** - give the new tab/sheet a time stamp backdated by 6 days of 'Month Year', so for this example "November 2025", which will become the name of the new tab/sheet. The offset number must take you back in time into the previous month.
|
||||
|
||||
**Notes**
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ By default, Gam displays the information as an indented list of keys and values.
|
||||
## Manage Resold Subscriptions
|
||||
```
|
||||
gam create resoldsubscription <CustomerID> (sku <SKUID>)
|
||||
(plan annual_monthly_pay|annual_yearly_pay|flexible|trial)
|
||||
(plan annual_monthly_pay|annual_yearly_pay|flexible|trial|free)
|
||||
(seats <Number>)
|
||||
[customer_auth_token <String>] [deal <String>] [purchaseorderid <String>]
|
||||
gam update resoldsubscription <CustomerID> <SKUID>
|
||||
|
||||
@@ -390,14 +390,14 @@ gam delete building <BuildingID>
|
||||
gam info building <BuildingID>
|
||||
[formatjson]
|
||||
gam show buildings
|
||||
[allfields|<BuildingFildName>*|(fields <BuildingFieldNameList>)]
|
||||
[allfields|<BuildingFieldName>*|(fields <BuildingFieldNameList>)]
|
||||
[formatjson]
|
||||
```
|
||||
By default, Gam displays the information as an indented list of keys and values.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
```
|
||||
gam print buildings [todrive <ToDriveAttribute>*]
|
||||
[allfields|<BuildingFildName>*|(fields <BuildingFieldNameList>)]
|
||||
[allfields|<BuildingFieldName>*|(fields <BuildingFieldNameList>)]
|
||||
[delimiter <Character>] [formatjson [quotechar <Character>]]
|
||||
```
|
||||
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format,
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
## Introduction
|
||||
GAM7 can run on a Linux or Windows [Google Compute Engine (GCE)](https://cloud.google.com/products/compute) virtual machine and use the attached service account to access Google Workspace APIs. The advantage of this configuration is that no service account private key is accessible to GAM7 directly and [there is no risk of the key being stolen/lost](https://cloud.google.com/iam/docs/best-practices-for-managing-service-account-keys#alternatives).
|
||||
|
||||
**Note**: This method is recommended when running GAM **inside** Google Cloud. If you're running GAM **outside** Google Cloud (on-premises, other cloud providers, CI/CD systems), consider [Workload Identity Federation](https://github.com/GAM-team/GAM/wiki/Using-GAM7-with-keyless-authentication-Workload-Identity-Federation) instead - Google's officially recommended keyless authentication method for external environments.
|
||||
|
||||
## Setup Steps
|
||||
1. Create a [GCP project](https://cloud.google.com/resource-manager/docs/creating-managing-projects).
|
||||
|
||||
|
||||
@@ -392,7 +392,7 @@ Your command line will have: `embedimage file1.jpg image1 embedimage file2.jpg i
|
||||
|
||||
## Send an email to users
|
||||
```
|
||||
gam <UserTypeEntity> sendemail [from <EmailAddress>]
|
||||
gam <UserTypeEntity> sendemail from <EmailAddress>
|
||||
[replyto <EmailAddress>]
|
||||
[cc <RecipientEntity>] [bcc <RecipientEntity>] [singlemessage]
|
||||
[subject <String>]
|
||||
@@ -406,8 +406,6 @@ gam <UserTypeEntity> sendemail [from <EmailAddress>]
|
||||
```
|
||||
Emails will be sent to the users in `<UserTypeEntity>`.
|
||||
|
||||
By default, emails will be sent from the admin user named in oauth2.txt, override this with the `from <EmailAddress>` option.
|
||||
|
||||
When using the Gmail API/SMTP, GAM gets no/little indication as to the status of the message delivery; the from user will get a non-delivery receipt if the message
|
||||
could not be sent to the specified recipients.
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
- [Query documentation](#query-documentation)
|
||||
- [Definitions](#definitions)
|
||||
- [Introduction](#introduction)
|
||||
- [GUI API permission name mapping](#gui-api-permission-name-mapping)
|
||||
- [API GUI permission name mapping](#api-gui-permission-name-mapping)
|
||||
- [API GUI restriction name mapping](#api-gui-restriction-name-mapping)
|
||||
- [Display Shared Drive themes](#display-shared-drive-themes)
|
||||
- [Manage Shared Drives](#manage-shared-drives)
|
||||
- [Create a Shared Drive](#create-a-shared-drive)
|
||||
@@ -45,6 +46,8 @@
|
||||
* [Shared Drives Search](https://developers.google.com/drive/api/guides/search-shareddrives)
|
||||
|
||||
## Definitions
|
||||
* [`<FileSelector> | <CSVFileSelector>`](Collections-of-Items)
|
||||
|
||||
```
|
||||
<ColorHex> ::= "#<Hex><Hex><Hex><Hex><Hex><Hex>"
|
||||
<ColorNameGoogle> ::=
|
||||
@@ -180,6 +183,7 @@
|
||||
createdtime|
|
||||
id|
|
||||
name|
|
||||
restrictions|
|
||||
themeid
|
||||
<SharedDriveFieldNameList> ::= "<SharedDriveFieldName>(,<SharedDriveFieldName>)*"
|
||||
|
||||
@@ -200,17 +204,12 @@
|
||||
allowcontentmanagerstosharefolders|
|
||||
copyrequireswriterpermission|
|
||||
domainusersonly|
|
||||
downloadrestrictedforreaders|downloadrestrictions.restrictedforreaders|
|
||||
downloadrestrictedforwriters|downloadrestrictions.restrictedforwriters|
|
||||
drivemembersonly|teammembersonly|
|
||||
sharingfoldersrequiresorganizerpermission
|
||||
|
||||
Each pair of restrictions below are equivalent:
|
||||
|
||||
allowcontentmanagerstosharefolders true
|
||||
sharingfoldersrequiresorganizerpermission false
|
||||
|
||||
allowcontentmanagerstosharefolders false
|
||||
sharingfoldersrequiresorganizerpermission true
|
||||
```
|
||||
|
||||
## Introduction
|
||||
A domain administrator with the Drive and Docs administrator privilege can search for Shared Drives or update permissions for Shared Drives
|
||||
owned by their organization, regardless of the admin's membership in any given Shared Drive.
|
||||
@@ -220,15 +219,47 @@ Three forms of the commands are available:
|
||||
* `gam <UserTypeEntity> action ... adminaccess` - The user named in `<UserTypeEntty>` is used, adminaccess indicates that the user is a domain administrator
|
||||
* `gam <UserTypeEntity> action ...` - The user named in `<UserTypeEntty>` is used, access is limited to drives for which they are an organizer
|
||||
|
||||
## GUI API permission name mapping
|
||||
## API GUI permission name mapping
|
||||
|
||||
| GUI setting | API setting |
|
||||
|------------|------------|
|
||||
| Manager | organizer |
|
||||
| Content manager | fileOrganizer |
|
||||
| Contributor | writer |
|
||||
| Commenter | commenter |
|
||||
| Viewer | reader |
|
||||
| API setting | GUI setting |
|
||||
|-------------|-------------|
|
||||
| organizer | Manager |
|
||||
| fileOrganizer | Content manager |
|
||||
| writer | Contributor |
|
||||
| commenter | Commenter |
|
||||
| reader | Viewer |
|
||||
|
||||
## API GUI restriction name mapping
|
||||
| API Setting | Description |
|
||||
|-------------|-------------|
|
||||
| adminManagedRestrictions | Whether administrative privileges on this shared drive are required to modify restrictions. |
|
||||
| domainUsersOnly | Whether access to this shared drive and items inside this shared drive is restricted to users of the domain to which this shared drive belongs. |
|
||||
| driveMembersOnly | Whether access to items inside this shared drive is restricted to its members. |
|
||||
| allowContentManagersToShareFolders (GAM defined) | If true, users with either the organizer role or the file organizer role can share folders. If false, only users with the organizer role can share folders. |
|
||||
| sharingFoldersRequiresOrganizerPermission | If true, only users with the organizer role can share folders. If false, users with either the organizer role or the file organizer role can share folders. |
|
||||
| copyRequiresWriterPermission | Whether the options to copy, print, or download files inside this shared drive, should be disabled for readers and commenters. |
|
||||
| downloadRestrictions.restrictedForWriters | Whether download and copy is restricted for writers. If true, download is also restricted for readers. |
|
||||
| downloadRestrictions.restrictedForReaders | Whether download and copy is restricted for readers. |
|
||||
|
||||
| API Setting | False | True | GUI Setting | Checked | Unchecked |
|
||||
|-------------|-------|------|-------------|---------|-----------|
|
||||
| adminManagedRestrictions | X | | Shared drive settings can be modified | | |
|
||||
| adminManagedRestrictions | | X | Shared drive settings can **not** be modified | | |
|
||||
| | | | **Access** |
|
||||
| domainUsersOnly | X | | Allow people outside of Domain name to access files | X | |
|
||||
| domainUsersOnly | | X | Allow people outside of Domain name to access files | | X |
|
||||
| driveMembersOnly | X | | Allow people who aren't shared drive members to access files | X | |
|
||||
| driveMembersOnly | | X | Allow people who aren't shared drive members to access files | | X |
|
||||
| | | | **Role permissions** |
|
||||
| allowContentManagersToShareFolders | X | | Allow content managers to share folders | | X |
|
||||
| allowContentManagersToShareFolders | | X | Allow content managers to share folders | X | |
|
||||
| sharingFoldersRequiresOrganizerPermission | X | | Allow content managers to share folders | X | |
|
||||
| sharingFoldersRequiresOrganizerPermission | | X | Allow content managers to share folders | | X |
|
||||
| | | | **People who can download, copy, and print** |
|
||||
| downloadRestrictions.restrictedForWriters | X | | Contributors and content managers | X | |
|
||||
| downloadRestrictions.restrictedForWriters | | X | Contributors and content managers | | X |
|
||||
| downloadRestrictions.restrictedForReaders | X | | Commenters and viewers | X | |
|
||||
| downloadRestrictions.restrictedForReaders | | X | Commenters and viewers | | X |
|
||||
|
||||
## Display Shared Drive themes
|
||||
```
|
||||
@@ -242,7 +273,7 @@ The user that creates a Shared Drive is given the permission role organizer for
|
||||
gam [<UserTypeEntity>] create shareddrive <Name>
|
||||
[(theme|themeid <String>)|
|
||||
([customtheme <DriveFileID> <Float> <Float> <Float>] [color <ColorValue>])]
|
||||
(<SharedDriveRestrictionsSubfieldName> <Boolean>)*
|
||||
([restrictions.]<SharedDriveRestrictionsSubfieldName> <Boolean>)*
|
||||
[hide <Boolean>] [ou|org|orgunit <OrgUnitItem>]
|
||||
[errorretries <Integer>] [updateinitialdelay <Integer>] [updateretrydelay <Integer>]
|
||||
[(csv [todrive <ToDriveAttribute>*] (addcsvdata <FieldName> <String>)*) | returnidonly]
|
||||
@@ -254,7 +285,7 @@ gam [<UserTypeEntity>] create shareddrive <Name>
|
||||
* `<Float>` - Y coordinate, typically 0.0
|
||||
* `<Float>` - width, typically 1.0
|
||||
* `color` - set the Shared Drive color
|
||||
* `<SharedDriveRestrictionsSubfieldName> <Boolean>` - Set Shared Drive Restrictions
|
||||
* `[restrictions.]<SharedDriveRestrictionsSubfieldName> <Boolean>` - Set Shared Drive Restrictions
|
||||
* `hide <Boolean>` - Set Shared Drive visibility
|
||||
|
||||
If any attributes other than `themeid` are specified, GAM must create the Drive and then update the Drive attributes.
|
||||
@@ -328,13 +359,13 @@ gam [<UserTypeEntity>] update shareddrive <SharedDriveEntity> [name <Name>]
|
||||
[adminaccess|asadmin]
|
||||
[(theme|themeid <String>)|
|
||||
([customtheme <DriveFileID> <Float> <Float> <Float>] [color <ColorValue>])]
|
||||
(<SharedDriveRestrictionsSubfieldName> <Boolean>)*
|
||||
([restrictions.]<SharedDriveRestrictionsSubfieldName> <Boolean>)*
|
||||
[hide|hidden <Boolean>] [ou|org|orgunit <OrgUnitItem>]
|
||||
```
|
||||
* `themeid` - a Shared Drive themeId obtained from `show shareddrivethemes`
|
||||
* `customtheme` - set the backgroundImageFile property described here: https://developers.google.com/drive/v3/reference/teamdrives
|
||||
* `color` - set the Shared Drive color
|
||||
* `<SharedDriveRestrictionsSubfieldName> <Boolean>` - Set Shared Drive Restrictions
|
||||
* `[restrictions.]<SharedDriveRestrictionsSubfieldName> <Boolean>` - Set Shared Drive Restrictions
|
||||
* `hidden <Boolean>` - Set Shared Drive visibility
|
||||
|
||||
* `ou|org|orgunit <OrgUnitItem>` - See: https://workspaceupdates.googleblog.com/2022/05/shared-drives-in-organizational-units-open-beta.html
|
||||
@@ -372,26 +403,38 @@ By default, Gam displays the information as an indented list of keys and values.
|
||||
gam [<UserTypeEntity>] show shareddrives
|
||||
[adminaccess|asadmin] [teamdriveadminquery|query <QueryTeamDrive>]
|
||||
[matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>]
|
||||
[fields <SharedDriveFieldNameList>] [formatjson]
|
||||
[fields <SharedDriveFieldNameList>]
|
||||
[showwebviewlink text|hyperlink]
|
||||
[formatjson]
|
||||
```
|
||||
By default, all Shared Drives are displayed; use the following options to select a subset of Shared Drives:
|
||||
* `teamdriveadminquery|query <QueryTeamDrive>` - Use a query to select Shared Drives
|
||||
* `matchname <REMatchPattern>` - Retrieve Shared Drives with names that match a pattern.
|
||||
* `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected
|
||||
|
||||
Use option `showwebviewlink` to display the web view link for the Shared Drive.
|
||||
* `showwebviewlink text` - Displays `https://drive.google.com/drive/folders/<SharedDriveID>`
|
||||
* `showwebviewlink hyperlink` - Dsiplays `=HYPERLINK("https://drive.google.com/drive/folders/<SharedDriveID>", "<SharedDriveName>")`
|
||||
|
||||
By default, Gam displays the information as an indented list of keys and values.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
```
|
||||
gam [<UserTypeEntity>] print shareddrives [todrive <ToDriveAttribute>*]
|
||||
[adminaccess|asadmin] [teamdriveadminquery|query <QueryTeamDrive>]
|
||||
[matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>]
|
||||
[fields <SharedDriveFieldNameList>] [formatjson [quotechar <Character>]]
|
||||
[fields <SharedDriveFieldNameList>]
|
||||
[showwebviewlink text|hyperlink]
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
By default, all Shared Drives are displayed; use the following options to select a subset of Shared Drives:
|
||||
* `teamdriveadminquery|query <QueryTeamDrive>` - Use a query to select Shared Drives
|
||||
* `matchname <REMatchPattern>` - Retrieve Shared Drives with names that match a pattern.
|
||||
* `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected
|
||||
|
||||
Use option `showwebviewlink` to display the web view link for the Shared Drive.
|
||||
* `showwebviewlink text` - Displays `https://drive.google.com/drive/folders/<SharedDriveID>`
|
||||
* `showwebviewlink hyperlink` - Dsiplays `=HYPERLINK("https://drive.google.com/drive/folders/<SharedDriveID>", "<SharedDriveName>")`
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ You can modify the default todrive behavior with options in `gam.cfg` or on the
|
||||
|
||||
## Definitions
|
||||
```
|
||||
<DateTimeFormat> ::= <String>
|
||||
See: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes
|
||||
<DriveFileID> ::= <String>
|
||||
<DriveFolderID> ::= <String>
|
||||
<TimeZone> ::= <String>
|
||||
@@ -194,11 +196,11 @@ direct the uploaded file to a particular user and location and add a timestamp t
|
||||
(tdreturnidonly [<Boolean>])|
|
||||
(tdshare <EmailAddress> commenter|reader|writer)*|
|
||||
(tdsheet (id:<Number>)|<String>)|
|
||||
(tdsheettimestamp [<Boolean>] [tdsheettimeformat <String>])
|
||||
(tdsheettimestamp [<Boolean>] [tdsheettimeformat <DateTimeFormat>])
|
||||
(tdsheettitle <String>)|
|
||||
(tdsubject <String>)|
|
||||
([tdsheetdaysoffset <Number>] [tdsheethoursoffset <Number>])|
|
||||
(tdtimestamp [<Boolean>] [tdtimeformat <String>]
|
||||
(tdtimestamp [<Boolean>] [tdtimeformat <DateTimeFormat>]
|
||||
([tddaysoffset <Number>] [tdhoursoffset <Number>])|
|
||||
(tdtimezone <TimeZone>)|
|
||||
(tdtitle <String>)|
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
(foregroundcolor <ColorValue>)|
|
||||
(hidden <Boolean>)|
|
||||
(notification clear|(email <CalendarEmailNotificatonEventTypeList>))|
|
||||
(reminder clear|(email|popup <Number>)|(<Number> email|popup))|
|
||||
(reminder clear|(email|popup <Number>)|(<Number> email|popup))*|
|
||||
(selected <Boolean>)|
|
||||
(summary <String>)
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
- [Manage Chat Messages](#manage-chat-messages)
|
||||
- [Display Chat Messages](#display-chat-messages)
|
||||
- [Display Chat Events](#display-chat-events)
|
||||
- [Manage Chat Emojis](#manage-chat-emojis)
|
||||
- [Display Chat Emojis](#display-chat-emojis)
|
||||
- [Bulk Operations](#bulk-operations)
|
||||
|
||||
## Introduction
|
||||
@@ -19,6 +21,7 @@ To use these commands you must update your service account authorization.
|
||||
```
|
||||
gam user user@domain.com update serviceaccount
|
||||
|
||||
[*] 3) Chat API - Custom Emojis (supports readonly)
|
||||
[*] 4) Chat API - Memberships (supports readonly)
|
||||
[*] 5) Chat API - Memberships Admin (supports readonly)
|
||||
[*] 6) Chat API - Messages (supports readonly)
|
||||
@@ -41,6 +44,7 @@ Google requires that you have a Chat Bot configured in order to use the Chat API
|
||||
## Set up a Chat Bot
|
||||
|
||||
* Run the command `gam setup chat`; it will point you to a URL to configure your Chat Bot.
|
||||
* Uncheck "Build this chat app as a workspace add-on"
|
||||
* Enter an App name and Description of your choosing.
|
||||
* For the Avatar URL you can use `https://dummyimage.com/384x256/4d4d4d/0011ff.png&text=+GAM` or a public URL to an image of your own choosing.
|
||||
* In Functionality, uncheck both "Receive 1:1 messages" and "Join spaces and group conversations"
|
||||
@@ -51,10 +55,12 @@ Google requires that you have a Chat Bot configured in order to use the Chat API
|
||||
## API documentation
|
||||
* [Overview](https://developers.google.com/workspace/chat/overview)
|
||||
* [Chat API](https://developers.google.com/workspace/chat/api/reference/rest)
|
||||
* [Chat API - Custom Emojis](https://developers.google.com/workspace/chat/api/reference/rest/v1/customEmojis)
|
||||
* [Chat API - Members](https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.members/list)
|
||||
* [Chat API - Messages](https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.messages/list)
|
||||
* [Chat API - Events](https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.spaceEvents/list)
|
||||
* [Apps in Google Chat](https://support.google.com/chat/answer/7655820)
|
||||
* [Manage customemoji permissions](https://support.google.com/a/answer/12850085)
|
||||
* [Manage Spaces in Admin Console](https://support.google.com/a/answer/13369245)
|
||||
* [Predefined permission settings](https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces#Space.FIELDS.predefined_permission_settings)
|
||||
|
||||
@@ -83,6 +89,8 @@ Google requires that you have a Chat Bot configured in order to use the Chat API
|
||||
(gdoc <UserGoogleDoc>)|
|
||||
(gcsdoc <StorageBucketObjectName>))
|
||||
|
||||
<ChatEmojiName> ::= :[0-9a-z_-]+:
|
||||
<ChatEmoji> ::= emojiname <ChatEmojiName> | customemojis/<String>
|
||||
<ChatEvent> ::= spaces/<String>/spaceEvents/<String>
|
||||
<ChatMember> ::= spaces/<String>/members/<String>
|
||||
<ChatMemberList> ::= "<ChatMember>(,<ChatMember>)*"
|
||||
@@ -313,24 +321,32 @@ By default, Gam displays the information as an indented list of keys and values.
|
||||
```
|
||||
gam <UserTypeEntity> show chatspaces
|
||||
[types <ChatSpaceTypeList>]
|
||||
[fields <ChatSpaceFieldNameList>]
|
||||
[fields <ChatSpaceFieldNameList>] [showaccessssettings]
|
||||
[formatjson]
|
||||
```
|
||||
By default, chat spaces of all types are displayed.
|
||||
* `types <ChatSpaceTypeList>` - Display specific types of spaces.
|
||||
|
||||
When listing Chat Spaces, the Chat API does not return the `accessSettings` field; if you need to see this fieldf,
|
||||
add `showaccesssettings` to the command. This requires an additional Chat API call per chat space of type `SPACE`
|
||||
to get the `accessSettings` field.
|
||||
|
||||
By default, Gam displays the information as an indented list of keys and values.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
|
||||
```
|
||||
gam <UserTypeEntity> print chatspaces [todrive <ToDriveAttribute>*]
|
||||
[types <ChatSpaceTypeList>]
|
||||
[fields <ChatSpaceFieldNameList>]
|
||||
[fields <ChatSpaceFieldNameList>] [showaccessssettings]
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
By default, chat spaces of all types are displayed.
|
||||
* `types <ChatSpaceTypeList>` - Display specific types of spaces.
|
||||
|
||||
When listing Chat Spaces, the Chat API does not return the `accessSettings` field; if you need to see this fieldf,
|
||||
add `showaccesssettings` to the command. This requires an additional Chat API call per chat space of type `SPACE`
|
||||
to get the `accessSettings` field.
|
||||
|
||||
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.
|
||||
|
||||
@@ -378,13 +394,17 @@ Only spaces of `<ChatSpaceType>` `space` are displayed; spaces of `<ChatSpaceTyp
|
||||
gam <UserItem> show chatspaces asadmin
|
||||
[query <String>] [querytime<String> <Time>]
|
||||
[orderby <ChatSpaceAdminOrderByFieldName> [ascending|descending]]
|
||||
[fields <ChatSpaceFieldNameList>]
|
||||
[fields <ChatSpaceFieldNameList>] [showaccessssettings]
|
||||
[formatjson]
|
||||
```
|
||||
By default, all chat spaces of type SPACE are displayed.
|
||||
* `query <String> [querytime<String> <Time>]` - Display selected chat spaces
|
||||
* See: https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces/search
|
||||
|
||||
When listing Chat Spaces, the Chat API does not return the `accessSettings` field; if you need to see this fieldf,
|
||||
add `showaccesssettings` to the command. This requires an additional Chat API call per chat space of type `SPACE`
|
||||
to get the `accessSettings` field.
|
||||
|
||||
By default, Gam displays the information as an indented list of keys and values.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
|
||||
@@ -392,13 +412,17 @@ By default, Gam displays the information as an indented list of keys and values.
|
||||
gam <UserItem> print chatspaces asadmin [todrive <ToDriveAttribute>*]
|
||||
[query <String>] [querytime<String> <Time>]
|
||||
[orderby <ChatSpaceAdminOrderByFieldName> [ascending|descending]]
|
||||
[fields <ChatSpaceFieldNameList>]
|
||||
[fields <ChatSpaceFieldNameList>] [showaccessssettings]
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
By default, all chat spaces of type SPACE are displayed.
|
||||
* `query <String> [querytime<String> <Time>]` - Display selected chat spaces
|
||||
* See: https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces/search
|
||||
|
||||
When listing Chat Spaces, the Chat API does not return the `accessSettings` field; if you need to see this fieldf,
|
||||
add `showaccesssettings` to the command. This requires an additional Chat API call per chat space of type `SPACE`
|
||||
to get the `accessSettings` field.
|
||||
|
||||
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.
|
||||
|
||||
@@ -457,7 +481,7 @@ gam <UserItem> delete chatmember asadmin <ChatSpace>
|
||||
|
||||
Delete members from a chat space by specifying chatmember names, asadmin
|
||||
```
|
||||
gam <UserItem> remove chatmember members asadmin <ChatMemberList>
|
||||
gam <UserItem> remove chatmember asadmin members <ChatMemberList>
|
||||
```
|
||||
|
||||
### Update a members role in a user's chat space
|
||||
@@ -896,11 +920,81 @@ filter 'start_time=\"2024-03-15T11:30:00-04:00\" AND event_types:\"google.worksp
|
||||
filter 'start_time=\"2024-03-15T11:30:00+00:00\" AND end_time=\"2024-03-3100:00:00+00:00\" AND event_types:\"google.workspace.chat.message.v1.created\"'
|
||||
```
|
||||
|
||||
## Manage Chat Emojis
|
||||
|
||||
### Create a Chat Emoji
|
||||
```
|
||||
gam <UserTypeEntity> create chatemoji <ChatEmojiName>
|
||||
([drivedir|(sourcefolder <FilePath>)] [filename <FileNamePattern>])
|
||||
[formatjson]
|
||||
```
|
||||
Emoji names must start and end with colons, must be lowercase and can only contain alphanumeric characters, hyphens, and underscores.
|
||||
Hyphens and underscores should be used to separate words and cannot be used consecutively.
|
||||
|
||||
By default, the emoji file will be uploaded from the current working directory.
|
||||
* `drivedir` - The emoji file will be uploaded from the directory specified by `drive_dir` in gam.cfg
|
||||
* `sourcefolder <FilePath>` - The emoji file will be uploaded from `<FilePath>`
|
||||
|
||||
Specify the emoji file name; the following substitutions will be made:
|
||||
* `#email#` and `#user#` will be replaced by the user's full email address
|
||||
* `#username#` will be replaced by the local part of the user's email address
|
||||
|
||||
### Delete a Chat Emoji
|
||||
Deletes the given Chat emoji.
|
||||
|
||||
```
|
||||
gam <UserTypeEntity> delete chatemoji <Chatemoji>
|
||||
```
|
||||
|
||||
## Display Chat Emojis
|
||||
### Display a specific Chat emoji
|
||||
|
||||
```
|
||||
gam <UserTypeEntity> info chatemoji <Chatemoji>
|
||||
[formatjson]
|
||||
```
|
||||
By default, Gam displays the information as an indented list of keys and values.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
|
||||
### Display information about all chat emojis
|
||||
```
|
||||
gam <UserTypeEntity> show chatemojis
|
||||
[showcreatedby any|me|others]
|
||||
[formatjson]
|
||||
```
|
||||
Select emojis to display:
|
||||
* `showcreatedby any` - Display all emojis regardless of creator
|
||||
* `showcreatedby ` - Display all emojis created by the user; this is the default
|
||||
* `showcreatedby others` - Display all emojis not created by the user
|
||||
|
||||
By default, Gam displays the information as an indented list of keys and values.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
|
||||
```
|
||||
gam <UserTypeEntity> print chatemojis [todrive <ToDriveAttribute>*]
|
||||
[showcreatedby any|me|others]
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
Select emojis to display:
|
||||
* `showcreatedby any` - Display all emojis regardless of creator
|
||||
* `showcreatedby ` - Display all emojis created by the user; this is the default
|
||||
* `showcreatedby others` - Display all emojis not created by the user
|
||||
|
||||
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.
|
||||
|
||||
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
|
||||
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
|
||||
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.
|
||||
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
|
||||
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
|
||||
|
||||
## Bulk Operations
|
||||
### Display information about all chat spaces for a collection of users
|
||||
```
|
||||
gam config auto_batch_min 1 redirect csv ./ChatSpaces.csv multiprocess [todrive <ToDriveAttribute>*] redirect stdout - multiprocess redirect stderr <UserTypeEntity> print chatspaces
|
||||
gam config auto_batch_min 1 redirect csv ./ChatSpaces.csv multiprocess [todrive <ToDriveAttribute>*] redirect stdout - multiprocess redirect stderr <UserTypeEntity> print chatsacesp
|
||||
[types <ChatSpaceTypeList>]
|
||||
[fields <ChatSpaceFieldNameList>] [showaccessssettings]
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
- [Move with ownership change](#move-with-ownership-change)
|
||||
- [Complex moves](#complex-moves)
|
||||
- [Move content of a Shared Drive to another Shared Drive](#move-content-of-a-shared-drive-to-another-shared-drive)
|
||||
- [Move content of a Shared Drive to a My Drive](#move-content-of-a-shared-drive-to-a-my-drive)
|
||||
|
||||
## API documentation
|
||||
* [Drive API - Files](https://developers.google.com/drive/api/v3/reference/files)
|
||||
@@ -569,17 +570,12 @@ gam config auto_batch_min 1 csv_output_row_filter "owners.0.emailAddress:notrege
|
||||
### Multiple parents
|
||||
No existing parents are copied for source top/sub files/folders.
|
||||
|
||||
### Removed options
|
||||
The following options will generate an error; they were removed in 6.23.00:
|
||||
* `copysubfileparents` and `copysubfolderparents`.
|
||||
|
||||
### Move Folder Permissions
|
||||
When a folder is moved by recreating it, its permissions are not copied; these options control copying permissions for folders.
|
||||
When a folder is moved by recreating it, its permissions are not copied by the Drive API; these options control copying permissions for folders.
|
||||
|
||||
For options of the form `option [<Boolean>]`; if `<Boolean>` is omitted, `true` is assumed.
|
||||
|
||||
When recreated, a target folder inherits the permissions of its parent folder; these options control whether/how GAM copies the existing source folder permissions;
|
||||
The default values of options introduced in version 6.14.00 are set to match the behavior of earlier versions.
|
||||
|
||||
When `mergewithparent` is `true`:
|
||||
* `copymergewithparentfolderpermissions false` - The permissions of the source top folder are not not copied to the target folder; this is the default action.
|
||||
@@ -593,7 +589,7 @@ When `duplicatefolders` is `merge` and a sub folder is a duplicate:
|
||||
* `copymergedsubfolderpermissions false` - The permissions of the source sub folder are not not copied to the target folder.
|
||||
* `copymergedsubfolderpermissions true` - The permissions of the source sub folder are copied to the target folder; this is the default action.
|
||||
|
||||
When `duplicatefolders` is `duplicatename` or `uniquename` and a top/sub folder is not a duplicate:
|
||||
When `duplicatefolders` is `merge` or `duplicatename` or `uniquename` and a top/sub folder is not a duplicate:
|
||||
* `copytopfolderpermissions true` - The permissions of the source top folder are copied to the target folder; this is the default action.
|
||||
* `copytopfolderpermissions false` - The permissions of the source top folder are not not copied to the target folder.
|
||||
* `copysubfolderpermissions true` - The permissions of the source sub folders are copied to the target folder; this is the default action.
|
||||
@@ -673,8 +669,10 @@ gam user user@domain.com move drivefile teamdriveid 0AC_1AB teamdriveparentid 0A
|
||||
```
|
||||
|
||||
If you want the source Shared Drive with ID 0AC_1AB to be contained in a top level folder of the target Shared Drive with ID 0AE_9ZX, omit the `mergewithparent` argument.
|
||||
The folder on the target Shared Drive will have the same name as the name of the source Shared Drive; use the `newfilename <DriveFileName>` to use a different name.
|
||||
```
|
||||
gam user user@domain.com move drivefile teamdriveid 0AC_1AB teamdriveparentid 0AE_9ZX
|
||||
gam user user@domain.com move drivefile teamdriveid 0AC_1AB teamdriveparentid 0AE_9ZX newfilename "Copy of source Shared Drive"
|
||||
```
|
||||
|
||||
### Inter-workspace moves
|
||||
@@ -692,3 +690,21 @@ User: user@domaina.com, Move 1 Drive File/Folder
|
||||
User: user@domaina.com, Drive Folder: Shared Drive A(<SharedDriveAID>), Retained
|
||||
```
|
||||
To get this to work, you must check `Allow people outside of Domain A to access files` on Shared Drive A in domaina.com
|
||||
|
||||
## Move content of a Shared Drive to a My Drive
|
||||
Suppose you have a Shared Drive with ID 0AC_1AB with multiple files and folders, and want to move all of its content to the root of a My Drive.
|
||||
|
||||
The following command will change the parents of the top level files and folders from 0AC_1AB to the root of the My Drive; the sub files and folders will move along with their top level folder.
|
||||
|
||||
* No permissions are processed.
|
||||
```
|
||||
gam user user@domain.com move drivefile teamdriveid 0AC_1AB parentid root mergewithparent
|
||||
```
|
||||
|
||||
If you want the contents of Shared Drive with ID 0AC_1AB to be contained in a top level folder of the My Drive, omit the `mergewithparent` argument.
|
||||
The folder on the My Drive will have the same name as the name of the Shared Drive; use the `newfilename <DriveFileName>` to use a different name.
|
||||
```
|
||||
gam user user@domain.com move drivefile teamdriveid 0AC_1AB parentid root
|
||||
gam user user@domain.com move drivefile teamdriveid 0AC_1AB parentid root newfilename "Copy of Shared Drive"
|
||||
```
|
||||
|
||||
|
||||
@@ -157,12 +157,16 @@
|
||||
contentrestrictions.restrictiontime|
|
||||
contentrestrictions.type
|
||||
|
||||
<DriveLabelInfoSubfieldName> ::=
|
||||
<DriveDownloadRestrictionsSubfieldName> ::=
|
||||
downloadrestrictions.itemdownloadrestriction|
|
||||
downloadrestrictions.effectivedownloadrestrictionwithcontext
|
||||
|
||||
<ClassificationLabelInfoSubfieldName> ::=
|
||||
labels.id| # modifiedByMe
|
||||
labels.revisionid| # copyRequiresWriterPermission
|
||||
labels.fields # viewedByMe
|
||||
|
||||
<DriveLabelsSubfieldName> ::=
|
||||
<ClassificationLabelsSubfieldName~> ::=
|
||||
labels.modified| # modifiedByMe
|
||||
labels.restricted| # copyRequiresWriterPermission
|
||||
labels.starred| # starred
|
||||
@@ -251,6 +255,8 @@
|
||||
copyrequireswriterpermission|
|
||||
createddate|createdtime|
|
||||
description|
|
||||
downloadrestictions|
|
||||
<DriveDownloadRestrictionsSubfieldName>|
|
||||
driveid|
|
||||
drivename|
|
||||
editable|
|
||||
@@ -269,9 +275,9 @@
|
||||
inheritedpermissionsdisabled|
|
||||
isappauthorized|
|
||||
labelinfo|
|
||||
<DriveLabelInfoSubfieldName>|
|
||||
<ClassificationLabelInfoSubfieldName>|
|
||||
labels|
|
||||
<DriveLabelsSubfieldName>|
|
||||
<ClassificationLabelsSubfieldName>|
|
||||
lastmodifyinguser|
|
||||
<DriveLastModifyingUserSubfieldName>|
|
||||
lastmodifyingusername|
|
||||
@@ -968,7 +974,8 @@ Display a list of file/folder names indented to show structure.
|
||||
owners|
|
||||
parents|
|
||||
size|
|
||||
trashed
|
||||
trashed|
|
||||
webviewlink
|
||||
<FileTreeFieldNameList> ::= "<FileTreeFieldName>(,<FileTreeFieldName>)*"
|
||||
|
||||
gam <UserTypeEntity> print filetree [todrive <ToDriveAttribute>*]
|
||||
@@ -1722,9 +1729,9 @@ User,Owner,id,name,ownedByMe,trashed,explicitlyTrashed,directFileCount,directFil
|
||||
user@domain.com,user@domain.com,012YenC8f12ALUk9PVA,My Drive,,False,False,100,138212,24,167,189598,79,-1,My Drive
|
||||
user@domain.com,user@domain.com,Trash,Trash,,True,True,0,0,1,3,3072,9,-1,Trash
|
||||
|
||||
$ gam redirect csv ./MyDriveUsage.csv user user@domain.com print diskusage shareddriveid 0AL5LiIe4dqxZUk9PVA show summaryandtrash
|
||||
$ gam redirect csv ./SharedDriveUsage.csv user user@domain.com print diskusage shareddriveid 0AL5LiIe4dqxZUk9PVA show summaryandtrash
|
||||
User: user@domain.com, Print 1 Drive Disk Usage
|
||||
$ more MyDriveUsage.csv
|
||||
$ more SharedDriveUsage.csv
|
||||
User,id,name,trashed,explicitlyTrashed,directFileCount,directFileSize,directFolderCount,totalFileCount,totalFileSize,totalFolderCount,depth,path
|
||||
user@domain.com,0125LiIe4dqxZUk9PVA,TS Shared Drive 1,False,False,16,6144,7,42,73799,25,-1,SharedDrives/TS Shared Drive 1
|
||||
user@domain.com,Trash,Trash,True,True,1,1024,0,1,1024,0,-1,Trash
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
<ColorValue> ::= <ColorName>|<ColorHex>
|
||||
```
|
||||
```
|
||||
<DateTimeFormat> ::= <String>
|
||||
See: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes
|
||||
<DomainName> ::= <String>(.<String>)+
|
||||
<EmailAddress> ::= <String>@<DomainName>
|
||||
<DriveFileRevisionID> ::= <String>
|
||||
@@ -125,6 +127,7 @@
|
||||
(folderColorRgb <ColorValue>)|
|
||||
(indexabletext <String>)|
|
||||
(inheritedpermissionsdisabled [<Boolean>])|
|
||||
(itemdownloadrestriction restrictedforreaders|restrictedforwriters [<Boolean>])|
|
||||
(keeprevisionforever|pinned)|
|
||||
(lastviewedbyme <Time>)|
|
||||
(mimetype <MimeType>)|
|
||||
@@ -177,7 +180,7 @@ gam <UserTypeEntity> create|add drivefile
|
||||
[(localfile <FileName>|-)|(url <URL>)]
|
||||
[(drivefilename|newfilename <DriveFileName>) | (replacefilename <REMatchPattern> <RESubstitution>)*]
|
||||
[stripnameprefix <String>] [noduplicate]
|
||||
[timestamp [<Boolean>]] [timeformat <String>]
|
||||
[timestamp [<Boolean>]] [timeformat <DateTimeFormat>]
|
||||
<DriveFileCreateAttribute>*
|
||||
[(csv [todrive <ToDriveAttribute>*] (addcsvdata <FieldName> <String>)*) |
|
||||
(returnidonly|returnlinkonly|returneditlinkonly|showdetails)]
|
||||
@@ -477,7 +480,7 @@ gam <UserTypeEntity> update drivefile <DriveFileEntity> [copy] [returnidonly|ret
|
||||
[(localfile <FileName>|-)|(url <URL>)]
|
||||
[retainname | (newfilename <DriveFileName>) | (replacefilename <REMatchPattern> <RESubstitution>)*]
|
||||
[stripnameprefix <String>]
|
||||
[timestamp [<Boolean>]] [timeformat <String>]
|
||||
[timestamp [<Boolean>]] [timeformat <DateTimeFormat>]
|
||||
<DriveFileUpdateAttribute>*
|
||||
[(gsheet|csvsheet <SheetEntity> [clearfilter])|(addsheet <String>)]
|
||||
[charset <Charset>] [columndelimiter <Character>]
|
||||
|
||||
@@ -10,10 +10,16 @@
|
||||
- [Delete all ACLs except owner from a user's My Drive](#delete-all-acls-except-owner-from-a-users-my-drive)
|
||||
- [Change shares to User1 to shares to User2](#change-shares-to-user1-to-shares-to-user2)
|
||||
- [Map All ACLs from an old domain to a new domain](#map-all-acls-from-an-old-domain-to-a-new-domain)
|
||||
- [Remove ACLs for a specific user or group email address](#remove-ACLs-for-a-specific-user-or-group-email-address)
|
||||
- [Remove ACLs for all users-groups in external domains](#remove-acls-for-all-users-groups-in-external-domains)
|
||||
- [Remove domainCanFind-domainWithLink ACLs for internal domain](#remove-domaincanfind-domainwithlink-acls-for-internal-domain)
|
||||
- [Remove My Drive ACLs for external domains](#remove-my-drive-acls-for-external-domains)
|
||||
- [Remove anyoneCanFind-anyoneWithLink ACLs](#remove-anyonecanfind-anyonewithlink-acls)
|
||||
|
||||
## API documentation
|
||||
* [Drive API - Permissions](https://developers.google.com/drive/api/v3/reference/permissions)
|
||||
* [Shortcuts](https://developers.google.com/drive/api/guides/shortcuts)
|
||||
* [Roles and permissions](https://developers.google.com/workspace/drive/api/guides/ref-roles)
|
||||
* [Limited and Expansive Access](https://developers.google.com/workspace/drive/api/guides/limited-expansive-access)
|
||||
|
||||
## Definitions
|
||||
@@ -23,6 +29,7 @@
|
||||
```
|
||||
<DomainName> ::= <String>(.<String>)+
|
||||
<EmailAddress> ::= <String>@<DomainName>
|
||||
<JSONData> ::= (json [charset <Charset>] <String>) | (json file <FileName> [charset <Charset>]) |
|
||||
<UniqueID> ::= id:<String>
|
||||
<UserItem> ::= <EmailAddress>|<UniqueID>|<String>
|
||||
|
||||
@@ -174,6 +181,16 @@ gam <UserTypeEntity> transfer ownership <DriveFileEntity> <UserItem>
|
||||
```
|
||||
See: https://github.com/GAM-team/GAM/wiki/Users-Drive-Ownership#transfer-ownership-of-files-that-a-source-user-owns-to-a-target-user
|
||||
|
||||
If you specify `role owner`, Google requires that a notification message be sent to the new owner.
|
||||
Google sends a preformatted message, use `emailmessage <String>` to include additional information in the message.
|
||||
|
||||
If you get the following error message from Google:
|
||||
```
|
||||
You are trying to invite user@domain.com. Since there is no Google account associated with this email address, you must check the "Notify people" box to invite this recipient."
|
||||
```
|
||||
|
||||
Use the `sendemail` option and `emailmessage <String>` (if desired) to `check the "Notify people" box`.
|
||||
|
||||
The options `withlink|allowfilediscovery|discoverable` are only valid for ACLs to `anyone` or `domain`.
|
||||
|
||||
The option `expiration <Time>` is only valid for `role commenter|contributor|viewer` for files and `commenter|viewer` for folders.
|
||||
@@ -214,6 +231,12 @@ The option `updatesheetprotectedranges` only applies to items in `<DriveFileEnti
|
||||
* ACLs with role reader or commenter will be removed from existing protected ranges
|
||||
* ACLs with role writer or higher will be added to existing protected ranges
|
||||
|
||||
`
|
||||
`enforceexpansiveaccess` defaults to the value of `gam.cfg/enforce_expansive_access` that controls
|
||||
the ability to update inherited ACLs.
|
||||
* False - Inherited ACLs can be updated
|
||||
* True = Inherited ACLs can not be updated
|
||||
|
||||
By default, the file ID is displayed in the output; to see the file name, use the `showtitles`
|
||||
option; this requires an additional API call per file.
|
||||
|
||||
@@ -234,6 +257,11 @@ The option `updatesheetprotectedranges` only applies to items in `<DriveFileEnti
|
||||
* Sheet Protected Ranges are updated to reflect the deleted ACL; additional API calls are required.
|
||||
* ACLs with any role will be removed from existing protected ranges
|
||||
|
||||
`enforceexpansiveaccess` defaults to the value of `gam.cfg/enforce_expansive_access` that controls
|
||||
the ability to delete delete inherited ACLs.
|
||||
* False - Inherited ACLs can be deleted
|
||||
* True = Inherited ACLs can not be deleted
|
||||
|
||||
By default, the file ID is displayed in the output; to see the file name, use the `showtitles`
|
||||
option; this requires an additional API call per file.
|
||||
|
||||
@@ -252,6 +280,16 @@ From the Google Drive API documentation.
|
||||
* `false` - Parents are not changed. The file is an orphan for the new owner. This is the default.
|
||||
* `true` - The item is moved to the new owner's My Drive root folder and all prior parents removed. The file is an orphan for the old owner.
|
||||
|
||||
If you specify a pernission with `role owner`, Google requires that a notification message be sent to the new owner.
|
||||
Google sends a preformatted message, use `emailmessage <String>` to include additional information in the message.
|
||||
|
||||
If you get the following error message from Google:
|
||||
```
|
||||
You are trying to invite user@domain.com. Since there is no Google account associated with this email address, you must check the "Notify people" box to invite this recipient."
|
||||
```
|
||||
|
||||
Use the `sendemail` option and `emailmessage <String>` (if desired) to `check the "Notify people" box`.
|
||||
|
||||
Permission matching only applies when the `(json [charset <Charset>] <JSONData>)|(json file <FileName> [charset <Charset>])`
|
||||
variant of `<DriveFilePermissionEntity>` and `<DriveFilePermissionIDEntity>` is used.
|
||||
|
||||
@@ -266,6 +304,11 @@ gam <UserTypeEntity> delete permissions <DriveFileEntity> <DriveFilePermissionID
|
||||
<PermissionMatch>* [<PermissionMatchAction>]
|
||||
[enforceexpansiveaccess [<Boolean>]]
|
||||
```
|
||||
`enforceexpansiveaccess` defaults to the value of `gam.cfg/enforce_expansive_access` that controls
|
||||
the ability to delete delete inherited ACLs.
|
||||
* False - Inherited ACLs can be deleted
|
||||
* True = Inherited ACLs can not be deleted
|
||||
|
||||
When deleting permissions from JSON data, permissions with role `owner` true are never processed.
|
||||
|
||||
## Display file permissions/sharing
|
||||
@@ -369,3 +412,205 @@ gam config csv_input_row_filter "permission.type:regex:user|group" redirect stdo
|
||||
gam config csv_input_row_filter "permission.type:regex:domain" redirect stdout ./AddNewDomainACLsDomainShares.txt multiprocess redirect stderr stdout csv ./allUsersFiles.csv gam user "~Owner" create drivefileacl "~id" "~permission.type" "~permission.domain" role "~permission.role" allowfilediscovery "~permission.allowFileDiscovery" mappermissionsdomain olddomain.com newdomain.com
|
||||
```
|
||||
|
||||
## Remove ACLs for a specific user or group email address
|
||||
|
||||
### My Drives
|
||||
|
||||
Get My Drive ACLs sharing to that email address:
|
||||
* Replace `<Type>` with user or group
|
||||
* Replace `email@domain.com` with actual email address
|
||||
```
|
||||
gam config auto_batch_min 1 num_threads 20 redirect csv ./MyDriveShares.csv multiprocess redirect stderr - multiprocess all users print filelist fields id,name,mimetype,basicpermissions query "'email@domain.com' in readers or 'email@domain.com' in writers" pm notrole owner type <Type> emailaddress email@domain.com em pmfilter oneitemperrow
|
||||
```
|
||||
|
||||
Delete those My Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
Add My Drive ACLs with a different email address and the same role.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./AddMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" add drivefileacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
```
|
||||
|
||||
### Shared Drives
|
||||
Get an organizer for each Shared Drive
|
||||
```
|
||||
gam redirect csv ./SharedDriveOrganizers.csv print shareddriveorganizers
|
||||
```
|
||||
|
||||
Get Shared Drive ACLs explicitly sharing to that email address:
|
||||
* Replace `<Type>` with user or group
|
||||
* Replace `email@domain.com` with actual email address
|
||||
```
|
||||
gam config num_threads 20 csv_input_row_filter "organizers:regex:^.+$" redirect csv ./SharedDriveShares.csv multiprocess redirect stderr - multiprocess csv SharedDriveOrganizers.csv gam user "~organizers" print filelist select shareddriveid "~id" fields id,name,mimetype,basicpermissions,driveid showdrivename query "'email@domain.com' in readers or 'email@domain.com' in writers" pm type <Type> emailaddress email@domain.com inherited false em pmfilter oneitemperrow
|
||||
```
|
||||
|
||||
Delete those Shared Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
Add Shared Drive ACLs with a different email address and the same role.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./ReplaceSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" add drivefileacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
```
|
||||
|
||||
## Remove ACLs for all users-groups in external domains
|
||||
|
||||
### My Drives
|
||||
|
||||
Get My Drive ACLs sharing to external domain users/groups.
|
||||
|
||||
Replace `<Types>` as required:
|
||||
* `type user` - External domain users
|
||||
* `type group` - External domain groups
|
||||
* `typelist user,group` - External domain users and groups
|
||||
|
||||
Replace `<Domains>` with specification of external domain(s)
|
||||
* `domain domain.com` - A single external domain
|
||||
* `domainlist domain1.com,domain2.com,domain3.com...` - A list of external domains
|
||||
|
||||
If you want domains other than your internal domain(s)
|
||||
* `notdomain domain.com` - A single internal domain
|
||||
* `notdomainlist domain1.com,domain2.com,domain3.com...` - A list of internal domains
|
||||
```
|
||||
gam config auto_batch_min 1 num_threads 20 redirect csv ./MyDriveShares.csv multiprocess redirect stderr - multiprocess all users print filelist fields id,name,mimetype,basicpermissions pm notrole owner <Types> <Domains> em pmfilter oneitemperrow
|
||||
```
|
||||
|
||||
Delete those My Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
Add My Drive ACLs with a different email address and the same role.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./AddMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" add drivefileacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
```
|
||||
|
||||
### Shared Drives
|
||||
Get an organizer for each Shared Drive
|
||||
```
|
||||
gam redirect csv ./SharedDriveOrganizers.csv print shareddriveorganizers
|
||||
```
|
||||
|
||||
Get Shared Drive ACLs sharing to external domain users/groups.
|
||||
|
||||
Replace `<Types>` as required:
|
||||
* `type user` - External domain users
|
||||
* `type group` - External domain groups
|
||||
* `typelist user,group` - External domain users and groups
|
||||
|
||||
Replace `<Domains>` with specification of external domain(s)
|
||||
* `domain domain.com` - A single external domain
|
||||
* `domainlist domain1.com,domain2.com,domain3.com...` - A list of external domains
|
||||
|
||||
If you want domains other than your internal domain(s)
|
||||
* `notdomain domain.com` - A single internal domain
|
||||
* `notdomainlist domain1.com,domain2.com,domain3.com...` - A list of internal domains
|
||||
```
|
||||
gam config num_threads 20 csv_input_row_filter "organizers:regex:^.+$" redirect csv ./SharedDriveShares.csv multiprocess redirect stderr - multiprocess csv SharedDriveOrganizers.csv gam user "~organizers" print filelist select shareddriveid "~id" fields id,name,mimetype,basicpermissions,driveid showdrivename pm <Types> <Domains> inherited false em pmfilter oneitemperrow
|
||||
```
|
||||
|
||||
Delete those Shared Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
Add Shared Drive ACLs with a different email address and the same role.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./ReplaceSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" add drivefileacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
```
|
||||
|
||||
## Remove domainCanFind-domainWithLink ACLs for internal domain
|
||||
|
||||
Replace `<Query>` below with one of these; they only apply to your internal domain:
|
||||
* domainCanFind - query "visibility='domainCanFind'"
|
||||
* domainWithLink - query "visibility='domainWithLink'"
|
||||
* both - query "(visibility='domainCanFind' or visibility='domainWithLink')"
|
||||
|
||||
### My Drives
|
||||
|
||||
Get My Drive domainCanFind/domainWithLink ACLs for internal domain
|
||||
```
|
||||
gam config auto_batch_min 1 num_threads 20 redirect csv ./MyDriveShares.csv multiprocess redirect stderr - multiprocess all users print filelist fields id,name,mimetype,basicpermissions <Query> pm type domain em pmfilter oneitemperrow
|
||||
```
|
||||
|
||||
Delete those My Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
### Shared Drives
|
||||
Get an organizer for each Shared Drive
|
||||
```
|
||||
gam redirect csv ./SharedDriveOrganizers.csv print shareddriveorganizers
|
||||
```
|
||||
|
||||
Get Shared Drive ACLs domainCanFind/domainWithLink ACLs for internal domain
|
||||
* Replace `<Domain>` with actual domain name
|
||||
```
|
||||
gam config num_threads 20 csv_input_row_filter "organizers:regex:^.+$" redirect csv ./SharedDriveShares.csv multiprocess redirect stderr - multiprocess csv SharedDriveOrganizers.csv gam user "~organizers" print filelist select shareddriveid "~id" fields id,name,mimetype,basicpermissions,driveid showdrivename <Query> pm type domain inherited false em pmfilter oneitemperrow
|
||||
```
|
||||
|
||||
Delete those Shared Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
## Remove My Drive ACLs for external domains
|
||||
|
||||
### My Drives
|
||||
|
||||
Get My Drive ACLs sharing to external domain(s)
|
||||
|
||||
Replace `<Domains>` with specification of external domain(s)
|
||||
* `domain domain.com` - A single external domain
|
||||
* `domainlist domain1.com,domain2.com,domain3.com...` - A list of external domains
|
||||
|
||||
If you want domains other than your internal domain(s)
|
||||
* `notdomain domain.com` - A single internal domain
|
||||
* `notdomainlist domain1.com,domain2.com,domain3.com...` - A list of internal domains
|
||||
```
|
||||
gam config auto_batch_min 1 num_threads 20 redirect csv ./MyDriveShares.csv multiprocess redirect stderr - multiprocess all users print filelist fields id,name,mimetype,basicpermissions pm type domain <Domains> em pmfilter oneitemperrow
|
||||
```
|
||||
|
||||
Delete those My Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
## Remove anyoneCanFind-anyoneWithLink ACLs
|
||||
|
||||
Replace `<Query>` below with one of these:
|
||||
* anyoneCanFind - query "visibility='anyoneCanFind'"
|
||||
* anyoneWithLink - query "visibility='anyoneWithLink'"
|
||||
* both - query "(visibility='anyoneCanFind' or visibility='anyoneWithLink')"
|
||||
|
||||
### My Drives
|
||||
|
||||
Get My Drive anyoneCanFind/anyoneWithLink ACLs
|
||||
```
|
||||
gam config auto_batch_min 1 num_threads 20 redirect csv ./MyDriveShares.csv multiprocess redirect stderr - multiprocess all users print filelist fields id,name,mimetype,basicpermissions <Query> pm type anyone em pmfilter oneitemperrow
|
||||
```
|
||||
|
||||
Delete those My Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
### Shared Drives
|
||||
Get an organizer for each Shared Drive
|
||||
```
|
||||
gam redirect csv ./SharedDriveOrganizers.csv print shareddriveorganizers
|
||||
```
|
||||
|
||||
Get Shared Drive anyoneCanFind/anyoneWithLink ACLs
|
||||
```
|
||||
gam config num_threads 20 csv_input_row_filter "organizers:regex:^.+$" redirect csv ./SharedDriveShares.csv multiprocess redirect stderr - multiprocess csv SharedDriveOrganizers.csv gam user "~organizers" print filelist select shareddriveid "~id" fields id,name,mimetype,basicpermissions,driveid showdrivename <Query> pm type anyone inherited false em pmfilter oneitemperrow
|
||||
```
|
||||
|
||||
Delete those Shared Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
@@ -49,10 +49,19 @@ gam user user@domain.com update serviceaccount
|
||||
```
|
||||
gam <UserTypeEntity> create form
|
||||
title <String> [description <String>] [isquiz [Boolean>]] [<JSONData>]
|
||||
[ispublished [<Boolean>] isacceptingresponses [<Boolean>]]
|
||||
[drivefilename <DriveFileName>] [<DriveFileParentAttribute>]
|
||||
[(csv [todrive <ToDriveAttribute>*]) | returnidonly]
|
||||
```
|
||||
|
||||
The valid combinations of `ispublished` and `isacceptingresponses` are:
|
||||
* `ispublished true isacceptingresponses true`
|
||||
* `ispublished true isacceptingresponses false`
|
||||
* `ispublished false isacceptingresponses false`
|
||||
* `ispublished false` - Sets `isacceptingresponses false`
|
||||
* `isacceptingresponses false` - Sets `ispublished false`
|
||||
* `isacceptingresponses true` - Sets `ispublished true`
|
||||
|
||||
`<JSONData>` is a list of form update requests.
|
||||
|
||||
* See: https://developers.google.com/forms/api/reference/rest/v1/forms/batchUpdate
|
||||
@@ -79,15 +88,24 @@ Select forms with `<DriveFileEntity>`:
|
||||
```
|
||||
gam <UserTypeEntity> update form <DriveFileEntity>
|
||||
[title <String>] [description <String>] [isquiz [Boolean>]] [<JSONData>]
|
||||
[ispublished [<Boolean>] isacceptingresponses [<Boolean>]]
|
||||
```
|
||||
|
||||
The valid combinations of `ispublished` and `isacceptingresponses` are:
|
||||
* `ispublished true isacceptingresponses true`
|
||||
* `ispublished true isacceptingresponses false`
|
||||
* `ispublished false isacceptingresponses false`
|
||||
* `ispublished false` - Sets `isacceptingresponses false`
|
||||
* `isacceptingresponses false` - Sets `ispublished false`
|
||||
* `isacceptingresponses true` - Sets `ispublished true`
|
||||
|
||||
`<JSONData>` is a list of form update requests.
|
||||
|
||||
* See: https://developers.google.com/forms/api/reference/rest/v1/forms/batchUpdate
|
||||
|
||||
## Extended Example
|
||||
|
||||
This example illustrates the use of JSN data to create and update forms
|
||||
This example illustrates the use of JSON data to create and update forms
|
||||
concerning student classtoom attendance.
|
||||
The form has two items: Absences and Notes.
|
||||
In `Absences`, the teacher can check `All present.` or check individual student absences.
|
||||
@@ -272,7 +290,7 @@ Select forms with `<DriveFileEntity>`:
|
||||
* `my_forms` - Display responses for all forms owned by the user
|
||||
```
|
||||
gam <UserTypeEntity> show formresponses <DriveFileEntity>
|
||||
[filtertime.* <Time>] [filter <String>]
|
||||
[filter <String> (filtertime<String> <Time>)*]
|
||||
[countsonly|formatjson]
|
||||
```
|
||||
By default, GAM displays form response details, use the `countsonly` option to get the number of responses but no response details.
|
||||
@@ -284,11 +302,12 @@ By default, GAM displays all form responses, you can filter by response time:
|
||||
For example, to get the form responses submitted since the beginning of the year:
|
||||
* `filter timestamp >= 2022-01-01T00:00:00Z`
|
||||
|
||||
Use the `filtertime.* <Time>` option to allow times, usually relative, to be substituted into the `filter <String>` option.
|
||||
Use the `filtertime<String <Time>` option to allow times, usually relative, to be substituted into the `filter <String>` option.
|
||||
The `filtertime<String> <Time>` value replaces the string `#filtertime<String>#` in any filters..
|
||||
The characters following `filtertime` can be any combination of lowercase letters and numbers.
|
||||
|
||||
For example, to get the responses subnitted in the last four hours:
|
||||
* `filtertime4h -4h filter "timestamp >= #filtertime4h#`
|
||||
For example, to get the responses submitted in the last four hours:
|
||||
* `filter "timestamp >= #filtertime4h#" filtertime4h -4h`
|
||||
|
||||
By default, Gam displays the information as an indented list of keys and values.
|
||||
* `formatjson` - Display the form response in JSON format
|
||||
@@ -296,7 +315,7 @@ By default, Gam displays the information as an indented list of keys and values.
|
||||
```
|
||||
gam <UserTypeEntity> print formresponses <DriveFileEntity> [todrive <ToDriveAttribute>*]
|
||||
(addcsvdata <FieldName> <String>)*
|
||||
[filtertime.* <Time>] [filter <String>]
|
||||
[filter <String> (filtertime<String> <Time>)*]
|
||||
[countsonly|(formatjson [quotechar <Character>])]
|
||||
```
|
||||
By default, GAM displays form response details, use the `countsonly` option to get the number of responses but no response details.
|
||||
@@ -310,11 +329,12 @@ By default, GAM displays all form responses, you can filter by response time:
|
||||
For example, to get the form responses submitted since the beginning of the year:
|
||||
* `filter timestamp >= 2022-01-01T00:00:00Z`
|
||||
|
||||
Use the `filtertime.* <Time>` option to allow times, usually relative, to be substituted into the `filter <String>` option.
|
||||
Use the `filtertime<String> <Time>` option to allow times, usually relative, to be substituted into the `filter <String>` option.
|
||||
The `filtertime<String> <Time>` value replaces the string `#filtertime<String>#` in any filters..
|
||||
The characters following `filtertime` can be any combination of lowercase letters and numbers.
|
||||
|
||||
For example, to get the responses subnitted in the last four hours:
|
||||
* `filtertime4h -4h filter "timestamp >= #filtertime4h#`
|
||||
* `filter "timestamp >= #filtertime4h#" filtertime4h -4h`
|
||||
|
||||
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
|
||||
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user