mirror of
https://github.com/GAM-team/GAM.git
synced 2026-07-04 12:51:36 +00:00
Compare commits
123 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
939a1afbbf | ||
|
|
ecda9fe232 | ||
|
|
76eb79eb2d | ||
|
|
325e597772 | ||
|
|
c6334d2bcd | ||
|
|
72ff9ff7e9 | ||
|
|
b45ad5dcaf | ||
|
|
3d14964365 | ||
|
|
d15bab5a29 | ||
|
|
c4deb29b21 | ||
|
|
0eafee3105 | ||
|
|
4d116e81c8 | ||
|
|
3a41b31e19 | ||
|
|
f9786468db | ||
|
|
a49124d1d0 | ||
|
|
3087b4b776 | ||
|
|
aa595fe623 | ||
|
|
30a571f56c | ||
|
|
7b0a8dce1e | ||
|
|
6fce941640 | ||
|
|
dbfbf61ddc | ||
|
|
5d618de296 | ||
|
|
3e556425ec | ||
|
|
370db726a4 | ||
|
|
12d6c8c3f5 | ||
|
|
0fdb6544cc | ||
|
|
ca52845c65 | ||
|
|
fac32f95d8 | ||
|
|
f27b37d21a | ||
|
|
e066fcc172 | ||
|
|
14535e814f | ||
|
|
1cfb873122 | ||
|
|
de16285bf2 | ||
|
|
d01f3f31ff | ||
|
|
edec98579d | ||
|
|
ea583e98b2 | ||
|
|
c4a080e081 | ||
|
|
4e35845ecf | ||
|
|
9d76fcbcf1 | ||
|
|
60290473e1 | ||
|
|
f94456ce7f | ||
|
|
65cda68f40 | ||
|
|
576731c386 | ||
|
|
0b56af76b7 | ||
|
|
10e6cbabcf | ||
|
|
f33529a1d4 | ||
|
|
7a5a6a8db2 | ||
|
|
c43c4a8b07 | ||
|
|
0e0e1332c7 | ||
|
|
ee19c5e25f | ||
|
|
c0c1355216 | ||
|
|
da3394f3fd | ||
|
|
c856723945 | ||
|
|
5e10ccdbdd | ||
|
|
a49f645647 | ||
|
|
cf8d714ba7 | ||
|
|
17bb625d0d | ||
|
|
5e7a858d55 | ||
|
|
8276474314 | ||
|
|
d108261654 | ||
|
|
aa98be443c | ||
|
|
eecb583f10 | ||
|
|
809aae27b1 | ||
|
|
028ca15498 | ||
|
|
be4403331f | ||
|
|
b84025debf | ||
|
|
4685f29aba | ||
|
|
a832698366 | ||
|
|
cf894fd0bd | ||
|
|
fd6c04bd94 | ||
|
|
49a2352d6d | ||
|
|
291871ec45 | ||
|
|
73c21a1156 | ||
|
|
27eed06617 | ||
|
|
a440cbbbdc | ||
|
|
eb9ca5eb1d | ||
|
|
5eb1277691 | ||
|
|
6de424b185 | ||
|
|
f89491d801 | ||
|
|
154de4818e | ||
|
|
c5895a3082 | ||
|
|
e085257a51 | ||
|
|
d8e84cf045 | ||
|
|
a5eb61421d | ||
|
|
cddbea2718 | ||
|
|
c9bf5158e4 | ||
|
|
7822b36f97 | ||
|
|
20d541ca8e | ||
|
|
72af9fb4a9 | ||
|
|
a2972a3329 | ||
|
|
97b74c0c8f | ||
|
|
332519e5d4 | ||
|
|
881641e2b4 | ||
|
|
82bfe74175 | ||
|
|
bac3451c21 | ||
|
|
c97495ab05 | ||
|
|
aa3dad1e07 | ||
|
|
2d4e15504c | ||
|
|
3cd41e3d0f | ||
|
|
a94518c48d | ||
|
|
2837671ed7 | ||
|
|
e49eed2a24 | ||
|
|
edfc27c960 | ||
|
|
41a10932cb | ||
|
|
119538c10c | ||
|
|
0a03fbb82e | ||
|
|
b838054e2f | ||
|
|
45ac118381 | ||
|
|
e1600eadbc | ||
|
|
cc23f98078 | ||
|
|
b68cc671eb | ||
|
|
8c215a0a0b | ||
|
|
374c6a9367 | ||
|
|
5d93d9893e | ||
|
|
010c26ea89 | ||
|
|
5da90f7585 | ||
|
|
5356591d9c | ||
|
|
8df5d22805 | ||
|
|
5684ab3c05 | ||
|
|
d7b8f4c228 | ||
|
|
66fe03bbcd | ||
|
|
e7496dc9cb | ||
|
|
3b52af0b8a |
4
.github/ISSUE_TEMPLATE.txt
vendored
4
.github/ISSUE_TEMPLATE.txt
vendored
@@ -1,8 +1,8 @@
|
|||||||
The issue tracker is for reporting product deficiencies. "How do I?" questions should be posted to the discussion forum at https://groups.google.com/group/google-apps-manager. When in doubt, start at the discussion forum and return here only when instructed to do so.
|
The issue tracker is for reporting product deficiencies. "How do I?" questions should be posted to the discussion forum at https://groups.google.com/group/google-apps-manager. When in doubt, start at the discussion forum and return here only when instructed to do so.
|
||||||
|
|
||||||
Please confirm the following:
|
Please confirm the following:
|
||||||
* I have upgraded to the latest GAM release from https://git.io/gamreleases and I still have this issue.
|
* I have upgraded to the latest GAM release from https://github.com/GAM-team/GAM/releases and I still have this issue.
|
||||||
* I am typing the command as described in the GAM Wiki at https://github.com/jay0lee/gam/wiki
|
* I am typing the command as described in the GAM Wiki at https://github.com/GAM-team/GAM/wiki
|
||||||
|
|
||||||
Full steps to reproduce the issue:
|
Full steps to reproduce the issue:
|
||||||
1.
|
1.
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/za-bug-report.md
vendored
2
.github/ISSUE_TEMPLATE/za-bug-report.md
vendored
@@ -10,7 +10,7 @@ assignees: jay0lee
|
|||||||
The issue tracker is for reporting product deficiencies. "How do I?" questions should be posted to the discussion forum at https://groups.google.com/group/google-apps-manager. When in doubt, start at the discussion forum and return here only when instructed to do so.
|
The issue tracker is for reporting product deficiencies. "How do I?" questions should be posted to the discussion forum at https://groups.google.com/group/google-apps-manager. When in doubt, start at the discussion forum and return here only when instructed to do so.
|
||||||
|
|
||||||
Please confirm the following:
|
Please confirm the following:
|
||||||
* I have upgraded to the latest GAM release from https://git.io/gamreleases and I still have this issue.
|
* I have upgraded to the latest GAM release from https://github.com/GAM-team/GAM/releases and I still have this issue.
|
||||||
* I am typing the command as described in the GAM Wiki at https://github.com/jay0lee/gam/wiki
|
* I am typing the command as described in the GAM Wiki at https://github.com/jay0lee/gam/wiki
|
||||||
|
|
||||||
Full steps to reproduce the issue:
|
Full steps to reproduce the issue:
|
||||||
|
|||||||
BIN
.github/actions/creds.tar.gpg
vendored
BIN
.github/actions/creds.tar.gpg
vendored
Binary file not shown.
132
.github/workflows/build.yml
vendored
132
.github/workflows/build.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-22.04
|
||||||
jid: 1
|
jid: 1
|
||||||
goal: build
|
goal: build
|
||||||
arch: x86_64
|
arch: x86_64
|
||||||
@@ -34,12 +34,7 @@ jobs:
|
|||||||
goal: build
|
goal: build
|
||||||
arch: aarch64
|
arch: aarch64
|
||||||
openssl_archs: linux-aarch64
|
openssl_archs: linux-aarch64
|
||||||
- os: [self-hosted, linux, arm]
|
- os: macos-12
|
||||||
jid: 3
|
|
||||||
goal: build
|
|
||||||
arch: armv7l
|
|
||||||
openssl_archs: linux-armv4
|
|
||||||
- os: macos-11
|
|
||||||
jid: 4
|
jid: 4
|
||||||
goal: build
|
goal: build
|
||||||
arch: universal2
|
arch: universal2
|
||||||
@@ -54,24 +49,28 @@ jobs:
|
|||||||
goal: build
|
goal: build
|
||||||
arch: Win32
|
arch: Win32
|
||||||
openssl_archs: VC-WIN32
|
openssl_archs: VC-WIN32
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-22.04
|
||||||
goal: test
|
goal: test
|
||||||
python: "3.7"
|
python: "3.7"
|
||||||
jid: 7
|
jid: 7
|
||||||
arch: x86_64
|
arch: x86_64
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-22.04
|
||||||
goal: test
|
goal: test
|
||||||
python: "3.8"
|
python: "3.8"
|
||||||
jid: 8
|
jid: 8
|
||||||
arch: x86_64
|
arch: x86_64
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-22.04
|
||||||
goal: test
|
goal: test
|
||||||
python: "3.9"
|
python: "3.9"
|
||||||
jid: 9
|
jid: 9
|
||||||
arch: x86_64
|
arch: x86_64
|
||||||
|
- os: ubuntu-22.04
|
||||||
|
goal: test
|
||||||
|
python: "3.11-dev"
|
||||||
|
jid: 10
|
||||||
|
arch: x86_64
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
@@ -83,7 +82,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
bin
|
bin
|
||||||
key: gam-${{ matrix.jid }}-20220316-01
|
key: gam-${{ matrix.jid }}-20220621
|
||||||
|
|
||||||
- name: Use pre-compiled Python for testing
|
- name: Use pre-compiled Python for testing
|
||||||
if: matrix.python != ''
|
if: matrix.python != ''
|
||||||
@@ -111,21 +110,21 @@ jobs:
|
|||||||
echo "ACTIONS_CACHE=${ACTIONS_CACHE}" >> $GITHUB_ENV
|
echo "ACTIONS_CACHE=${ACTIONS_CACHE}" >> $GITHUB_ENV
|
||||||
echo "ACTIONS_GOAL=${ACTIONS_GOAL}" >> $GITHUB_ENV
|
echo "ACTIONS_GOAL=${ACTIONS_GOAL}" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Install necessary hosted Linux packages
|
- name: Install necessary Github-hosted Linux packages
|
||||||
if: matrix.os == 'ubuntu-20.04'
|
if: runner.os == 'Linux' && runner.arch == 'X64'
|
||||||
run: |
|
run: |
|
||||||
echo "RUNNING: apt update..."
|
echo "RUNNING: apt update..."
|
||||||
sudo apt-get -qq --yes update
|
sudo apt-get -qq --yes update
|
||||||
sudo apt-get -qq --yes install swig libpcsclite-dev
|
sudo apt-get -qq --yes install swig libpcsclite-dev
|
||||||
|
|
||||||
- name: MacOS remove Homebrew
|
- name: MacOS remove Homebrew
|
||||||
if: matrix.os == 'macos-11'
|
if: runner.os == 'macOS'
|
||||||
run: |
|
run: |
|
||||||
# remove everything except the libraries needed by yubikey-manager
|
# remove everything except the libraries needed by yubikey-manager
|
||||||
brew uninstall $(brew list | grep -v 'pcre\|swig\|pcsc-lite')
|
brew uninstall $(brew list | grep -v 'pcre\|swig\|pcsc-lite')
|
||||||
|
|
||||||
- name: MacOS install tools
|
- name: MacOS install tools
|
||||||
if: matrix.os == 'macos-11'
|
if: runner.os == 'macOS'
|
||||||
run: |
|
run: |
|
||||||
# Install latest Rust
|
# Install latest Rust
|
||||||
curl -fsS -o rust.sh https://sh.rustup.rs
|
curl -fsS -o rust.sh https://sh.rustup.rs
|
||||||
@@ -136,7 +135,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Windows Configure VCode
|
- name: Windows Configure VCode
|
||||||
uses: ilammy/msvc-dev-cmd@v1
|
uses: ilammy/msvc-dev-cmd@v1
|
||||||
if: matrix.os == 'windows-2022' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
if: runner.os == 'Windows' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
arch: ${{ matrix.arch }}
|
arch: ${{ matrix.arch }}
|
||||||
|
|
||||||
@@ -220,7 +219,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Windows NASM Install
|
- name: Windows NASM Install
|
||||||
uses: ilammy/setup-nasm@v1
|
uses: ilammy/setup-nasm@v1
|
||||||
if: matrix.goal == 'build' && matrix.os == 'windows-2022' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
if: matrix.goal == 'build' && runner.os == 'Windows' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||||
|
|
||||||
- name: Config OpenSSL
|
- name: Config OpenSSL
|
||||||
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||||
@@ -232,7 +231,7 @@ jobs:
|
|||||||
done
|
done
|
||||||
|
|
||||||
- name: Rename GNU link on Windows
|
- name: Rename GNU link on Windows
|
||||||
if: matrix.goal == 'build' && matrix.os == 'windows-2022' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
if: matrix.goal == 'build' && runner.os == 'Windows' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||||
shell: bash
|
shell: bash
|
||||||
run: mv /usr/bin/link /usr/bin/gnulink
|
run: mv /usr/bin/link /usr/bin/gnulink
|
||||||
|
|
||||||
@@ -295,7 +294,7 @@ jobs:
|
|||||||
echo "COMPILED_PYTHON_VERSION=${COMPILED_PYTHON_VERSION}" >> $GITHUB_ENV
|
echo "COMPILED_PYTHON_VERSION=${COMPILED_PYTHON_VERSION}" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Mac/Linux Configure Python
|
- name: Mac/Linux Configure Python
|
||||||
if: matrix.goal == 'build' && matrix.os != 'windows-2022' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
if: matrix.goal == 'build' && runner.os != 'Windows' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
cd "${PYTHON_SOURCE_PATH}"
|
cd "${PYTHON_SOURCE_PATH}"
|
||||||
if [[ "${RUNNER_OS}" == "macOS" ]]; then
|
if [[ "${RUNNER_OS}" == "macOS" ]]; then
|
||||||
@@ -312,14 +311,14 @@ jobs:
|
|||||||
"${extra_args[@]}"
|
"${extra_args[@]}"
|
||||||
|
|
||||||
- name: Windows Get External Python deps
|
- name: Windows Get External Python deps
|
||||||
if: matrix.goal == 'build' && matrix.os == 'windows-2022' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
if: matrix.goal == 'build' && runner.os == 'Windows' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: |
|
run: |
|
||||||
cd "${env:PYTHON_SOURCE_PATH}"
|
cd "${env:PYTHON_SOURCE_PATH}"
|
||||||
PCBuild\get_externals.bat
|
PCBuild\get_externals.bat
|
||||||
|
|
||||||
- name: Windows overwrite external OpenSSL with local
|
- name: Windows overwrite external OpenSSL with local
|
||||||
if: matrix.goal == 'build' && matrix.os == 'windows-2022' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
if: matrix.goal == 'build' && runner.os == 'Windows' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: |
|
run: |
|
||||||
cd "${env:PYTHON_SOURCE_PATH}"
|
cd "${env:PYTHON_SOURCE_PATH}"
|
||||||
@@ -338,7 +337,7 @@ jobs:
|
|||||||
cp -v "$env:OPENSSL_INSTALL_PATH\include\openssl\applink.c" "${env:OPENSSL_EXT_TARGET_PATH}\include\"
|
cp -v "$env:OPENSSL_INSTALL_PATH\include\openssl\applink.c" "${env:OPENSSL_EXT_TARGET_PATH}\include\"
|
||||||
|
|
||||||
- name: Windows Install sphinx-build
|
- name: Windows Install sphinx-build
|
||||||
if: matrix.goal == 'build' && matrix.os == 'windows-2022' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
if: matrix.goal == 'build' && runner.os == 'Windows' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: |
|
run: |
|
||||||
pip install --upgrade pip
|
pip install --upgrade pip
|
||||||
@@ -346,7 +345,7 @@ jobs:
|
|||||||
sphinx-build --version
|
sphinx-build --version
|
||||||
|
|
||||||
- name: Windows Config/Build Python
|
- name: Windows Config/Build Python
|
||||||
if: matrix.goal == 'build' && matrix.os == 'windows-2022' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
if: matrix.goal == 'build' && runner.os == 'Windows' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: |
|
run: |
|
||||||
cd "${env:PYTHON_SOURCE_PATH}"
|
cd "${env:PYTHON_SOURCE_PATH}"
|
||||||
@@ -356,7 +355,7 @@ jobs:
|
|||||||
PCBuild\build.bat -m --pgo -c Release -p "${env:PYBUILDRELEASE_ARCH}"
|
PCBuild\build.bat -m --pgo -c Release -p "${env:PYBUILDRELEASE_ARCH}"
|
||||||
|
|
||||||
- name: Windows Install Python
|
- name: Windows Install Python
|
||||||
if: matrix.goal == 'build' && matrix.os == 'windows-2022' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
if: matrix.goal == 'build' && runner.os == 'Windows' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: |
|
run: |
|
||||||
cd "${env:PYTHON_SOURCE_PATH}"
|
cd "${env:PYTHON_SOURCE_PATH}"
|
||||||
@@ -368,14 +367,14 @@ jobs:
|
|||||||
Copy-Item -Path "${env:PYTHON_SOURCE_PATH}\PC\*.h" "${env:PYTHON_INSTALL_PATH}\include\"
|
Copy-Item -Path "${env:PYTHON_SOURCE_PATH}\PC\*.h" "${env:PYTHON_INSTALL_PATH}\include\"
|
||||||
|
|
||||||
- name: Mac/Linux Build Python
|
- name: Mac/Linux Build Python
|
||||||
if: matrix.goal == 'build' && matrix.os != 'windows-2022' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
if: matrix.goal == 'build' && runner.os != 'Windows' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
cd "${PYTHON_SOURCE_PATH}"
|
cd "${PYTHON_SOURCE_PATH}"
|
||||||
echo "Running: ${MAKE} ${MAKEOPT}"
|
echo "Running: ${MAKE} ${MAKEOPT}"
|
||||||
$MAKE $MAKEOPT
|
$MAKE $MAKEOPT
|
||||||
|
|
||||||
- name: Mac/Linux Install Python
|
- name: Mac/Linux Install Python
|
||||||
if: matrix.goal == 'build' && matrix.os != 'windows-2022' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
if: matrix.goal == 'build' && runner.os != 'Windows' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
cd "${PYTHON_SOURCE_PATH}"
|
cd "${PYTHON_SOURCE_PATH}"
|
||||||
$MAKE altinstall
|
$MAKE altinstall
|
||||||
@@ -408,12 +407,12 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
echo "PyInstaller build arguments: ${PYINSTALLER_BUILD_ARGS}"
|
echo "PyInstaller build arguments: ${PYINSTALLER_BUILD_ARGS}"
|
||||||
"${PYTHON}" ./waf all $PYINSTALLER_BUILD_ARGS
|
"${PYTHON}" ./waf all $PYINSTALLER_BUILD_ARGS
|
||||||
cd ..
|
cd ../..
|
||||||
"${PYTHON}" -m pip install .
|
echo "---- Installing PyInstaller ----"
|
||||||
|
"${PYTHON}" -m pip install pyinstaller
|
||||||
|
|
||||||
- name: Install pip requirements
|
- name: Install pip requirements
|
||||||
run: |
|
run: |
|
||||||
set +e
|
|
||||||
if [[ "${RUNNER_OS}" == "macOS" ]]; then
|
if [[ "${RUNNER_OS}" == "macOS" ]]; then
|
||||||
for package in cryptography; do
|
for package in cryptography; do
|
||||||
"${PYTHON}" -m pip install --upgrade cffi ${PIP_ARGS}
|
"${PYTHON}" -m pip install --upgrade cffi ${PIP_ARGS}
|
||||||
@@ -444,7 +443,7 @@ jobs:
|
|||||||
echo "gampath=${gampath}" >> $GITHUB_ENV
|
echo "gampath=${gampath}" >> $GITHUB_ENV
|
||||||
echo "gam=${gam}" >> $GITHUB_ENV
|
echo "gam=${gam}" >> $GITHUB_ENV
|
||||||
echo -e "GAM: ${gam}\nGAMPATH: ${gampath}"
|
echo -e "GAM: ${gam}\nGAMPATH: ${gampath}"
|
||||||
"${PYTHON}" -m PyInstaller --clean --noupx --strip --onefile --distpath="${gampath}" gam.spec
|
"${PYTHON}" -m PyInstaller --clean --distpath="${gampath}" gam.spec
|
||||||
|
|
||||||
- name: Basic Tests all jobs
|
- name: Basic Tests all jobs
|
||||||
run: |
|
run: |
|
||||||
@@ -455,7 +454,7 @@ jobs:
|
|||||||
echo "GAMVERSION=${GAMVERSION}" >> $GITHUB_ENV
|
echo "GAMVERSION=${GAMVERSION}" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Linux/MacOS package
|
- name: Linux/MacOS package
|
||||||
if: matrix.os != 'windows-2022' && matrix.goal == 'build'
|
if: runner.os != 'Windows' && matrix.goal == 'build'
|
||||||
run: |
|
run: |
|
||||||
cp -v LICENSE $gampath
|
cp -v LICENSE $gampath
|
||||||
cp -v GamCommands.txt $gampath
|
cp -v GamCommands.txt $gampath
|
||||||
@@ -467,31 +466,40 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
tar -C dist/ --create --verbose --exclude-from "${GITHUB_WORKSPACE}/.github/actions/package_exclusions.txt" --file $GAM_ARCHIVE --xz gam
|
tar -C dist/ --create --verbose --exclude-from "${GITHUB_WORKSPACE}/.github/actions/package_exclusions.txt" --file $GAM_ARCHIVE --xz gam
|
||||||
|
|
||||||
- name: Linux install patchelf/staticx
|
- name: Linux 64-bit install patchelf/staticx
|
||||||
if: matrix.os == 'ubuntu-20.04' && matrix.goal != 'test'
|
if: runner.os == 'Linux' && contains(runner.arch, '64') && matrix.goal != 'test'
|
||||||
run: |
|
run: |
|
||||||
"${PYTHON}" -m pip install --upgrade patchelf-wrapper
|
"${PYTHON}" -m pip install --upgrade patchelf-wrapper
|
||||||
"${PYTHON}" -m pip install --upgrade staticx
|
"${PYTHON}" -m pip install --upgrade staticx
|
||||||
|
|
||||||
- name: Linux Make Static
|
- name: Linux 64-bit Make Static
|
||||||
if: matrix.os == 'ubuntu-20.04' && matrix.goal != 'test'
|
if: runner.os == 'Linux' && contains(runner.arch, '64') && matrix.goal != 'test'
|
||||||
run: |
|
run: |
|
||||||
$PYTHON -m staticx "${gam}" "${gam}-staticx"
|
case $RUNNER_ARCH in
|
||||||
|
X64)
|
||||||
|
ldlib=/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
|
||||||
|
;;
|
||||||
|
ARM64)
|
||||||
|
ldlib=/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo "ldlib=${ldlib}"
|
||||||
|
$PYTHON -m staticx -l "${ldlib}" "${gam}" "${gam}-staticx"
|
||||||
|
|
||||||
- name: Linux Run StaticX-ed
|
- name: Linux Run StaticX-ed
|
||||||
if: matrix.os == 'ubuntu-20.04' && matrix.goal != 'test'
|
if: runner.os == 'Linux' && contains(runner.arch, '64') && matrix.goal != 'test'
|
||||||
run: |
|
run: |
|
||||||
"${gam}-staticx" version extended
|
"${gam}-staticx" version extended
|
||||||
mv -v "${gam}-staticx" "${gam}"
|
mv -v "${gam}-staticx" "${gam}"
|
||||||
|
|
||||||
- name: Linux package staticx
|
- name: Linux package staticx
|
||||||
if: matrix.os == 'ubuntu-20.04' && matrix.goal != 'test'
|
if: runner.os == 'Linux' && contains(runner.arch, '64') && matrix.goal != 'test'
|
||||||
run: |
|
run: |
|
||||||
GAM_ARCHIVE="gam-${GAMVERSION}-linux-x86_64-legacy.tar.xz"
|
GAM_ARCHIVE="gam-${GAMVERSION}-linux-$(uname -m)-legacy.tar.xz"
|
||||||
tar -C dist/ --create --verbose --exclude-from "${GITHUB_WORKSPACE}/.github/actions/package_exclusions.txt" --file $GAM_ARCHIVE --xz gam
|
tar -C dist/ --create --verbose --exclude-from "${GITHUB_WORKSPACE}/.github/actions/package_exclusions.txt" --file $GAM_ARCHIVE --xz gam
|
||||||
|
|
||||||
- name: Windows package
|
- name: Windows package
|
||||||
if: matrix.os == 'windows-2022' && matrix.goal != 'test'
|
if: runner.os == 'Windows' && matrix.goal != 'test'
|
||||||
run: |
|
run: |
|
||||||
cp -v LICENSE $gampath
|
cp -v LICENSE $gampath
|
||||||
cp -v GamCommands.txt $gampath
|
cp -v GamCommands.txt $gampath
|
||||||
@@ -543,7 +551,7 @@ jobs:
|
|||||||
$gam info user
|
$gam info user
|
||||||
#$gam info user $gam_user grouptree
|
#$gam info user $gam_user grouptree
|
||||||
export tstamp=$($PYTHON -c "import time; print(time.time_ns())")
|
export tstamp=$($PYTHON -c "import time; print(time.time_ns())")
|
||||||
export newbase=gha-test-$JID-$tstamp
|
export newbase=gha_test_$JID_$tstamp
|
||||||
export newuser=$newbase@pdl.jaylee.us
|
export newuser=$newbase@pdl.jaylee.us
|
||||||
export newgroup=$newbase-group@pdl.jaylee.us
|
export newgroup=$newbase-group@pdl.jaylee.us
|
||||||
export newalias=$newbase-alias@pdl.jaylee.us
|
export newalias=$newbase-alias@pdl.jaylee.us
|
||||||
@@ -551,7 +559,7 @@ jobs:
|
|||||||
export newresource=$newbase-resource
|
export newresource=$newbase-resource
|
||||||
export GAM_THREADS=5
|
export GAM_THREADS=5
|
||||||
echo email > sample.csv;
|
echo email > sample.csv;
|
||||||
for i in {01..10}; do
|
for i in {1..10}; do
|
||||||
echo "${newbase}-bulkuser-$i" >> sample.csv;
|
echo "${newbase}-bulkuser-$i" >> sample.csv;
|
||||||
done
|
done
|
||||||
$gam create user $newuser firstname GHA lastname $JID password random recoveryphone 12125121110 recoveryemail jay0lee@gmail.com gha.jid $JID languages en+,en-GB-
|
$gam create user $newuser firstname GHA lastname $JID password random recoveryphone 12125121110 recoveryemail jay0lee@gmail.com gha.jid $JID languages en+,en-GB-
|
||||||
@@ -561,12 +569,12 @@ jobs:
|
|||||||
$gam create group $newgroup name "GHA $JID group" description "This is a description" isarchived true
|
$gam create group $newgroup name "GHA $JID group" description "This is a description" isarchived true
|
||||||
$gam user $gam_user sendemail recipient $newuser subject "test message $newbase" message "GHA test message"
|
$gam user $gam_user sendemail recipient $newuser subject "test message $newbase" message "GHA test message"
|
||||||
$gam user $gam_user sendemail recipient exchange@pdl.jaylee.us subject "test ${tstamp}" message "test message"
|
$gam user $gam_user sendemail recipient exchange@pdl.jaylee.us subject "test ${tstamp}" message "test message"
|
||||||
|
$gam user $newuser add license workspaceenterpriseplus
|
||||||
|
$gam print privileges
|
||||||
$gam update cigroup $newgroup memberrestriction 'member.type == 1 || member.customer_id == groupCustomerId()'
|
$gam update cigroup $newgroup memberrestriction 'member.type == 1 || member.customer_id == groupCustomerId()'
|
||||||
$gam info cigroup $newgroup
|
$gam info cigroup $newgroup
|
||||||
$gam user $newuser add license workspaceenterpriseplus
|
|
||||||
$gam update group $newgroup add owner $gam_user
|
$gam update group $newgroup add owner $gam_user
|
||||||
$gam update group $newgroup add member $newuser
|
$gam update group $newgroup add member $newuser
|
||||||
$gam print privileges
|
|
||||||
$gam create admin $newuser _GROUPS_EDITOR_ROLE CUSTOMER condition nonsecuritygroup
|
$gam create admin $newuser _GROUPS_EDITOR_ROLE CUSTOMER condition nonsecuritygroup
|
||||||
$gam csv sample.csv gam create user ~~email~~ firstname "GHA Bulk" lastname ~~email~~ gha.jid $JID
|
$gam csv sample.csv gam create user ~~email~~ firstname "GHA Bulk" lastname ~~email~~ gha.jid $JID
|
||||||
$gam csv sample.csv gam update user ~~email~~ recoveryphone 12125121110 recoveryemail jay0lee@gmail.com password random
|
$gam csv sample.csv gam update user ~~email~~ recoveryphone 12125121110 recoveryemail jay0lee@gmail.com password random
|
||||||
@@ -582,7 +590,7 @@ jobs:
|
|||||||
$gam user $newuser imap on
|
$gam user $newuser imap on
|
||||||
$gam user $newuser show imap
|
$gam user $newuser show imap
|
||||||
$gam user $newuser show delegates
|
$gam user $newuser show delegates
|
||||||
#$gam user $newuser add contactdelegate "${newbase}-bulkuser-01"
|
#$gam user $newuser add contactdelegate "${newbase}-bulkuser-1"
|
||||||
#$gam user $newuser print contactdelegates
|
#$gam user $newuser print contactdelegates
|
||||||
export biohazard=$(echo -e '\xe2\x98\xa3')
|
export biohazard=$(echo -e '\xe2\x98\xa3')
|
||||||
$gam user $newuser label "$biohazard unicode biohazard $biohazard"
|
$gam user $newuser label "$biohazard unicode biohazard $biohazard"
|
||||||
@@ -593,10 +601,10 @@ jobs:
|
|||||||
$gam user $gam_user sendemail subject "GHA send $gam_user $newbase" file gam.py recipient admin@pdl.jaylee.us
|
$gam user $gam_user sendemail subject "GHA send $gam_user $newbase" file gam.py recipient admin@pdl.jaylee.us
|
||||||
$gam user $gam_user draftemail subject "GHA draft $newbase" message "Draft message test"
|
$gam user $gam_user draftemail subject "GHA draft $newbase" message "Draft message test"
|
||||||
$gam csvfile sample.csv:email waitformailbox
|
$gam csvfile sample.csv:email waitformailbox
|
||||||
$gam user $newuser delegate to "${newbase}-bulkuser-01"
|
$gam user $newuser delegate to "${newbase}-bulkuser-1"
|
||||||
$gam users "$gam_user $newbase-bulkuser-01 $newbase-bulkuser-02 $newbase-bulkuser-03" delete messages query in:anywhere maxtodelete 99999 doit
|
$gam users "$gam_user $newbase-bulkuser-1 $newbase-bulkuser-2 $newbase-bulkuser-3" delete messages query in:anywhere maxtodelete 99999 doit
|
||||||
$gam users "$newbase-bulkuser-04 $newbase-bulkuser-05 $newbase-bulkuser-06" trash messages query in:anywhere maxtotrash 99999 doit
|
$gam users "$newbase-bulkuser-4 $newbase-bulkuser-5 $newbase-bulkuser-6" trash messages query in:anywhere maxtotrash 99999 doit
|
||||||
$gam users "$newbase-bulkuser-07 $newbase-bulkuser-08 $newbase-bulkuser-09" modify messages query in:anywhere maxtomodify 99999 addlabel IMPORTANT addlabel STARRED doit
|
$gam users "$newbase-bulkuser-7 $newbase-bulkuser-8 $newbase-bulkuser-9" modify messages query in:anywhere maxtomodify 99999 addlabel IMPORTANT addlabel STARRED doit
|
||||||
$gam user $newuser delete label --ALL_LABELS--
|
$gam user $newuser delete label --ALL_LABELS--
|
||||||
GAM_CSV_ROW_FILTER="name:regex:gha-test-${JID}" $gam print features | $gam csv - gam delete feature ~name
|
GAM_CSV_ROW_FILTER="name:regex:gha-test-${JID}" $gam print features | $gam csv - gam delete feature ~name
|
||||||
$gam create feature name Whiteboard-$newbase
|
$gam create feature name Whiteboard-$newbase
|
||||||
@@ -620,7 +628,7 @@ jobs:
|
|||||||
$gam print vaultmatters matterstate open
|
$gam print vaultmatters matterstate open
|
||||||
$gam print vaultholds matter $matterid
|
$gam print vaultholds matter $matterid
|
||||||
$gam print vaultcount matter $matterid corpus mail everyone todrive
|
$gam print vaultcount matter $matterid corpus mail everyone todrive
|
||||||
$gam create vaultexport matter $matterid name "GHA export $newbase" corpus mail accounts $newuser use_new_export true
|
$gam create vaultexport matter $matterid name "GHA export $newbase" corpus mail accounts $newuser use_new_export false
|
||||||
$gam print exports matter $matterid | $gam csv - gam info export $matterid id:~~id~~
|
$gam print exports matter $matterid | $gam csv - gam info export $matterid id:~~id~~
|
||||||
$gam csv sample.csv gam user ~email add calendar id:$newresource
|
$gam csv sample.csv gam user ~email add calendar id:$newresource
|
||||||
$gam delete resource $newresource
|
$gam delete resource $newresource
|
||||||
@@ -646,7 +654,7 @@ jobs:
|
|||||||
export sn="$JID$JID$JID$JID-$(openssl rand -base64 32 | sed 's/[^a-zA-Z0-9]//g')"
|
export sn="$JID$JID$JID$JID-$(openssl rand -base64 32 | sed 's/[^a-zA-Z0-9]//g')"
|
||||||
$gam create device serialnumber $sn devicetype android
|
$gam create device serialnumber $sn devicetype android
|
||||||
$gam print cros allfields orderby serialnumber
|
$gam print cros allfields orderby serialnumber
|
||||||
#$gam show crostelemetry storagepercentonly
|
$gam show crostelemetry storagepercentonly
|
||||||
$gam report usageparameters customer
|
$gam report usageparameters customer
|
||||||
$gam report usage customer parameters gmail:num_emails_sent,accounts:num_1day_logins
|
$gam report usage customer parameters gmail:num_emails_sent,accounts:num_1day_logins
|
||||||
$gam report customer todrive
|
$gam report customer todrive
|
||||||
@@ -655,14 +663,24 @@ jobs:
|
|||||||
$gam print devices nopersonaldevices nodeviceusers filter "serial:$JID$JID$JID$JID-" | $gam csv - gam delete device id ~name
|
$gam print devices nopersonaldevices nodeviceusers filter "serial:$JID$JID$JID$JID-" | $gam csv - gam delete device id ~name
|
||||||
$gam print userinvitations
|
$gam print userinvitations
|
||||||
$gam print userinvitations | $gam csv - gam send userinvitation ~name
|
$gam print userinvitations | $gam csv - gam send userinvitation ~name
|
||||||
export CUSTOMER_ID="C01wfv983"
|
$gam create caalevel "zzz_${newbase}" basic condition ipsubnetworks 1.1.1.1/32,2.2.2.2/32 endcondition
|
||||||
export GA_DOMAIN="pdl.jaylee.us"
|
$gam print caalevels
|
||||||
touch $gampath/enabledasa.txt
|
$gam delete caalevel "zzz_${newbase}"
|
||||||
|
driveid=$($gam user $gam_user add shareddrive "${newbase}" | awk '{print $NF}')
|
||||||
|
echo "Created shared drive ${driveid}"
|
||||||
|
$gam user $gam_user add drivefile localfile gam.py parentid "${driveid}"
|
||||||
|
$gam user $gam_user update shareddrive "${driveid}" ou "id:03ph8a2z1t2ph5z"
|
||||||
|
$gam user $gam_user show shareddrives asadmin
|
||||||
|
$gam user $gam_user delete shareddrive "${driveid}" nukefromorbit
|
||||||
echo "printer model count:"
|
echo "printer model count:"
|
||||||
$gam print printermodels | wc -l
|
$gam print printermodels | wc -l
|
||||||
#$gam print printers
|
#$gam print printers
|
||||||
#$gam create printer displayname "${newbase}" uri ipp://localhost:631 driverless description "made by $(gam_user)"
|
#$gam create printer displayname "${newbase}" uri ipp://localhost:631 driverless description "made by $(gam_user)" ou /
|
||||||
rm -f -v $gampath/enabledasa.txt
|
#export CUSTOMER_ID="C01wfv983"
|
||||||
|
#export GA_DOMAIN="pdl.jaylee.us"
|
||||||
|
#touch $gampath/enabledasa.txt
|
||||||
|
#echo "using delegated admin service account"
|
||||||
|
#$gam print users
|
||||||
|
|
||||||
# - name: Upload to Google Drive, build only.
|
# - name: Upload to Google Drive, build only.
|
||||||
# if: github.event_name == 'push' && matrix.goal != 'test'
|
# if: github.event_name == 'push' && matrix.goal != 'test'
|
||||||
|
|||||||
70
.github/workflows/codeql-analysis.yml
vendored
Normal file
70
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
#
|
||||||
|
# ******** NOTE ********
|
||||||
|
# We have attempted to detect the languages in your repository. Please check
|
||||||
|
# the `language` matrix defined below to confirm you have the correct set of
|
||||||
|
# supported CodeQL languages.
|
||||||
|
#
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ main ]
|
||||||
|
schedule:
|
||||||
|
- cron: '25 10 * * 1'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'python' ]
|
||||||
|
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||||
|
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v2
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 https://git.io/JvXDl
|
||||||
|
|
||||||
|
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||||
|
# and modify them (or add more) to build your code if your project
|
||||||
|
# uses a compiled language
|
||||||
|
|
||||||
|
#- run: |
|
||||||
|
# make bootstrap
|
||||||
|
# make release
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v2
|
||||||
@@ -9,7 +9,7 @@ GAM is a command line tool for Google Workspace admins to manage domain and user
|
|||||||
Open a terminal and run:
|
Open a terminal and run:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
bash <(curl -s -S -L https://git.io/install-gam)
|
bash <(curl -s -S -L https://gam-shortn.appspot.com/gam-install)
|
||||||
```
|
```
|
||||||
|
|
||||||
this will download GAM, install it and start setup.
|
this will download GAM, install it and start setup.
|
||||||
@@ -28,13 +28,13 @@ The GAM mailing list / discussion group is hosted on [Google Groups]. You can j
|
|||||||
|
|
||||||
# Chat Room
|
# Chat Room
|
||||||
|
|
||||||
There is a public chat room hosted in Google Chat. [Instructions to join](https://git.io/gam-chat).
|
There is a public chat room hosted in Google Chat. [Instructions to join](https://github.com/GAM-team/GAM/wiki/GAM-Public-Chat-Room).
|
||||||
|
|
||||||
# Author
|
# Author
|
||||||
|
|
||||||
GAM is maintained by [Jay Lee](mailto:jay0lee@gmail.com). Please direct "how do I?" questions to [Google Groups].
|
GAM is maintained by [Jay Lee](mailto:jay0lee@gmail.com). Please direct "how do I?" questions to [Google Groups].
|
||||||
|
|
||||||
[GAM release]: https://git.io/gamreleases
|
[GAM release]: https://github.com/GAM-team/GAM/releases
|
||||||
[GitHub Releases]: https://github.com/GAM-team/GAM/releases
|
[GitHub Releases]: https://github.com/GAM-team/GAM/releases
|
||||||
[GitHub]: https://github.com/GAM-team/GAM/tree/master
|
[GitHub]: https://github.com/GAM-team/GAM/tree/master
|
||||||
[GitHub Wiki]: https://github.com/GAM-team/GAM/wiki/
|
[GitHub Wiki]: https://github.com/GAM-team/GAM/wiki/
|
||||||
|
|||||||
@@ -243,6 +243,7 @@ If an item contains spaces, it should be surrounded by ".
|
|||||||
<SMTPHostName> ::= <String>
|
<SMTPHostName> ::= <String>
|
||||||
<StudentItem> ::= <EmailAddress>|<UniqueID>|<String>
|
<StudentItem> ::= <EmailAddress>|<UniqueID>|<String>
|
||||||
<TeamDriveID> ::= <String>
|
<TeamDriveID> ::= <String>
|
||||||
|
<TeamDriveName> ::= <String>
|
||||||
<Timezone> ::= <String>
|
<Timezone> ::= <String>
|
||||||
<Title> ::= <String>
|
<Title> ::= <String>
|
||||||
<URI> ::= <String>
|
<URI> ::= <String>
|
||||||
@@ -632,6 +633,7 @@ Items, separated by spaces, with spaces, commas or single quotes in the items th
|
|||||||
<SchemaNameList> ::= "<SchemaName>(,<SchemaName>)*"
|
<SchemaNameList> ::= "<SchemaName>(,<SchemaName>)*"
|
||||||
<SerialNumberList> ::= "<SerialNumber>(,<SerialNumber>)*"
|
<SerialNumberList> ::= "<SerialNumber>(,<SerialNumber>)*"
|
||||||
<ServiceAccountKeyList> ::= "<ServiceAccountKey>(,<ServiceAccountKey>)*"
|
<ServiceAccountKeyList> ::= "<ServiceAccountKey>(,<ServiceAccountKey>)*"
|
||||||
|
<StringList> ::= "<String>(,<String>)*"
|
||||||
<TeamDriveIDList> ::= "<TeamDriveID>(,<TeamDriveID>)*"
|
<TeamDriveIDList> ::= "<TeamDriveID>(,<TeamDriveID>)*"
|
||||||
<UserFieldNameList> ::= "<UserFieldName>(,<UserFieldName>)*"
|
<UserFieldNameList> ::= "<UserFieldName>(,<UserFieldName>)*"
|
||||||
<UserList> ::= "<UserItem>(,<UserItem>)*"
|
<UserList> ::= "<UserItem>(,<UserItem>)*"
|
||||||
@@ -680,12 +682,19 @@ Specify a collection of Users by directly specifying them or by specifying items
|
|||||||
## Item attributes
|
## Item attributes
|
||||||
|
|
||||||
<BuildingAttribute> ::=
|
<BuildingAttribute> ::=
|
||||||
|
(address|addresslines <String>)|
|
||||||
|
(city|locality <String>)|
|
||||||
|
(country|regioncode <String>)|
|
||||||
(description <String>)|
|
(description <String>)|
|
||||||
(floors <FloorNameList>)|
|
(floors <FloorNameList>)|
|
||||||
(id <String>)|
|
(id <String>)|
|
||||||
|
(language|languageCode <Language>)|
|
||||||
(latitude <Float>)|
|
(latitude <Float>)|
|
||||||
(longitude <Float>)|
|
(longitude <Float>)|
|
||||||
(name <String>)
|
(name <String>)
|
||||||
|
(state|administrativearea <String>)|
|
||||||
|
(sublocality <String>)|
|
||||||
|
(zipcode|postalcode <String>)
|
||||||
|
|
||||||
<CalendarAttribute> ::=
|
<CalendarAttribute> ::=
|
||||||
(selected <Boolean>)|(hidden <Boolean>)|(summary <String>)|(colorindex|colorid <CalendarColorIndex>)|(backgroundcolor <ColorValue>)|(foregroundcolor <ColorValue>)|
|
(selected <Boolean>)|(hidden <Boolean>)|(summary <String>)|(colorindex|colorid <CalendarColorIndex>)|(backgroundcolor <ColorValue>)|(foregroundcolor <ColorValue>)|
|
||||||
@@ -1210,6 +1219,76 @@ gam print browsertokens [todrive]
|
|||||||
[fields <BrowserTokenFieldNameList>]
|
[fields <BrowserTokenFieldNameList>]
|
||||||
[sortheaders]
|
[sortheaders]
|
||||||
|
|
||||||
|
<CAAAllowedEncryptionStatus> ::=
|
||||||
|
encryption_unsupported |
|
||||||
|
encrypted |
|
||||||
|
unencrypted
|
||||||
|
<CAAAllowedEncryptionStatusList> ::= "<CAAAllowedEncryptionStatus>(,<CAAAllowedEncryptionStatus>)"
|
||||||
|
|
||||||
|
<CAAAllowedDeviceManagementLevel> ::=
|
||||||
|
basic |
|
||||||
|
advanced|complete |
|
||||||
|
none
|
||||||
|
<CAAAllowedDeviceManagementLevelList> ::= "<CAAAllowedDeviceManagementLevel>(,<CAAAllowedDeviceManagementLevel>)"
|
||||||
|
|
||||||
|
<CAACombiningFunction> ::=
|
||||||
|
and |
|
||||||
|
or
|
||||||
|
|
||||||
|
<CAAIPSubNetwork> ::=
|
||||||
|
<CIDRnetmask>
|
||||||
|
<CAAIPSubNetworkList> ::= "<CAAIPSubNetwork>(,<CAAIPSubNetwork>)"
|
||||||
|
|
||||||
|
<CAAMember> ::=
|
||||||
|
user:<EmailAddress> |
|
||||||
|
serviceAccount:<EmailAddress>
|
||||||
|
<CAAMemberList> ::= "<CAAMember>(,<CAAMember>)"
|
||||||
|
|
||||||
|
<CAAOsType> ::=
|
||||||
|
DESKTOP_MAC |
|
||||||
|
DESKTOP_WINDOWS |
|
||||||
|
DESKTOP_LINUX |
|
||||||
|
DESKTOP_CHROME_OS |
|
||||||
|
VERIFIED_DESKTOP_CHROME_OS |
|
||||||
|
ANDROID |
|
||||||
|
IOS
|
||||||
|
|
||||||
|
<CAAOsConstraint> ::=
|
||||||
|
<CAAOsType> |
|
||||||
|
<CAAOsType>:<String>.<String>.<String>
|
||||||
|
<CAAOsConstraintList> ::= "<CAAOsConstraint>(,<CAAOsConstraint>)"
|
||||||
|
|
||||||
|
<CAARegion> ::=
|
||||||
|
<Character><Character>
|
||||||
|
<CAARegionList> ::= "<CAARegion>(,<CAARegion>)"
|
||||||
|
See: https://www.iso.org/obp/ui/#search
|
||||||
|
|
||||||
|
<CAADevicePolicyAttribute> ::=
|
||||||
|
(requirescreenlock <Boolean>) |
|
||||||
|
(allowedencryptionstatuses <CAAAllowedEncryptionStatusList>) |
|
||||||
|
(osconstraints <CAAOsConstraintList>) |
|
||||||
|
(alloweddevicemanagementlevels <CAAAllowedDeviceManagementLevelList>) |
|
||||||
|
(requireadminapproval <Boolean>) |
|
||||||
|
(requirecorpowned <Boolean>)
|
||||||
|
|
||||||
|
<CAAConditionAttribute> ::=
|
||||||
|
(ipsubnetworks <CAAIPSubNetworkList>) |
|
||||||
|
(devicepolicy <CAADevicePolicyAttribute> enddevicepolicy) |
|
||||||
|
(requiredaccesslevels <StringList>) |
|
||||||
|
(negate <Boolean>) |
|
||||||
|
(members <CAARegionList>) |
|
||||||
|
(regions <CAAMemberList>)
|
||||||
|
|
||||||
|
<CAABasicAttribute> ::+
|
||||||
|
(combiningfunction <CAACombiningFunction>) |
|
||||||
|
(condition <CAAConditionAttribute>+ endcondition)
|
||||||
|
|
||||||
|
gam create caalevel <String> (basic <CAABasicAttribute>+)|(custom <String>)
|
||||||
|
gam update caalevel <CAALevelName> (basic <CAABasicAttribute>+)|(custom <String>)
|
||||||
|
gam delete caalevel <CAALevelName>
|
||||||
|
gam show caalevels
|
||||||
|
gam print caalevels [todrive]
|
||||||
|
|
||||||
gam print chatspaces [todrive]
|
gam print chatspaces [todrive]
|
||||||
gam print chatmembers space <ChatSpace> [todrive]
|
gam print chatmembers space <ChatSpace> [todrive]
|
||||||
gam create chatmessage space <ChatSpace> [thread <String>]
|
gam create chatmessage space <ChatSpace> [thread <String>]
|
||||||
@@ -1423,7 +1502,7 @@ gam print printermodels [todrive] [filter <String>]
|
|||||||
gam create cigroup <EmailAddress> <CIGroupAttribute>*
|
gam create cigroup <EmailAddress> <CIGroupAttribute>*
|
||||||
[makeowner] [alias|aliases <AliasList>] [dynamic <QueryDynamicGroup>]
|
[makeowner] [alias|aliases <AliasList>] [dynamic <QueryDynamicGroup>]
|
||||||
gam update cigroup <GroupItem> [email <EmailAddress>] <CIGroupAttribute>*
|
gam update cigroup <GroupItem> [email <EmailAddress>] <CIGroupAttribute>*
|
||||||
[security] [dynamic <QueryDynamicGroup>]
|
[security|dynamicsecurity] [dynamic <QueryDynamicGroup>]
|
||||||
[memberrestrictions <QueryMemberRestrictions>]
|
[memberrestrictions <QueryMemberRestrictions>]
|
||||||
gam update cigroup <GroupItem> add [owner|manager|member] [notsuspended|suspended] [expires never|<Time>] <UserTypeEntity>
|
gam update cigroup <GroupItem> add [owner|manager|member] [notsuspended|suspended] [expires never|<Time>] <UserTypeEntity>
|
||||||
gam update cigroup <GroupItem> delete|remove [owner|manager|member] [notsuspended|suspended] <UserTypeEntity>
|
gam update cigroup <GroupItem> delete|remove [owner|manager|member] [notsuspended|suspended] <UserTypeEntity>
|
||||||
@@ -1488,6 +1567,9 @@ gam update feature <Name> name <Name>
|
|||||||
gam delete feature <Name>
|
gam delete feature <Name>
|
||||||
gam print features [todrive]
|
gam print features [todrive]
|
||||||
|
|
||||||
|
gam show oushareddrives|orgunitshareddrives [ou|org|orgunit <OrgUnitItem>]
|
||||||
|
gam print oushareddrives|orgunitshareddrives [todrive] [ou|org|orgunit <OrgUnitItem>]
|
||||||
|
|
||||||
gam create resource <ResourceID> <Name> <ResourceAttribute>*
|
gam create resource <ResourceID> <Name> <ResourceAttribute>*
|
||||||
gam update resource <ResourceID> <ResourceAttribute>*
|
gam update resource <ResourceID> <ResourceAttribute>*
|
||||||
gam delete resource <ResourceID>
|
gam delete resource <ResourceID>
|
||||||
@@ -1760,12 +1842,12 @@ gam <UserTypeEntity> show signature|sig [format]
|
|||||||
teammembersonly
|
teammembersonly
|
||||||
|
|
||||||
gam <UserTypeEntity> create|add teamdrive <Name>
|
gam <UserTypeEntity> create|add teamdrive <Name>
|
||||||
gam <UserTypeEntity> update teamdrive <TeamDriveID> [asadmin] [name <Name>]
|
gam <UserTypeEntity> update teamdrive <TeamDriveID>|(name <TeamDriveName>) [asadmin] [name <Name>]
|
||||||
[(theme|themeid <String>) | ([customtheme <DriveFileID> <Float> <Float> <Float>] [color <ColorValue>])]
|
[(theme|themeid <String>) | ([customtheme <DriveFileID> <Float> <Float> <Float>] [color <ColorValue>])]
|
||||||
(<TeamDriveRestrictionsSubfieldName> <Boolean>)*
|
(<TeamDriveRestrictionsSubfieldName> <Boolean>)*
|
||||||
[hidden <Boolean>]
|
[hidden <Boolean>]
|
||||||
gam <UserTypeEntity> delete teamdrive <TeamDriveID>
|
gam <UserTypeEntity> delete teamdrive <TeamDriveID>|(name <TeamDriveName>) [asadmin] [allowitemdeletion|nukefromorbit]
|
||||||
gam <UserTypeEntity> show teamdriveinfo <TeamDriveID> [asadmin]
|
gam <UserTypeEntity> show teamdriveinfo <TeamDriveID>|(name <TeamDriveName>) [asadmin]
|
||||||
gam <UserTypeEntity> show teamdrives [query <QueryTeamDrive>] [asadmin]
|
gam <UserTypeEntity> show teamdrives [query <QueryTeamDrive>] [asadmin]
|
||||||
gam <UserTypeEntity> print teamdrives [query <QueryTeamDrive>] [todrive] [asadmin]
|
gam <UserTypeEntity> print teamdrives [query <QueryTeamDrive>] [todrive] [asadmin]
|
||||||
gam <UserTypeEntity> show teamdrivethemes
|
gam <UserTypeEntity> show teamdrivethemes
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ trap "rm -rf $temp_archive_dir" EXIT
|
|||||||
|
|
||||||
echo_yellow "Downloading file $name from $browser_download_url to $temp_archive_dir ($check_type)..."
|
echo_yellow "Downloading file $name from $browser_download_url to $temp_archive_dir ($check_type)..."
|
||||||
# Save archive to temp w/o losing our path
|
# Save archive to temp w/o losing our path
|
||||||
(cd "$temp_archive_dir" && curl -O -L $GHCLIENT $browser_download_url)
|
(cd "$temp_archive_dir" && curl -# -O -L $GHCLIENT $browser_download_url)
|
||||||
|
|
||||||
mkdir -p "$target_dir"
|
mkdir -p "$target_dir"
|
||||||
|
|
||||||
|
|||||||
@@ -33,11 +33,15 @@ for d in a.datas:
|
|||||||
|
|
||||||
pyz = PYZ(a.pure)
|
pyz = PYZ(a.pure)
|
||||||
|
|
||||||
|
|
||||||
if sys.platform == "darwin":
|
if sys.platform == "darwin":
|
||||||
target_arch="universal2"
|
target_arch="universal2"
|
||||||
else:
|
else:
|
||||||
target_arch=None
|
target_arch=None
|
||||||
|
|
||||||
|
# use strip on all non-Windows platforms
|
||||||
|
strip = not sys.platform == 'win32'
|
||||||
|
|
||||||
exe = EXE(pyz,
|
exe = EXE(pyz,
|
||||||
a.scripts,
|
a.scripts,
|
||||||
a.binaries,
|
a.binaries,
|
||||||
@@ -45,7 +49,7 @@ exe = EXE(pyz,
|
|||||||
a.datas,
|
a.datas,
|
||||||
name='gam',
|
name='gam',
|
||||||
debug=False,
|
debug=False,
|
||||||
strip=None,
|
strip=strip,
|
||||||
upx=False,
|
upx=False,
|
||||||
target_arch=target_arch,
|
target_arch=target_arch,
|
||||||
console=True)
|
console=True)
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ from gam import auth
|
|||||||
from gam import controlflow
|
from gam import controlflow
|
||||||
from gam import display
|
from gam import display
|
||||||
from gam import fileutils
|
from gam import fileutils
|
||||||
|
from gam.gapi import caa as gapi_caa
|
||||||
from gam.gapi import calendar as gapi_calendar
|
from gam.gapi import calendar as gapi_calendar
|
||||||
from gam.gapi import cloudidentity as gapi_cloudidentity
|
from gam.gapi import cloudidentity as gapi_cloudidentity
|
||||||
from gam.gapi import cbcm as gapi_cbcm
|
from gam.gapi import cbcm as gapi_cbcm
|
||||||
@@ -64,6 +65,7 @@ from gam.gapi import chromemanagement as gapi_chromemanagement
|
|||||||
from gam.gapi import chromepolicy as gapi_chromepolicy
|
from gam.gapi import chromepolicy as gapi_chromepolicy
|
||||||
from gam.gapi.cloudidentity import devices as gapi_cloudidentity_devices
|
from gam.gapi.cloudidentity import devices as gapi_cloudidentity_devices
|
||||||
from gam.gapi.cloudidentity import groups as gapi_cloudidentity_groups
|
from gam.gapi.cloudidentity import groups as gapi_cloudidentity_groups
|
||||||
|
from gam.gapi.cloudidentity import orgunits as gapi_cloudidentity_orgunits
|
||||||
from gam.gapi.cloudidentity import userinvitations as gapi_cloudidentity_userinvitations
|
from gam.gapi.cloudidentity import userinvitations as gapi_cloudidentity_userinvitations
|
||||||
from gam.gapi import contactdelegation as gapi_contactdelegation
|
from gam.gapi import contactdelegation as gapi_contactdelegation
|
||||||
from gam.gapi.directory import asps as gapi_directory_asps
|
from gam.gapi.directory import asps as gapi_directory_asps
|
||||||
@@ -80,6 +82,7 @@ from gam.gapi.directory import resource as gapi_directory_resource
|
|||||||
from gam.gapi.directory import roles as gapi_directory_roles
|
from gam.gapi.directory import roles as gapi_directory_roles
|
||||||
from gam.gapi.directory import roleassignments as gapi_directory_roleassignments
|
from gam.gapi.directory import roleassignments as gapi_directory_roleassignments
|
||||||
from gam.gapi.directory import users as gapi_directory_users
|
from gam.gapi.directory import users as gapi_directory_users
|
||||||
|
from gam.gapi.drive import drives as gapi_drive_drives
|
||||||
from gam.gapi import licensing as gapi_licensing
|
from gam.gapi import licensing as gapi_licensing
|
||||||
from gam.gapi import siteverification as gapi_siteverification
|
from gam.gapi import siteverification as gapi_siteverification
|
||||||
from gam.gapi import errors as gapi_errors
|
from gam.gapi import errors as gapi_errors
|
||||||
@@ -848,7 +851,9 @@ def _getSvcAcctData():
|
|||||||
controlflow.system_error_exit(6, None)
|
controlflow.system_error_exit(6, None)
|
||||||
GM_Globals[GM_OAUTH2SERVICE_JSON_DATA] = json.loads(json_string)
|
GM_Globals[GM_OAUTH2SERVICE_JSON_DATA] = json.loads(json_string)
|
||||||
|
|
||||||
jwt_apis = ['chat'] # APIs which can handle OAuthless JWT tokens
|
jwt_apis = ['chat',
|
||||||
|
'cloudresourcemanager',
|
||||||
|
'accesscontextmanager'] # APIs which can handle OAuthless JWT tokens
|
||||||
def getSvcAcctCredentials(scopes, act_as, api=None):
|
def getSvcAcctCredentials(scopes, act_as, api=None):
|
||||||
try:
|
try:
|
||||||
_getSvcAcctData()
|
_getSvcAcctData()
|
||||||
@@ -2730,7 +2735,7 @@ def printDriveSettings(users):
|
|||||||
display.write_csv_file(csvRows, titles, 'User Drive Settings', todrive)
|
display.write_csv_file(csvRows, titles, 'User Drive Settings', todrive)
|
||||||
|
|
||||||
|
|
||||||
def getTeamDriveThemes(users):
|
def getSharedDriveThemes(users):
|
||||||
for user in users:
|
for user in users:
|
||||||
user, drive = buildDrive3GAPIObject(user)
|
user, drive = buildDrive3GAPIObject(user)
|
||||||
if not drive:
|
if not drive:
|
||||||
@@ -7009,6 +7014,8 @@ def getUserAttributes(i, cd, updateCmd):
|
|||||||
if schemaValue['type'] == 'custom':
|
if schemaValue['type'] == 'custom':
|
||||||
schemaValue['customType'] = sys.argv[i]
|
schemaValue['customType'] = sys.argv[i]
|
||||||
i += 1
|
i += 1
|
||||||
|
else:
|
||||||
|
schemaValue['type'] = 'work'
|
||||||
schemaValue['value'] = sys.argv[i]
|
schemaValue['value'] = sys.argv[i]
|
||||||
if schemaValue['value'] or multivalue != 'multinonempty':
|
if schemaValue['value'] or multivalue != 'multinonempty':
|
||||||
body[up][schemaName][fieldName].append(schemaValue)
|
body[up][schemaName][fieldName].append(schemaValue)
|
||||||
@@ -8014,10 +8021,17 @@ def doPrintShowProjects(csvFormat):
|
|||||||
display.write_csv_file(csvRows, titles, 'Projects', todrive)
|
display.write_csv_file(csvRows, titles, 'Projects', todrive)
|
||||||
|
|
||||||
|
|
||||||
def doGetTeamDriveInfo(users):
|
def getSharedDriveId(i):
|
||||||
teamDriveId = sys.argv[5]
|
driveId = sys.argv[i]
|
||||||
|
if driveId.lower() == 'name':
|
||||||
|
i += 1
|
||||||
|
driveId = gapi_drive_drives.drive_name_to_id(sys.argv[i])
|
||||||
|
return (i+1, driveId)
|
||||||
|
|
||||||
|
|
||||||
|
def doGetSharedDriveInfo(users):
|
||||||
|
i, driveId = getSharedDriveId(5)
|
||||||
useDomainAdminAccess = False
|
useDomainAdminAccess = False
|
||||||
i = 6
|
|
||||||
while i < len(sys.argv):
|
while i < len(sys.argv):
|
||||||
myarg = sys.argv[i].lower().replace('_', '')
|
myarg = sys.argv[i].lower().replace('_', '')
|
||||||
if myarg == 'asadmin':
|
if myarg == 'asadmin':
|
||||||
@@ -8025,7 +8039,7 @@ def doGetTeamDriveInfo(users):
|
|||||||
i += 1
|
i += 1
|
||||||
else:
|
else:
|
||||||
controlflow.invalid_argument_exit(myarg,
|
controlflow.invalid_argument_exit(myarg,
|
||||||
'gam <users> show teamdrive')
|
'gam <users> show shareddrive')
|
||||||
for user in users:
|
for user in users:
|
||||||
drive = buildGAPIServiceObject('drive3', user)
|
drive = buildGAPIServiceObject('drive3', user)
|
||||||
if not drive:
|
if not drive:
|
||||||
@@ -8033,13 +8047,15 @@ def doGetTeamDriveInfo(users):
|
|||||||
continue
|
continue
|
||||||
result = gapi.call(drive.drives(),
|
result = gapi.call(drive.drives(),
|
||||||
'get',
|
'get',
|
||||||
driveId=teamDriveId,
|
driveId=driveId,
|
||||||
useDomainAdminAccess=useDomainAdminAccess,
|
useDomainAdminAccess=useDomainAdminAccess,
|
||||||
fields='*')
|
fields='*')
|
||||||
|
if useDomainAdminAccess and 'orgUnitId' in result:
|
||||||
|
result['orgUnit'] = gapi_directory_orgunits.orgunit_from_orgunitid(f'id:{result["orgUnitId"]}')
|
||||||
display.print_json(result)
|
display.print_json(result)
|
||||||
|
|
||||||
|
|
||||||
def doCreateTeamDrive(users):
|
def doCreateSharedDrive(users):
|
||||||
body = {'name': sys.argv[5]}
|
body = {'name': sys.argv[5]}
|
||||||
i = 6
|
i = 6
|
||||||
while i < len(sys.argv):
|
while i < len(sys.argv):
|
||||||
@@ -8049,7 +8065,7 @@ def doCreateTeamDrive(users):
|
|||||||
i += 2
|
i += 2
|
||||||
else:
|
else:
|
||||||
controlflow.invalid_argument_exit(sys.argv[i],
|
controlflow.invalid_argument_exit(sys.argv[i],
|
||||||
'gam <users> create teamdrive')
|
'gam <users> create shareddrive')
|
||||||
for user in users:
|
for user in users:
|
||||||
drive = buildGAPIServiceObject('drive3', user)
|
drive = buildGAPIServiceObject('drive3', user)
|
||||||
if not drive:
|
if not drive:
|
||||||
@@ -8061,7 +8077,7 @@ def doCreateTeamDrive(users):
|
|||||||
requestId=requestId,
|
requestId=requestId,
|
||||||
body=body,
|
body=body,
|
||||||
fields='id')
|
fields='id')
|
||||||
print(f'Created Team Drive {body["name"]} with id {result["id"]}')
|
print(f'Created Shared Drive {body["name"]} with id {result["id"]}')
|
||||||
|
|
||||||
|
|
||||||
TEAMDRIVE_RESTRICTIONS_MAP = {
|
TEAMDRIVE_RESTRICTIONS_MAP = {
|
||||||
@@ -8072,17 +8088,20 @@ TEAMDRIVE_RESTRICTIONS_MAP = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def doUpdateTeamDrive(users):
|
def doUpdateSharedDrive(users):
|
||||||
teamDriveId = sys.argv[5]
|
i, driveId = getSharedDriveId(5)
|
||||||
body = {}
|
body = {}
|
||||||
useDomainAdminAccess = False
|
useDomainAdminAccess = False
|
||||||
change_hide = None
|
change_hide = None
|
||||||
i = 6
|
orgUnit = None
|
||||||
while i < len(sys.argv):
|
while i < len(sys.argv):
|
||||||
myarg = sys.argv[i].lower().replace('_', '')
|
myarg = sys.argv[i].lower().replace('_', '')
|
||||||
if myarg == 'name':
|
if myarg == 'name':
|
||||||
body['name'] = sys.argv[i + 1]
|
body['name'] = sys.argv[i + 1]
|
||||||
i += 2
|
i += 2
|
||||||
|
elif myarg in ['ou', 'org', 'orgunit']:
|
||||||
|
orgUnit = sys.argv[i+1]
|
||||||
|
i += 2
|
||||||
elif myarg == 'theme':
|
elif myarg == 'theme':
|
||||||
body['themeId'] = sys.argv[i + 1]
|
body['themeId'] = sys.argv[i + 1]
|
||||||
i += 2
|
i += 2
|
||||||
@@ -8100,9 +8119,9 @@ def doUpdateTeamDrive(users):
|
|||||||
elif myarg == 'asadmin':
|
elif myarg == 'asadmin':
|
||||||
useDomainAdminAccess = True
|
useDomainAdminAccess = True
|
||||||
i += 1
|
i += 1
|
||||||
elif myarg in ['ou', 'org', 'orgunit']:
|
# elif myarg in ['ou', 'org', 'orgunit']:
|
||||||
body['orgUnitId'] = gapi_directory_orgunits.getOrgUnitId(sys.argv[i + 1])
|
# body['orgUnitId'] = gapi_directory_orgunits.getOrgUnitId(sys.argv[i + 1])
|
||||||
i += 2
|
# i += 2
|
||||||
elif myarg in ['hidden']:
|
elif myarg in ['hidden']:
|
||||||
if getBoolean(sys.argv[i+1], myarg):
|
if getBoolean(sys.argv[i+1], myarg):
|
||||||
change_hide = 'hide'
|
change_hide = 'hide'
|
||||||
@@ -8117,8 +8136,8 @@ def doUpdateTeamDrive(users):
|
|||||||
i += 2
|
i += 2
|
||||||
else:
|
else:
|
||||||
controlflow.invalid_argument_exit(sys.argv[i],
|
controlflow.invalid_argument_exit(sys.argv[i],
|
||||||
'gam <users> update teamdrive')
|
'gam <users> update shareddrive')
|
||||||
if not body and not change_hide:
|
if not body and not change_hide and not orgUnit:
|
||||||
controlflow.system_error_exit(
|
controlflow.system_error_exit(
|
||||||
4, 'nothing to update. Need at least a name argument.')
|
4, 'nothing to update. Need at least a name argument.')
|
||||||
for user in users:
|
for user in users:
|
||||||
@@ -8130,7 +8149,7 @@ def doUpdateTeamDrive(users):
|
|||||||
'update',
|
'update',
|
||||||
useDomainAdminAccess=useDomainAdminAccess,
|
useDomainAdminAccess=useDomainAdminAccess,
|
||||||
body=body,
|
body=body,
|
||||||
driveId=teamDriveId,
|
driveId=driveId,
|
||||||
fields='id',
|
fields='id',
|
||||||
soft_errors=True)
|
soft_errors=True)
|
||||||
if not result:
|
if not result:
|
||||||
@@ -8138,15 +8157,19 @@ def doUpdateTeamDrive(users):
|
|||||||
if change_hide:
|
if change_hide:
|
||||||
ch_result = gapi.call(drive.drives(),
|
ch_result = gapi.call(drive.drives(),
|
||||||
change_hide,
|
change_hide,
|
||||||
driveId=teamDriveId,
|
driveId=driveId,
|
||||||
fields='id',
|
fields='id',
|
||||||
soft_errors=True)
|
soft_errors=True)
|
||||||
print(f'Updated Team Drive {teamDriveId}')
|
if orgUnit:
|
||||||
|
gapi_cloudidentity_orgunits.move_shared_drive(driveId,
|
||||||
|
orgUnit)
|
||||||
|
print(f'Updated Shared Drive {driveId}')
|
||||||
|
|
||||||
def printShowTeamDrives(users, csvFormat):
|
def printShowSharedDrives(users, csvFormat):
|
||||||
todrive = False
|
todrive = False
|
||||||
useDomainAdminAccess = False
|
useDomainAdminAccess = False
|
||||||
q = None
|
q = None
|
||||||
|
get_orgunits = True
|
||||||
i = 5
|
i = 5
|
||||||
while i < len(sys.argv):
|
while i < len(sys.argv):
|
||||||
myarg = sys.argv[i].lower().replace('_', '')
|
myarg = sys.argv[i].lower().replace('_', '')
|
||||||
@@ -8159,13 +8182,18 @@ def printShowTeamDrives(users, csvFormat):
|
|||||||
elif myarg == 'query':
|
elif myarg == 'query':
|
||||||
q = sys.argv[i + 1]
|
q = sys.argv[i + 1]
|
||||||
i += 2
|
i += 2
|
||||||
|
elif myarg == 'noorgunits':
|
||||||
|
get_orgunits = False
|
||||||
|
i += 1
|
||||||
else:
|
else:
|
||||||
controlflow.invalid_argument_exit(
|
controlflow.invalid_argument_exit(
|
||||||
myarg, f"gam {['show', 'print'][csvFormat]} teamdrives")
|
myarg, f"gam {['show', 'print'][csvFormat]} shareddrives")
|
||||||
tds = []
|
tds = []
|
||||||
titles = []
|
titles = []
|
||||||
|
if get_orgunits and useDomainAdminAccess:
|
||||||
|
ou_map = gapi_directory_orgunits.orgid_to_org_map()
|
||||||
for user in users:
|
for user in users:
|
||||||
sys.stderr.write(f'Getting Team Drives for {user}\n')
|
sys.stderr.write(f'Getting Shared Drives for {user}\n')
|
||||||
user, drive = buildDrive3GAPIObject(user)
|
user, drive = buildDrive3GAPIObject(user)
|
||||||
if not drive:
|
if not drive:
|
||||||
continue
|
continue
|
||||||
@@ -8180,12 +8208,16 @@ def printShowTeamDrives(users, csvFormat):
|
|||||||
continue
|
continue
|
||||||
for td in results:
|
for td in results:
|
||||||
td = utils.flatten_json(td)
|
td = utils.flatten_json(td)
|
||||||
|
if get_orgunits and useDomainAdminAccess:
|
||||||
|
td_ouid = td.get('orgUnitId')
|
||||||
|
if td_ouid:
|
||||||
|
td['orgUnit'] = ou_map.get(f'id:{td_ouid}', 'Unknown')
|
||||||
for key in td:
|
for key in td:
|
||||||
if key not in titles:
|
if key not in titles:
|
||||||
titles.append(key)
|
titles.append(key)
|
||||||
tds.append(td)
|
tds.append(td)
|
||||||
if csvFormat:
|
if csvFormat:
|
||||||
display.write_csv_file(tds, titles, 'Team Drives', todrive)
|
display.write_csv_file(tds, titles, 'Shared Drives', todrive)
|
||||||
else:
|
else:
|
||||||
for td in tds:
|
for td in tds:
|
||||||
name = td.pop('name')
|
name = td.pop('name')
|
||||||
@@ -8195,17 +8227,38 @@ def printShowTeamDrives(users, csvFormat):
|
|||||||
print()
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def doDeleteSharedDrive(users):
|
||||||
def doDeleteTeamDrive(users):
|
_, driveId = getSharedDriveId(5)
|
||||||
teamDriveId = sys.argv[5]
|
allowItemDeletion = False
|
||||||
|
useDomainAdminAccess = False
|
||||||
|
i = 6
|
||||||
|
if driveId.lower().startswith('name'):
|
||||||
|
driveId = gapi_drive_drives.drive_name_to_id(sys.argv[i])
|
||||||
|
i += 1
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].lower().replace('_', '')
|
||||||
|
if myarg in ['nukefromorbit', 'allowitemdeletion']:
|
||||||
|
print("I say we take off and nuke the entire site from orbit. It's the only way to be sure...")
|
||||||
|
print('(deleting the shared drive and all files on it...)')
|
||||||
|
allowItemDeletion = True
|
||||||
|
useDomainAdminAccess = True
|
||||||
|
i += 1
|
||||||
|
elif myarg == 'asadmin':
|
||||||
|
useDomainAdminAccess = True
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(
|
||||||
|
myarg, 'gam delete shareddrive')
|
||||||
for user in users:
|
for user in users:
|
||||||
user, drive = buildDrive3GAPIObject(user)
|
user, drive = buildDrive3GAPIObject(user)
|
||||||
if not drive:
|
if not drive:
|
||||||
continue
|
continue
|
||||||
print(f'Deleting Team Drive {teamDriveId}')
|
print(f'Deleting Shared Drive {driveId}')
|
||||||
gapi.call(drive.drives(),
|
gapi.call(drive.drives(),
|
||||||
'delete',
|
'delete',
|
||||||
driveId=teamDriveId,
|
driveId=driveId,
|
||||||
|
allowItemDeletion=allowItemDeletion,
|
||||||
|
useDomainAdminAccess=useDomainAdminAccess,
|
||||||
soft_errors=True)
|
soft_errors=True)
|
||||||
|
|
||||||
|
|
||||||
@@ -8994,8 +9047,9 @@ def doGetUserInfo(user_email=None):
|
|||||||
if isinstance(user['customSchemas'][schema][field], list):
|
if isinstance(user['customSchemas'][schema][field], list):
|
||||||
print(f' {field}:')
|
print(f' {field}:')
|
||||||
for an_item in user['customSchemas'][schema][field]:
|
for an_item in user['customSchemas'][schema][field]:
|
||||||
print(f' type: {an_item["type"]}')
|
an_type = an_item.get('type', 'work')
|
||||||
if an_item['type'] == 'custom':
|
print(f' type: {an_type}')
|
||||||
|
if an_type == 'custom':
|
||||||
print(
|
print(
|
||||||
f' customType: {an_item["customType"]}')
|
f' customType: {an_item["customType"]}')
|
||||||
print(f' value: {an_item["value"]}')
|
print(f' value: {an_item["value"]}')
|
||||||
@@ -10453,6 +10507,11 @@ OAUTH2_SCOPES = [
|
|||||||
'subscopes': ['readonly'],
|
'subscopes': ['readonly'],
|
||||||
'scopes': 'https://www.googleapis.com/auth/cloud-identity.groups'
|
'scopes': 'https://www.googleapis.com/auth/cloud-identity.groups'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'name': 'Cloud Identity - OrgUnits',
|
||||||
|
'subscopes': ['readonly'],
|
||||||
|
'scopes': 'https://www.googleapis.com/auth/cloud-identity.orgunits',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
'name': 'Cloud Identity - User Invitations',
|
'name': 'Cloud Identity - User Invitations',
|
||||||
'subscopes': ['readonly'],
|
'subscopes': ['readonly'],
|
||||||
@@ -11374,6 +11433,8 @@ def ProcessGAMCommand(args):
|
|||||||
gapi_directory_printers.create()
|
gapi_directory_printers.create()
|
||||||
elif argument in ['chatmessage']:
|
elif argument in ['chatmessage']:
|
||||||
gapi_chat.create_message()
|
gapi_chat.create_message()
|
||||||
|
elif argument in ['caalevel']:
|
||||||
|
gapi_caa.create_access_level()
|
||||||
else:
|
else:
|
||||||
controlflow.invalid_argument_exit(argument, 'gam create')
|
controlflow.invalid_argument_exit(argument, 'gam create')
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
@@ -11438,6 +11499,8 @@ def ProcessGAMCommand(args):
|
|||||||
gapi_directory_printers.update()
|
gapi_directory_printers.update()
|
||||||
elif argument in ['chatmessage']:
|
elif argument in ['chatmessage']:
|
||||||
gapi_chat.update_message()
|
gapi_chat.update_message()
|
||||||
|
elif argument in ['caalevel']:
|
||||||
|
gapi_caa.update_access_level()
|
||||||
else:
|
else:
|
||||||
controlflow.invalid_argument_exit(argument, 'gam update')
|
controlflow.invalid_argument_exit(argument, 'gam update')
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
@@ -11578,6 +11641,8 @@ def ProcessGAMCommand(args):
|
|||||||
gapi_chromepolicy.delete_policy()
|
gapi_chromepolicy.delete_policy()
|
||||||
elif argument == 'chatmessage':
|
elif argument == 'chatmessage':
|
||||||
gapi_chat.delete_message()
|
gapi_chat.delete_message()
|
||||||
|
elif argument == 'caalevel':
|
||||||
|
gapi_caa.delete_access_level()
|
||||||
else:
|
else:
|
||||||
controlflow.invalid_argument_exit(argument, 'gam delete')
|
controlflow.invalid_argument_exit(argument, 'gam delete')
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
@@ -11699,6 +11764,10 @@ def ProcessGAMCommand(args):
|
|||||||
gapi_chat.print_spaces()
|
gapi_chat.print_spaces()
|
||||||
elif argument in ['chatmembers']:
|
elif argument in ['chatmembers']:
|
||||||
gapi_chat.print_members()
|
gapi_chat.print_members()
|
||||||
|
elif argument in ['caalevels']:
|
||||||
|
gapi_caa.printshow_access_levels(True)
|
||||||
|
elif argument in ['oushareddrives', 'orgunitshareddrives']:
|
||||||
|
gapi_cloudidentity_orgunits.printshow_orgunit_shared_drives(True)
|
||||||
else:
|
else:
|
||||||
controlflow.invalid_argument_exit(argument, 'gam print')
|
controlflow.invalid_argument_exit(argument, 'gam print')
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
@@ -11729,6 +11798,10 @@ def ProcessGAMCommand(args):
|
|||||||
gapi_chromepolicy.printshow_policies()
|
gapi_chromepolicy.printshow_policies()
|
||||||
elif argument == 'crostelemetry':
|
elif argument == 'crostelemetry':
|
||||||
gapi_chromemanagement.printShowCrosTelemetry('show')
|
gapi_chromemanagement.printShowCrosTelemetry('show')
|
||||||
|
elif argument in ['caalevels']:
|
||||||
|
gapi_caa.printshow_access_levels(False)
|
||||||
|
elif argument in ['oushareddrives', 'orgunitshareddrives']:
|
||||||
|
gapi_cloudidentity_orgunits.printshow_orgunit_shared_drives(False)
|
||||||
else:
|
else:
|
||||||
controlflow.invalid_argument_exit(argument, 'gam show')
|
controlflow.invalid_argument_exit(argument, 'gam show')
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
@@ -11887,8 +11960,8 @@ def ProcessGAMCommand(args):
|
|||||||
gapi_calendar.showCalSettings(users)
|
gapi_calendar.showCalSettings(users)
|
||||||
elif showWhat == 'drivesettings':
|
elif showWhat == 'drivesettings':
|
||||||
printDriveSettings(users)
|
printDriveSettings(users)
|
||||||
elif showWhat == 'teamdrivethemes':
|
elif showWhat in ['teamdrivethemes', 'shareddrivethemes']:
|
||||||
getTeamDriveThemes(users)
|
getSharedDriveThemes(users)
|
||||||
elif showWhat == 'drivefileacl':
|
elif showWhat == 'drivefileacl':
|
||||||
showDriveFileACL(users)
|
showDriveFileACL(users)
|
||||||
elif showWhat == 'filelist':
|
elif showWhat == 'filelist':
|
||||||
@@ -11931,10 +12004,10 @@ def ProcessGAMCommand(args):
|
|||||||
printShowFilters(users, False)
|
printShowFilters(users, False)
|
||||||
elif showWhat in ['forwardingaddress', 'forwardingaddresses']:
|
elif showWhat in ['forwardingaddress', 'forwardingaddresses']:
|
||||||
printShowForwardingAddresses(users, False)
|
printShowForwardingAddresses(users, False)
|
||||||
elif showWhat in ['teamdrive', 'teamdrives']:
|
elif showWhat in shared_drive_values:
|
||||||
printShowTeamDrives(users, False)
|
printShowSharedDrives(users, False)
|
||||||
elif showWhat in ['teamdriveinfo']:
|
elif showWhat in ['shareddriveinfo', 'teamdriveinfo']:
|
||||||
doGetTeamDriveInfo(users)
|
doGetSharedDriveInfo(users)
|
||||||
elif showWhat in ['contactdelegate', 'contactdelegates']:
|
elif showWhat in ['contactdelegate', 'contactdelegates']:
|
||||||
gapi_contactdelegation.print_(users, False)
|
gapi_contactdelegation.print_(users, False)
|
||||||
elif showWhat in ['holds', 'vaultholds']:
|
elif showWhat in ['holds', 'vaultholds']:
|
||||||
@@ -11965,8 +12038,8 @@ def ProcessGAMCommand(args):
|
|||||||
printShowSmime(users, True)
|
printShowSmime(users, True)
|
||||||
elif printWhat in ['token', 'tokens', 'oauth', '3lo']:
|
elif printWhat in ['token', 'tokens', 'oauth', '3lo']:
|
||||||
printShowTokens(5, 'users', users, True)
|
printShowTokens(5, 'users', users, True)
|
||||||
elif printWhat in ['teamdrive', 'teamdrives']:
|
elif printWhat in shared_drive_values:
|
||||||
printShowTeamDrives(users, True)
|
printShowSharedDrives(users, True)
|
||||||
elif printWhat in ['contactdelegate', 'contactdelegates']:
|
elif printWhat in ['contactdelegate', 'contactdelegates']:
|
||||||
gapi_contactdelegation.print_(users, True)
|
gapi_contactdelegation.print_(users, True)
|
||||||
elif printWhat in ['labels']:
|
elif printWhat in ['labels']:
|
||||||
@@ -12049,8 +12122,8 @@ def ProcessGAMCommand(args):
|
|||||||
deleteSendAs(users)
|
deleteSendAs(users)
|
||||||
elif delWhat == 'smime':
|
elif delWhat == 'smime':
|
||||||
deleteSmime(users)
|
deleteSmime(users)
|
||||||
elif delWhat == 'teamdrive':
|
elif delWhat in shared_drive_values:
|
||||||
doDeleteTeamDrive(users)
|
doDeleteSharedDrive(users)
|
||||||
elif delWhat == 'contactdelegate':
|
elif delWhat == 'contactdelegate':
|
||||||
gapi_contactdelegation.delete(users)
|
gapi_contactdelegation.delete(users)
|
||||||
else:
|
else:
|
||||||
@@ -12083,8 +12156,8 @@ def ProcessGAMCommand(args):
|
|||||||
addUpdateSendAs(users, 5, True)
|
addUpdateSendAs(users, 5, True)
|
||||||
elif addWhat == 'smime':
|
elif addWhat == 'smime':
|
||||||
addSmime(users)
|
addSmime(users)
|
||||||
elif addWhat == 'teamdrive':
|
elif addWhat in shared_drive_values:
|
||||||
doCreateTeamDrive(users)
|
doCreateSharedDrive(users)
|
||||||
elif addWhat == 'contactdelegate':
|
elif addWhat == 'contactdelegate':
|
||||||
gapi_contactdelegation.create(users)
|
gapi_contactdelegation.create(users)
|
||||||
else:
|
else:
|
||||||
@@ -12125,8 +12198,8 @@ def ProcessGAMCommand(args):
|
|||||||
addUpdateSendAs(users, 5, False)
|
addUpdateSendAs(users, 5, False)
|
||||||
elif updateWhat == 'smime':
|
elif updateWhat == 'smime':
|
||||||
updateSmime(users)
|
updateSmime(users)
|
||||||
elif updateWhat == 'teamdrive':
|
elif updateWhat in shared_drive_values:
|
||||||
doUpdateTeamDrive(users)
|
doUpdateSharedDrive(users)
|
||||||
else:
|
else:
|
||||||
controlflow.invalid_argument_exit(updateWhat,
|
controlflow.invalid_argument_exit(updateWhat,
|
||||||
'gam <users> update')
|
'gam <users> update')
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"""GAM is a command line tool which allows Administrators to control their Google Workspace domain and accounts.
|
"""GAM is a command line tool which allows Administrators to control their Google Workspace domain and accounts.
|
||||||
|
|
||||||
With GAM you can programmatically create users, turn on/off services for users like POP and Forwarding and much more.
|
With GAM you can programmatically create users, turn on/off services for users like POP and Forwarding and much more.
|
||||||
For more information, see https://git.io/gam
|
For more information, see https://jaylee.us/gam
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|||||||
274
src/gam/gapi/caa.py
Normal file
274
src/gam/gapi/caa.py
Normal file
@@ -0,0 +1,274 @@
|
|||||||
|
import string
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import googleapiclient.errors
|
||||||
|
|
||||||
|
import gam
|
||||||
|
from gam.var import *
|
||||||
|
from gam import controlflow
|
||||||
|
from gam import display
|
||||||
|
from gam import gapi
|
||||||
|
from gam import utils
|
||||||
|
from gam.gapi import errors as gapi_errors
|
||||||
|
from gam.gapi import cloudresourcemanager as gapi_crm
|
||||||
|
|
||||||
|
|
||||||
|
THROW_REASONS = [gapi_errors.ErrorReason.FOUR_O_THREE]
|
||||||
|
|
||||||
|
def _gen_role_error(caa):
|
||||||
|
sa_email = caa._http.credentials.signer_email
|
||||||
|
role_error = f'Please grant service account {sa_email} the Access Context Manager Editor role to your GCP organization.'
|
||||||
|
controlflow.system_error_exit(2, role_error)
|
||||||
|
|
||||||
|
|
||||||
|
def build():
|
||||||
|
return gam.buildGAPIServiceObject('accesscontextmanager',
|
||||||
|
act_as=None)
|
||||||
|
|
||||||
|
|
||||||
|
def get_access_policy(caa=None):
|
||||||
|
if not caa:
|
||||||
|
caa = build()
|
||||||
|
parent = gapi_crm.get_org_id()
|
||||||
|
if not parent:
|
||||||
|
_gen_role_error(caa)
|
||||||
|
try:
|
||||||
|
aps = gapi.get_all_pages(caa.accessPolicies(),
|
||||||
|
'list',
|
||||||
|
'accessPolicies',
|
||||||
|
throw_reasons=THROW_REASONS,
|
||||||
|
parent=parent,
|
||||||
|
fields='accessPolicies(name,title)')
|
||||||
|
except googleapiclient.errors.HttpError:
|
||||||
|
_gen_role_error(caa)
|
||||||
|
if not aps:
|
||||||
|
controlflow.system_error_exit(2, 'You don\'t seem to have any access policies. That is odd.')
|
||||||
|
elif len(aps) == 1:
|
||||||
|
return aps[0]['name']
|
||||||
|
for ap in aps:
|
||||||
|
if ap.get('title') == 'Access policy created in Cloud Identity Console':
|
||||||
|
return ap['name']
|
||||||
|
controlflow.system_error_exit(2, ' Could not find a org level access policy. That is odd.')
|
||||||
|
|
||||||
|
|
||||||
|
def printshow_access_levels(csvFormat):
|
||||||
|
caa = build()
|
||||||
|
ap_name = get_access_policy(caa)
|
||||||
|
if csvFormat:
|
||||||
|
todrive = False
|
||||||
|
csvRows = []
|
||||||
|
titles = ['name', 'title']
|
||||||
|
i = 3
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].lower()
|
||||||
|
if csvFormat and myarg == 'todrive':
|
||||||
|
todrive = True
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(sys.argv[i],
|
||||||
|
f"gam {['show', 'print'][csvFormat]} caalevels")
|
||||||
|
try:
|
||||||
|
levels = gapi.get_all_pages(caa.accessPolicies().accessLevels(),
|
||||||
|
'list',
|
||||||
|
'accessLevels',
|
||||||
|
throw_reasons=THROW_REASONS,
|
||||||
|
parent=ap_name,
|
||||||
|
accessLevelFormat='CEL', fields='*')
|
||||||
|
except googleapiclient.errors.HttpError:
|
||||||
|
_gen_role_error(caa)
|
||||||
|
if not csvFormat:
|
||||||
|
for level in levels:
|
||||||
|
display.print_json(level)
|
||||||
|
print()
|
||||||
|
else:
|
||||||
|
for level in levels:
|
||||||
|
display.add_row_titles_to_csv_file(
|
||||||
|
utils.flatten_json(level),
|
||||||
|
csvRows, titles)
|
||||||
|
display.write_csv_file(csvRows, titles, 'CAA Levels', todrive)
|
||||||
|
|
||||||
|
|
||||||
|
def build_os_constraints(constraints):
|
||||||
|
consts_obj = []
|
||||||
|
constraints = constraints.upper().split(',')
|
||||||
|
valid_os_types = ['DESKTOP_MAC', 'DESKTOP_WINDOWS', 'DESKTOP_LINUX',
|
||||||
|
'DESKTOP_CHROME_OS', 'VERIFIED_DESKTOP_CHROME_OS', 'ANDROID', 'IOS']
|
||||||
|
for constraint in constraints:
|
||||||
|
new_const = {}
|
||||||
|
if ':' in constraint:
|
||||||
|
new_const['osType'], new_const['minimumVersion'] = constraint.split(':')
|
||||||
|
else:
|
||||||
|
new_const['osType'] = constraint
|
||||||
|
if new_const['osType'] not in valid_os_types:
|
||||||
|
controlflow.system_error_exit(2, f'expected os type of {", ".join(valid_os_types)} got {new_const["osType"]}')
|
||||||
|
if new_const['osType'] == 'VERIFIED_DESKTOP_CHROME_OS':
|
||||||
|
new_const['osType'] = 'DESKTOP_CHROME_OS'
|
||||||
|
new_const['requireVerifiedChromeOs'] = True
|
||||||
|
consts_obj.append(new_const)
|
||||||
|
return consts_obj
|
||||||
|
|
||||||
|
|
||||||
|
def build_device_policy(i, schemas):
|
||||||
|
device_policy = {}
|
||||||
|
while True:
|
||||||
|
myarg = sys.argv[i].replace('_', '').lower()
|
||||||
|
if myarg == 'requirescreenlock':
|
||||||
|
device_policy['requireScreenLock'] = gam.getBoolean(sys.argv[i+1], myarg)
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'allowedencryptionstatuses':
|
||||||
|
allowed_statuses = gapi.get_enum_values_minus_unspecified(schemas["DevicePolicy"]["properties"]["allowedEncryptionStatuses"]["items"]["enum"])
|
||||||
|
device_policy['allowedEncryptionStatuses'] = sys.argv[i+1].upper().split(',')
|
||||||
|
for status in device_policy['allowedEncryptionStatuses']:
|
||||||
|
if status not in allowed_statuses:
|
||||||
|
controlflow.system_error_exit(2, f'expected encryption status of {", ".join(allowed_statuses)} got {status}')
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'osconstraints':
|
||||||
|
device_policy['osConstraints'] = build_os_constraints(sys.argv[i+1])
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'alloweddevicemanagementlevels':
|
||||||
|
allowed_levels = gapi.get_enum_values_minus_unspecified(schemas["DevicePolicy"]["properties"]["allowedDeviceManagementLevels"]["items"]["enum"])
|
||||||
|
device_policy['allowedDeviceManagementLevels'] = sys.argv[i+1].upper().split(',')
|
||||||
|
for level in device_policy['allowedDeviceManagementLevels']:
|
||||||
|
if level == 'ADVANCED':
|
||||||
|
level = 'COMPLETE'
|
||||||
|
if level not in allowed_levels:
|
||||||
|
controlflow.system_error_exit(2, f'expected device management level of {", ".join(allowed_levels)} got {level}')
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'requireadminapproval':
|
||||||
|
device_policy['requireAdminApproval'] = gam.getBoolean(sys.argv[i+1], myarg)
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'requirecorpowned':
|
||||||
|
device_policy['requireCorpOwned'] = gam.getBoolean(sys.argv[i+1], myarg)
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'enddevicepolicy':
|
||||||
|
i += 1
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(myarg, 'gam create/update caalevel')
|
||||||
|
return i, device_policy
|
||||||
|
|
||||||
|
|
||||||
|
def build_condition(i, schemas):
|
||||||
|
condition = {}
|
||||||
|
while True:
|
||||||
|
myarg = sys.argv[i].replace('_', '').lower()
|
||||||
|
if myarg == 'ipsubnetworks':
|
||||||
|
condition['ipSubnetworks'] = sys.argv[i+1].split(',')
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'devicepolicy':
|
||||||
|
i += 1
|
||||||
|
i, condition['devicePolicy'] = build_device_policy(i, schemas)
|
||||||
|
elif myarg == 'requiredaccesslevels':
|
||||||
|
condition['requiredAccessLevels'] = sys.argv[i+1].split(',')
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'negate':
|
||||||
|
condition['negate'] = gam.getBoolean(sys.argv[i+1], myarg)
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'members':
|
||||||
|
condition['members'] = sys.argv[i+1].split(',')
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'regions':
|
||||||
|
condition['regions'] = sys.argv[i+1].upper().split(',')
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'endcondition':
|
||||||
|
i += 1
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(myarg, 'gam create/update caalevel')
|
||||||
|
return i, condition
|
||||||
|
|
||||||
|
|
||||||
|
def build_basic_level(i, schemas):
|
||||||
|
basic_level = {'conditions': []}
|
||||||
|
valid_functions = gapi.get_enum_values_minus_unspecified(schemas['BasicLevel']['properties']['combiningFunction']['enum'])
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].replace('_', '').lower()
|
||||||
|
if myarg == 'combiningfunction':
|
||||||
|
combiningFunction = sys.argv[i+1].upper()
|
||||||
|
if combiningFunction not in valid_functions:
|
||||||
|
controlflow.system_error_exit(2, f'expected combining function of {",".join(valid_functions)} got {combiningFunction}')
|
||||||
|
basic_level['combiningFunction'] = combiningFunction
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'condition':
|
||||||
|
i += 1
|
||||||
|
i, condition = build_condition(i, schemas)
|
||||||
|
basic_level['conditions'].append(condition)
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(myarg, 'gam create/update caalevel')
|
||||||
|
return i, basic_level
|
||||||
|
|
||||||
|
|
||||||
|
def build_caa_level(i, caa, body):
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].lower().replace('_', '')
|
||||||
|
if myarg == 'basic':
|
||||||
|
schemas = caa._rootDesc['schemas']
|
||||||
|
i += 1
|
||||||
|
i, body['basic'] = build_basic_level(i, schemas)
|
||||||
|
elif myarg == 'custom':
|
||||||
|
body['custom'] = {'expr': {'expression': sys.argv[i+1], 'title': 'expr'}}
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'description':
|
||||||
|
body['description'] = sys.argv[i+1]
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(myarg, 'gam create/update caalevel')
|
||||||
|
|
||||||
|
|
||||||
|
def create_access_level():
|
||||||
|
caa = build()
|
||||||
|
ap_name = get_access_policy(caa)
|
||||||
|
title = sys.argv[3].replace(' ', '_')
|
||||||
|
allowed_title_chars = string.ascii_letters + string.digits + '_'
|
||||||
|
name = ''.join([c for c in title if c in allowed_title_chars])[:50]
|
||||||
|
name = f'{ap_name}/accessLevels/{name}'
|
||||||
|
body = {
|
||||||
|
'name': name,
|
||||||
|
'title': title,
|
||||||
|
}
|
||||||
|
build_caa_level(4, caa, body)
|
||||||
|
print(f'Creating access level {name}...')
|
||||||
|
try:
|
||||||
|
gapi.call(caa.accessPolicies().accessLevels(),
|
||||||
|
'create',
|
||||||
|
throw_reasons=THROW_REASONS,
|
||||||
|
parent=ap_name,
|
||||||
|
body=body)
|
||||||
|
except googleapiclient.errors.HttpError:
|
||||||
|
_gen_role_error(caa)
|
||||||
|
|
||||||
|
def get_access_level_name(i, caa):
|
||||||
|
name = sys.argv[i]
|
||||||
|
if not name.startswith('accessPolicies/'):
|
||||||
|
ap_name = get_access_policy(caa)
|
||||||
|
name = f'{ap_name}/accessLevels/{name}'
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
def update_access_level():
|
||||||
|
caa = build()
|
||||||
|
name = get_access_level_name(3, caa)
|
||||||
|
body = {}
|
||||||
|
build_caa_level(4, caa, body)
|
||||||
|
updateMask = ','.join(body.keys())
|
||||||
|
print(f'Updating access level {name}...')
|
||||||
|
try:
|
||||||
|
gapi.call(caa.accessPolicies().accessLevels(),
|
||||||
|
'patch',
|
||||||
|
throw_reasons=THROW_REASONS,
|
||||||
|
name=name,
|
||||||
|
updateMask=updateMask,
|
||||||
|
body=body)
|
||||||
|
except googleapiclient.errors.HttpError:
|
||||||
|
_gen_role_error(caa)
|
||||||
|
|
||||||
|
def delete_access_level():
|
||||||
|
caa = build()
|
||||||
|
name = get_access_level_name(3, caa)
|
||||||
|
print(f'Deleting access level {name}...')
|
||||||
|
try:
|
||||||
|
gapi.call(caa.accessPolicies().accessLevels(),
|
||||||
|
'delete',
|
||||||
|
name=name)
|
||||||
|
except googleapiclient.errors.HttpError:
|
||||||
|
_gen_role_error(caa)
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
import gam
|
import gam
|
||||||
|
from gam.var import GC_Values, GC_ENABLE_DASA
|
||||||
|
|
||||||
def build(api='cloudidentity'):
|
def build(api='cloudidentity'):
|
||||||
return gam.buildGAPIObject(api)
|
return gam.buildGAPIObject(api)
|
||||||
|
|
||||||
def build_dwd(api='cloudidentity'):
|
def build_dwd(api='cloudidentity'):
|
||||||
|
# If we are using DASA we don't need to use DwD.
|
||||||
|
if GC_Values[GC_ENABLE_DASA]:
|
||||||
|
return gam.buildGAPIObject(api)
|
||||||
admin = gam._get_admin_email()
|
admin = gam._get_admin_email()
|
||||||
return gam.buildGAPIServiceObject(api, admin, True)
|
return gam.buildGAPIServiceObject(api, admin, True)
|
||||||
|
|||||||
@@ -253,6 +253,13 @@ def update_state():
|
|||||||
|
|
||||||
|
|
||||||
def print_():
|
def print_():
|
||||||
|
# This function is rather messy thanks to
|
||||||
|
# https://github.com/GAM-team/GAM/issues/1534
|
||||||
|
# I'd prefer to keep it all in this function for now but if:
|
||||||
|
# - we find other list() operations that also hit this bug OR
|
||||||
|
# - it looks like this issue is going to exist on Google's side
|
||||||
|
# for a long time.
|
||||||
|
# I'll enterain some cleanup here to "functionalize" (yuck) all of this.
|
||||||
ci = gapi_cloudidentity.build_dwd()
|
ci = gapi_cloudidentity.build_dwd()
|
||||||
customer = _get_device_customerid()
|
customer = _get_device_customerid()
|
||||||
parent = 'devices/-'
|
parent = 'devices/-'
|
||||||
@@ -260,6 +267,8 @@ def print_():
|
|||||||
get_device_users = True
|
get_device_users = True
|
||||||
view = None
|
view = None
|
||||||
orderByList = []
|
orderByList = []
|
||||||
|
# default sort order needed by our 1 hour bug workaround
|
||||||
|
orderBy = 'create_time'
|
||||||
titles = []
|
titles = []
|
||||||
csvRows = []
|
csvRows = []
|
||||||
todrive = False
|
todrive = False
|
||||||
@@ -319,26 +328,97 @@ def print_():
|
|||||||
}
|
}
|
||||||
if orderByList:
|
if orderByList:
|
||||||
orderBy = ','.join(orderByList)
|
orderBy = ','.join(orderByList)
|
||||||
else:
|
custom_device_filter = bool(device_filter)
|
||||||
orderBy = None
|
# we store the devices in a dict keyed by name which is a unique ID.
|
||||||
devices = []
|
# that way when we get duplicate devices we just overwrite the name
|
||||||
|
# with the latest copy we saw.
|
||||||
|
devices = {}
|
||||||
page_message = gapi.got_total_items_msg(view_name_map[view], '...\n')
|
page_message = gapi.got_total_items_msg(view_name_map[view], '...\n')
|
||||||
devices += gapi.get_all_pages(ci.devices(), 'list', 'devices',
|
pageToken = None
|
||||||
customer=customer, page_message=page_message,
|
newest_device_date = ''
|
||||||
pageSize=100, filter=device_filter, view=view, orderBy=orderBy)
|
total_items = 0
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
a_page = gapi.call(ci.devices(),
|
||||||
|
'list',
|
||||||
|
customer=customer,
|
||||||
|
pageSize=100,
|
||||||
|
pageToken=pageToken,
|
||||||
|
filter=device_filter,
|
||||||
|
view=view,
|
||||||
|
orderBy=orderBy,
|
||||||
|
throw_reasons=[gapi_errors.ErrorReason.FOUR_O_O])
|
||||||
|
except googleapiclient.errors.HttpError:
|
||||||
|
sys.stderr.write('WARNING: GAM hit Google internal bug 237397223. Please file a Google Support ticket stating that you are encountering this bug.\n')
|
||||||
|
if orderBy != 'create_time' or custom_device_filter:
|
||||||
|
controlflow.system_error_exit(5, 'GAM workaround for this issue only works if filter and orderby arguments are not used.\n')
|
||||||
|
sys.stderr.write(f' attempting to work around the bug by filtering for devices created on or after the newest we\'ve seen ({newest_device_date})...')
|
||||||
|
device_filter = f'register:{newest_device_date}..'
|
||||||
|
pageToken = None
|
||||||
|
continue
|
||||||
|
for dev in a_page.get('devices', []):
|
||||||
|
total_items += 1
|
||||||
|
devices[dev['name']] = dev
|
||||||
|
dev_date = dev.get('createTime', '')
|
||||||
|
# remove the Z
|
||||||
|
dev_date = dev_date[:-1]
|
||||||
|
# remove microseconds
|
||||||
|
dev_date = dev_date.split('.')[0]
|
||||||
|
if dev_date > newest_device_date:
|
||||||
|
newest_device_date = dev_date
|
||||||
|
pageToken = a_page.get('nextPageToken')
|
||||||
|
if not pageToken:
|
||||||
|
break
|
||||||
|
sys.stderr.write(page_message.replace('%%total_items%%', str(total_items)))
|
||||||
if get_device_users:
|
if get_device_users:
|
||||||
page_message = gapi.got_total_items_msg('Device Users', '...\n')
|
page_message = gapi.got_total_items_msg('Device Users', '...\n')
|
||||||
device_users = gapi.get_all_pages(ci.devices().deviceUsers(), 'list',
|
pageToken = None
|
||||||
'deviceUsers', customer=customer, parent=parent,
|
newest_deviceuser_date = ''
|
||||||
page_message=page_message, pageSize=20, filter=device_filter)
|
total_items = 0
|
||||||
for device_user in device_users:
|
device_users = {}
|
||||||
for device in devices:
|
if not custom_device_filter:
|
||||||
if device_user.get('name').startswith(device.get('name')):
|
device_filter = None
|
||||||
if 'users' not in device:
|
while True:
|
||||||
device['users'] = []
|
try:
|
||||||
device['users'].append(device_user)
|
a_page = gapi.call(ci.devices().deviceUsers(),
|
||||||
|
'list',
|
||||||
|
customer=customer,
|
||||||
|
parent=parent,
|
||||||
|
pageSize=20,
|
||||||
|
orderBy=orderBy,
|
||||||
|
filter=device_filter,
|
||||||
|
pageToken=pageToken,
|
||||||
|
throw_reasons=[gapi_errors.ErrorReason.FOUR_O_O])
|
||||||
|
except googleapiclient.errors.HttpError:
|
||||||
|
sys.stderr.write('WARNING: GAM hit Google internal bug 237397223. Please file a Google Support ticket stating that you are encountering this bug.\n')
|
||||||
|
if orderBy != 'create_time' or custom_device_filter:
|
||||||
|
controlflow.system_error_exit(5, 'GAM workaround for this issue only works if filter and orderby arguments are not used.\n')
|
||||||
|
sys.stderr.write(f' attempting to work around the bug by filtering for device users created on or after the newest we\'ve seen ({newest_deviceuser_date})...')
|
||||||
|
device_filter = f'register:{newest_deviceuser_date}..'
|
||||||
|
pageToken = None
|
||||||
|
continue
|
||||||
|
for device_user in a_page.get('deviceUsers', []):
|
||||||
|
total_items += 1
|
||||||
|
dev_date = device_user.get('createTime', '')
|
||||||
|
# remove the Z
|
||||||
|
dev_date = dev_date[:-1]
|
||||||
|
# remove microseconds
|
||||||
|
dev_date = dev_date.split('.')[0]
|
||||||
|
if dev_date > newest_deviceuser_date:
|
||||||
|
newest_deviceuser_date = dev_date
|
||||||
|
deviceuser_name = device_user['name']
|
||||||
|
device_users[deviceuser_name] = device_user
|
||||||
|
pageToken = a_page.get('nextPageToken')
|
||||||
|
if not pageToken:
|
||||||
break
|
break
|
||||||
for device in devices:
|
sys.stderr.write(page_message.replace('%%total_items%%', str(total_items)))
|
||||||
|
for deviceuser_name, device_user in device_users.items():
|
||||||
|
device_id = deviceuser_name.split('/')[1]
|
||||||
|
device_name = f'devices/{device_id}'
|
||||||
|
if 'users' not in devices[device_name]:
|
||||||
|
devices[device_name]['users'] = []
|
||||||
|
devices[device_name]['users'].append(device_user)
|
||||||
|
for device in devices.values():
|
||||||
device = utils.flatten_json(device)
|
device = utils.flatten_json(device)
|
||||||
for a_key in device:
|
for a_key in device:
|
||||||
if a_key not in titles:
|
if a_key not in titles:
|
||||||
|
|||||||
@@ -866,6 +866,13 @@ def update():
|
|||||||
'cloudidentity.googleapis.com/groups.discussion_forum': ''
|
'cloudidentity.googleapis.com/groups.discussion_forum': ''
|
||||||
}
|
}
|
||||||
i += 1
|
i += 1
|
||||||
|
elif myarg == 'dynamicsecurity':
|
||||||
|
body['labels'] = {
|
||||||
|
'cloudidentity.googleapis.com/groups.dynamic': '',
|
||||||
|
'cloudidentity.googleapis.com/groups.security': '',
|
||||||
|
'cloudidentity.googleapis.com/groups.discussion_forum': ''
|
||||||
|
}
|
||||||
|
i += 1
|
||||||
elif myarg in ['dynamic']:
|
elif myarg in ['dynamic']:
|
||||||
body['dynamicGroupMetadata'] = {
|
body['dynamicGroupMetadata'] = {
|
||||||
'queries': [{
|
'queries': [{
|
||||||
|
|||||||
72
src/gam/gapi/cloudidentity/orgunits.py
Normal file
72
src/gam/gapi/cloudidentity/orgunits.py
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
import googleapiclient
|
||||||
|
|
||||||
|
import gam
|
||||||
|
from gam.var import * # pylint: disable=unused-wildcard-import
|
||||||
|
from gam import controlflow
|
||||||
|
from gam import display
|
||||||
|
from gam import gapi
|
||||||
|
from gam import utils
|
||||||
|
from gam.gapi import errors as gapi_errors
|
||||||
|
from gam.gapi import cloudidentity as gapi_cloudidentity
|
||||||
|
from gam.gapi.directory import orgunits as gapi_directory_orgunits
|
||||||
|
|
||||||
|
def _get_orgunit_customerid():
|
||||||
|
customer = GC_Values[GC_CUSTOMER_ID]
|
||||||
|
if customer != MY_CUSTOMER and not customer.startswith('C'):
|
||||||
|
customer = f'C{customer}'
|
||||||
|
return f'customers/{customer}'
|
||||||
|
|
||||||
|
def move_shared_drive(driveId, orgUnit):
|
||||||
|
_, orgUnitId = gapi_directory_orgunits.getOrgUnitId(orgUnit)
|
||||||
|
orgUnitId = f'orgUnits/{orgUnitId[3:]}'
|
||||||
|
name = f'orgUnits/-/memberships/shared_drive;{driveId}'
|
||||||
|
ci = gapi_cloudidentity.build('cloudidentity_beta')
|
||||||
|
body = {
|
||||||
|
'customer': _get_orgunit_customerid(),
|
||||||
|
'destinationOrgUnit': orgUnitId,
|
||||||
|
}
|
||||||
|
return gapi.call(ci.orgUnits().memberships(),
|
||||||
|
'move',
|
||||||
|
name=name,
|
||||||
|
body=body)
|
||||||
|
|
||||||
|
def printshow_orgunit_shared_drives(csvFormat):
|
||||||
|
orgunit = '/'
|
||||||
|
if csvFormat:
|
||||||
|
todrive = False
|
||||||
|
csvRows = []
|
||||||
|
titles = ['name']
|
||||||
|
i = 3
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].lower()
|
||||||
|
if csvFormat and myarg == 'todrive':
|
||||||
|
todrive = True
|
||||||
|
i += 1
|
||||||
|
elif myarg in ['ou', 'org', 'orgunit']:
|
||||||
|
orgunit = sys.argv[i + 1]
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(sys.argv[i],
|
||||||
|
f"gam {['show', 'print'][csvFormat]} oushareddrives")
|
||||||
|
ci = gapi_cloudidentity.build('cloudidentity_beta')
|
||||||
|
_, orgUnitId = gapi_directory_orgunits.getOrgUnitId(orgunit)
|
||||||
|
parent = f'orgUnits/{orgUnitId[3:]}'
|
||||||
|
filter_ = "type == 'shared_drive'"
|
||||||
|
sds = gapi.get_all_pages(ci.orgUnits().memberships(),
|
||||||
|
'list',
|
||||||
|
'orgMemberships',
|
||||||
|
parent=parent,
|
||||||
|
customer=_get_orgunit_customerid(),
|
||||||
|
filter=filter_)
|
||||||
|
if not csvFormat:
|
||||||
|
for sd in sds:
|
||||||
|
display.print_json(sd)
|
||||||
|
print()
|
||||||
|
else:
|
||||||
|
for sd in sds:
|
||||||
|
display.add_row_titles_to_csv_file(
|
||||||
|
utils.flatten_json(sd),
|
||||||
|
csvRows, titles)
|
||||||
|
display.write_csv_file(csvRows, titles, f'OrgUnit {orgunit} Shared Drives', todrive)
|
||||||
24
src/gam/gapi/cloudresourcemanager.py
Normal file
24
src/gam/gapi/cloudresourcemanager.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import gam
|
||||||
|
from gam.var import GC_Values, GC_CUSTOMER_ID
|
||||||
|
from gam import controlflow
|
||||||
|
from gam import gapi
|
||||||
|
from gam.gapi.directory import customer as gapi_directory_customer
|
||||||
|
|
||||||
|
def build():
|
||||||
|
return gam.buildGAPIServiceObject('cloudresourcemanager',
|
||||||
|
act_as=None)
|
||||||
|
|
||||||
|
|
||||||
|
def get_org_id():
|
||||||
|
gapi_directory_customer.setTrueCustomerId()
|
||||||
|
crm = build()
|
||||||
|
query = f'directorycustomerid:{GC_Values[GC_CUSTOMER_ID]}'
|
||||||
|
orgs = gapi.get_all_pages(crm.organizations(),
|
||||||
|
'search',
|
||||||
|
'organizations',
|
||||||
|
query=query)
|
||||||
|
if len(orgs) < 1:
|
||||||
|
# return nothing and let calling API deal with it
|
||||||
|
# since caller knows what GCP role would serve best
|
||||||
|
return
|
||||||
|
return orgs[0]['name']
|
||||||
@@ -304,6 +304,8 @@ def doGetCrosInfo():
|
|||||||
if 'autoUpdateExpiration' in cros:
|
if 'autoUpdateExpiration' in cros:
|
||||||
cros['autoUpdateExpiration'] = utils.formatTimestampYMD(
|
cros['autoUpdateExpiration'] = utils.formatTimestampYMD(
|
||||||
cros['autoUpdateExpiration'])
|
cros['autoUpdateExpiration'])
|
||||||
|
if 'orgUnitId' in cros:
|
||||||
|
cros['orgUnitId'] = f"id:{cros['orgUnitId']}"
|
||||||
_checkTPMVulnerability(cros)
|
_checkTPMVulnerability(cros)
|
||||||
for up in CROS_SCALAR_PROPERTY_PRINT_ORDER:
|
for up in CROS_SCALAR_PROPERTY_PRINT_ORDER:
|
||||||
if up in cros:
|
if up in cros:
|
||||||
@@ -739,6 +741,8 @@ def doPrintCrosDevices():
|
|||||||
if 'autoUpdateExpiration' in cros:
|
if 'autoUpdateExpiration' in cros:
|
||||||
cros['autoUpdateExpiration'] = utils.formatTimestampYMD(
|
cros['autoUpdateExpiration'] = utils.formatTimestampYMD(
|
||||||
cros['autoUpdateExpiration'])
|
cros['autoUpdateExpiration'])
|
||||||
|
if 'orgUnitId' in cros:
|
||||||
|
cros['orgUnitId'] = f"id:{cros['orgUnitId']}"
|
||||||
for cpuStatusReport in cros.get('cpuStatusReports', []):
|
for cpuStatusReport in cros.get('cpuStatusReports', []):
|
||||||
tempInfos = cpuStatusReport.get('cpuTemperatureInfo', [])
|
tempInfos = cpuStatusReport.get('cpuTemperatureInfo', [])
|
||||||
for tempInfo in tempInfos:
|
for tempInfo in tempInfos:
|
||||||
@@ -753,6 +757,8 @@ def doPrintCrosDevices():
|
|||||||
if 'autoUpdateExpiration' in cros:
|
if 'autoUpdateExpiration' in cros:
|
||||||
cros['autoUpdateExpiration'] = utils.formatTimestampYMD(
|
cros['autoUpdateExpiration'] = utils.formatTimestampYMD(
|
||||||
cros['autoUpdateExpiration'])
|
cros['autoUpdateExpiration'])
|
||||||
|
if 'orgUnitId' in cros:
|
||||||
|
cros['orgUnitId'] = f"id:{cros['orgUnitId']}"
|
||||||
row = {}
|
row = {}
|
||||||
for attrib in cros:
|
for attrib in cros:
|
||||||
if attrib not in {
|
if attrib not in {
|
||||||
|
|||||||
@@ -160,42 +160,15 @@ def info(name=None, return_attrib=None):
|
|||||||
print('')
|
print('')
|
||||||
|
|
||||||
|
|
||||||
def print_():
|
def list_orgunits(listType='all', orgUnitPath=None, fields=None):
|
||||||
print_order = [
|
|
||||||
'orgUnitPath', 'orgUnitId', 'name', 'description', 'parentOrgUnitPath',
|
|
||||||
'parentOrgUnitId', 'blockInheritance'
|
|
||||||
]
|
|
||||||
cd = gapi_directory.build()
|
|
||||||
listType = 'all'
|
|
||||||
orgUnitPath = '/'
|
|
||||||
todrive = False
|
|
||||||
fields = ['orgUnitPath', 'name', 'orgUnitId', 'parentOrgUnitId']
|
|
||||||
titles = []
|
|
||||||
csvRows = []
|
|
||||||
parentOrgIds = []
|
|
||||||
retrievedOrgIds = []
|
retrievedOrgIds = []
|
||||||
i = 3
|
parentOrgIds = []
|
||||||
while i < len(sys.argv):
|
cd = gapi_directory.build()
|
||||||
myarg = sys.argv[i].lower().replace('_', '')
|
|
||||||
if myarg == 'todrive':
|
|
||||||
todrive = True
|
|
||||||
i += 1
|
|
||||||
elif myarg == 'toplevelonly':
|
|
||||||
listType = 'children'
|
|
||||||
i += 1
|
|
||||||
elif myarg == 'fromparent':
|
|
||||||
orgUnitPath = getOrgUnitItem(sys.argv[i + 1])
|
|
||||||
i += 2
|
|
||||||
elif myarg == 'allfields':
|
|
||||||
fields = None
|
|
||||||
i += 1
|
|
||||||
elif myarg == 'fields':
|
|
||||||
fields += sys.argv[i + 1].split(',')
|
|
||||||
i += 2
|
|
||||||
else:
|
|
||||||
controlflow.invalid_argument_exit(sys.argv[i], 'gam print orgs')
|
|
||||||
gam.printGettingAllItems('Organizational Units', None)
|
|
||||||
if fields:
|
if fields:
|
||||||
|
# Always get parentOrgUnitId so we can
|
||||||
|
# find missing parents
|
||||||
|
if 'parentOrgUnitId' not in fields:
|
||||||
|
fields.append('parentOrgUnitId')
|
||||||
get_fields = ','.join(fields)
|
get_fields = ','.join(fields)
|
||||||
list_fields = f'organizationUnits({get_fields})'
|
list_fields = f'organizationUnits({get_fields})'
|
||||||
else:
|
else:
|
||||||
@@ -230,6 +203,44 @@ def print_():
|
|||||||
orgunits.append(result)
|
orgunits.append(result)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
return orgunits
|
||||||
|
|
||||||
|
|
||||||
|
def print_():
|
||||||
|
print_order = [
|
||||||
|
'orgUnitPath', 'orgUnitId', 'name', 'description', 'parentOrgUnitPath',
|
||||||
|
'parentOrgUnitId', 'blockInheritance'
|
||||||
|
]
|
||||||
|
listType = 'all'
|
||||||
|
orgUnitPath = '/'
|
||||||
|
todrive = False
|
||||||
|
fields = ['orgUnitPath', 'name', 'orgUnitId', 'parentOrgUnitId']
|
||||||
|
titles = []
|
||||||
|
csvRows = []
|
||||||
|
i = 3
|
||||||
|
while i < len(sys.argv):
|
||||||
|
myarg = sys.argv[i].lower().replace('_', '')
|
||||||
|
if myarg == 'todrive':
|
||||||
|
todrive = True
|
||||||
|
i += 1
|
||||||
|
elif myarg == 'toplevelonly':
|
||||||
|
listType = 'children'
|
||||||
|
i += 1
|
||||||
|
elif myarg == 'fromparent':
|
||||||
|
orgUnitPath = getOrgUnitItem(sys.argv[i + 1])
|
||||||
|
i += 2
|
||||||
|
elif myarg == 'allfields':
|
||||||
|
fields = None
|
||||||
|
i += 1
|
||||||
|
elif myarg == 'fields':
|
||||||
|
fields += sys.argv[i + 1].split(',')
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
controlflow.invalid_argument_exit(sys.argv[i], 'gam print orgs')
|
||||||
|
gam.printGettingAllItems('Organizational Units', None)
|
||||||
|
orgunits = list_orgunits(listType=listType,
|
||||||
|
orgUnitPath=orgUnitPath,
|
||||||
|
fields=fields)
|
||||||
for row in orgunits:
|
for row in orgunits:
|
||||||
orgEntity = {}
|
orgEntity = {}
|
||||||
for key, value in list(row.items()):
|
for key, value in list(row.items()):
|
||||||
@@ -248,6 +259,11 @@ def print_():
|
|||||||
display.write_csv_file(csvRows, titles, 'Orgs', todrive)
|
display.write_csv_file(csvRows, titles, 'Orgs', todrive)
|
||||||
|
|
||||||
|
|
||||||
|
def orgid_to_org_map():
|
||||||
|
orgunits = list_orgunits(fields=['orgUnitPath', 'orgUnitId'])
|
||||||
|
result = {ou['orgUnitId']:ou['orgUnitPath'] for ou in orgunits}
|
||||||
|
return result
|
||||||
|
|
||||||
def update():
|
def update():
|
||||||
cd = gapi_directory.build()
|
cd = gapi_directory.build()
|
||||||
orgUnitPath = getOrgUnitItem(sys.argv[3])
|
orgUnitPath = getOrgUnitItem(sys.argv[3])
|
||||||
@@ -357,17 +373,20 @@ def makeOrgUnitPathRelative(path):
|
|||||||
|
|
||||||
|
|
||||||
def encodeOrgUnitPath(path):
|
def encodeOrgUnitPath(path):
|
||||||
if path.find('+') == -1 and path.find('%') == -1:
|
# 6.22 - This method no longer works.
|
||||||
|
# % no longer needs encoding and + is handled incorrectly in API with or without encoding
|
||||||
return path
|
return path
|
||||||
encpath = ''
|
# if path.find('+') == -1 and path.find('%') == -1:
|
||||||
for c in path:
|
# return path
|
||||||
if c == '+':
|
# encpath = ''
|
||||||
encpath += '%2B'
|
# for c in path:
|
||||||
elif c == '%':
|
# if c == '+':
|
||||||
encpath += '%25'
|
# encpath += '%2B'
|
||||||
else:
|
# elif c == '%':
|
||||||
encpath += c
|
# encpath += '%25'
|
||||||
return encpath
|
# else:
|
||||||
|
# encpath += c
|
||||||
|
# return encpath
|
||||||
|
|
||||||
|
|
||||||
def getOrgUnitItem(orgUnit, pathOnly=False, absolutePath=True):
|
def getOrgUnitItem(orgUnit, pathOnly=False, absolutePath=True):
|
||||||
|
|||||||
@@ -227,6 +227,22 @@ def printFeatures():
|
|||||||
display.write_csv_file(csvRows, titles, 'Features', to_drive)
|
display.write_csv_file(csvRows, titles, 'Features', to_drive)
|
||||||
|
|
||||||
|
|
||||||
|
BUILDING_ADDRESS_FIELD_MAP = {
|
||||||
|
'address': 'addressLines',
|
||||||
|
'addresslines': 'addressLines',
|
||||||
|
'administrativearea': 'administrativeArea',
|
||||||
|
'city': 'locality',
|
||||||
|
'country': 'regionCode',
|
||||||
|
'language': 'languageCode',
|
||||||
|
'languagecode': 'languageCode',
|
||||||
|
'locality': 'locality',
|
||||||
|
'postalcode': 'postalCode',
|
||||||
|
'regioncode': 'regionCode',
|
||||||
|
'state': 'administrativeArea',
|
||||||
|
'sublocality': 'sublocality',
|
||||||
|
'zipcode': 'postalCode',
|
||||||
|
}
|
||||||
|
|
||||||
def _getBuildingAttributes(args, body={}):
|
def _getBuildingAttributes(args, body={}):
|
||||||
i = 0
|
i = 0
|
||||||
while i < len(args):
|
while i < len(args):
|
||||||
@@ -253,6 +269,16 @@ def _getBuildingAttributes(args, body={}):
|
|||||||
elif myarg == 'floors':
|
elif myarg == 'floors':
|
||||||
body['floorNames'] = args[i + 1].split(',')
|
body['floorNames'] = args[i + 1].split(',')
|
||||||
i += 2
|
i += 2
|
||||||
|
elif myarg in BUILDING_ADDRESS_FIELD_MAP:
|
||||||
|
myarg = BUILDING_ADDRESS_FIELD_MAP[myarg]
|
||||||
|
body.setdefault('address', {})
|
||||||
|
if myarg == 'addressLines':
|
||||||
|
body['address'][myarg] = args[i + 1].split('\n')
|
||||||
|
elif myarg == 'languageCode':
|
||||||
|
body['address'][myarg] = LANGUAGE_CODES_MAP.get(args[i + 1].lower(), args[i + 1])
|
||||||
|
else:
|
||||||
|
body['address'][myarg] = args[i + 1]
|
||||||
|
i += 2
|
||||||
else:
|
else:
|
||||||
controlflow.invalid_argument_exit(myarg,
|
controlflow.invalid_argument_exit(myarg,
|
||||||
'gam create|update building')
|
'gam create|update building')
|
||||||
|
|||||||
@@ -21,6 +21,18 @@ def create():
|
|||||||
body['roleId'] = gapi_directory_roles.getRoleId(role)
|
body['roleId'] = gapi_directory_roles.getRoleId(role)
|
||||||
body['scopeType'] = sys.argv[5].upper()
|
body['scopeType'] = sys.argv[5].upper()
|
||||||
i = 6
|
i = 6
|
||||||
|
if body['scopeType'] not in ['CUSTOMER', 'ORG_UNIT']:
|
||||||
|
controlflow.expected_argument_exit('scope type',
|
||||||
|
', '.join(['customer', 'org_unit']),
|
||||||
|
body['scopeType'])
|
||||||
|
if body['scopeType'] == 'ORG_UNIT':
|
||||||
|
orgUnit, orgUnitId = gapi_directory_orgunits.getOrgUnitId(
|
||||||
|
sys.argv[i], cd)
|
||||||
|
body['orgUnitId'] = orgUnitId[3:]
|
||||||
|
scope = f'ORG_UNIT {orgUnit}'
|
||||||
|
i = 7
|
||||||
|
else:
|
||||||
|
scope = 'CUSTOMER'
|
||||||
while i < len(sys.argv):
|
while i < len(sys.argv):
|
||||||
myarg = sys.argv[i].lower()
|
myarg = sys.argv[i].lower()
|
||||||
if myarg == 'condition':
|
if myarg == 'condition':
|
||||||
@@ -33,17 +45,6 @@ def create():
|
|||||||
i += 2
|
i += 2
|
||||||
else:
|
else:
|
||||||
controlflow.invalid_argument_exit(sys.argv[i], 'gam create admin')
|
controlflow.invalid_argument_exit(sys.argv[i], 'gam create admin')
|
||||||
if body['scopeType'] not in ['CUSTOMER', 'ORG_UNIT']:
|
|
||||||
controlflow.expected_argument_exit('scope type',
|
|
||||||
', '.join(['customer', 'org_unit']),
|
|
||||||
body['scopeType'])
|
|
||||||
if body['scopeType'] == 'ORG_UNIT':
|
|
||||||
orgUnit, orgUnitId = gapi_directory_orgunits.getOrgUnitId(
|
|
||||||
sys.argv[6], cd)
|
|
||||||
body['orgUnitId'] = orgUnitId[3:]
|
|
||||||
scope = f'ORG_UNIT {orgUnit}'
|
|
||||||
else:
|
|
||||||
scope = 'CUSTOMER'
|
|
||||||
print(f'Giving {user} admin role {role} for {scope}')
|
print(f'Giving {user} admin role {role} for {scope}')
|
||||||
gapi.call(cd.roleAssignments(),
|
gapi.call(cd.roleAssignments(),
|
||||||
'insert',
|
'insert',
|
||||||
|
|||||||
8
src/gam/gapi/drive/__init__.py
Normal file
8
src/gam/gapi/drive/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import gam
|
||||||
|
|
||||||
|
|
||||||
|
def build(user=None):
|
||||||
|
if not user:
|
||||||
|
user = gam._get_admin_email()
|
||||||
|
userEmail = gam.convertUIDtoEmailAddress(user)
|
||||||
|
return (userEmail, gam.buildGAPIServiceObject('drive3', userEmail))
|
||||||
26
src/gam/gapi/drive/drives.py
Normal file
26
src/gam/gapi/drive/drives.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
"""Methods related to Drive API Shared Drives"""
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
import gam
|
||||||
|
from gam.var import GC_CUSTOMER_ID, GC_Values, MY_CUSTOMER, SORTORDER_CHOICES_MAP
|
||||||
|
from gam import controlflow
|
||||||
|
from gam import display
|
||||||
|
from gam import gapi
|
||||||
|
from gam.gapi import errors as gapi_errors
|
||||||
|
from gam.gapi import drive as gapi_drive
|
||||||
|
|
||||||
|
def drive_name_to_id(name, drive=None):
|
||||||
|
if not drive:
|
||||||
|
_, drive = gapi_drive.build()
|
||||||
|
q = f"name = '{name}'"
|
||||||
|
sds = gapi.get_all_pages(drive.drives(),
|
||||||
|
'list',
|
||||||
|
'drives',
|
||||||
|
q=q,
|
||||||
|
useDomainAdminAccess=True)
|
||||||
|
if len(sds) == 0:
|
||||||
|
controlflow.system_error_exit(3, f'Could not find shared drive named "{name}"')
|
||||||
|
elif len(sds) > 1:
|
||||||
|
controlflow.system_error_exit(3, f'Got more than one shared drive named "{name}"')
|
||||||
|
return sds[0]['id']
|
||||||
@@ -120,6 +120,7 @@ class ErrorReason(Enum):
|
|||||||
FAILED_PRECONDITION = 'failedPrecondition'
|
FAILED_PRECONDITION = 'failedPrecondition'
|
||||||
FORBIDDEN = 'forbidden'
|
FORBIDDEN = 'forbidden'
|
||||||
FIVE_O_THREE = '503'
|
FIVE_O_THREE = '503'
|
||||||
|
FIVE_O_O = '500'
|
||||||
FOUR_O_NINE = '409'
|
FOUR_O_NINE = '409'
|
||||||
FOUR_O_O = '400'
|
FOUR_O_O = '400'
|
||||||
FOUR_O_FOUR = '404'
|
FOUR_O_FOUR = '404'
|
||||||
@@ -159,6 +160,7 @@ DEFAULT_RETRY_REASONS = [
|
|||||||
ErrorReason.GATEWAY_TIMEOUT,
|
ErrorReason.GATEWAY_TIMEOUT,
|
||||||
ErrorReason.INTERNAL_ERROR,
|
ErrorReason.INTERNAL_ERROR,
|
||||||
ErrorReason.FOUR_TWO_NINE,
|
ErrorReason.FOUR_TWO_NINE,
|
||||||
|
ErrorReason.FIVE_O_O,
|
||||||
ErrorReason.FIVE_O_THREE,
|
ErrorReason.FIVE_O_THREE,
|
||||||
]
|
]
|
||||||
GMAIL_THROW_REASONS = [ErrorReason.SERVICE_NOT_AVAILABLE]
|
GMAIL_THROW_REASONS = [ErrorReason.SERVICE_NOT_AVAILABLE]
|
||||||
@@ -231,6 +233,7 @@ ERROR_REASON_TO_EXCEPTION = {
|
|||||||
OAUTH2_TOKEN_ERRORS = [
|
OAUTH2_TOKEN_ERRORS = [
|
||||||
'access_denied',
|
'access_denied',
|
||||||
'access_denied: Requested client not authorized',
|
'access_denied: Requested client not authorized',
|
||||||
|
'access_denied: Account restricted',
|
||||||
'internal_failure: Backend Error',
|
'internal_failure: Backend Error',
|
||||||
'internal_failure: None',
|
'internal_failure: None',
|
||||||
'invalid_grant',
|
'invalid_grant',
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ def create(users, sku=None):
|
|||||||
productId = sys.argv[i+1]
|
productId = sys.argv[i+1]
|
||||||
i += 2
|
i += 2
|
||||||
for user in users:
|
for user in users:
|
||||||
print(f'Adding license {sku_name} from to {user}')
|
print(f'Adding license {sku_name} to {user}')
|
||||||
gapi.call(lic.licenseAssignments(),
|
gapi.call(lic.licenseAssignments(),
|
||||||
'insert',
|
'insert',
|
||||||
soft_errors=True,
|
soft_errors=True,
|
||||||
|
|||||||
@@ -348,7 +348,7 @@ def print_count():
|
|||||||
# so we keep track of which accounts we searched and can report
|
# so we keep track of which accounts we searched and can report
|
||||||
# zero data for them.
|
# zero data for them.
|
||||||
if search_method == 'ACCOUNT':
|
if search_method == 'ACCOUNT':
|
||||||
query_accounts = query.get('accountInfo', [])
|
query_accounts = query.get('accountInfo', {}).get('emails', [])
|
||||||
elif search_method == 'ENTIRE_ORG':
|
elif search_method == 'ENTIRE_ORG':
|
||||||
query_accounts = gam.getUsersToModify('all', 'users')
|
query_accounts = gam.getUsersToModify('all', 'users')
|
||||||
elif search_method == 'ORG_UNIT':
|
elif search_method == 'ORG_UNIT':
|
||||||
@@ -367,7 +367,8 @@ def print_count():
|
|||||||
if account in query_accounts: query_accounts.remove(account)
|
if account in query_accounts: query_accounts.remove(account)
|
||||||
for account in a_count.get('accountCounts', []):
|
for account in a_count.get('accountCounts', []):
|
||||||
email = account.get('account', {}).get('email', '')
|
email = account.get('account', {}).get('email', '')
|
||||||
csv_rows.append({'account': email, 'count': account.get('count')})
|
if email:
|
||||||
|
csv_rows.append({'account': email, 'count': account.get('count', 0)})
|
||||||
if email in query_accounts: query_accounts.remove(email)
|
if email in query_accounts: query_accounts.remove(email)
|
||||||
for account in query_accounts:
|
for account in query_accounts:
|
||||||
csv_rows.append({'account': account, 'count': 0})
|
csv_rows.append({'account': account, 'count': 0})
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import platform
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
GAM_AUTHOR = 'Jay Lee <jay0lee@gmail.com>'
|
GAM_AUTHOR = 'Jay Lee <jay0lee@gmail.com>'
|
||||||
GAM_VERSION = '6.17'
|
GAM_VERSION = '6.22'
|
||||||
GAM_LICENSE = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
GAM_LICENSE = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
||||||
|
|
||||||
GAM_URL = 'https://git.io/gam'
|
GAM_URL = 'https://jaylee.us/gam'
|
||||||
GAM_INFO = (
|
GAM_INFO = (
|
||||||
f'GAM {GAM_VERSION} - {GAM_URL} / {GAM_AUTHOR} / '
|
f'GAM {GAM_VERSION} - {GAM_URL} / {GAM_AUTHOR} / '
|
||||||
f'Python {platform.python_version()} {sys.version_info.releaselevel} / '
|
f'Python {platform.python_version()} {sys.version_info.releaselevel} / '
|
||||||
@@ -116,6 +116,11 @@ SKUS = {
|
|||||||
'aliases': ['gvpremier', 'voicepremier', 'googlevoicepremier'],
|
'aliases': ['gvpremier', 'voicepremier', 'googlevoicepremier'],
|
||||||
'displayName': 'Google Voice Premier'
|
'displayName': 'Google Voice Premier'
|
||||||
},
|
},
|
||||||
|
'1010360001': {
|
||||||
|
'product': '101036',
|
||||||
|
'aliases': ['meetdialing','googlemeetglobaldialing'],
|
||||||
|
'displayName': 'Google Meet Global Dialing'
|
||||||
|
},
|
||||||
'1010370001': {
|
'1010370001': {
|
||||||
'product': '101037',
|
'product': '101037',
|
||||||
'aliases': ['gwetlu', 'workspaceeducationupgrade'],
|
'aliases': ['gwetlu', 'workspaceeducationupgrade'],
|
||||||
@@ -193,6 +198,11 @@ SKUS = {
|
|||||||
'wsentplus', 'workspaceenterpriseplus'],
|
'wsentplus', 'workspaceenterpriseplus'],
|
||||||
'displayName': 'Workspace Enterprise Plus'
|
'displayName': 'Workspace Enterprise Plus'
|
||||||
},
|
},
|
||||||
|
'1010020029': {
|
||||||
|
'product': 'Google-Apps',
|
||||||
|
'aliases': ['wes', 'workspaceenterprisestarter'],
|
||||||
|
'displayName': 'Workspace Enterprise Starter'
|
||||||
|
},
|
||||||
'1010020030': {
|
'1010020030': {
|
||||||
'product': 'Google-Apps',
|
'product': 'Google-Apps',
|
||||||
'aliases': ['workspacefrontline', 'workspacefrontlineworker'],
|
'aliases': ['workspacefrontline', 'workspacefrontlineworker'],
|
||||||
@@ -277,6 +287,7 @@ PRODUCTID_NAME_MAPPINGS = {
|
|||||||
'101033': 'Google Voice',
|
'101033': 'Google Voice',
|
||||||
'101034': 'G Suite Archived',
|
'101034': 'G Suite Archived',
|
||||||
'101035': 'Cloud Search',
|
'101035': 'Cloud Search',
|
||||||
|
'101036': 'Google Meet Global Dialing',
|
||||||
'101037': 'G Suite Workspace for Education',
|
'101037': 'G Suite Workspace for Education',
|
||||||
'Google-Apps': 'Google Workspace',
|
'Google-Apps': 'Google Workspace',
|
||||||
'Google-Chrome-Device-Management': 'Google Chrome Device Management',
|
'Google-Chrome-Device-Management': 'Google Chrome Device Management',
|
||||||
@@ -301,6 +312,7 @@ API_NAME_MAPPING = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
API_VER_MAPPING = {
|
API_VER_MAPPING = {
|
||||||
|
'accesscontextmanager': 'v1',
|
||||||
'alertcenter': 'v1beta1',
|
'alertcenter': 'v1beta1',
|
||||||
'driveactivity': 'v2',
|
'driveactivity': 'v2',
|
||||||
'calendar': 'v3',
|
'calendar': 'v3',
|
||||||
@@ -976,6 +988,7 @@ CROS_ARGUMENT_TO_PROPERTY_MAP = {
|
|||||||
'notes': ['notes',],
|
'notes': ['notes',],
|
||||||
'ordernumber': ['orderNumber',],
|
'ordernumber': ['orderNumber',],
|
||||||
'org': ['orgUnitPath',],
|
'org': ['orgUnitPath',],
|
||||||
|
'orgunitid': ['orgUnitId',],
|
||||||
'orgunitpath': ['orgUnitPath',],
|
'orgunitpath': ['orgUnitPath',],
|
||||||
'osversion': ['osVersion',],
|
'osversion': ['osVersion',],
|
||||||
'ou': ['orgUnitPath',],
|
'ou': ['orgUnitPath',],
|
||||||
@@ -1001,6 +1014,7 @@ CROS_BASIC_FIELDS_LIST = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
CROS_SCALAR_PROPERTY_PRINT_ORDER = [
|
CROS_SCALAR_PROPERTY_PRINT_ORDER = [
|
||||||
|
'orgUnitId',
|
||||||
'orgUnitPath',
|
'orgUnitPath',
|
||||||
'annotatedAssetId',
|
'annotatedAssetId',
|
||||||
'annotatedLocation',
|
'annotatedLocation',
|
||||||
@@ -1524,6 +1538,9 @@ MESSAGE_UPDATE_GAM_TO_64BIT = 'You\'re running a 32-bit version of GAM on a' \
|
|||||||
MESSAGE_YOUR_SYSTEM_TIME_DIFFERS_FROM_GOOGLE_BY = 'Your system time differs' \
|
MESSAGE_YOUR_SYSTEM_TIME_DIFFERS_FROM_GOOGLE_BY = 'Your system time differs' \
|
||||||
' from %s by %s'
|
' from %s by %s'
|
||||||
|
|
||||||
|
shared_drive_values = ['teamdrive', 'teamdrives',
|
||||||
|
'shareddrive', 'shareddrives']
|
||||||
|
|
||||||
USER_ADDRESS_TYPES = ['home', 'work', 'other']
|
USER_ADDRESS_TYPES = ['home', 'work', 'other']
|
||||||
USER_EMAIL_TYPES = ['home', 'work', 'other']
|
USER_EMAIL_TYPES = ['home', 'work', 'other']
|
||||||
USER_EXTERNALID_TYPES = [
|
USER_EXTERNALID_TYPES = [
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
accesscontextmanager.googleapis.com
|
||||||
admin.googleapis.com
|
admin.googleapis.com
|
||||||
alertcenter.googleapis.com
|
alertcenter.googleapis.com
|
||||||
calendar-json.googleapis.com
|
calendar-json.googleapis.com
|
||||||
@@ -6,6 +7,7 @@ chromemanagement.googleapis.com
|
|||||||
chromepolicy.googleapis.com
|
chromepolicy.googleapis.com
|
||||||
classroom.googleapis.com
|
classroom.googleapis.com
|
||||||
cloudidentity.googleapis.com
|
cloudidentity.googleapis.com
|
||||||
|
cloudresourcemanager.googleapis.com
|
||||||
contacts.googleapis.com
|
contacts.googleapis.com
|
||||||
drive.googleapis.com
|
drive.googleapis.com
|
||||||
driveactivity.googleapis.com
|
driveactivity.googleapis.com
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
name = GAM for Google Workspace
|
name = GAM for Google Workspace
|
||||||
version = 6.0.14
|
version = 6.0.22
|
||||||
description = Command line management for Google Workspaces
|
description = Command line management for Google Workspaces
|
||||||
long_description = file: readme.md
|
long_description = file: readme.md
|
||||||
long_description_content_type = text/markdown
|
long_description_content_type = text/markdown
|
||||||
|
|||||||
Reference in New Issue
Block a user