mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-21 06:31:37 +00:00
Compare commits
15 Commits
20240519.1
...
20240531.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f9624ad5c | ||
|
|
9c9ddff973 | ||
|
|
f1636c7768 | ||
|
|
0ebefda760 | ||
|
|
5a335fb57b | ||
|
|
db95cbcfa4 | ||
|
|
33d9949283 | ||
|
|
41078d5ff6 | ||
|
|
52316774ad | ||
|
|
ce545ad062 | ||
|
|
2e5df12df1 | ||
|
|
46b9de642d | ||
|
|
a9d600234c | ||
|
|
5c8b69e8b7 | ||
|
|
29792677d7 |
63
.github/workflows/build.yml
vendored
63
.github/workflows/build.yml
vendored
@@ -35,13 +35,11 @@ jobs:
|
||||
goal: build
|
||||
arch: x86_64
|
||||
openssl_archs: linux-x86_64
|
||||
fullGamTest: yes
|
||||
- os: [self-hosted, linux, arm64]
|
||||
jid: 2
|
||||
goal: build
|
||||
arch: aarch64
|
||||
openssl_archs: linux-aarch64
|
||||
fullGamTest: yes
|
||||
- os: ubuntu-20.04
|
||||
jid: 3
|
||||
goal: build
|
||||
@@ -59,13 +57,11 @@ jobs:
|
||||
goal: build
|
||||
arch: x86_64
|
||||
openssl_archs: darwin64-x86_64
|
||||
fullGamTest: yes
|
||||
- os: macos-14
|
||||
jid: 6
|
||||
goal: build
|
||||
arch: aarch64
|
||||
openssl_archs: darwin64-arm64
|
||||
fullGamTest: yes
|
||||
- os: macos-14
|
||||
jid: 7
|
||||
goal: build
|
||||
@@ -76,7 +72,6 @@ jobs:
|
||||
goal: build
|
||||
arch: Win64
|
||||
openssl_archs: VC-WIN64A
|
||||
fullGamTest: yes
|
||||
- os: ubuntu-22.04
|
||||
goal: test
|
||||
python: "3.8"
|
||||
@@ -119,7 +114,7 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
cache.tar.xz
|
||||
key: gam-${{ matrix.jid }}-20240416
|
||||
key: gam-${{ matrix.jid }}-20240526
|
||||
|
||||
- name: Untar Cache archive
|
||||
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
|
||||
@@ -200,8 +195,9 @@ jobs:
|
||||
bash ./rust.sh -y
|
||||
source $HOME/.cargo/env
|
||||
# Install needed packages
|
||||
brew update
|
||||
brew install gpg swig
|
||||
# brew update
|
||||
# brew install gpg
|
||||
brew install swig
|
||||
|
||||
- name: Windows Configure VCode
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
@@ -223,12 +219,6 @@ jobs:
|
||||
GAM_ARCHIVE_ARCH="x86_64"
|
||||
WIX_ARCH="x64"
|
||||
CHOC_OPS=""
|
||||
elif [[ "${arch}" == "Win32" ]]; then
|
||||
PYEXTERNALS_PATH="win32"
|
||||
PYBUILDRELEASE_ARCH="Win32"
|
||||
GAM_ARCHIVE_ARCH="x86"
|
||||
WIX_ARCH="x86"
|
||||
CHOC_OPS="--forcex86"
|
||||
fi
|
||||
if [[ "${RUNNER_OS}" == "macOS" ]]; then
|
||||
MAKE=make
|
||||
@@ -498,22 +488,20 @@ jobs:
|
||||
cd pyinstaller
|
||||
export latest_release=$(git tag --list | grep -v dev | grep -v rc | sort -Vr | head -n1)
|
||||
#V6.0.0 causes errors on staticx
|
||||
if [[ "${staticx}" == "yes" ]]; then
|
||||
git checkout "v5.13.2"
|
||||
elif [[ "${RUNNER_OS}" == "Windows" ]]; then
|
||||
git checkout "v5.13.2"
|
||||
elif [[ "${RUNNER_OS}" == "macOS" ]]; then
|
||||
git checkout "v5.13.2"
|
||||
else
|
||||
git checkout "${latest_release}"
|
||||
fi
|
||||
#if [[ "${staticx}" == "yes" ]]; then
|
||||
# git checkout "v5.13.2"
|
||||
#elif [[ "${RUNNER_OS}" == "Windows" ]]; then
|
||||
# git checkout "v5.13.2"
|
||||
#elif [[ "${RUNNER_OS}" == "macOS" ]]; then
|
||||
# git checkout "v5.13.2"
|
||||
#else
|
||||
git checkout "${latest_release}"
|
||||
#fi
|
||||
# remove pre-compiled bootloaders so we fail if bootloader compile fails
|
||||
rm -rvf PyInstaller/bootloader/*-*/*
|
||||
cd bootloader
|
||||
export PYINSTALLER_BUILD_ARGS=""
|
||||
case "${arch}" in
|
||||
"Win32")
|
||||
export PYINSTALLER_BUILD_ARGS="--target-arch=32bit"
|
||||
;;
|
||||
"Win64")
|
||||
export PYINSTALLER_BUILD_ARGS="--target-arch=64bit"
|
||||
;;
|
||||
@@ -540,7 +528,7 @@ jobs:
|
||||
elif [[ "${RUNNER_OS}" == "Windows" ]]; then
|
||||
# Work around issue where PyInstaller picks up python3.dll from other Python versions
|
||||
# https://github.com/pyinstaller/pyinstaller/issues/7102
|
||||
export PATH="/usr/bin"
|
||||
export PATH="$(dirname ${PYTHON}):/usr/bin"
|
||||
else
|
||||
export gampath=$(realpath "${gampath}")
|
||||
fi
|
||||
@@ -618,15 +606,16 @@ jobs:
|
||||
if: runner.os != 'Windows' && matrix.goal == 'build'
|
||||
run: |
|
||||
if [[ "${RUNNER_OS}" == "macOS" ]]; then
|
||||
GAM_ARCHIVE="gam-${GAMVERSION}-macos-${arch}.tar.xz"
|
||||
GAM_ARCHIVE="gam-${GAMVERSION}-macos-${arch}.tar.xz"
|
||||
elif [[ "${RUNNER_OS}" == "Linux" ]]; then
|
||||
if [[ "${staticx}" == "yes" ]]; then
|
||||
libver="legacy"
|
||||
else
|
||||
libver="glibc$(ldd --version | awk '/ldd/{print $NF}')"
|
||||
fi
|
||||
GAM_ARCHIVE="gam-${GAMVERSION}-linux-$(arch)-${libver}.tar.xz"
|
||||
if [[ "${staticx}" == "yes" ]]; then
|
||||
libver="legacy"
|
||||
else
|
||||
libver="glibc$(ldd --version | awk '/ldd/{print $NF}')"
|
||||
fi
|
||||
GAM_ARCHIVE="gam-${GAMVERSION}-linux-$(arch)-${libver}.tar.xz"
|
||||
fi
|
||||
echo "GAM Archive ${GAM_ARCHIVE}"
|
||||
tar -C dist/ --create --verbose --exclude-from "${GITHUB_WORKSPACE}/.github/actions/package_exclusions.txt" --file $GAM_ARCHIVE --xz gam
|
||||
|
||||
- name: Windows package
|
||||
@@ -661,7 +650,7 @@ jobs:
|
||||
echo "We successfully compiled Python ${this_python} and OpenSSL ${this_openssl}"
|
||||
|
||||
- name: Live API tests push only
|
||||
if: (github.event_name == 'push' || github.event_name == 'schedule') && matrix.fullGamTest == 'yes'
|
||||
if: (github.event_name == 'push' || github.event_name == 'schedule')
|
||||
env:
|
||||
PASSCODE: ${{ secrets.PASSCODE }}
|
||||
run: |
|
||||
@@ -748,7 +737,7 @@ jobs:
|
||||
$gam info group $newgroup
|
||||
$gam info cigroup $newgroup membertree
|
||||
# confirm mailbox is provisoned before continuing
|
||||
$gam user $newuser waitformailbox
|
||||
$gam user $newuser waitformailbox retries 20
|
||||
$gam user $newuser imap on
|
||||
$gam user $newuser show imap
|
||||
$gam user $newuser show delegates
|
||||
@@ -762,7 +751,7 @@ jobs:
|
||||
$gam user $gam_user insertemail subject "GHA insert $newbase" file gam.py labels INBOX,UNREAD # yep body is gam code
|
||||
$gam user $gam_user sendemail subject "GHA send $gam_user $newbase" file gam.py recipient admin@pdl.jaylee.us
|
||||
$gam user $gam_user draftemail subject "GHA draft $newbase" message "Draft message test"
|
||||
$gam csvfile sample.csv:email waitformailbox
|
||||
$gam csvfile sample.csv:email waitformailbox retries 20
|
||||
$gam user $newuser delegate to "${newbase}-bulkuser-1" || if [ $? != 50 ]; then exit $?; fi # expect a 50 return code (delegation failed)
|
||||
$gam users "$gam_user $newbase-bulkuser-1 $newbase-bulkuser-2 $newbase-bulkuser-3" delete messages query in:anywhere maxtodelete 99999 doit || if [ $? != 60 ]; then exit $?; fi # expect a 60 return code (no messages)
|
||||
$gam users "$newbase-bulkuser-4 $newbase-bulkuser-5 $newbase-bulkuser-6" trash messages query in:anywhere maxtotrash 99999 doit || if [ $? != 60 ]; then exit $?; fi # expect a 60 return code (no messages)
|
||||
|
||||
@@ -837,7 +837,7 @@ gam update sakey
|
||||
(algorithm KEY_ALG_RSA_1024|KEY_ALG_RSA_2048)|
|
||||
(localkeysize 1024|2048|4096 [validityhours <Number>])|
|
||||
(yubikey yubikey_pin yubikey_slot AUTHENTICATION|SIGNATURE yubikey_serialnumber <Number>)
|
||||
gam rotate sakey replace_existing
|
||||
gam rotate sakey replace_current
|
||||
(algorithm KEY_ALG_RSA_1024|KEY_ALG_RSA_2048)|
|
||||
(localkeysize 1024|2048|4096 [validityhours <Number>])|
|
||||
(yubikey yubikey_pin yubikey_slot AUTHENTICATION|SIGNATURE yubikey_serialnumber <Number>)
|
||||
|
||||
@@ -457,6 +457,7 @@
|
||||
<ResellerID> ::= <String>
|
||||
<ResourceID> ::= <String>
|
||||
<SchemaName> ::= <String>
|
||||
<SchemaNameField> ::= <SchemaName>.<FieldName>
|
||||
<Section> ::= <String>
|
||||
<SendAsContent> ::=
|
||||
(sig|signature|htmlsig <String>)|
|
||||
@@ -513,6 +514,7 @@
|
||||
<Title> ::= <String>
|
||||
<ToDriveAttribute> ::=
|
||||
(tdaddsheet [<Boolean>])|
|
||||
(tdalert <EmailAddress>)*|
|
||||
(tdbackupsheet (id:<Number>)|<String>)|
|
||||
(tdcellnumberformat text|number)|
|
||||
(tdcellwrap clip|overflow|wrap)|
|
||||
@@ -520,17 +522,20 @@
|
||||
(tdcopysheet (id:<Number>)|<String>)|
|
||||
(tddescription <String>)|
|
||||
(tdfileid <DriveFileID>)|
|
||||
(tdfrom <EmailAddress>)|
|
||||
(tdlocalcopy [<Boolean>])|
|
||||
(tdlocale <Locale>)|
|
||||
(tdnobrowser [<Boolean>])|
|
||||
(tdnoemail [<Boolean>])|
|
||||
(tdnoescapechar [<Boolean>])|
|
||||
(tdnotify [<Boolean>])|
|
||||
(tdparent (id:<DriveFolderID>)|<DriveFolderName>)|
|
||||
(tdretaintitle [<Boolean>])|
|
||||
(tdshare <EmailAddress> commenter|reader|writer)*|
|
||||
(tdsheet (id:<Number>)|<String>)|
|
||||
(tdsheettimestamp [<Boolean>] [tdsheettimeformat <String>])
|
||||
(tdsheettitle <String>)|
|
||||
(tdsubject <String>)|
|
||||
([tdsheetdaysoffset <Number>] [tdsheethoursoffset <Number>])|
|
||||
(tdtimestamp [<Boolean>] [tdtimeformat <String>]
|
||||
[tddaysoffset <Number>] [tdhoursoffset <Number>])|
|
||||
|
||||
@@ -178,6 +178,7 @@ Client access works when accessing Resource calendars.
|
||||
<EventType> ::=
|
||||
default|
|
||||
focustime|
|
||||
fromgmail|
|
||||
outofoffice|
|
||||
workinglocation
|
||||
<EventTypeList> ::= "<EventType>(,<EventType>)*"
|
||||
|
||||
@@ -182,7 +182,7 @@ gam user testuser show fileinfo anydrivefilename "Test File"
|
||||
gam user testuser show fileinfo anydrivefilename:"Test File"
|
||||
```
|
||||
## Select file ownership
|
||||
By default, files the user owns are sisplayed; you can select the ownership characteristic.
|
||||
By default, files the user owns are displayed; you can select the ownership characteristic.
|
||||
```
|
||||
anyowner|(showownedby any|me|others)
|
||||
```
|
||||
|
||||
@@ -10,6 +10,42 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
|
||||
|
||||
See [Downloads](https://github.com/taers232c/GAMADV-XTD3/wiki/Downloads) for Windows or other options, including manual installation
|
||||
|
||||
### 6.76.10
|
||||
|
||||
Added `fromgmail` to `<EventType>` that can be used in `gam calendars <CalendarEntity> print|show events ... eventtype fromgmail`.
|
||||
|
||||
* See: https://workspaceupdates.googleblog.com/2024/05/google-calendar-api-event-type-fromgmail.html
|
||||
|
||||
### 6.76.09
|
||||
|
||||
Updated `gam update|delete|info adminrole` to handle the following error:
|
||||
```
|
||||
ERROR: 400: failedPrecondition - Precondition check failed.
|
||||
```
|
||||
|
||||
### 6.76.08
|
||||
|
||||
Updated `<SchemaNameList>` to `"<SchemaName>|<SchemaFieldName>(,<SchemaName>|<SchemaFieldName>)*"`
|
||||
that allows `schemas <SchemaNameList>` in `gam info user` and `gam print users` to display all fields or selected fields
|
||||
of the specified custom schemas.
|
||||
|
||||
### 6.76.07
|
||||
|
||||
Fixed bug where control-C was not recognized when GAM had processed all rows in a CSV file
|
||||
and was `Waiting for N running processes to finish before terminating`.
|
||||
|
||||
### 6.76.06
|
||||
|
||||
Fixed bug in `gam <UserTypeEntity> print messages ... positivecountsonly` where message counts with value 0 were deiplayed.
|
||||
|
||||
Added option `addcsvdata <FieldName> <String>` to `gam <UserTypeEntity> print|messages` that adds
|
||||
additional columns of data to the CSV file output.
|
||||
|
||||
Added option `showusagebytes` to `gam <UserTypeEntity> print|show drivesettings` that displays
|
||||
the following fields in bytes ```usageBytes,usageInDriveBytes,usageInDriveTrashBytes```
|
||||
in addition to the fields in their formatted form with units: ```usage,usageInDrive,usageInDriveTrash```.
|
||||
This will be most useful with `print` as the rows can be sorted based on the `usagexxxBytes` columns.
|
||||
|
||||
### 6.76.05
|
||||
|
||||
Added options `deletefromoldowner`, `addtonewowner <CalendarAttribute>*` and `nolistmessages`
|
||||
|
||||
@@ -335,7 +335,7 @@ writes the credentials into the file oauth2.txt.
|
||||
admin@server:/Users/admin/bin/gamadv-xtd3$ rm -f /Users/admin/GAMConfig/oauth2.txt
|
||||
admin@server:/Users/admin/bin/gamadv-xtd3$ ./gam version
|
||||
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
|
||||
GAMADV-XTD3 6.76.05 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.76.10 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.3 64-bit final
|
||||
MacOS Sonoma 14.4.1 x86_64
|
||||
@@ -1009,7 +1009,7 @@ writes the credentials into the file oauth2.txt.
|
||||
C:\GAMADV-XTD3>del C:\GAMConfig\oauth2.txt
|
||||
C:\GAMADV-XTD3>gam version
|
||||
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
|
||||
GAMADV-XTD3 6.76.05 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.76.10 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.3 64-bit final
|
||||
Windows-10-10.0.17134 AMD64
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
<QueryMobileList> ::= "<QueryMobile>(,<QueryMobile>)*"
|
||||
<QueryUserList> ::= "<QueryUser>(,<QueryUser>)*"
|
||||
<ResourceIDList> ::= "<ResourceID>(,<ResourceID>)*"
|
||||
<SchemaNameList> ::= "<SchemaName>(,<SchemaName>)*"
|
||||
<SchemaNameList> ::= "<SchemaName>|<SchemaFieldName>(,<SchemaName>|<SchemaFieldName>)*"
|
||||
<SerialNumberList> ::= "<SerialNumber>(,<SerialNumber>)*"
|
||||
<ServiceAccountKeyList> ::= "<ServiceAccountKey>(,<ServiceAccountKey>)*"
|
||||
<SiteACLScopeList> ::= "<SiteACLScope>(,<SiteACLScope>)*"
|
||||
|
||||
@@ -243,6 +243,7 @@
|
||||
<EventType> ::=
|
||||
default|
|
||||
focustime|
|
||||
fromgmail|
|
||||
outofoffice|
|
||||
workinglocation
|
||||
<EventTypeList> ::= "<EventType>(,<EventType>)*"
|
||||
|
||||
@@ -141,10 +141,16 @@ The `quotechar <Character>` option allows you to choose an alternate quote chara
|
||||
```
|
||||
gam <UserTypeEntity> print drivesettings [todrive <ToDriveAttribute>*]
|
||||
[allfields|<DriveSettingsFieldName>*|(fields <DriveSettingsFieldNameList>)]
|
||||
[delimiter <Character>]
|
||||
[delimiter <Character>] [showusagebytes]
|
||||
gam <UserTypeEntity> show drivesettings
|
||||
[allfields|<DriveSettingsFieldName>*|(fields <DriveSettingsFieldNameList>)]
|
||||
[delimiter <Character>]
|
||||
[delimiter <Character>] [showusagebytes]
|
||||
```
|
||||
If no fields are selected, these fields will be displayed:
|
||||
`name,appInstalled,largestChangeId,limit,maxUploadSize,permissionId,rootFolderId,usage,usageInDrive,usageInDriveTrash`
|
||||
|
||||
By default, these fields are displayed in formatted form with units: ```usage,usageInDrive,usageInDriveTrash```.
|
||||
|
||||
The option `showusagebytes` also displays the following fields in bytes ```usageBytes,usageInDriveBytes,usageInDriveTrashBytes```.
|
||||
|
||||
This will be most useful with `print` as the rows can be sorted based on the `usagexxxBytes` columns.
|
||||
|
||||
@@ -1036,6 +1036,10 @@ When `allfields` is specified (or no fields are specified), use `showshareddrive
|
||||
when shared drives are queried/selected. In this case, the Drive API returns the permission IDs
|
||||
but not the permissions themselves so GAM makes an additional API call per file to get the permissions.
|
||||
|
||||
By default, when `showimimetype` and `filepath|fullpath`are both specified, GAM locally filters files by MimeType;
|
||||
this may be slow if the user has a large number of files. Adding the option `mimetypeinquery` or `mimetypeinquery true`
|
||||
causes GAM to have Google filter files by MimeType; this will increase performance.
|
||||
|
||||
See [Select files for Display file counts, list, tree](#select-files-for-display-file-counts-list-tree)
|
||||
|
||||
## File selection by name and entity shortcuts for Display file list
|
||||
|
||||
@@ -110,6 +110,11 @@ queries "`"orgUnitPath=\'/Students/Lower\ School/2027\'`",`"orgUnitPath=\'/Stude
|
||||
<QueryUser> ::= <String>
|
||||
See: https://developers.google.com/admin-sdk/directory/v1/guides/search-users
|
||||
|
||||
<FieldName> ::= <String>
|
||||
<SchemaName> ::= <String>
|
||||
<SchemaNameField> ::= <SchemaName>.<FieldName>
|
||||
<SchemaNameList> ::= "<SchemaName>|<SchemaFieldName>(,<SchemaName>|<SchemaFieldName>)*"
|
||||
|
||||
<StorageBucketName> ::= <String>
|
||||
<StorageObjectName> ::= <String>
|
||||
<StorageBucketObjectName> ::=
|
||||
@@ -488,7 +493,7 @@ clearschema <SchemaName>
|
||||
```
|
||||
Clear a specific field in a schema:
|
||||
```
|
||||
clearschema <SchemaName>.<FieldName>
|
||||
clearschema <SchemaNameField>
|
||||
```
|
||||
|
||||
## Create a user
|
||||
@@ -614,7 +619,7 @@ gam update user <UserItem> [ignorenullpassword] <UserAttribute>*
|
||||
[updateoufromgroup <FileName> [charset <Charset>]
|
||||
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
|
||||
[fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]]
|
||||
[clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>]
|
||||
[clearschema <SchemaName>|<SchemaNameField>]
|
||||
[createifnotfound] [notfoundpassword random|<Password>]
|
||||
(groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)*
|
||||
[alias|aliases <EmailAddressList>]
|
||||
@@ -635,7 +640,7 @@ gam update users <UserTypeEntity> [ignorenullpassword] <UserAttribute>*
|
||||
[updateoufromgroup <FileName> [charset <Charset>]
|
||||
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
|
||||
[fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]]
|
||||
[clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>]
|
||||
[clearschema <SchemaName>|<SchemaNameField>]
|
||||
[createifnotfound] [notfoundpassword random|<Password>]
|
||||
(groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)*
|
||||
[alias|aliases <EmailAddressList>]
|
||||
@@ -656,7 +661,7 @@ gam <UserTypeEntity> update users [ignorenullpassword] <UserAttribute>*
|
||||
[updateoufromgroup <FileName> [charset <Charset>]
|
||||
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
|
||||
[fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]]
|
||||
[clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>]
|
||||
[clearschema <SchemaName>|<SchemaNameField>]
|
||||
[createifnotfound] [notfoundpassword random|<Password>]
|
||||
(groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)*
|
||||
[alias|aliases <EmailAddressList>]
|
||||
@@ -954,7 +959,7 @@ Starting in version `5.23.01`, the variable `quick_info_user` was added to `gam.
|
||||
|
||||
These existing options enable the display of additional information.
|
||||
* `(products|product <ProductIDList>)|(skus|sku <SKUIDList>)` - Display license information for a selected list of products/SKUs.
|
||||
* `schemas|custom|customschemas <SchemaNameList>` - Display the specified custom schemas
|
||||
* `schemas|custom|customschemas <SchemaNameList>` - Display all fields or selected fields of the specified custom schemas
|
||||
|
||||
By default, Gam displays fields that only an adminstrator can view.
|
||||
* `userview` - Only display fields that other users in the domain can view.
|
||||
@@ -1064,8 +1069,8 @@ By default, Gam displays only the primary email address for each user.
|
||||
* `allfields|basic` - Display all non custom schema fields for each user.
|
||||
* `full` - Display all fields including all custom schema fields for each user.
|
||||
* `<UserFieldName>* [fields <UserFieldNameList>]` - Only display selected fields.
|
||||
* `schemas|custom all` - Get custom schema information for all schemas.
|
||||
* `schemas|custom <SchemaNameList>` - Get custom schema information for a selected list of schemas.
|
||||
* `schemas|custom all` - Display custom schema information for all schemas.
|
||||
* `schemas|custom <SchemaNameList>` - Display all fields or selected fields of the specified custom schemas
|
||||
|
||||
By default, when aliases are displayed, all aliases are displayed. Use `aliasmatchpattern <RegularExpression>`
|
||||
to limit the display of aliases to those that match `<RegularExpression>`.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Version and Help
|
||||
\# Version and Help
|
||||
|
||||
Print the current version of Gam with details
|
||||
```
|
||||
gam version
|
||||
GAMADV-XTD3 6.76.05 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.76.10 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.3 64-bit final
|
||||
MacOS Sonoma 14.4.1 x86_64
|
||||
@@ -15,7 +15,7 @@ Time: 2023-06-02T21:10:00-07:00
|
||||
Print the current version of Gam with details and time offset information
|
||||
```
|
||||
gam version timeoffset
|
||||
GAMADV-XTD3 6.76.05 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.76.10 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.3 64-bit final
|
||||
MacOS Sonoma 14.4.1 x86_64
|
||||
@@ -27,7 +27,7 @@ Your system time differs from www.googleapis.com by less than 1 second
|
||||
Print the current version of Gam with extended details and SSL information
|
||||
```
|
||||
gam version extended
|
||||
GAMADV-XTD3 6.76.05 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.76.10 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.3 64-bit final
|
||||
MacOS Sonoma 14.4.1 x86_64
|
||||
@@ -64,7 +64,7 @@ MacOS High Sierra 10.13.6 x86_64
|
||||
Path: /Users/Admin/bin/gamadv-xtd3
|
||||
Version Check:
|
||||
Current: 5.35.08
|
||||
Latest: 6.76.05
|
||||
Latest: 6.76.10
|
||||
echo $?
|
||||
1
|
||||
```
|
||||
@@ -72,7 +72,7 @@ echo $?
|
||||
Print the current version number without details
|
||||
```
|
||||
gam version simple
|
||||
6.76.05
|
||||
6.76.10
|
||||
```
|
||||
In Linux/MacOS you can do:
|
||||
```
|
||||
@@ -82,7 +82,7 @@ echo $VER
|
||||
Print the current version of Gam and address of this Wiki
|
||||
```
|
||||
gam help
|
||||
GAM 6.76.05 - https://github.com/taers232c/GAMADV-XTD3
|
||||
GAM 6.76.10 - https://github.com/taers232c/GAMADV-XTD3
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.3 64-bit final
|
||||
MacOS Sonoma 14.4.1 x86_64
|
||||
|
||||
@@ -546,6 +546,7 @@ If an item contains spaces, it should be surrounded by ".
|
||||
<ResellerID> ::= <String>
|
||||
<ResourceID> ::= <String>
|
||||
<SchemaName> ::= <String>
|
||||
<SchemaNameField> ::= <SchemaName>.<FieldName>
|
||||
<Section> ::= <String>
|
||||
<SendAsContent> ::=
|
||||
(sig|signature|htmlsig <String>)|
|
||||
@@ -626,7 +627,7 @@ If an item contains spaces, it should be surrounded by ".
|
||||
(tdsubject <String>)|
|
||||
([tdsheetdaysoffset <Number>] [tdsheethoursoffset <Number>])|
|
||||
(tdtimestamp [<Boolean>] [tdtimeformat <String>]
|
||||
([tddaysoffset <Number>] [tdhoursoffset <Number>])|
|
||||
[tddaysoffset <Number>] [tdhoursoffset <Number>])|
|
||||
(tdtimezone <TimeZone>)|
|
||||
(tdtitle <String>)|
|
||||
(tdupdatesheet [<Boolean>])|
|
||||
@@ -725,7 +726,7 @@ If an item contains spaces, it should be surrounded by ".
|
||||
<QueryMobileList> ::= "<QueryMobile>(,<QueryMobile>)*"
|
||||
<QueryUserList> ::= "<QueryUser>(,<QueryUser>)*"
|
||||
<ResourceIDList> ::= "<ResourceID>(,<ResourceID>)*"
|
||||
<SchemaNameList> ::= "<SchemaName>(,<SchemaName>)*"
|
||||
<SchemaNameList> ::= "<SchemaName>|<SchemaFieldName>(,<SchemaName>|<SchemaFieldName>)*"
|
||||
<SerialNumberList> ::= "<SerialNumber>(,<SerialNumber>)*"
|
||||
<ServiceAccountKeyList> ::= "<ServiceAccountKey>(,<ServiceAccountKey>)*"
|
||||
<SiteACLScopeList> ::= "<SiteACLScope>(,<SiteACLScope>)*"
|
||||
@@ -4220,7 +4221,8 @@ gam report usage customer [todrive <ToDriveAttribute>*]
|
||||
rules|
|
||||
saml|
|
||||
token|tokens|oauthtoken|
|
||||
useraccounts
|
||||
useraccounts|
|
||||
vault
|
||||
|
||||
gam report <ActivityApplicationName> [todrive <ToDriveAttribute>*]
|
||||
[(user all|<UserItem>)|(orgunit|org|ou <OrgUnitPath> [showorgunit])|(select <UserTypeEntity>)]
|
||||
@@ -4991,7 +4993,7 @@ gam <UserTypeEntity> show teamdriveacls
|
||||
(field:<UserReplacementField>)|
|
||||
(field:<UserReplacementFieldSubfield>)|
|
||||
(field:<UserReplacementFieldSubfieldMatchSubfield>)|
|
||||
(schema:<SchemaName>.<FieldName>)|
|
||||
(schema:<SchemaNameField>)|
|
||||
<String>
|
||||
|
||||
# Vault/Takeout
|
||||
@@ -5256,9 +5258,9 @@ gam download storagefile <StorageBucketObjectName>
|
||||
(recoveryemail <EmailAddress>)|
|
||||
(recoveryphone <string>)|
|
||||
(suspend|suspended <Boolean>)|
|
||||
(<SchemaName>.<FieldName> [scalarnonempty|
|
||||
[multivalued|multivalue|value|multinonempty [type home|other|work|(custom <String>)]]]
|
||||
<String>)
|
||||
(<SchemaNameField> [scalarnonempty|
|
||||
[multivalued|multivalue|value|multinonempty [type home|other|work|(custom <String>)]]]
|
||||
<String>)
|
||||
|
||||
<UserMultiAttribute> ::=
|
||||
(address type home|other|work|(custom <String>)
|
||||
@@ -5347,7 +5349,7 @@ gam update user <UserItem> [ignorenullpassword] <UserAttribute>*
|
||||
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
|
||||
[fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]]
|
||||
[immutableous <OrgUnitEntity>]|
|
||||
[clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>]
|
||||
[clearschema <SchemaName> | <SchemaNameField>]
|
||||
[createifnotfound] [notfoundpassword (random [<Integer>])|blocklogin|<Password>]
|
||||
(groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)*
|
||||
[alias|aliases <EmailAddressList>]
|
||||
@@ -5382,7 +5384,7 @@ gam update users <UserTypeEntity> [ignorenullpassword] <UserAttribute>*
|
||||
[updateoufromgroup <FileName> [charset <CharSet>]
|
||||
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
|
||||
[fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]]
|
||||
[clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>]
|
||||
[clearschema <SchemaName>|<SchemaNameField>]
|
||||
[createifnotfound] [notfoundpassword (random [<Integer>])|blocklogin|<Password>]
|
||||
(groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)*
|
||||
[alias|aliases <EmailAddressList>]
|
||||
@@ -5415,7 +5417,7 @@ gam <UserTypeEntity> update users [ignorenullpassword] <UserAttribute>*
|
||||
[verifynotinvitable] [noactionifalias]
|
||||
[updateprimaryemail <RegularExpression> <EmailReplacement>]
|
||||
[updateoufromgroup <CSVFileInput> [keyfield <FieldName>] [datafield <FieldName>]]
|
||||
[clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>]
|
||||
[clearschema <SchemaName> | <SchemaNameField>]
|
||||
[createifnotfound] [notfoundpassword (random [<Integer>])|blocklogin|<Password>]
|
||||
(groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)*
|
||||
[alias|aliases <EmailAddressList>]
|
||||
@@ -6904,8 +6906,12 @@ gam <UserTypeEntity> print|show driveactivity [todrive <ToDriveAttribute>*]
|
||||
usageindrivetrash
|
||||
<DriveSettingsFieldNameList> ::= "<DriveSettingsFieldName>(,<DriveSettingsFieldName>)*"
|
||||
|
||||
gam <UserTypeEntity> print drivesettings [todrive <ToDriveAttribute>*] [allfields|<DriveSettingsFieldName>*|(fields <DriveSettingsFieldNameList>)] [delimiter <Character>]
|
||||
gam <UserTypeEntity> show drivesettings [allfields|<DriveSettingsFieldName>*|(fields <DriveSettingsFieldNameList>)] [delimiter <Character>]
|
||||
gam <UserTypeEntity> print drivesettings [todrive <ToDriveAttribute>*]
|
||||
[allfields|<DriveSettingsFieldName>*|(fields <DriveSettingsFieldNameList>)]
|
||||
[delimiter <Character>] [showusagebytes]
|
||||
gam <UserTypeEntity> show drivesettings
|
||||
[allfields|<DriveSettingsFieldName>*|(fields <DriveSettingsFieldNameList>)]
|
||||
[delimiter <Character>] [showusagebytes]
|
||||
|
||||
gam <UserTypeEntity> print emptydrivefolders [todrive <ToDriveAttribute>*]
|
||||
[select <DriveFileEntity>]
|
||||
@@ -7222,9 +7228,10 @@ gam <UserTypeEntity> print messages|threads [todrive <ToDriveAttribute>*]
|
||||
[countsonly|positivecountsonly] [useronly]
|
||||
[headers all|<SMTPHeaderList>] [dateheaderformat iso|rfc2822|<String> [dateheaderconverttimezone [<Boolean>]]]
|
||||
[showlabels] [delimiter <Character>] [showbody] [showdate] [showsize] [showsnippet]
|
||||
[convertcrnl] [delimiter <Character>]
|
||||
[[attachmentnamepattern <RegularExpression>]
|
||||
[showattachments [noshowtextplain]]]
|
||||
[convertcrnl]
|
||||
(addcsvdata <FieldName> <String>)*
|
||||
|
||||
# Users - Gmail - Profile
|
||||
|
||||
|
||||
@@ -2,6 +2,42 @@
|
||||
|
||||
Merged GAM-Team version
|
||||
|
||||
6.76.10
|
||||
|
||||
Added `fromgmail` to `<EventType>` that can be used in `gam calendars <CalendarEntity> print|show events ... eventtype fromgmail`.
|
||||
|
||||
* See: https://workspaceupdates.googleblog.com/2024/05/google-calendar-api-event-type-fromgmail.html
|
||||
|
||||
6.76.09
|
||||
|
||||
Updated `gam update|delete|info adminrole` to handle the following error:
|
||||
```
|
||||
ERROR: 400: failedPrecondition - Precondition check failed.
|
||||
```
|
||||
|
||||
6.76.08
|
||||
|
||||
Updated `<SchemaNameList>` to `"<SchemaName>|<SchemaFieldName>(,<SchemaName>|<SchemaFieldName>)*"`
|
||||
that allows `schemas <SchemaNameList>` in `gam info user` and `gam print users` to display all fields or selected fields
|
||||
of the specified custom schemas.
|
||||
|
||||
6.76.07
|
||||
|
||||
Fixed bug where control-C was not recognized when GAM had processed all rows in a CSV file
|
||||
and was `Waiting for N running processes to finish before terminating`.
|
||||
|
||||
6.76.06
|
||||
|
||||
Fixed bug in `gam <UserTypeEntity> print messages ... positivecountsonly` where message counts with value 0 were deiplayed.
|
||||
|
||||
Added option `addcsvdata <FieldName> <String>` to `gam <UserTypeEntity> print|messages` that adds
|
||||
additional columns of data to the CSV file output.
|
||||
|
||||
Added option `showusagebytes` to `gam <UserTypeEntity> print|show drivesettings` that displays
|
||||
the following fields in bytes ```usageBytes,usageInDriveBytes,usageInDriveTrashBytes```
|
||||
in addition to the fields in their formatted form with units: ```usage,usageInDrive,usageInDriveTrash```.
|
||||
This will be most useful with `print` as the rows can be sorted based on the `usagexxxBytes` columns.
|
||||
|
||||
6.76.05
|
||||
|
||||
Added options `deletefromoldowner`, `addtonewowner <CalendarAttribute>*` and `nolistmessages`
|
||||
|
||||
@@ -4163,6 +4163,8 @@ def SetGlobalVariables():
|
||||
GC.Values[GC.PRINT_CROS_OUS] = GM.Globals[GM.PRINT_CROS_OUS]
|
||||
if not GC.Values[GC.PRINT_CROS_OUS_AND_CHILDREN]:
|
||||
GC.Values[GC.PRINT_CROS_OUS_AND_CHILDREN] = GM.Globals[GM.PRINT_CROS_OUS_AND_CHILDREN]
|
||||
GC.Values[GC.SHOW_GETTINGS] = GM.Globals[GM.SHOW_GETTINGS]
|
||||
GC.Values[GC.SHOW_GETTINGS_GOT_NL] = GM.Globals[GM.SHOW_GETTINGS_GOT_NL]
|
||||
# customer_id, domain and admin_email must be set when enable_dasa = true
|
||||
if GC.Values[GC.ENABLE_DASA]:
|
||||
errors = 0
|
||||
@@ -9574,6 +9576,7 @@ def ProcessGAMCommandMulti(pid, numItems, logCmd, mpQueueCSVFile, mpQueueStdout,
|
||||
csvHeaderForce,
|
||||
csvRowFilter, csvRowFilterMode, csvRowDropFilter, csvRowDropFilterMode,
|
||||
csvRowLimit,
|
||||
showGettings, showGettingsGotNL,
|
||||
args):
|
||||
global mplock
|
||||
|
||||
@@ -9612,6 +9615,8 @@ def ProcessGAMCommandMulti(pid, numItems, logCmd, mpQueueCSVFile, mpQueueStdout,
|
||||
GM.Globals[GM.PRINT_CROS_OUS] = printCrosOUs
|
||||
GM.Globals[GM.PRINT_CROS_OUS_AND_CHILDREN] = printCrosOUsAndChildren
|
||||
GM.Globals[GM.SAVED_STDOUT] = None
|
||||
GM.Globals[GM.SHOW_GETTINGS] = showGettings
|
||||
GM.Globals[GM.SHOW_GETTINGS_GOT_NL] = showGettingsGotNL
|
||||
GM.Globals[GM.SYSEXITRC] = 0
|
||||
GM.Globals[GM.PARSER] = None
|
||||
if mpQueueCSVFile:
|
||||
@@ -9690,16 +9695,18 @@ def MultiprocessGAMCommands(items, showCmds):
|
||||
GM.Globals[GM.MULTIPROCESS_EXIT_PROCESSING] = True
|
||||
|
||||
def signal_handler(sig, frame):
|
||||
controlC['trapped'] = True
|
||||
nonlocal controlC
|
||||
controlC = True
|
||||
|
||||
def handleControlC(source):
|
||||
nonlocal controlC
|
||||
batchWriteStderr(f'Control-C (Multiprocess-{source})\n')
|
||||
setSysExitRC(KEYBOARD_INTERRUPT_RC)
|
||||
batchWriteStderr(Msg.BATCH_CSV_TERMINATE_N_PROCESSES.format(currentISOformatTimeStamp(),
|
||||
numItems, poolProcessResults[0],
|
||||
PROCESS_PLURAL_SINGULAR[poolProcessResults[0] == 1]))
|
||||
pool.terminate()
|
||||
controlC['trapped'] = False
|
||||
controlC = False
|
||||
|
||||
if not items:
|
||||
return
|
||||
@@ -9753,7 +9760,7 @@ def MultiprocessGAMCommands(items, showCmds):
|
||||
else:
|
||||
mpQueueCSVFile = None
|
||||
# signal.signal(signal.SIGINT, origSigintHandler)
|
||||
controlC = {'trapped': False}
|
||||
controlC = False
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
batchWriteStderr(Msg.USING_N_PROCESSES.format(currentISOformatTimeStamp(),
|
||||
numItems, numPoolProcesses,
|
||||
@@ -9764,7 +9771,7 @@ def MultiprocessGAMCommands(items, showCmds):
|
||||
for item in items:
|
||||
if GM.Globals[GM.MULTIPROCESS_EXIT_PROCESSING]:
|
||||
break
|
||||
if controlC['trapped']:
|
||||
if controlC:
|
||||
break
|
||||
if item[0] == Cmd.COMMIT_BATCH_CMD:
|
||||
batchWriteStderr(Msg.COMMIT_BATCH_WAIT_N_PROCESSES.format(currentISOformatTimeStamp(),
|
||||
@@ -9818,6 +9825,7 @@ def MultiprocessGAMCommands(items, showCmds):
|
||||
GC.Values[GC.CSV_OUTPUT_ROW_DROP_FILTER],
|
||||
GC.Values[GC.CSV_OUTPUT_ROW_DROP_FILTER_MODE],
|
||||
GC.Values[GC.CSV_OUTPUT_ROW_LIMIT],
|
||||
GC.Values[GC.SHOW_GETTINGS], GC.Values[GC.SHOW_GETTINGS_GOT_NL],
|
||||
item])
|
||||
poolProcessResults[0] += 1
|
||||
if parallelPoolProcesses > 0:
|
||||
@@ -9833,7 +9841,7 @@ def MultiprocessGAMCommands(items, showCmds):
|
||||
break
|
||||
time.sleep(1)
|
||||
processWaitStart = time.time()
|
||||
if not controlC['trapped']:
|
||||
if not controlC:
|
||||
if GC.Values[GC.PROCESS_WAIT_LIMIT] > 0:
|
||||
waitRemaining = GC.Values[GC.PROCESS_WAIT_LIMIT]
|
||||
else:
|
||||
@@ -9851,6 +9859,9 @@ def MultiprocessGAMCommands(items, showCmds):
|
||||
for p in completedProcesses:
|
||||
del poolProcessResults[p]
|
||||
if poolProcessResults[0] > 0:
|
||||
if controlC:
|
||||
handleControlC('SIG')
|
||||
break
|
||||
time.sleep(5)
|
||||
if GC.Values[GC.PROCESS_WAIT_LIMIT] > 0:
|
||||
delta = int(time.time()-processWaitStart)
|
||||
@@ -12358,7 +12369,7 @@ def _formatOAuth2ServiceData(service_data):
|
||||
GM.Globals[GM.OAUTH2SERVICE_JSON_DATA] = service_data.copy()
|
||||
return json.dumps(GM.Globals[GM.OAUTH2SERVICE_JSON_DATA], indent=2, sort_keys=True)
|
||||
|
||||
def doProcessSvcAcctKeys(mode, iam=None, projectId=None, clientEmail=None, clientId=None):
|
||||
def doProcessSvcAcctKeys(mode=None, iam=None, projectId=None, clientEmail=None, clientId=None):
|
||||
def getSAKeyParms(body, new_data):
|
||||
nonlocal local_key_size, validityHours
|
||||
while Cmd.ArgumentsRemaining():
|
||||
@@ -12380,7 +12391,7 @@ def doProcessSvcAcctKeys(mode, iam=None, projectId=None, clientEmail=None, clien
|
||||
new_data['yubikey_serial_number'] = getInteger()
|
||||
else:
|
||||
unknownArgumentExit()
|
||||
|
||||
|
||||
def waitForCompletion(i):
|
||||
sleep_time = i*5
|
||||
if i > 3:
|
||||
@@ -12390,6 +12401,8 @@ def doProcessSvcAcctKeys(mode, iam=None, projectId=None, clientEmail=None, clien
|
||||
local_key_size = 2048
|
||||
validityHours = 0
|
||||
body = {}
|
||||
if mode is None:
|
||||
mode = getChoice(['retainnone', 'retainexisting', 'replacecurrent'])
|
||||
if iam is None or mode == 'upload':
|
||||
if iam is None:
|
||||
_, iam = buildGAPIServiceObject(API.IAM, None)
|
||||
@@ -13284,6 +13297,7 @@ REPORT_CHOICE_MAP = {
|
||||
'user': 'user',
|
||||
'users': 'user',
|
||||
'useraccounts': 'user_accounts',
|
||||
'vault': 'vault',
|
||||
}
|
||||
|
||||
REPORT_ACTIVITIES_UPPERCASE_EVENTS = {
|
||||
@@ -16175,12 +16189,12 @@ def doCreateUpdateAdminRoles():
|
||||
customer=GC.Values[GC.CUSTOMER_ID], body=body, fields='roleId,roleName')
|
||||
else:
|
||||
result = callGAPI(cd.roles(), 'patch',
|
||||
throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND, GAPI.FORBIDDEN]+[GAPI.NOT_FOUND],
|
||||
throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND, GAPI.FORBIDDEN]+[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION],
|
||||
customer=GC.Values[GC.CUSTOMER_ID], roleId=roleId, body=body, fields='roleId,roleName')
|
||||
entityActionPerformed([Ent.ADMIN_ROLE, f"{result['roleName']}({result['roleId']})"])
|
||||
except GAPI.duplicate as e:
|
||||
entityActionFailedWarning([Ent.ADMIN_ROLE, f"{body['roleName']}"], str(e))
|
||||
except (GAPI.notFound, GAPI.forbidden) as e:
|
||||
except (GAPI.notFound, GAPI.forbidden, GAPI.failedPrecondition) as e:
|
||||
entityActionFailedWarning([Ent.ADMIN_ROLE, roleId], str(e))
|
||||
except (GAPI.badRequest, GAPI.customerNotFound):
|
||||
accessErrorExit(cd)
|
||||
@@ -16192,10 +16206,10 @@ def doDeleteAdminRole():
|
||||
checkForExtraneousArguments()
|
||||
try:
|
||||
callGAPI(cd.roles(), 'delete',
|
||||
throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND, GAPI.FORBIDDEN]+[GAPI.NOT_FOUND],
|
||||
throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND, GAPI.FORBIDDEN]+[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION],
|
||||
customer=GC.Values[GC.CUSTOMER_ID], roleId=roleId)
|
||||
entityActionPerformed([Ent.ADMIN_ROLE, f"{role}({roleId})"])
|
||||
except (GAPI.notFound, GAPI.forbidden) as e:
|
||||
except (GAPI.notFound, GAPI.forbidden, GAPI.failedPrecondition) as e:
|
||||
entityActionFailedWarning([Ent.ADMIN_ROLE, roleId], str(e))
|
||||
except (GAPI.badRequest, GAPI.customerNotFound):
|
||||
accessErrorExit(cd)
|
||||
@@ -16236,12 +16250,12 @@ def doInfoAdminRole():
|
||||
fields = ','.join(set(fieldsList))
|
||||
try:
|
||||
role = callGAPI(cd.roles(), 'get',
|
||||
throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND, GAPI.FORBIDDEN]+[GAPI.NOT_FOUND],
|
||||
throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND, GAPI.FORBIDDEN]+[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION],
|
||||
customer=GC.Values[GC.CUSTOMER_ID], roleId=roleId, fields=fields)
|
||||
role.setdefault('isSuperAdminRole', False)
|
||||
role.setdefault('isSystemRole', False)
|
||||
_showAdminRole(role)
|
||||
except (GAPI.notFound, GAPI.forbidden) as e:
|
||||
except (GAPI.notFound, GAPI.forbidden, GAPI.failedPrecondition) as e:
|
||||
entityActionFailedWarning([Ent.ADMIN_ROLE, roleId], str(e))
|
||||
except (GAPI.badRequest, GAPI.customerNotFound):
|
||||
accessErrorExit(cd)
|
||||
@@ -16395,9 +16409,9 @@ def doPrintShowAdmins():
|
||||
if roleId not in rolePrivileges:
|
||||
try:
|
||||
rolePrivileges[roleId] = callGAPI(cd.roles(), 'get',
|
||||
throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND, GAPI.FORBIDDEN]+[GAPI.NOT_FOUND],
|
||||
throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND, GAPI.FORBIDDEN]+[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION],
|
||||
customer=GC.Values[GC.CUSTOMER_ID], roleId=roleId, fields='rolePrivileges')
|
||||
except (GAPI.notFound, GAPI.forbidden) as e:
|
||||
except (GAPI.notFound, GAPI.forbidden, GAPI.failedPrecondition) as e:
|
||||
entityActionFailedExit([Ent.USER, userKey, Ent.ADMIN_ROLE, admin['roleId']], str(e))
|
||||
rolePrivileges[roleId] = None
|
||||
except (GAPI.badRequest, GAPI.customerNotFound):
|
||||
@@ -25470,6 +25484,11 @@ def _getChatPageMessage(entityType, user, i, count, pfilter):
|
||||
return getPageMessage()
|
||||
|
||||
CHAT_PAGE_SIZE = 1000
|
||||
CHAT_SPACES_ADMIN_ORDERBY_CHOICE_MAP = {
|
||||
'createtime': 'createTime',
|
||||
'lastactivetime': 'lastActiveTime',
|
||||
'membershipcount': 'membershipCount.joined_direct_human_user_count'
|
||||
}
|
||||
|
||||
# gam [<UserTypeEntity>] show chatspaces
|
||||
# [types <ChatSpaceTypeList>]
|
||||
@@ -25477,15 +25496,34 @@ CHAT_PAGE_SIZE = 1000
|
||||
# gam [<UserTypeEntity>] print chatspaces [todrive <ToDriveAttribute>*]
|
||||
# [types <ChatSpaceTypeList>]
|
||||
# [formatjson [quotechar <Character>]]
|
||||
# gam [<UserTypeEntity>] show chatspaces adminaccess|asadmin
|
||||
# [query <String>]]
|
||||
# [orderby <ChatSpaceAdminOrderByFieldName> [ascending|descending]]
|
||||
# [formatjson]
|
||||
# gam [<UserTypeEntity>] print chatspaces adminaccess|asadmin [todrive <ToDriveAttribute>*]
|
||||
# [query <String>]]
|
||||
# [orderby <ChatSpaceAdminOrderByFieldName> [ascending|descending]]
|
||||
# [formatjson [quotechar <Character>]]
|
||||
def printShowChatSpaces(users):
|
||||
csvPF = CSVPrintFile(['User', 'name'] if not isinstance(users, list) else ['name']) if Act.csvFormat() else None
|
||||
FJQC = FormatJSONQuoteChar(csvPF)
|
||||
useAdminAccess = checkArgumentPresent(ADMIN_ACCESS_OPTIONS)
|
||||
OBY = OrderBy(CHAT_SPACES_ADMIN_ORDERBY_CHOICE_MAP)
|
||||
pfilter = ''
|
||||
kwargs = {}
|
||||
if not useAdminAccess:
|
||||
api = API.CHAT_SPACES
|
||||
function = 'list'
|
||||
else:
|
||||
api = API.CHAT_SPACES_ADMIN
|
||||
function = 'search'
|
||||
kwargs['useAdminAccess'] = True
|
||||
kwargs['query'] = 'customer = "customers/my_customer" AND spaceType = "SPACE"'
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if csvPF and myarg == 'todrive':
|
||||
csvPF.GetTodriveParameters()
|
||||
elif myarg in {'type', 'types'}:
|
||||
elif not useAdminAccess and myarg in {'type', 'types'}:
|
||||
for ctype in getString(Cmd.OB_GROUP_ROLE_LIST).lower().replace(',', ' ').split():
|
||||
if ctype in CHAT_SPACE_TYPE_MAP:
|
||||
if pfilter:
|
||||
@@ -25493,23 +25531,30 @@ def printShowChatSpaces(users):
|
||||
pfilter += f'spaceType = "{CHAT_SPACE_TYPE_MAP[ctype]}"'
|
||||
else:
|
||||
invalidChoiceExit(ctype, CHAT_SPACE_TYPE_MAP, True)
|
||||
elif useAdminAccess and myarg == 'orderby':
|
||||
OBY.GetChoice()
|
||||
elif useAdminAccess and myarg == 'query':
|
||||
kwargs['query'] += ' AND '+ getString(Cmd.OB_QUERY)
|
||||
else:
|
||||
FJQC.GetFormatJSONQuoteChar(myarg, True)
|
||||
if not pfilter:
|
||||
pfilter = None
|
||||
if not useAdminAccess:
|
||||
if pfilter:
|
||||
kwargs['filter'] = pfilter
|
||||
else:
|
||||
kwargs['orderBy'] = OBY.orderBy
|
||||
i, count, users = getEntityArgument(users)
|
||||
for user in users:
|
||||
i += 1
|
||||
user, chat, kvList = buildChatServiceObject(API.CHAT_SPACES, user, i, count)
|
||||
user, chat, kvList = buildChatServiceObject(api, user, i, count)
|
||||
if not chat:
|
||||
continue
|
||||
try:
|
||||
spaces = callGAPIpages(chat.spaces(), 'list', 'spaces',
|
||||
spaces = callGAPIpages(chat.spaces(), function, 'spaces',
|
||||
pageMessage=_getChatPageMessage(Ent.CHAT_SPACE, user, i, count, pfilter),
|
||||
bailOnInternalError=True,
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.INTERNAL_ERROR,
|
||||
GAPI.PERMISSION_DENIED, GAPI.FAILED_PRECONDITION],
|
||||
pageSize=CHAT_PAGE_SIZE, filter=pfilter)
|
||||
pageSize=CHAT_PAGE_SIZE, **kwargs)
|
||||
except (GAPI.notFound, GAPI.invalidArgument, GAPI.internalError,
|
||||
GAPI.permissionDenied, GAPI.failedPrecondition) as e:
|
||||
exitIfChatNotConfigured(chat, kvList, str(e), i, count)
|
||||
@@ -36146,32 +36191,36 @@ def doCalendarsPrintShowACLs(calIds):
|
||||
|
||||
EVENT_TYPE_DEFAULT = 'default'
|
||||
EVENT_TYPE_FOCUSTIME = 'focusTime'
|
||||
EVENT_TYPE_FROMGMAIL = 'fromGmail'
|
||||
EVENT_TYPE_OUTOFOFFICE = 'outOfOffice'
|
||||
EVENT_TYPE_WORKINGLOCATION = 'workingLocation'
|
||||
|
||||
EVENT_TYPES_CHOICE_MAP = {
|
||||
'default': EVENT_TYPE_DEFAULT,
|
||||
'focustime': EVENT_TYPE_FOCUSTIME,
|
||||
'fromgmail': EVENT_TYPE_FROMGMAIL,
|
||||
'outofoffice': EVENT_TYPE_OUTOFOFFICE,
|
||||
'workinglocation': EVENT_TYPE_WORKINGLOCATION,
|
||||
}
|
||||
|
||||
EVENT_TYPE_DEFAULT_PROPERTIES_MAP = {
|
||||
EVENT_TYPE_DEFAULT: {'eventType': EVENT_TYPE_DEFAULT},
|
||||
EVENT_TYPE_FOCUSTIME: {'eventType': EVENT_TYPE_FOCUSTIME,
|
||||
'focusTimeProperties': {'autoDeclineMode': 'declineNone', 'declineMessage': 'Declined', 'chatStatus': 'doNotDisturb'},
|
||||
'transparency':'opaque'},
|
||||
EVENT_TYPE_OUTOFOFFICE: {'eventType': EVENT_TYPE_OUTOFOFFICE,
|
||||
'outOfOfficeProperties': {'autoDeclineMode': 'declineOnlyNewConflictingInvitations', 'declineMessage': 'Declined'},
|
||||
'transparency':'opaque'},
|
||||
EVENT_TYPE_WORKINGLOCATION: {'eventType': EVENT_TYPE_WORKINGLOCATION,
|
||||
'workingLocationProperties': {},
|
||||
'visibility': 'public', 'transparency':'transparent'},
|
||||
}
|
||||
#EVENT_TYPE_DEFAULT_PROPERTIES_MAP = {
|
||||
# EVENT_TYPE_DEFAULT: {'eventType': EVENT_TYPE_DEFAULT},
|
||||
# EVENT_TYPE_FOCUSTIME: {'eventType': EVENT_TYPE_FOCUSTIME,
|
||||
# 'focusTimeProperties': {'autoDeclineMode': 'declineNone', 'declineMessage': 'Declined', 'chatStatus': 'doNotDisturb'},
|
||||
# 'transparency':'opaque'},
|
||||
# EVENT_TYPE_FROMGMAIL: {'eventType': EVENT_TYPE_FROMGMAIL},
|
||||
# EVENT_TYPE_OUTOFOFFICE: {'eventType': EVENT_TYPE_OUTOFOFFICE,
|
||||
# 'outOfOfficeProperties': {'autoDeclineMode': 'declineOnlyNewConflictingInvitations', 'declineMessage': 'Declined'},
|
||||
# 'transparency':'opaque'},
|
||||
# EVENT_TYPE_WORKINGLOCATION: {'eventType': EVENT_TYPE_WORKINGLOCATION,
|
||||
# 'workingLocationProperties': {},
|
||||
# 'visibility': 'public', 'transparency':'transparent'},
|
||||
# }
|
||||
|
||||
EVENT_TYPE_PROPERTIES_NAME_MAP = {
|
||||
EVENT_TYPE_DEFAULT: None,
|
||||
EVENT_TYPE_FOCUSTIME: f'{EVENT_TYPE_FOCUSTIME}Properties',
|
||||
EVENT_TYPE_FROMGMAIL: None,
|
||||
EVENT_TYPE_OUTOFOFFICE: f'{EVENT_TYPE_OUTOFOFFICE}Properties',
|
||||
EVENT_TYPE_WORKINGLOCATION: f'{EVENT_TYPE_WORKINGLOCATION}Properties',
|
||||
}
|
||||
@@ -36179,6 +36228,7 @@ EVENT_TYPE_PROPERTIES_NAME_MAP = {
|
||||
EVENT_TYPE_ENTITY_MAP = {
|
||||
EVENT_TYPE_DEFAULT: None,
|
||||
EVENT_TYPE_FOCUSTIME: Ent.EVENT_FOCUSTIME,
|
||||
EVENT_TYPE_FROMGMAIL: None,
|
||||
EVENT_TYPE_OUTOFOFFICE: Ent.EVENT_OUTOFOFFICE,
|
||||
EVENT_TYPE_WORKINGLOCATION: Ent.EVENT_WORKINGLOCATION,
|
||||
}
|
||||
@@ -41875,7 +41925,7 @@ def verifyUserPrimaryEmail(cd, user, createIfNotFound, i, count):
|
||||
# [updateprimaryemail <RegularExpression> <EmailReplacement>]
|
||||
# [updateoufromgroup <CSVFileInput> [keyfield <FieldName>] [datafield <FieldName>]]
|
||||
# [immutableous <OrgUnitEntity>]|
|
||||
# [clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>]
|
||||
# [clearschema <SchemaName>|<SchemaNameField>]
|
||||
# [createifnotfound] [notfoundpassword (random [<Integer>])|blocklogin|<Password>]
|
||||
# (groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)*
|
||||
# [alias|aliases <EmailAddressList>]
|
||||
@@ -42481,6 +42531,44 @@ def _formatLanguagesList(propertyValue, delimiter):
|
||||
languages.append(lang)
|
||||
return delimiter.join(languages)
|
||||
|
||||
def _initSchemaParms(projection):
|
||||
return {'projection': projection, 'customFieldMask': None, 'selectedSchemaFields': {}}
|
||||
|
||||
def _getSchemaNameList(schemaParms):
|
||||
customFieldMask = getString(Cmd.OB_SCHEMA_NAME_LIST).replace(' ', ',')
|
||||
if customFieldMask.lower() == 'all':
|
||||
schemaParms['projection'] = 'full'
|
||||
schemaParms['customFieldMask'] = None
|
||||
schemaParms['selectedSchemaFields'] = {}
|
||||
else:
|
||||
schemaParms['projection'] = 'custom'
|
||||
customFieldMaskList = []
|
||||
for schemaField in customFieldMask.split(','):
|
||||
if schemaField.find('.') == -1:
|
||||
customFieldMaskList.append(schemaField)
|
||||
else:
|
||||
schemaName, fieldName = schemaField.split('.', 1)
|
||||
customFieldMaskList.append(schemaName)
|
||||
schemaParms['selectedSchemaFields'] .setdefault(schemaName, set())
|
||||
schemaParms['selectedSchemaFields'][schemaName].add(fieldName)
|
||||
schemaParms['customFieldMask'] = ','.join(customFieldMaskList)
|
||||
|
||||
def _filterSchemaFields(userEntity, schemaParms):
|
||||
schemas = userEntity.pop('customSchemas', None)
|
||||
if schemas is None:
|
||||
return
|
||||
customSchemas = {}
|
||||
for schema in sorted(schemas):
|
||||
if schema in schemaParms['selectedSchemaFields']:
|
||||
for field, value in sorted(iter(schemas[schema].items())):
|
||||
if field not in schemaParms['selectedSchemaFields'][schema]:
|
||||
continue
|
||||
customSchemas.setdefault(schema, {})
|
||||
customSchemas[schema][field] = value
|
||||
else:
|
||||
customSchemas[schema] = schemas[schema]
|
||||
userEntity['customSchemas'] = customSchemas
|
||||
|
||||
def infoUsers(entityList):
|
||||
def printUserCIGroupMap(parent, group_name_mappings, seen_group_count, edges, direction):
|
||||
for a_parent, a_child in edges:
|
||||
@@ -42516,8 +42604,7 @@ def infoUsers(entityList):
|
||||
getAliases = getBuildingNames = getCIGroupsTree = getGroups = getLicenses = getSchemas = not GC.Values[GC.QUICK_INFO_USER]
|
||||
getGroupsTree = False
|
||||
FJQC = FormatJSONQuoteChar()
|
||||
projection = 'full'
|
||||
customFieldMask = None
|
||||
schemaParms = _initSchemaParms('full')
|
||||
viewType = 'admin_view'
|
||||
fieldsList = []
|
||||
groups = []
|
||||
@@ -42540,19 +42627,13 @@ def infoUsers(entityList):
|
||||
getLicenses = myarg in {'licenses', 'licences'}
|
||||
elif myarg == 'noschemas':
|
||||
getSchemas = False
|
||||
projection = 'basic'
|
||||
schemaParms = _initSchemaParms('basic')
|
||||
elif myarg == 'allschemas':
|
||||
getSchemas = True
|
||||
projection = 'full'
|
||||
schemaParms = _initSchemaParms('full')
|
||||
elif myarg in {'custom', 'schemas', 'customschemas'}:
|
||||
getSchemas = True
|
||||
customFieldMask = getString(Cmd.OB_SCHEMA_NAME_LIST).replace(' ', ',')
|
||||
if customFieldMask.lower() == 'all':
|
||||
customFieldMask = None
|
||||
projection = 'full'
|
||||
else:
|
||||
projection = 'custom'
|
||||
fieldsList.append('customSchemas')
|
||||
_getSchemaNameList(schemaParms)
|
||||
elif myarg in {'products', 'product'}:
|
||||
skus = SKU.convertProductListToSKUList(getGoogleProductList())
|
||||
elif myarg in {'sku', 'skus'}:
|
||||
@@ -42569,6 +42650,8 @@ def infoUsers(entityList):
|
||||
FJQC.GetFormatJSON(myarg)
|
||||
if fieldsList:
|
||||
fieldsList.append('primaryEmail')
|
||||
if getSchemas:
|
||||
fieldsList.append('customSchemas')
|
||||
if getAliases:
|
||||
fieldsList.extend(['aliases', 'nonEditableAliases'])
|
||||
fields = getFieldsFromFieldsList(fieldsList)
|
||||
@@ -42585,7 +42668,8 @@ def infoUsers(entityList):
|
||||
try:
|
||||
user = callGAPI(cd.users(), 'get',
|
||||
throwReasons=GAPI.USER_GET_THROW_REASONS+[GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND],
|
||||
userKey=userEmail, projection=projection, customFieldMask=customFieldMask, viewType=viewType, fields=fields)
|
||||
userKey=userEmail, projection=schemaParms['projection'], customFieldMask=schemaParms['customFieldMask'],
|
||||
viewType=viewType, fields=fields)
|
||||
groups = []
|
||||
memberships = []
|
||||
if getGroups or getGroupsTree:
|
||||
@@ -42817,25 +42901,29 @@ def infoUsers(entityList):
|
||||
typeKey = userProperty[UProp.TYPE_KEYWORDS][UProp.PTKW_ATTR_TYPE_KEYWORD]
|
||||
typeCustomValue = userProperty[UProp.TYPE_KEYWORDS][UProp.PTKW_ATTR_TYPE_CUSTOM_VALUE]
|
||||
customTypeKey = userProperty[UProp.TYPE_KEYWORDS][UProp.PTKW_ATTR_CUSTOMTYPE_KEYWORD]
|
||||
printKeyValueList([UProp.PROPERTIES[up][UProp.TITLE], None])
|
||||
Ind.Increment()
|
||||
for schema in sorted(propertyValue):
|
||||
printKeyValueList(['Schema', schema])
|
||||
if schemaParms['selectedSchemaFields']:
|
||||
_filterSchemaFields(user, schemaParms)
|
||||
propertyValue = user[up]
|
||||
if propertyValue:
|
||||
printKeyValueList([UProp.PROPERTIES[up][UProp.TITLE], None])
|
||||
Ind.Increment()
|
||||
for field in propertyValue[schema]:
|
||||
if isinstance(propertyValue[schema][field], list):
|
||||
printKeyValueList([field])
|
||||
Ind.Increment()
|
||||
for an_item in propertyValue[schema][field]:
|
||||
_showType(an_item, typeKey, typeCustomValue, customTypeKey, defaultType='work')
|
||||
for schema in sorted(propertyValue):
|
||||
printKeyValueList(['Schema', schema])
|
||||
Ind.Increment()
|
||||
for field in propertyValue[schema]:
|
||||
if isinstance(propertyValue[schema][field], list):
|
||||
printKeyValueList([field])
|
||||
Ind.Increment()
|
||||
printKeyValueList(['value', an_item['value']])
|
||||
for an_item in propertyValue[schema][field]:
|
||||
_showType(an_item, typeKey, typeCustomValue, customTypeKey, defaultType='work')
|
||||
Ind.Increment()
|
||||
printKeyValueList(['value', an_item['value']])
|
||||
Ind.Decrement()
|
||||
Ind.Decrement()
|
||||
Ind.Decrement()
|
||||
else:
|
||||
printKeyValueList([field, propertyValue[schema][field]])
|
||||
else:
|
||||
printKeyValueList([field, propertyValue[schema][field]])
|
||||
Ind.Decrement()
|
||||
Ind.Decrement()
|
||||
Ind.Decrement()
|
||||
if getAliases:
|
||||
for up in ['aliases', 'nonEditableAliases']:
|
||||
propertyValue = user.get(up, [])
|
||||
@@ -42900,8 +42988,8 @@ def infoUsers(entityList):
|
||||
GAPI.badRequest, GAPI.backendError, GAPI.systemError) as e:
|
||||
entityActionFailedWarning([Ent.USER, userEmail], str(e), i, count)
|
||||
except (GAPI.invalidInput, GAPI.invalidMember) as e:
|
||||
if customFieldMask:
|
||||
entityActionFailedWarning([Ent.USER, userEmail], invalidUserSchema(customFieldMask), i, count)
|
||||
if schemaParms['customFieldMask']:
|
||||
entityActionFailedWarning([Ent.USER, userEmail], invalidUserSchema(schemaParms['customFieldMask']), i, count)
|
||||
else:
|
||||
entityActionFailedWarning([Ent.USER, userEmail], str(e), i, count)
|
||||
|
||||
@@ -43016,6 +43104,8 @@ def doPrintUsers(entityList=None):
|
||||
phoneNumber = phone.get('value', '')
|
||||
if phoneNumber.startswith('+'):
|
||||
phone['value'] = "'"+phoneNumber
|
||||
if schemaParms['selectedSchemaFields']:
|
||||
_filterSchemaFields(userEntity, schemaParms)
|
||||
if printOptions['getGroupFeed']:
|
||||
printGettingAllEntityItemsForWhom(Ent.GROUP_MEMBERSHIP, userEmail, i, count)
|
||||
try:
|
||||
@@ -43086,8 +43176,8 @@ def doPrintUsers(entityList=None):
|
||||
entityUnknownWarning(Ent.USER, ri[RI_ITEM], int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||
else:
|
||||
_writeUserEntity({'primaryEmail': ri[RI_ITEM], showValidColumn: False})
|
||||
elif (reason == GAPI.INVALID_INPUT) and customFieldMask:
|
||||
entityActionFailedWarning([Ent.USER, ri[RI_ITEM]], invalidUserSchema(customFieldMask), int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||
elif (reason == GAPI.INVALID_INPUT) and schemaParms['customFieldMask']:
|
||||
entityActionFailedWarning([Ent.USER, ri[RI_ITEM]], invalidUserSchema(schemaParms['customFieldMask']), int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||
elif reason not in GAPI.DEFAULT_RETRY_REASONS:
|
||||
errMsg = getHTTPError(_PRINT_USER_REASON_TO_MESSAGE_MAP, http_status, reason, message)
|
||||
printKeyValueList([ERROR, errMsg])
|
||||
@@ -43096,7 +43186,8 @@ def doPrintUsers(entityList=None):
|
||||
try:
|
||||
user = callGAPI(cd.users(), 'get',
|
||||
throwReasons=GAPI.USER_GET_THROW_REASONS+[GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND, GAPI.RATE_LIMIT_EXCEEDED],
|
||||
userKey=ri[RI_ITEM], projection=projection, customFieldMask=customFieldMask, viewType=viewType, fields=fields)
|
||||
userKey=ri[RI_ITEM], projection=schemaParms['projection'], customFieldMask=schemaParms['customFieldMask'],
|
||||
viewType=viewType, fields=fields)
|
||||
_printUser(user, int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||
except (GAPI.userNotFound, GAPI.resourceNotFound):
|
||||
if not showValidColumn:
|
||||
@@ -43107,8 +43198,8 @@ def doPrintUsers(entityList=None):
|
||||
GAPI.badRequest, GAPI.backendError, GAPI.systemError, GAPI.rateLimitExceeded) as e:
|
||||
entityActionFailedWarning([Ent.USER, ri[RI_ITEM]], str(e), int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||
except GAPI.invalidInput as e:
|
||||
if customFieldMask:
|
||||
entityActionFailedWarning([Ent.USER, ri[RI_ITEM]], invalidUserSchema(customFieldMask), int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||
if schemaParms['customFieldMask']:
|
||||
entityActionFailedWarning([Ent.USER, ri[RI_ITEM]], invalidUserSchema(schemaParms['customFieldMask']), int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||
else:
|
||||
entityActionFailedWarning([Ent.USER, ri[RI_ITEM]], str(e), int(ri[RI_J]), int(ri[RI_JCOUNT]))
|
||||
|
||||
@@ -43132,9 +43223,8 @@ def doPrintUsers(entityList=None):
|
||||
lic = None
|
||||
skus = None
|
||||
maxResults = GC.Values[GC.USER_MAX_RESULTS]
|
||||
projection = 'basic'
|
||||
schemaParms = _initSchemaParms('basic')
|
||||
projectionSet = False
|
||||
customFieldMask = None
|
||||
oneLicensePerRow = quotePlusPhoneNumbers = showDeleted = False
|
||||
aliasMatchPattern = isSuspended = orgUnitPath = orgUnitPathLower = orderBy = sortOrder = None
|
||||
viewType = 'admin_view'
|
||||
@@ -43161,27 +43251,22 @@ def doPrintUsers(entityList=None):
|
||||
orderBy, sortOrder = getOrderBySortOrder(USERS_ORDERBY_CHOICE_MAP)
|
||||
elif myarg == 'userview':
|
||||
viewType = 'domain_public'
|
||||
elif myarg in {'allfields', 'basic'}:
|
||||
schemaParms = _initSchemaParms('basic')
|
||||
projectionSet = printOptions['sortHeaders'] = True
|
||||
fieldsList = []
|
||||
elif myarg == 'full':
|
||||
if schemaParms['projection'] != 'custom':
|
||||
schemaParms = _initSchemaParms(myarg)
|
||||
projectionSet = printOptions['sortHeaders'] = True
|
||||
fieldsList = []
|
||||
elif myarg in {'custom', 'schemas', 'customschemas'}:
|
||||
if not fieldsList:
|
||||
fieldsList = ['primaryEmail']
|
||||
fieldsList.append('customSchemas')
|
||||
customFieldMask = getString(Cmd.OB_SCHEMA_NAME_LIST).replace(' ', ',')
|
||||
if customFieldMask.lower() == 'all':
|
||||
customFieldMask = None
|
||||
projection = 'full'
|
||||
else:
|
||||
projection = 'custom'
|
||||
projectionSet = True
|
||||
_getSchemaNameList(schemaParms)
|
||||
if fieldsList:
|
||||
fieldsList.append('customSchemas')
|
||||
elif myarg == 'delimiter':
|
||||
delimiter = getCharacter()
|
||||
elif myarg in PROJECTION_CHOICE_MAP:
|
||||
projection = myarg
|
||||
projectionSet = printOptions['sortHeaders'] = True
|
||||
fieldsList = []
|
||||
elif myarg == 'allfields':
|
||||
projection = 'basic'
|
||||
projectionSet = printOptions['sortHeaders'] = True
|
||||
fieldsList = []
|
||||
elif myarg == 'sortheaders':
|
||||
printOptions['sortHeaders'] = getBoolean()
|
||||
elif myarg == 'scalarsfirst':
|
||||
@@ -43284,7 +43369,8 @@ def doPrintUsers(entityList=None):
|
||||
GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
|
||||
query=query, fields=fields,
|
||||
showDeleted=showDeleted, orderBy=orderBy, sortOrder=sortOrder, viewType=viewType,
|
||||
projection=projection, customFieldMask=customFieldMask, maxResults=maxResults, **kwargs)
|
||||
projection=schemaParms['projection'], customFieldMask=schemaParms['customFieldMask'],
|
||||
maxResults=maxResults, **kwargs)
|
||||
for users in feed:
|
||||
if showItemCountOnly:
|
||||
itemCount += len(users)
|
||||
@@ -43309,12 +43395,12 @@ def doPrintUsers(entityList=None):
|
||||
entityActionFailedWarning([Ent.USER, None, Ent.DOMAIN, kwargs['domain']], Msg.NOT_FOUND)
|
||||
continue
|
||||
except (GAPI.invalidOrgunit, GAPI.invalidInput) as e:
|
||||
if query and not customFieldMask:
|
||||
if query and not schemaParms['customFieldMask']:
|
||||
entityActionFailedWarning([Ent.USER, None], invalidQuery(query))
|
||||
elif customFieldMask and not query:
|
||||
entityActionFailedWarning([Ent.USER, None], invalidUserSchema(customFieldMask))
|
||||
elif query and customFieldMask:
|
||||
entityActionFailedWarning([Ent.USER, None], f'{invalidQuery(query)} or {invalidUserSchema(customFieldMask)}')
|
||||
elif schemaParms['customFieldMask'] and not query:
|
||||
entityActionFailedWarning([Ent.USER, None], invalidUserSchema(schemaParms['customFieldMask']))
|
||||
elif query and schemaParms['customFieldMask']:
|
||||
entityActionFailedWarning([Ent.USER, None], f'{invalidQuery(query)} or {invalidUserSchema(schemaParms["customFieldMask"])}')
|
||||
else:
|
||||
entityActionFailedWarning([Ent.USER, None], str(e))
|
||||
continue
|
||||
@@ -43335,7 +43421,9 @@ def doPrintUsers(entityList=None):
|
||||
jcount = len(entityList)
|
||||
fields = getFieldsFromFieldsList(fieldsList)
|
||||
if GC.Values[GC.BATCH_SIZE] > 1 and jcount > 1:
|
||||
svcargs = dict([('userKey', None), ('fields', fields), ('projection', projection), ('customFieldMask', customFieldMask), ('viewType', viewType)]+GM.Globals[GM.EXTRA_ARGS_LIST])
|
||||
svcargs = dict([('userKey', None), ('fields', fields),
|
||||
('projection', schemaParms['projection']), ('customFieldMask', schemaParms['customFieldMask']),
|
||||
('viewType', viewType)]+GM.Globals[GM.EXTRA_ARGS_LIST])
|
||||
method = getattr(cd.users(), 'get')
|
||||
dbatch = cd.new_batch_http_request(callback=_callbackPrintUser)
|
||||
bcount = 0
|
||||
@@ -43360,7 +43448,8 @@ def doPrintUsers(entityList=None):
|
||||
try:
|
||||
user = callGAPI(cd.users(), 'get',
|
||||
throwReasons=GAPI.USER_GET_THROW_REASONS+[GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND, GAPI.RATE_LIMIT_EXCEEDED],
|
||||
userKey=userEmail, projection=projection, customFieldMask=customFieldMask, viewType=viewType, fields=fields)
|
||||
userKey=userEmail, projection=schemaParms['projection'], customFieldMask=schemaParms['customFieldMask'],
|
||||
viewType=viewType, fields=fields)
|
||||
_printUser(user, j, jcount)
|
||||
except (GAPI.userNotFound, GAPI.resourceNotFound):
|
||||
if not showValidColumn:
|
||||
@@ -43371,8 +43460,8 @@ def doPrintUsers(entityList=None):
|
||||
GAPI.badRequest, GAPI.backendError, GAPI.systemError, GAPI.rateLimitExceeded) as e:
|
||||
entityActionFailedWarning([Ent.USER, userEmail], str(e), j, jcount)
|
||||
except GAPI.invalidInput as e:
|
||||
if customFieldMask:
|
||||
entityActionFailedWarning([Ent.USER, userEmail], invalidUserSchema(customFieldMask), j, jcount)
|
||||
if schemaParms['customFieldMask']:
|
||||
entityActionFailedWarning([Ent.USER, userEmail], invalidUserSchema(schemaParms['customFieldMask']), j, jcount)
|
||||
else:
|
||||
entityActionFailedWarning([Ent.USER, userEmail], str(e), j, jcount)
|
||||
# The only field specified was primaryEmail, just list the users/count the domains
|
||||
@@ -43446,7 +43535,7 @@ def doPrintUserList(entityList):
|
||||
def doPrintUserCountsByOrgUnit():
|
||||
def _printUserCounts(title, v):
|
||||
csvPF.WriteRow({'orgUnitPath': title, 'archived': v['archived'], 'active': v['active'], 'suspended': v['suspended'], 'total': v['total']})
|
||||
|
||||
|
||||
USER_COUNTS_FIELDS = ['archived', 'active', 'suspended', 'total']
|
||||
USER_COUNTS_ZERO_FIELDS = {'archived': 0, 'active': 0, 'suspended': 0, 'total': 0}
|
||||
cd = buildGAPIObject(API.DIRECTORY)
|
||||
@@ -51424,6 +51513,12 @@ DRIVESETTINGS_SCALAR_FIELDS = [
|
||||
'usageInDriveTrash',
|
||||
]
|
||||
|
||||
DRIVESETTINGS_USAGE_BYTES_FIELDS = {
|
||||
'usage': 'usageBytes',
|
||||
'usageInDrive': 'usageInDriveBytes',
|
||||
'usageInDriveTrash': 'usageInDriveTrashBytes',
|
||||
}
|
||||
|
||||
def _showSharedDriveThemeSettings(themes):
|
||||
Ind.Increment()
|
||||
for theme in themes:
|
||||
@@ -51435,9 +51530,11 @@ def _showSharedDriveThemeSettings(themes):
|
||||
Ind.Decrement()
|
||||
|
||||
# gam <UserTypeEntity> print drivesettings [todrive <ToDriveAttribute>*]
|
||||
# [allfields|<DriveSettingsFieldName>*|(fields <DriveSettingsFieldNameList>)] [delimiter <Character>]
|
||||
# [allfields|<DriveSettingsFieldName>*|(fields <DriveSettingsFieldNameList>)]
|
||||
# [delimiter <Character>] [showusagebytes]
|
||||
# gam <UserTypeEntity> show drivesettings
|
||||
# [allfields|<DriveSettingsFieldName>*|(fields <DriveSettingsFieldNameList>)] [delimiter <Character>]
|
||||
# [allfields|<DriveSettingsFieldName>*|(fields <DriveSettingsFieldNameList>)]
|
||||
# [delimiter <Character>] [showusagebytes]
|
||||
def printShowDriveSettings(users):
|
||||
def _showFormats(title):
|
||||
if title in fieldsList and title in feed:
|
||||
@@ -51473,6 +51570,7 @@ def printShowDriveSettings(users):
|
||||
csvPF = CSVPrintFile(['email'], ['email']+DRIVESETTINGS_SCALAR_FIELDS) if Act.csvFormat() else None
|
||||
fieldsList = []
|
||||
delimiter = GC.Values[GC.CSV_OUTPUT_FIELD_DELIMITER]
|
||||
showUsageBytes = False
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if csvPF and myarg == 'todrive':
|
||||
@@ -51483,6 +51581,8 @@ def printShowDriveSettings(users):
|
||||
fieldsList.extend(DRIVESETTINGS_FIELDS_CHOICE_MAP.values())
|
||||
elif getFieldsList(myarg, DRIVESETTINGS_FIELDS_CHOICE_MAP, fieldsList):
|
||||
pass
|
||||
elif myarg == 'showusagebytes':
|
||||
showUsageBytes = True
|
||||
else:
|
||||
unknownArgumentExit()
|
||||
if not fieldsList:
|
||||
@@ -51507,7 +51607,10 @@ def printShowDriveSettings(users):
|
||||
else:
|
||||
feed['limit'] = 'UNLIMITED'
|
||||
for setting in ['usage', 'usageInDrive', 'usageInDriveTrash']:
|
||||
feed[setting] = formatFileSize(int(feed['storageQuota'].get(setting, '0')))
|
||||
uval = int(feed['storageQuota'].get(setting, '0'))
|
||||
feed[setting] = formatFileSize(uval)
|
||||
if showUsageBytes:
|
||||
feed[DRIVESETTINGS_USAGE_BYTES_FIELDS[setting]] = uval
|
||||
if 'rootFolderId' in fieldsList:
|
||||
feed['rootFolderId'] = callGAPI(drive.files(), 'get',
|
||||
throwReasons=GAPI.DRIVE_USER_THROW_REASONS,
|
||||
@@ -51521,6 +51624,10 @@ def printShowDriveSettings(users):
|
||||
Ind.Increment()
|
||||
for setting in DRIVESETTINGS_SCALAR_FIELDS:
|
||||
_showSetting(setting)
|
||||
if showUsageBytes:
|
||||
for title, setting in DRIVESETTINGS_USAGE_BYTES_FIELDS.items():
|
||||
if title in fieldsList and setting in feed:
|
||||
printKeyValueList([setting, feed[setting]])
|
||||
_showSetting('folderColorPalette')
|
||||
_showFormats('exportFormats')
|
||||
_showFormats('importFormats')
|
||||
@@ -51538,6 +51645,10 @@ def printShowDriveSettings(users):
|
||||
row = {'email': user}
|
||||
for setting in DRIVESETTINGS_SCALAR_FIELDS:
|
||||
_addSetting(row, setting)
|
||||
if showUsageBytes:
|
||||
for title, setting in DRIVESETTINGS_USAGE_BYTES_FIELDS.items():
|
||||
if title in fieldsList and setting in feed:
|
||||
row[setting] = feed[setting]
|
||||
_addSetting(row, 'folderColorPalette')
|
||||
_addFormats(row, 'exportFormats')
|
||||
_addFormats(row, 'importFormats')
|
||||
@@ -53887,10 +53998,9 @@ def printFileList(users):
|
||||
showParent = getBoolean()
|
||||
elif myarg == 'nodataheaders':
|
||||
nodataFields = getString(Cmd.OB_FIELD_NAME_LIST).replace('_', '').replace(',', ' ').split()
|
||||
elif myarg == 'filepath':
|
||||
elif myarg in {'filepath', 'fullpath'}:
|
||||
filepath = True
|
||||
elif myarg == 'fullpath':
|
||||
filepath = fullpath = True
|
||||
fullpath = myarg == 'fullpath'
|
||||
elif myarg == 'folderpathonly':
|
||||
folderPathOnly = getBoolean()
|
||||
elif myarg == 'pathdelimiter':
|
||||
@@ -68530,6 +68640,7 @@ def printShowMessagesThreads(users, entityType):
|
||||
dateHeaderFormat = ''
|
||||
dateHeaderConvertTimezone = False
|
||||
uploadAttachmentBody = {}
|
||||
addCSVData = {}
|
||||
parentParms = initDriveFileAttributes()
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
@@ -68588,6 +68699,9 @@ def printShowMessagesThreads(users, entityType):
|
||||
dateHeaderConvertTimezone = getBoolean()
|
||||
if not dateHeaderFormat:
|
||||
dateHeaderFormat = RFC2822_TIME_FORMAT
|
||||
elif myarg == 'addcsvdata':
|
||||
k = getString(Cmd.OB_STRING)
|
||||
addCSVData[k] = getString(Cmd.OB_STRING, minLen=0)
|
||||
else:
|
||||
unknownArgumentExit()
|
||||
labelMatchPattern = parameters['labelMatchPattern']
|
||||
@@ -68612,11 +68726,15 @@ def printShowMessagesThreads(users, entityType):
|
||||
_callbacks = {'batch': _callbackCountLabels, 'process': _countMessages if entityType == Ent.MESSAGE else _countThreads}
|
||||
if show_size:
|
||||
sortTitles.append('size')
|
||||
if addCSVData:
|
||||
sortTitles.extend(sorted(addCSVData.keys()))
|
||||
csvPF.SetTitles(sortTitles)
|
||||
else:
|
||||
sortTitles = ['User', 'threadId', 'id']
|
||||
csvPF.SetTitles(sortTitles)
|
||||
sortTitles.extend(defaultHeaders)
|
||||
if addCSVData:
|
||||
sortTitles.extend(sorted(addCSVData.keys()))
|
||||
_callbacks = {'batch': _callbackPrint, 'process': _printMessage if entityType == Ent.MESSAGE else _printThread}
|
||||
csvPF.SetSortTitles(sortTitles)
|
||||
else:
|
||||
@@ -68648,6 +68766,8 @@ def printShowMessagesThreads(users, entityType):
|
||||
if not senderMatchPattern:
|
||||
_initSenderLabelsMap(user)
|
||||
messageThreadCounts = {'User': user, parameters['listType']: 0, 'size': 0}
|
||||
if addCSVData:
|
||||
messageThreadCounts.update(addCSVData)
|
||||
senderCounts = {}
|
||||
if save_attachments:
|
||||
_, userName, _ = splitEmailAddressOrUID(user)
|
||||
@@ -68678,14 +68798,14 @@ def printShowMessagesThreads(users, entityType):
|
||||
if jcount == 0:
|
||||
setSysExitRC(NO_ENTITIES_FOUND_RC)
|
||||
if countsOnly and not show_labels and not senderMatchPattern and not show_size:
|
||||
if not csvPF:
|
||||
printEntityKVList([Ent.USER, user], [parameters['listType'], jcount], i, count)
|
||||
else:
|
||||
csvPF.WriteRow({'User': user, parameters['listType']: jcount})
|
||||
continue
|
||||
if jcount == 0:
|
||||
if not csvPF:
|
||||
entityNumEntitiesActionNotPerformedWarning([Ent.USER, user], entityType, jcount, Msg.NO_ENTITIES_MATCHED.format(Ent.Plural(entityType)), i, count)
|
||||
if not positiveCountsOnly or jcount > 0:
|
||||
if not csvPF:
|
||||
printEntityKVList([Ent.USER, user], [parameters['listType'], jcount], i, count)
|
||||
else:
|
||||
row = {'User': user, parameters['listType']: jcount}
|
||||
if addCSVData:
|
||||
row.update(addCSVData)
|
||||
csvPF.WriteRow(row)
|
||||
continue
|
||||
if not csvPF and not countsOnly:
|
||||
if (parameters['messageEntity'] is not None or
|
||||
@@ -68741,32 +68861,46 @@ def printShowMessagesThreads(users, entityType):
|
||||
if not show_size:
|
||||
for label in labelsMap.values():
|
||||
label.pop('size', None)
|
||||
if addCSVData:
|
||||
row.update(addCSVData)
|
||||
csvPF.WriteRowTitles(flattenJSON({'Labels': sorted(iter(labelsMap.values()), key=lambda k: k['name'])}, flattened=row))
|
||||
elif not senderMatchPattern:
|
||||
if not csvPF:
|
||||
if not show_size:
|
||||
printEntityKVList([Ent.USER, user], [parameters['listType'], messageThreadCounts[parameters['listType']]], i, count)
|
||||
v = messageThreadCounts[parameters['listType']]
|
||||
if not positiveCountsOnly or v > 0:
|
||||
if not csvPF:
|
||||
if not show_size:
|
||||
printEntityKVList([Ent.USER, user], [parameters['listType'], v], i, count)
|
||||
else:
|
||||
printEntityKVList([Ent.USER, user], [parameters['listType'], v, 'size', messageThreadCounts['size']], i, count)
|
||||
else:
|
||||
printEntityKVList([Ent.USER, user], [parameters['listType'], messageThreadCounts[parameters['listType']], 'size', messageThreadCounts['size']], i, count)
|
||||
else:
|
||||
if not show_size:
|
||||
messageThreadCounts.pop('size', None)
|
||||
csvPF.WriteRow(messageThreadCounts)
|
||||
if not show_size:
|
||||
messageThreadCounts.pop('size', None)
|
||||
csvPF.WriteRow(messageThreadCounts)
|
||||
else:
|
||||
if not show_size:
|
||||
if not csvPF:
|
||||
for k, v in sorted(iter(senderCounts.items())):
|
||||
printEntityKVList([Ent.USER, user, Ent.SENDER, k], [parameters['listType'], v['count']], i, count)
|
||||
if not positiveCountsOnly or v['count'] > 0:
|
||||
printEntityKVList([Ent.USER, user, Ent.SENDER, k], [parameters['listType'], v['count']], i, count)
|
||||
else:
|
||||
for k, v in sorted(iter(senderCounts.items())):
|
||||
csvPF.WriteRow({'User': user, 'Sender': k, parameters['listType']: v['count']})
|
||||
if not positiveCountsOnly or v['count'] > 0:
|
||||
row = {'User': user, 'Sender': k, parameters['listType']: v['count']}
|
||||
if addCSVData:
|
||||
row.update(addCSVData)
|
||||
csvPF.WriteRow(row)
|
||||
else:
|
||||
if not csvPF:
|
||||
for k, v in sorted(iter(senderCounts.items())):
|
||||
printEntityKVList([Ent.USER, user, Ent.SENDER, k], [parameters['listType'], v['count'], 'size', v['size']], i, count)
|
||||
if not positiveCountsOnly or v['count'] > 0:
|
||||
printEntityKVList([Ent.USER, user, Ent.SENDER, k], [parameters['listType'], v['count'], 'size', v['size']], i, count)
|
||||
else:
|
||||
for k, v in sorted(iter(senderCounts.items())):
|
||||
csvPF.WriteRow({'User': user, 'Sender': k, parameters['listType']: v['count'], 'size': v['size']})
|
||||
if not positiveCountsOnly or v['count'] > 0:
|
||||
row = {'User': user, 'Sender': k, parameters['listType']: v['count'], 'size': v['size']}
|
||||
if addCSVData:
|
||||
row.update(addCSVData)
|
||||
csvPF.WriteRow(row)
|
||||
if csvPF:
|
||||
if not countsOnly:
|
||||
csvPF.RemoveTitles(['SizeEstimate', 'LabelsCount', 'Labels', 'Snippet', 'Body'])
|
||||
@@ -68783,15 +68917,16 @@ def printShowMessagesThreads(users, entityType):
|
||||
else:
|
||||
csvPF.writeCSVfile('Message Counts' if not show_labels else 'Message Label Counts')
|
||||
|
||||
# gam <UserTypeEntity> print message|messages
|
||||
# gam <UserTypeEntity> print message|messages [todrive <ToDriveAttribute>*]
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_print <Number>] [includespamtrash])|(ids <MessageIDEntity>)
|
||||
# [labelmatchpattern <RegularExpression>] [sendermatchpattern <RegularExpression>]
|
||||
# [headers all|<SMTPHeaderList>] [dateheaderformat iso|rfc2822|<String>] [dateheaderconverttimezone [<Boolean>]]
|
||||
# [showlabels] [showbody] [showdate] [showsize] [showsnippet]
|
||||
# [convertcrnl] [delimiter <Character>] [todrive <ToDriveAttribute>*]
|
||||
# [convertcrnl] [delimiter <Character>]
|
||||
# [countsonly|positivecountsonly] [useronly]
|
||||
# [[attachmentnamepattern <RegularExpression>]
|
||||
# [showattachments [noshowtextplain]]]
|
||||
# (addcsvdata <FieldName> <String>)*
|
||||
# gam <UserTypeEntity> show message|messages
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_show <Number>] [includespamtrash])|(ids <MessageIDEntity>)
|
||||
# [labelmatchpattern <RegularExpression>] [sendermatchpattern <RegularExpression>]
|
||||
@@ -68805,15 +68940,16 @@ def printShowMessagesThreads(users, entityType):
|
||||
def printShowMessages(users):
|
||||
printShowMessagesThreads(users, Ent.MESSAGE)
|
||||
|
||||
# gam <UserTypeEntity> print thread|threads
|
||||
# gam <UserTypeEntity> print thread|threads [todrive <ToDriveAttribute>*]
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_print <Number>] [includespamtrash])|(ids <ThreadIDEntity>)
|
||||
# [labelmatchpattern <RegularExpression>]
|
||||
# [headers all|<SMTPHeaderList>] [dateheaderformat iso|rfc2822|<String>] [dateheaderconverttimezone [<Boolean>]]
|
||||
# [showlabels] [showbody] [showdate] [showsize] [showsnippet]
|
||||
# [convertcrnl] [delimiter <Character>] [todrive <ToDriveAttribute>*]
|
||||
# [convertcrnl] [delimiter <Character>]
|
||||
# [countsonly|positivecountsonly] [useronly]
|
||||
# [[attachmentnamepattern <RegularExpression>]
|
||||
# [showattachments [noshowtextplain]]]
|
||||
# (addcsvdata <FieldName> <String>)*
|
||||
# gam <UserTypeEntity> show thread|threads
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_show <Number>] [includespamtrash])|(ids <ThreadIDEntity>)
|
||||
# [labelmatchpattern <RegularExpression>]
|
||||
|
||||
@@ -29,8 +29,10 @@ CBCM = 'cbcm'
|
||||
CHAT = 'chat'
|
||||
CHAT_EVENTS = 'chatevents'
|
||||
CHAT_MEMBERSHIPS = 'chatmemberships'
|
||||
CHAT_MEMBERSHIPS_ADMIN = 'chatmembershipsadmin'
|
||||
CHAT_MESSAGES = 'chatmessages'
|
||||
CHAT_SPACES = 'chatspaces'
|
||||
CHAT_SPACES_ADMIN = 'chatspacesadmin'
|
||||
CHAT_SPACES_DELETE = 'chatspacesdelete'
|
||||
CHROMEMANAGEMENT = 'chromemanagement'
|
||||
CHROMEMANAGEMENT_APPDETAILS = 'chromemanagementappdetails'
|
||||
@@ -197,8 +199,10 @@ _INFO = {
|
||||
CHAT: {'name': 'Chat API', 'version': 'v1', 'v2discovery': True},
|
||||
CHAT_EVENTS: {'name': 'Chat API - Events', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_MEMBERSHIPS: {'name': 'Chat API - Memberships', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_MEMBERSHIPS_ADMIN: {'name': 'Chat API - Admin Memberships', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_MESSAGES: {'name': 'Chat API - Messages', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_SPACES: {'name': 'Chat API - Spaces', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_SPACES_ADMIN: {'name': 'Chat API - Admin Spaces', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_SPACES_DELETE: {'name': 'Chat API - Spaces Delete', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CLASSROOM: {'name': 'Classroom API', 'version': 'v1', 'v2discovery': True},
|
||||
CHROMEMANAGEMENT: {'name': 'Chrome Management API', 'version': 'v1', 'v2discovery': True},
|
||||
@@ -514,6 +518,10 @@ _SVCACCT_SCOPES = [
|
||||
'api': CHAT_MEMBERSHIPS,
|
||||
'subscopes': READONLY,
|
||||
'scope': 'https://www.googleapis.com/auth/chat.memberships'},
|
||||
# {'name': 'Chat API - Admin Memberships',
|
||||
# 'api': CHAT_MEMBERSHIPS_ADMIN,
|
||||
# 'subscopes': READONLY,
|
||||
# 'scope': 'https://www.googleapis.com/auth/chat.admin.memberships'},
|
||||
{'name': 'Chat API - Messages',
|
||||
'api': CHAT_MESSAGES,
|
||||
'subscopes': READONLY,
|
||||
@@ -522,6 +530,10 @@ _SVCACCT_SCOPES = [
|
||||
'api': CHAT_SPACES,
|
||||
'subscopes': READONLY,
|
||||
'scope': 'https://www.googleapis.com/auth/chat.spaces'},
|
||||
# {'name': 'Chat API - Admin Spaces',
|
||||
# 'api': CHAT_SPACES_ADMIN,
|
||||
# 'subscopes': READONLY,
|
||||
# 'scope': 'https://www.googleapis.com/auth/chat.admin.spaces'},
|
||||
{'name': 'Chat API - Spaces Delete',
|
||||
'api': CHAT_SPACES_DELETE,
|
||||
'subscopes': [],
|
||||
|
||||
@@ -171,6 +171,10 @@ RATE_CHECK_COUNT = 'rccn'
|
||||
RATE_CHECK_START = 'rcst'
|
||||
# Section name from outer gam, passed to inner gams
|
||||
SECTION = 'sect'
|
||||
# Enable/disable "Getting ... " messages
|
||||
SHOW_GETTINGS = 'shog'
|
||||
# Enable/disable NL at end of "Got ..." messages
|
||||
SHOW_GETTINGS_GOT_NL = 'shgn'
|
||||
# redirected files
|
||||
SAVED_STDOUT = 'svso'
|
||||
STDERR = 'stde'
|
||||
@@ -287,6 +291,8 @@ Globals = {
|
||||
RATE_CHECK_COUNT: 0,
|
||||
RATE_CHECK_START: 0,
|
||||
SECTION: None,
|
||||
SHOW_GETTINGS: True,
|
||||
SHOW_GETTINGS_GOT_NL: False,
|
||||
SAVED_STDOUT: None,
|
||||
STDERR: {},
|
||||
STDOUT: {},
|
||||
|
||||
@@ -92,6 +92,10 @@ _SKUS = {
|
||||
'product': '101047', 'aliases': ['gwlabs', 'workspacelabs'], 'displayName': 'Google Workspace Labs'},
|
||||
'1010470003': {
|
||||
'product': '101047', 'aliases': ['geminibiz'], 'displayName': 'Gemini Business'},
|
||||
'1010470006': {
|
||||
'product': '101047', 'aliases': ['aisecurity'], 'displayName': 'AI Security'},
|
||||
'1010470007': {
|
||||
'product': '101047', 'aliases': ['aimeetingsandmessaging'], 'displayName': 'AI Meetings and Messaging'},
|
||||
'1010490001': {
|
||||
'product': '101049', 'aliases': ['eeu'], 'displayName': 'Endpoint Education Upgrade'},
|
||||
'Google-Apps': {
|
||||
|
||||
Reference in New Issue
Block a user