mirror of
https://github.com/GAM-team/GAM.git
synced 2025-07-06 04:33:34 +00:00
Multiple updates
This commit is contained in:
@ -137,7 +137,7 @@ gam csv UpdateBrowsers.csv gam update browser ~deviceId updatenotes "~~notes~~\n
|
||||
```
|
||||
gam move browsers ou|org|orgunit <OrgUnitPath>
|
||||
((ids <DeviceIDList>) |
|
||||
(queries <QueryBrowserList> [querytime.* <Time>]) |
|
||||
(queries <QueryBrowserList> [querytime<String> <Time>]) |
|
||||
(browserou <OrgUnitItem>) | (browserous <OrgUnitList>) |
|
||||
<FileSelector> | <CSVFileSelector>)
|
||||
[batchsize <Integer>]
|
||||
@ -178,7 +178,7 @@ By default, Gam displays the information as an indented list of keys and values:
|
||||
```
|
||||
gam show browsers
|
||||
([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser>)|(queries <QueryBrowserList>))|(select <BrowserEntity>))
|
||||
[querytime.* <Time>]
|
||||
[querytime<String> <Time>]
|
||||
[orderby <BrowserOrderByFieldName> [ascending|descending]]
|
||||
[basic|full|allfields|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>]
|
||||
[formatjson]
|
||||
@ -205,7 +205,7 @@ The characters following `querytime` can be any combination of lowercase letters
|
||||
```
|
||||
gam print browsers [todrive <ToDriveAttribute>*]
|
||||
([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser>)|(queries <QueryBrowserList>))|(select <BrowserEntity>))
|
||||
[querytime.* <Time>]
|
||||
[querytime<String> <Time>]
|
||||
[orderby <BrowserOrderByFieldName> [ascending|descending]]
|
||||
[basic|full|allfields|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>]
|
||||
[sortheaders] [formatjson [quotechar <Character>]]
|
||||
@ -372,7 +372,7 @@ gam revoke browsertoken <BrowserTokenPermanentID>
|
||||
```
|
||||
gam show browsertokens
|
||||
([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowserToken)|(queries <QueryBrowserTokenList>)))
|
||||
[querytime.* <Time>]
|
||||
[querytime<String> <Time>]
|
||||
[orderby <BrowserTokenFieldName> [ascending|descending]]
|
||||
[allfields] <BrowserTokenFieldName>* [fields <BrowserTokenFieldNameList>]
|
||||
[formatjson]
|
||||
@ -395,7 +395,7 @@ By default, Gam displays the information as an indented list of keys and values:
|
||||
```
|
||||
gam print browsertokens [todrive <ToDriveAttribute>*]
|
||||
([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowserToken)|(queries <QueryBrowserTokenList>)))
|
||||
[querytime.* <Time>]
|
||||
[querytime<String> <Time>]
|
||||
[orderby <BrowserTokenFieldName> [ascending|descending]]
|
||||
[allfields] <BrowserTokenFieldName>* [fields <BrowserTokenFieldNameList>]
|
||||
[sortheaders] [formatjson [quotechar <Character>]]
|
||||
|
@ -538,7 +538,7 @@ gam <CrOSTypeEntity> print cros
|
||||
|
||||
```
|
||||
gam print cros [todrive <ToDriveAttribute>*]
|
||||
[(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime.* <Time>]
|
||||
[(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime<String> <Time>]
|
||||
[(limittoou|cros_ou <OrgUnitItem>)|(cros_ou_and_children <OrgUnitItem>)|
|
||||
(cros_ous <OrgUnitList>)|(cros_ous_and_children <OrgUnitList>)]]
|
||||
[orderby <CrOSOrderByFieldName> [ascending|descending]]
|
||||
@ -691,7 +691,7 @@ gam <CrOSTypeEntity> show count
|
||||
|
||||
```
|
||||
gam print crosactivity [todrive <ToDriveAttribute>*]
|
||||
[(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime.* <Time>]
|
||||
[(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime<String> <Time>]
|
||||
[(limittoou|cros_ou <OrgUnitItem>)|(cros_ou_and_children <OrgUnitItem>)|
|
||||
(cros_ous <OrgUnitList>)|(cros_ous_and_children <OrgUnitList>)]]
|
||||
[orderby <CrOSOrderByFieldName> [ascending|descending]]
|
||||
|
@ -167,7 +167,7 @@ These two/three columns are used to match current company devices against the CS
|
||||
If `preview` is specified, the operations that would be performed are previewed but are not performed; use this to test.
|
||||
```
|
||||
gam sync devices
|
||||
[(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime.* <Time>)*]
|
||||
[(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime<String> <Time>)*]
|
||||
csvfile <FileName>
|
||||
(devicetype_column <String>)|(static_devicetype <DeviceType>)
|
||||
(serialnumber_column <String>)
|
||||
@ -190,7 +190,7 @@ By default, Gam displays the information as an indented list of keys and values.
|
||||
## Print devices
|
||||
```
|
||||
gam print devices [todrive <ToDriveAttribute>*]
|
||||
[(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime.* <Time>)*]
|
||||
[(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime<String> <Time>)*]
|
||||
<DeviceFieldName>* [fields <DeviceFieldNameList>] [userfields <DeviceUserFieldNameList>]
|
||||
[orderby <DeviceOrderByFieldName> [ascending|descending]]
|
||||
[all|company|personal|nocompanydevices|nopersonaldevices]
|
||||
@ -266,7 +266,7 @@ gam info deviceuser <DeviceUserEntity>
|
||||
```
|
||||
gam print deviceusers [todrive <ToDriveAttribute>*]
|
||||
[select <DeviceID>]
|
||||
[(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime.* <Time>)*]
|
||||
[(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime<String> <Time>)*]
|
||||
<DeviceUserFieldName>* [fields <DeviceUserFieldNameList>]
|
||||
[orderby <DeviceOrderByFieldName> [ascending|descending]]
|
||||
[formatjson [quotechar <Character>]]
|
||||
|
@ -10,6 +10,27 @@ 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
|
||||
|
||||
Updated `gam <UserTypeEntity> import|insert message` to allow `replace <Tag> <UserReplacement>` as documented.
|
||||
|
||||
### 6.65.05
|
||||
|
||||
Updated `gam info users <UserTypeEntity>` to make option `grouptree` effective when used
|
||||
with option `formatjson`.
|
||||
|
||||
Added option `[formatjson [quotechar <Character>]]]`
|
||||
to these commands so that event details are displayed in CSV format.
|
||||
```
|
||||
gam print|show grouptree <GroupEntity>
|
||||
gam <UserTypeEntity> print|show grouptree
|
||||
```
|
||||
|
||||
Added option `querytime<String> <Date>` to all commands that process messages.
|
||||
For example, you can identify all messages within a particular time period, in this case, all messages unread
|
||||
in the last 30 days.
|
||||
```
|
||||
gam user user@domain.com print messages querytime30d -30d query "after:#querytime30d# is:unread"
|
||||
```
|
||||
|
||||
### 6.65.04
|
||||
|
||||
Fixed bug where license SKU `1010020031` (Google Workspace Frontline Standard) was improperly entered making it unusable;
|
||||
|
@ -334,7 +334,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.65.04 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.65.05 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.10.8 64-bit final
|
||||
MacOS High Sierra 10.13.6 x86_64
|
||||
@ -1002,7 +1002,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.65.04 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.65.05 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.0 64-bit final
|
||||
Windows-10-10.0.17134 AMD64
|
||||
|
@ -100,7 +100,7 @@ By default, Gam displays the information as an indented list of keys and values.
|
||||
## Print mobile devices
|
||||
```
|
||||
gam print mobile [todrive <ToDriveAttribute>*]
|
||||
[(query <QueryMobile>)|(queries <QueryMobileList>) (querytime.* <Time>)*]
|
||||
[(query <QueryMobile>)|(queries <QueryMobileList>) (querytime<String> <Time>)*]
|
||||
[orderby <MobileOrderByFieldName> [ascending|descending]]
|
||||
[basic|full|allfields] <MobileFieldName>* [fields <MobileFieldNameList>]
|
||||
[delimiter <Character>] [appslimit <Number>] [oneappperrow] [listlimit <Number>]
|
||||
|
@ -173,6 +173,22 @@
|
||||
(gcsdoc|gcshtml <StorageBucketObjectName>)|
|
||||
(emlfile <FileName>)
|
||||
```
|
||||
## Message queries with dates
|
||||
```
|
||||
query <QueryGmail> [querytime<String> <Date>]*
|
||||
```
|
||||
* `query "xxx"` - ` xxx` is appended to the current query; you can repeat the query argument to build up a longer query.
|
||||
|
||||
Use the `querytime<String> <Date>` option to allow dates, usually relative, to be substituted into the `query <QueryGmail>` option.
|
||||
The `querytime<String> <Date>` value replaces the string `#querytime<String>#` in any queries.
|
||||
The characters following `querytime` can be any combination of lowercase letters and numbers. This is most useful in scripts
|
||||
where you can specify a relative date without having to change the script.
|
||||
|
||||
For example, query for messages from moree than 5 years ago:
|
||||
```
|
||||
querytime5years -5y query "before:#querytime5years#"
|
||||
```
|
||||
|
||||
## Subject and label queries
|
||||
Using a query to select messages by subject or label requires some attention in order to achieve the desired effect.
|
||||
* https://support.google.com/mail/answer/7190
|
||||
@ -316,7 +332,7 @@ Your command line will have: `embedimage file1.jpg image1` embedimage file2.jpg
|
||||
## Archive messages
|
||||
```
|
||||
gam <UserTypeEntity> archive messages <GroupItem>
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[quick|notquick] [doit] [max_to_archive <Number>])|(ids <MessageIDEntity>)
|
||||
```
|
||||
|
||||
@ -328,10 +344,10 @@ See below for message selection.
|
||||
Export messages in EML format.
|
||||
```
|
||||
gam <UserTypeEntity> export message|messages
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_export <Number>])|(ids <MessageIDEntity>)
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_export <Number>])|(ids <MessageIDEntity>)
|
||||
[targetfolder <FilePath>] [targetname <FileName>] [overwrite [<Boolean>]]
|
||||
gam <UserTypeEntity> export thread|threads
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_export <Number>])|(ids <ThreadIDEntity>)
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_export <Number>])|(ids <ThreadIDEntity>)
|
||||
[targetfolder <FilePath>] [targetname <FileName>] [overwrite [<Boolean>]]
|
||||
```
|
||||
|
||||
@ -354,11 +370,11 @@ See below for message selection.
|
||||
## Forward messages/threads
|
||||
```
|
||||
gam <UserTypeEntity> forward message|messages recipient|to <RecipientEntity>
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[quick|notquick] [doit] [max_to_forward <Number>])|(ids <MessageIDEntity>)
|
||||
[subject <String>]
|
||||
gam <UserTypeEntity> forward thread|threads recipient|to <RecipientEntity>
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[quick|notquick] [doit] [max_to_forward <Number>])|(ids <ThreadIDEntity>)
|
||||
[subject <String>]
|
||||
```
|
||||
@ -372,27 +388,27 @@ See below for message selection.
|
||||
## Manage messages/threads
|
||||
```
|
||||
gam <UserTypeEntity> delete messages|threads
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[quick|notquick] [doit] [max_to_delete <Number>])|(ids <MessageIDEntity>)
|
||||
gam <UserTypeEntity> modify messages|threads
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[quick|notquick] [doit] [max_to_modify <Number>])|(ids <MessageIDEntity>)
|
||||
(addlabel <LabelName>)* (removelabel <LabelName>)*
|
||||
gam <UserTypeEntity> spam messages|threads
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[quick|notquick] [doit] [max_to_spam <Number>])|(ids <MessageIDEntity>)
|
||||
gam <UserTypeEntity> trash messages|threads
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[quick|notquick] [doit] [max_to_trash <Number>])|(ids <MessageIDEntity>)
|
||||
gam <UserTypeEntity> untrash messages|threads
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[quick|notquick] [doit] [max_to_untrash <Number>])|(ids <MessageIDEntity>)
|
||||
```
|
||||
### Manage a specific set of messages
|
||||
* `ids <MessageIDEntity>` - A list of message ids
|
||||
|
||||
### Manage a selected set of messages
|
||||
* `((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+` - Criteria to select messages
|
||||
* `((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+` - Criteria to select messages
|
||||
* `max_to_xxx` - Limit the number of messages that will be processed; use a value of 0 for no limit
|
||||
* `doit` - No messages are processed unless you specify `doit`. By not specifying `doit`, you can preview the messages selected to verify that the results match your expectations.
|
||||
|
||||
@ -439,7 +455,7 @@ gam config auto_batch_min 1 groups_inde EastOffice delete message query "rfc822m
|
||||
## Display messages/threads
|
||||
```
|
||||
gam <UserTypeEntity> show messages|threads
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])*
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])*
|
||||
[quick|notquick] [max_to_show <Number>] [includespamtrash])|(ids <MessageIDEntity>)
|
||||
[labelmatchpattern <RegularExpression>] [sendermatchpattern <RegularExpression>]
|
||||
[countsonly|positivecountsonly] [useronly]
|
||||
@ -449,7 +465,7 @@ gam <UserTypeEntity> show messages|threads
|
||||
[saveattachments [attachmentnamepattern <RegularExpression>]]
|
||||
[targetfolder <FilePath>] [overwrite [<Boolean>]]
|
||||
gam <UserTypeEntity> print messages|threads [todrive <ToDriveAttribute>*]
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])*
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])*
|
||||
[quick|notquick] [max_to_print <Number>] [includespamtrash])|(ids <MessageIDEntity>)
|
||||
[labelmatchpattern <RegularExpression>] [sendermatchpattern <RegularExpression>]
|
||||
[countsonly|positivecountsonly] [useronly]
|
||||
@ -467,7 +483,7 @@ By default, Gam displays all messages.
|
||||
* `ids <MessageIDEntity>` - A list of message ids
|
||||
|
||||
## Display a selected set of messages
|
||||
* `((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+` - Criteria to select messages
|
||||
* `((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+` - Criteria to select messages
|
||||
* `max_to_xxx` - Limit the number of messages that will be displayed
|
||||
* `includespamtrash` - Include messages in the Spam and Trash folders
|
||||
* `labelmatchpattern <RegularExpression>` - Only display messages with some label that matches `<RegularExpression>`
|
||||
|
@ -4,7 +4,7 @@
|
||||
Print the current version of Gam with details
|
||||
```
|
||||
gam version
|
||||
GAMADV-XTD3 6.65.04 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.65.05 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.0 64-bit final
|
||||
MacOS Monterey 12.7 x86_64
|
||||
@ -16,7 +16,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.65.04 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.65.05 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.0 64-bit final
|
||||
MacOS Monterey 12.7 x86_64
|
||||
@ -28,7 +28,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.65.04 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.65.05 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.0 64-bit final
|
||||
MacOS Monterey 12.7 x86_64
|
||||
@ -65,7 +65,7 @@ MacOS High Sierra 10.13.6 x86_64
|
||||
Path: /Users/Admin/bin/gamadv-xtd3
|
||||
Version Check:
|
||||
Current: 5.35.08
|
||||
Latest: 6.65.04
|
||||
Latest: 6.65.05
|
||||
echo $?
|
||||
1
|
||||
```
|
||||
@ -73,7 +73,7 @@ echo $?
|
||||
Print the current version number without details
|
||||
```
|
||||
gam version simple
|
||||
6.65.04
|
||||
6.65.05
|
||||
```
|
||||
In Linux/MacOS you can do:
|
||||
```
|
||||
@ -83,7 +83,7 @@ echo $VER
|
||||
Print the current version of Gam and address of this Wiki
|
||||
```
|
||||
gam help
|
||||
GAM 6.65.04 - https://github.com/taers232c/GAMADV-XTD3
|
||||
GAM 6.65.05 - https://github.com/taers232c/GAMADV-XTD3
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.0 64-bit final
|
||||
MacOS Monterey 12.7 x86_64
|
||||
|
@ -1906,7 +1906,7 @@ gam delete browser <DeviceID>
|
||||
gam update browser <BrowserEntity> <BrowserAttibute>+
|
||||
gam move browsers ou|org|orgunit <OrgUnitPath>
|
||||
((ids <DeviceIDList>) |
|
||||
(queries <QueryBrowserList> [querytime.* <Time>]) |
|
||||
(queries <QueryBrowserList> [querytime<String> <Time>]) |
|
||||
(browserou <OrgUnitItem>) | (browserous <OrgUnitList>) |
|
||||
<FileSelector> | <CSVFileSelector>)
|
||||
[batchsize <Integer>]
|
||||
@ -1916,13 +1916,13 @@ gam info browser <DeviceID>
|
||||
[formatjson]
|
||||
gam show browsers
|
||||
([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser>)|(queries <QueryBrowserList>))|(select <BrowserEntity>))
|
||||
[querytime.* <Time>]
|
||||
[querytime<String> <Time>]
|
||||
[orderby <BrowserOrderByFieldName> [ascending|descending]]
|
||||
[basic|full|allfields|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>]
|
||||
[formatjson]
|
||||
gam print browsers [todrive <ToDriveAttribute>*]
|
||||
([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser>)|(queries <QueryBrowserList>))|(select <BrowserEntity>))
|
||||
[querytime.* <Time>]
|
||||
[querytime<String> <Time>]
|
||||
[orderby <BrowserOrderByFieldName> [ascending|descending]]
|
||||
[basic|full|allfields|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>]
|
||||
[sortheaders]
|
||||
@ -1950,13 +1950,13 @@ gam revoke browsertoken <BrowserTokenPermanentID>
|
||||
|
||||
gam show browsertokens
|
||||
([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowserToken>)|(queries <QueryBrowserTokenList>)))
|
||||
[querytime.* <Time>]
|
||||
[querytime<String> <Time>]
|
||||
[orderby <BrowserTokenFieldName> [ascending|descending]]
|
||||
[allfields] <BrowserTokenFieldName>* [fields <BrowserTokenFieldNameList>]
|
||||
[formatjson]
|
||||
gam print browsertokens [todrive <ToDriveAttribute>*]
|
||||
([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowserToken>)|(queries <QueryBrowserTokenList>)))
|
||||
[querytime.* <Time>]
|
||||
[querytime<String> <Time>]
|
||||
[orderby <BrowserTokenFieldName> [ascending|descending]]
|
||||
[allfields] <BrowserTokenFieldName>* [fields <BrowserTokenFieldNameList>]
|
||||
[sortheaders]
|
||||
@ -2253,13 +2253,13 @@ gam <CrOSTypeEntity> info
|
||||
[formatjson]
|
||||
|
||||
Print fields for selected CrOS devices; use these options to select CrOS devices:
|
||||
[(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime.* <Time>]
|
||||
[(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime<String> <Time>]
|
||||
[(limittoou|cros_ou <OrgUnitItem>)|(cros_ou_and_children <OrgUnitItem>)|
|
||||
(cros_ous <OrgUnitList>)|(cros_ous_and_children <OrgUnitList>)]]
|
||||
If none of these options are chosen, all CrOS devices are selected.
|
||||
|
||||
gam print cros [todrive <ToDriveAttribute>*]
|
||||
[(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime.* <Time>]
|
||||
[(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime<String> <Time>]
|
||||
[(limittoou|cros_ou <OrgUnitItem>)|(cros_ou_and_children <OrgUnitItem>)|
|
||||
(cros_ous <OrgUnitList>)|(cros_ous_and_children <OrgUnitList>)]]
|
||||
[orderby <CrOSOrderByFieldName> [ascending|descending]]
|
||||
@ -2315,13 +2315,13 @@ Show count of CrOS devices
|
||||
gam <CrOSTypeEntity> show count
|
||||
|
||||
Print activity for selected CrOS devices; use these options to select CrOS devices:
|
||||
[(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime.* <Time>]
|
||||
[(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime<String> <Time>]
|
||||
[(limittoou|cros_ou <OrgUnitItem>)|(cros_ou_and_children <OrgUnitItem>)|
|
||||
(cros_ous <OrgUnitList>)|(cros_ous_and_children <OrgUnitList>)]]
|
||||
If none of these options are chosen, all CrOS devices are selected.
|
||||
|
||||
gam print crosactivity [todrive <ToDriveAttribute>*]
|
||||
[(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime.* <Time>]
|
||||
[(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime<String> <Time>]
|
||||
[(limittoou|cros_ou <OrgUnitItem>)|(cros_ou_and_children <OrgUnitItem>)|
|
||||
(cros_ous <OrgUnitList>)|(cros_ous_and_children <OrgUnitList>)]]
|
||||
[orderby <CrOSOrderByFieldName> [ascending|descending]]
|
||||
@ -3593,7 +3593,9 @@ gam print groups [todrive <ToDriveAttribute>*]
|
||||
|
||||
gam print grouptree <GroupEntity> [todrive <ToDriveAttribute>*]
|
||||
[showparentsaslist [<Boolean>]] [delimiter <Character>]
|
||||
[formatjson [quotechar <Character>]]
|
||||
gam show grouptree <GroupEntity>
|
||||
[formatjson]
|
||||
|
||||
<MembersFieldName> ::=
|
||||
delivery|deliverysettings|
|
||||
@ -3807,7 +3809,7 @@ gam wipe device <DeviceEntity> [removeresetlock] [doit]
|
||||
|
||||
gam sync devices
|
||||
<CSVFileSelector>
|
||||
[(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime.* <Time>)*]
|
||||
[(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime<String> <Time>)*]
|
||||
(devicetype_column <String>)|(static_devicetype <DeviceType>)
|
||||
(serialnumber_column <String>)
|
||||
[assettag_column <String>]
|
||||
@ -3820,7 +3822,7 @@ gam info device <DeviceEntity>
|
||||
[nodeviceusers]
|
||||
[formatjson]
|
||||
gam print devices [todrive <ToDriveAttribute>*]
|
||||
[(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime.* <Time>)*]
|
||||
[(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime<String> <Time>)*]
|
||||
<DeviceFieldName>* [fields <DeviceFieldNameList>] [userfields <DeviceUserFieldNameList>]
|
||||
[orderby <DeviceOrderByFieldName> [ascending|descending]]
|
||||
[all|company|personal|nocompanydevices|nopersonaldevices]
|
||||
@ -3845,7 +3847,7 @@ gam info deviceuser <DeviceUserEntity>
|
||||
[formatjson]
|
||||
gam print deviceusers [todrive <ToDriveAttribute>*]
|
||||
[select <DeviceID>]
|
||||
[(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime.* <Time>)*]
|
||||
[(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime<String> <Time>)*]
|
||||
<DeviceUserFieldName>* [fields <DeviceUserFieldNameList>]
|
||||
[orderby <DeviceOrderByFieldName> [ascending|descending]]
|
||||
[formatjson [quotechar <Character>]]
|
||||
@ -3986,7 +3988,7 @@ gam info mobile <MobileEntity>
|
||||
[basic|full|allfields] <MobileFieldName>* [fields <MobileFieldNameList>]
|
||||
[formatjson]
|
||||
gam print mobile [todrive <ToDriveAttribute>*]
|
||||
[(query <QueryMobile>)|(queries <QueryMobileList>) (querytime.* <Time>)*]
|
||||
[(query <QueryMobile>)|(queries <QueryMobileList>) (querytime<String> <Time>)*]
|
||||
[orderby <MobileOrderByFieldName> [ascending|descending]]
|
||||
[basic|full|allfields] <MobileFieldName>* [fields <MobileFieldNameList>]
|
||||
[delimiter <Character>] [appslimit <Number>] [oneappperrow] [listlimit <Number>]
|
||||
@ -6865,43 +6867,43 @@ gam <UserTypeEntity> insert message
|
||||
[deleted [<Boolean>]]
|
||||
|
||||
gam <UserTypeEntity> archive messages <GroupItem>
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[quick|notquick] [doit] [max_to_archive <Number>])|(ids <MessageIDEntity>)
|
||||
gam <UserTypeEntity> delete messages|threads
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[quick|notquick] [doit] [max_to_delete <Number>])|(ids <MessageIDEntity>)
|
||||
gam <UserTypeEntity> modify messages|threads
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[quick|notquick] [doit] [max_to_modify <Number>])|(ids <MessageIDEntity>)
|
||||
(addlabel <LabelName>)* (removelabel <LabelName>)*
|
||||
gam <UserTypeEntity> spam messages|threads
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[quick|notquick] [doit] [max_to_spam <Number>])|(ids <MessageIDEntity>)
|
||||
gam <UserTypeEntity> trash messages|threads
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[quick|notquick] [doit] [max_to_trash <Number>])|(ids <MessageIDEntity>)
|
||||
gam <UserTypeEntity> untrash messages|threads
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[quick|notquick] [doit] [max_to_untrash <Number>])|(ids <MessageIDEntity>)
|
||||
|
||||
gam <UserTypeEntity> export message|messages
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_export <Number>])|(ids <MessageIDEntity>)
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_export <Number>])|(ids <MessageIDEntity>)
|
||||
[targetfolder <FilePath>] [targetname <FileName>] [overwrite [<Boolean>]]
|
||||
gam <UserTypeEntity> export thread|threads
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_export <Number>])|(ids <ThreadIDEntity>)
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_export <Number>])|(ids <ThreadIDEntity>)
|
||||
[targetfolder <FilePath>] [targetname <FileName>] [overwrite [<Boolean>]]
|
||||
|
||||
gam <UserTypeEntity> forward message|messages recipient|to <RecipientEntity>
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[quick|notquick] [doit] [max_to_forward <Number>])|(ids <MessageIDEntity>)
|
||||
[subject <String>] [altcharset <String>]
|
||||
gam <UserTypeEntity> forward thread|thtreads recipient|to <RecipientEntity>
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
quick|notquick] [doit] [max_to_forward <Number>])|(ids <ThreadIDEntity>)
|
||||
[subject <String>] [altcharset <String>]
|
||||
|
||||
gam <UserTypeEntity> show messages|threads
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])*
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])*
|
||||
[quick|notquick] [max_to_show <Number>] [includespamtrash])|(ids <MessageIDEntity>)
|
||||
[labelmatchpattern <RegularExpression>] [sendermatchpattern <RegularExpression>]
|
||||
[countsonly|positivecountsonly] [useronly]
|
||||
@ -6911,7 +6913,7 @@ gam <UserTypeEntity> show messages|threads
|
||||
[saveattachments [attachmentnamepattern <RegularExpression>]]
|
||||
[targetfolder <FilePath>] [overwrite [<Boolean>]]
|
||||
gam <UserTypeEntity> print messages|threads [todrive <ToDriveAttribute>*]
|
||||
(((query <QueryGmail>) (matchlabel <LabelName>) [or|and])*
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])*
|
||||
[quick|notquick] [max_to_print <Number>] [includespamtrash])|(ids <MessageIDEntity>)
|
||||
[labelmatchpattern <RegularExpression>] [sendermatchpattern <RegularExpression>]
|
||||
[countsonly|positivecountsonly] [useronly]
|
||||
@ -7014,9 +7016,11 @@ gam <UserTypeEntity> print grouptree [todrive <ToDriveAttribute>*]
|
||||
[(domain <DomainName>)|(customerid <CustomerID>)]
|
||||
[roles <GroupRoleList>]
|
||||
[showparentsaslist [<Boolean>]] [delimiter <Character>]
|
||||
[formatjson [quotechar <Character>]]
|
||||
gam <UserTypeEntity> show grouptree
|
||||
[(domain <DomainName>)|(customerid <CustomerID>)]
|
||||
[roles <GroupRoleList>]
|
||||
[formatjson]
|
||||
gam <UserTypeEntity> print groupslist [todrive <ToDriveAttribute>*]
|
||||
[(domain <DomainName>)|(customerid <CustomerID>)]
|
||||
[delimiter <Character>] [quotechar <Character>]
|
||||
|
@ -1,3 +1,30 @@
|
||||
7.00.00
|
||||
|
||||
Merged GAM-Team version
|
||||
|
||||
6.65.05
|
||||
|
||||
Updated `gam info users <UserTypeEntity>` to make option `grouptree` effective when used
|
||||
with option `formatjson`.
|
||||
|
||||
Added option `[formatjson [quotechar <Character>]]]`
|
||||
to these commands so that event details are displayed in CSV format.
|
||||
```
|
||||
gam print|show grouptree <GroupEntity>
|
||||
gam <UserTypeEntity> print|show grouptree
|
||||
```
|
||||
|
||||
Added option `querytime<String> <Date>` to all commands that process messages.
|
||||
For example, you can identify all messages within a particular time period, in this case, all messages unread
|
||||
in the last 30 days.
|
||||
```
|
||||
gam user user@domain.com print messages querytime30d -30d query "after:#querytime30d# is:unread"
|
||||
```
|
||||
|
||||
Updated `gam <UserTypeEntity> import|insert message` to allow `replace <Tag> <UserReplacement>` as documented.
|
||||
|
||||
Updated non-owner permission handling in `gam <UserTypeEntity> copy|move drivefile`.
|
||||
|
||||
6.65.04
|
||||
|
||||
Fixed bug where license SKU `1010020031` (Google Workspace Frontline Standard) was improperly entered making it unusable;
|
||||
@ -7,10 +34,6 @@ Added support for Google Workspace Additional Storage.
|
||||
* ProductID - 101043
|
||||
* SKUID - 1010430001 | gwas | plusstorage
|
||||
|
||||
7.00.00
|
||||
|
||||
Merged GAM-Team version
|
||||
|
||||
6.65.03
|
||||
|
||||
Fixed bug in commands that display calendar events where event start and end times were not properly displayed
|
||||
|
@ -2191,6 +2191,7 @@ def getJSON(deleteFields):
|
||||
if not Cmd.ArgumentsRemaining():
|
||||
missingArgumentExit(Cmd.OB_JSON_DATA)
|
||||
argstr = Cmd.Current()
|
||||
# argstr = Cmd.Current().replace(r'\\"', r'\"')
|
||||
Cmd.Advance()
|
||||
try:
|
||||
if encoding == UTF8:
|
||||
@ -4509,17 +4510,26 @@ def runSqliteQuery(db_file, query):
|
||||
return curr.fetchone()[0]
|
||||
|
||||
def refreshCredentialsWithReauth(credentials):
|
||||
def gcloudError():
|
||||
writeStderr(f'Failed to run gcloud as {admin_email}. Please make sure it\'s setup')
|
||||
e = Msg.REAUTHENTICATION_IS_NEEDED
|
||||
handleOAuthTokenError(e, False)
|
||||
|
||||
writeStderr(Msg.CALLING_GCLOUD_FOR_REAUTH)
|
||||
if 'termios' in sys.modules:
|
||||
old_settings = termios.tcgetattr(sys.stdin)
|
||||
admin_email = _getAdminEmail()
|
||||
# First makes sure gcloud has a valid access token and thus
|
||||
# should also have a valid RAPT token
|
||||
try:
|
||||
devnull = open(os.devnull, 'w', encoding=UTF8)
|
||||
subprocess.run(['gcloud',
|
||||
'auth',
|
||||
'print-identity-token',
|
||||
'--no-user-output-enabled'],
|
||||
stderr=devnull,
|
||||
check=False)
|
||||
devnull.close()
|
||||
# now determine gcloud's config path and token file
|
||||
gcloud_path_result = subprocess.run(['gcloud',
|
||||
'info',
|
||||
@ -4532,14 +4542,14 @@ def refreshCredentialsWithReauth(credentials):
|
||||
printBlankLine()
|
||||
raise KeyboardInterrupt from e
|
||||
token_path = gcloud_path_result.stdout.decode().strip()
|
||||
if not token_path:
|
||||
gcloudError()
|
||||
token_file = f'{token_path}/access_tokens.db'
|
||||
admin_email = _getAdminEmail()
|
||||
try:
|
||||
credentials._rapt_token = runSqliteQuery(token_file,
|
||||
f'SELECT rapt_token FROM access_tokens WHERE account_id = "{admin_email}"')
|
||||
except TypeError:
|
||||
systemErrorExit(SYSTEM_ERROR_RC,
|
||||
f'Failed to run gcloud as {admin_email}. Please make sure it\'s setup')
|
||||
gcloudError()
|
||||
if not credentials._rapt_token:
|
||||
systemErrorExit(SYSTEM_ERROR_RC,
|
||||
'Failed to retrieve reauth token from gcloud. You may need to wait until gcloud is also prompted for reauth.')
|
||||
@ -4792,7 +4802,7 @@ def checkGDataError(e, service):
|
||||
reason = error[0].get('reason', '')
|
||||
body = error[0].get('body', '').decode(UTF8)
|
||||
# First check for errors that need special handling
|
||||
if reason in ['Token invalid - Invalid token: Stateless token expired', 'Token invalid - Invalid token: Token not found']:
|
||||
if reason in ['Token invalid - Invalid token: Stateless token expired', 'Token invalid - Invalid token: Token not found', 'gone']:
|
||||
keep_domain = service.domain
|
||||
getGDataOAuthToken(service)
|
||||
service.domain = keep_domain
|
||||
@ -23302,7 +23312,7 @@ CROS_INDEXED_TITLES = ['activeTimeRanges', 'recentUsers', 'deviceFiles',
|
||||
'cpuStatusReports', 'diskVolumeReports', 'lastKnownNetwork', 'screenshotFiles', 'systemRamFreeReports']
|
||||
|
||||
# gam print cros [todrive <ToDriveAttribute>*]
|
||||
# [(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime.* <Time>]
|
||||
# [(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime<String> <Time>]
|
||||
# [(limittoou|cros_ou <OrgUnitItem>)|(cros_ou_and_children <OrgUnitItem>)|
|
||||
# (cros_ous <OrgUnitList>)|(cros_ous_and_children <OrgUnitList>)]]
|
||||
# gam print cros [todrive <ToDriveAttribute>*] select <CrOSTypeEntity>
|
||||
@ -23628,7 +23638,7 @@ CROS_ACTIVITY_LIST_FIELDS_CHOICE_MAP = {
|
||||
CROS_ACTIVITY_TIME_OBJECTS = {'createTime'}
|
||||
|
||||
# gam print crosactivity [todrive <ToDriveAttribute>*]
|
||||
# [(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime.* <Time>]
|
||||
# [(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime<String> <Time>]
|
||||
# [(limittoou|cros_ou <OrgUnitItem>)|(cros_ou_and_children <OrgUnitItem>)|
|
||||
# (cros_ous <OrgUnitList>)|(cros_ous_and_children <OrgUnitList>)]]
|
||||
# gam print crosactivity [todrive <ToDriveAttribute>*] select <CrOSTypeEntity>
|
||||
@ -24215,7 +24225,7 @@ def doInfoBrowsers():
|
||||
|
||||
# gam move browsers ou|org|orgunit <OrgUnitPath>
|
||||
# ((ids <DeviceIDList>) |
|
||||
# (queries <QueryBrowserList> [querytime.* <Time>]) |
|
||||
# (queries <QueryBrowserList> [querytime<String> <Time>]) |
|
||||
# (browserou <OrgUnitItem>) | (browserous <OrgUnitList>) |
|
||||
# <FileSelector> | <CSVFileSelector>)
|
||||
# [batchsize <Integer>]
|
||||
@ -24354,13 +24364,13 @@ BROWSER_ORDERBY_CHOICE_MAP = {
|
||||
|
||||
# gam show browsers
|
||||
# ([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser)|(queries <QueryBrowserList>))|(select <BrowserEntity>))
|
||||
# [querytime.* <Time>]
|
||||
# [querytime<String> <Time>]
|
||||
# [orderby <BrowserOrderByFieldName> [ascending|descending]]
|
||||
# [basic|full|allfields|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>]
|
||||
# [formatjson]
|
||||
# gam print browsers [todrive <ToDriveAttribute>*]
|
||||
# ([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser)|(queries <QueryBrowserList>))|(select <BrowserEntity>))
|
||||
# [querytime.* <Time>]
|
||||
# [querytime<String> <Time>]
|
||||
# [orderby <BrowserOrderByFieldName> [ascending|descending]]
|
||||
# [basic|full|allfields|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>]
|
||||
# [sortheaders] [formatjson [quotechar <Character>]]
|
||||
@ -24556,13 +24566,13 @@ BROWSER_TOKEN_FIELDS_CHOICE_MAP = {
|
||||
|
||||
# gam show browsertokens
|
||||
# ([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowserToken)|(queries <QueryBrowserTokenList>)))
|
||||
# [querytime.* <Time>]
|
||||
# [querytime<String> <Time>]
|
||||
# [orderby <BrowserTokenFieldName> [ascending|descending]]
|
||||
# [allfields] <BrowserTokenFieldName>* [fields <BrowserTokenFieldNameList>]
|
||||
# [formatjson]
|
||||
# gam print browsertokens [todrive <ToDriveAttribute>*]
|
||||
# ([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowserToken)|(queries <QueryBrowserTokenList>)))
|
||||
# [querytime.* <Time>]
|
||||
# [querytime<String> <Time>]
|
||||
# [orderby <BrowserTokenFieldName> [ascending|descending]]
|
||||
# [allfields] <BrowserTokenFieldName>* [fields <BrowserTokenFieldNameList>]
|
||||
# [sortheaders] [formatjson [quotechar <Character>]]
|
||||
@ -26677,7 +26687,7 @@ DEVICE_MISSING_ACTION_MAP = {
|
||||
|
||||
# gam sync devices
|
||||
# <CSVFileSelector>
|
||||
# [(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime.* <Time>)*]
|
||||
# [(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime<String> <Time>)*]
|
||||
# (devicetype_column <String>)|(static_devicetype <DeviceType>)
|
||||
# (serialnumber_column <String>)
|
||||
# [assettag_column <String>]
|
||||
@ -26976,7 +26986,7 @@ DEVICE_ORDERBY_CHOICE_MAP = {
|
||||
}
|
||||
|
||||
# gam print devices [todrive <ToDriveAttribute>*]
|
||||
# [(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime.* <Time>)*]
|
||||
# [(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime<String> <Time>)*]
|
||||
# <DeviceFieldName>* [fields <DeviceFieldNameList>] [userfields <DeviceUserFieldNameList>]
|
||||
# [orderby <DeviceOrderByFieldName> [ascending|descending]]
|
||||
# [all|company|personal|nocompanydevices|nopersonaldevices]
|
||||
@ -27163,7 +27173,7 @@ def doInfoCIDeviceUser():
|
||||
|
||||
# gam print deviceusers [todrive <ToDriveAttribute>*]
|
||||
# [select <DeviceID>]
|
||||
# [(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime.* <Time>)*]
|
||||
# [(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime<String> <Time>)*]
|
||||
# <DeviceUserFieldName>* [fields <DevieUserFieldNameList>]
|
||||
# [orderby <DeviceOrderByFieldName> [ascending|descending]]
|
||||
# [formatjson [quotechar <Character>]]
|
||||
@ -28948,7 +28958,7 @@ MOBILE_ORDERBY_CHOICE_MAP = {
|
||||
}
|
||||
|
||||
# gam print mobile [todrive <ToDriveAttribute>*]
|
||||
# [(query <QueryMobile>)|(queries <QueryMobileList>) [querytime.* <Time>]]
|
||||
# [(query <QueryMobile>)|(queries <QueryMobileList>) [querytime<String> <Time>]]
|
||||
# [orderby <MobileOrderByFieldName> [ascending|descending]]
|
||||
# [basic|full|allfields] <MobileFieldName>* [fields <MobileFieldNameList>]
|
||||
# [delimiter <Character>] [appslimit <Number>] [oneappperrow] [listlimit <Number>]
|
||||
@ -32006,11 +32016,7 @@ def doShowGroupMembers():
|
||||
if checkGroupMatchPatterns(groupEmail, group, matchPatterns):
|
||||
_showGroup(groupEmail, 0)
|
||||
|
||||
# gam print grouptree <GroupEntity> [todrive <ToDriveAttribute>*]
|
||||
# [showparentsaslist [<Boolean>]] [delimiter <Character>]
|
||||
# gam show grouptree <GroupEntity>
|
||||
def doPrintShowGroupTree():
|
||||
def getGroupParents(groupEmail, groupName):
|
||||
def getGroupParents(cd, groupParents, groupEmail, groupName, kwargs):
|
||||
groupParents[groupEmail] = {'name': groupName, 'parents': []}
|
||||
_setUserGroupArgs(groupEmail, kwargs)
|
||||
try:
|
||||
@ -32021,38 +32027,57 @@ def doPrintShowGroupTree():
|
||||
for parentGroup in entityList:
|
||||
groupParents[groupEmail]['parents'].append(parentGroup['email'])
|
||||
if parentGroup['email'] not in groupParents:
|
||||
getGroupParents(parentGroup['email'], parentGroup['name'])
|
||||
getGroupParents(cd, groupParents, parentGroup['email'], parentGroup['name'], kwargs)
|
||||
except (GAPI.invalidMember, GAPI.invalidInput):
|
||||
badRequestWarning(Ent.GROUP, Ent.MEMBER, groupEmail)
|
||||
except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.forbidden, GAPI.badRequest):
|
||||
accessErrorExit(cd)
|
||||
|
||||
def showGroupParents(groupEmail, i, count):
|
||||
printKeyValueListWithCount([f'{groupEmail}: {groupParents[groupEmail]["name"]}'], i, count)
|
||||
def showGroupParents(groupParents, groupEmail, role, i, count):
|
||||
kvList = [groupEmail, f'{groupParents[groupEmail]["name"]}']
|
||||
if role:
|
||||
kvList.extend([Ent.Singular(Ent.ROLE), role])
|
||||
printKeyValueListWithCount(kvList, i, count)
|
||||
Ind.Increment()
|
||||
for parentEmail in groupParents[groupEmail]['parents']:
|
||||
showGroupParents(parentEmail, 0, 0)
|
||||
showGroupParents(groupParents, parentEmail, None, 0, 0)
|
||||
Ind.Decrement()
|
||||
|
||||
def printGroupParents(groupEmail, row):
|
||||
def addJsonGroupParents(groupParents, userGroup, groupEmail):
|
||||
userGroup.setdefault('parents', [])
|
||||
for parentEmail in groupParents[groupEmail]['parents']:
|
||||
userGroup['parents'].append({'email': parentEmail, 'name': groupParents[parentEmail]['name'], 'parents': []})
|
||||
addJsonGroupParents(groupParents, userGroup['parents'][-1], parentEmail)
|
||||
|
||||
def printGroupParents(groupParents, groupEmail, row, csvPF, delimiter, showParentsAsList):
|
||||
if groupParents[groupEmail]['parents']:
|
||||
for parentEmail in groupParents[groupEmail]['parents']:
|
||||
row['parents'].append({'email': parentEmail, 'name': groupParents[parentEmail]['name']})
|
||||
printGroupParents(parentEmail, row)
|
||||
printGroupParents(groupParents, parentEmail, row, csvPF, delimiter, showParentsAsList)
|
||||
del row['parents'][-1]
|
||||
else:
|
||||
if not showParentsAsList:
|
||||
csvPF.WriteRowTitles(flattenJSON(row))
|
||||
else:
|
||||
crow = {'Group': row['Group'], 'Name': row['Name']}
|
||||
crow['ParentsCount'] = len(row['parents'])
|
||||
crow['Parents'] = delimiter.join([parent['email'] for parent in row['parents']])
|
||||
crow['ParentsName'] = delimiter.join([parent['name'] for parent in row['parents']])
|
||||
crow = row.copy()
|
||||
if 'Role' in row:
|
||||
crow['Role'] = row['Role']
|
||||
parents = crow.pop('parents')
|
||||
crow['ParentsCount'] = len(parents)
|
||||
crow['Parents'] = delimiter.join([parent['email'] for parent in parents])
|
||||
crow['ParentsName'] = delimiter.join([parent['name'] for parent in parents])
|
||||
csvPF.WriteRow(flattenJSON(crow))
|
||||
|
||||
# gam print grouptree <GroupEntity> [todrive <ToDriveAttribute>*]
|
||||
# [showparentsaslist [<Boolean>]] [delimiter <Character>]
|
||||
# [formatjson [quotechar <Character>]]
|
||||
# gam show grouptree <GroupEntity>
|
||||
# [formatjson]
|
||||
def doPrintShowGroupTree():
|
||||
cd = buildGAPIObject(API.DIRECTORY)
|
||||
kwargs = {'customer': GC.Values[GC.CUSTOMER_ID]}
|
||||
csvPF = CSVPrintFile(['Group', 'Name']) if Act.csvFormat() else None
|
||||
FJQC = FormatJSONQuoteChar(csvPF)
|
||||
delimiter = GC.Values[GC.CSV_OUTPUT_FIELD_DELIMITER]
|
||||
showParentsAsList = False
|
||||
entityList = getEntityList(Cmd.OB_GROUP_ENTITY)
|
||||
@ -32065,8 +32090,8 @@ def doPrintShowGroupTree():
|
||||
elif csvPF and myarg == 'showparentsaslist':
|
||||
showParentsAsList = getBoolean()
|
||||
else:
|
||||
unknownArgumentExit()
|
||||
if csvPF:
|
||||
FJQC.GetFormatJSONQuoteChar(myarg, True)
|
||||
if csvPF and not FJQC.formatJSON:
|
||||
if not showParentsAsList:
|
||||
csvPF.SetIndexedTitles(['parents'])
|
||||
else:
|
||||
@ -32074,7 +32099,7 @@ def doPrintShowGroupTree():
|
||||
groupParents = {}
|
||||
i = 0
|
||||
count = len(entityList)
|
||||
if not csvPF:
|
||||
if not csvPF and not FJQC.formatJSON:
|
||||
performActionNumItems(count, Ent.GROUP_TREE)
|
||||
for group in entityList:
|
||||
i += 1
|
||||
@ -32088,12 +32113,24 @@ def doPrintShowGroupTree():
|
||||
GAPI.invalid, GAPI.systemError) as e:
|
||||
entityActionFailedWarning([Ent.GROUP, groupEmail], str(e), i, count)
|
||||
continue
|
||||
getGroupParents(groupEmail, groupName)
|
||||
getGroupParents(cd, groupParents, groupEmail, groupName, kwargs)
|
||||
if not FJQC.formatJSON:
|
||||
if not csvPF:
|
||||
showGroupParents(groupEmail, i, count)
|
||||
showGroupParents(groupParents, groupEmail, None, i, count)
|
||||
else:
|
||||
row = {'Group': groupEmail, 'Name': groupParents[groupEmail]['name'], 'parents': []}
|
||||
printGroupParents(groupEmail, row)
|
||||
printGroupParents(groupParents, groupEmail, row, csvPF, delimiter, showParentsAsList)
|
||||
else:
|
||||
groupInfo = {'email': groupEmail, 'name': groupParents[groupEmail]['name'], 'parents': []}
|
||||
addJsonGroupParents(groupParents, groupInfo, groupEmail)
|
||||
if not csvPF:
|
||||
printLine(json.dumps(cleanJSON(groupInfo), ensure_ascii=False, sort_keys=True))
|
||||
else:
|
||||
row = flattenJSON(groupInfo)
|
||||
if csvPF.CheckRowTitles(row):
|
||||
csvPF.WriteRowNoFilter({'Group': groupEmail, 'Name': groupParents[groupEmail]['name'],
|
||||
'JSON': json.dumps(cleanJSON(groupInfo),
|
||||
ensure_ascii=False, sort_keys=True)})
|
||||
if csvPF:
|
||||
csvPF.writeCSVfile('Group Tree')
|
||||
|
||||
@ -41513,29 +41550,6 @@ def _formatLanguagesList(propertyValue, delimiter):
|
||||
return delimiter.join(languages)
|
||||
|
||||
def infoUsers(entityList):
|
||||
def getGroupParents(groupEmail, groupName):
|
||||
groupParents[groupEmail] = {'name': groupName, 'parents': []}
|
||||
try:
|
||||
entityList = callGAPIpages(cd.groups(), 'list', 'groups',
|
||||
throwReasons=GAPI.GROUP_LIST_USERKEY_THROW_REASONS,
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
userKey=groupEmail, orderBy='email', fields='nextPageToken,groups(email,name)')
|
||||
for parentGroup in entityList:
|
||||
groupParents[groupEmail]['parents'].append(parentGroup['email'])
|
||||
if parentGroup['email'] not in groupParents:
|
||||
getGroupParents(parentGroup['email'], parentGroup['name'])
|
||||
except (GAPI.invalidMember, GAPI.invalidInput):
|
||||
badRequestWarning(Ent.GROUP, Ent.MEMBER, groupEmail)
|
||||
except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.forbidden, GAPI.badRequest):
|
||||
accessErrorExit(cd)
|
||||
|
||||
def showGroupParents(groupEmail):
|
||||
printKeyValueList([groupEmail, f'{groupParents[groupEmail]["name"]}'])
|
||||
Ind.Increment()
|
||||
for parentEmail in groupParents[groupEmail]['parents']:
|
||||
showGroupParents(parentEmail)
|
||||
Ind.Decrement()
|
||||
|
||||
def printUserCIGroupMap(parent, group_name_mappings, seen_group_count, edges, direction):
|
||||
for a_parent, a_child in edges:
|
||||
if a_parent == parent:
|
||||
@ -41662,8 +41676,14 @@ def infoUsers(entityList):
|
||||
getCIGroupsTree = False
|
||||
licenses = getUserLicenses(lic, user, skus) if getLicenses else []
|
||||
if FJQC.formatJSON:
|
||||
if getGroups:
|
||||
if getGroups or getGroupsTree:
|
||||
user['groups'] = groups
|
||||
if getGroupsTree:
|
||||
for group in user['groups']:
|
||||
groupEmail = group['email']
|
||||
if groupEmail not in groupParents:
|
||||
getGroupParents(cd, groupParents, groupEmail, group['name'], {})
|
||||
addJsonGroupParents(groupParents, group, groupEmail)
|
||||
if getLicenses:
|
||||
user['licenses'] = [SKU.formatSKUIdDisplayName(u_license) for u_license in licenses]
|
||||
if not getAliases:
|
||||
@ -41901,8 +41921,8 @@ def infoUsers(entityList):
|
||||
for group in groups:
|
||||
groupEmail = group['email']
|
||||
if groupEmail not in groupParents:
|
||||
getGroupParents(groupEmail, group['name'])
|
||||
showGroupParents(groupEmail)
|
||||
getGroupParents(cd, groupParents, groupEmail, group['name'], {})
|
||||
showGroupParents(groupParents, groupEmail, None, 0, 0)
|
||||
Ind.Decrement()
|
||||
elif getCIGroupsTree:
|
||||
printEntity([Ent.GROUP_MEMBERSHIP_TREE, ''])
|
||||
@ -52092,7 +52112,7 @@ FILECOUNT_SUMMARY_CHOICE_MAP = {
|
||||
FILECOUNT_SUMMARY_USER = 'Summary'
|
||||
|
||||
# gam <UserTypeEntity> print filelist [todrive <ToDriveAttribute>*]
|
||||
# [((query <QueryDriveFile>) | (fullquery <QueryDriveFile>) | <DriveFileQueryShortcut>) (querytime.* <Time>)*]
|
||||
# [((query <QueryDriveFile>) | (fullquery <QueryDriveFile>) | <DriveFileQueryShortcut>) (querytime<String> <Time>)*]
|
||||
# [choose <DriveFileNameEntity>|<DriveFileEntityShortcut>]
|
||||
# [corpora <CorporaAttribute>]
|
||||
# [select <DriveFileEntity> [selectsubquery <QueryDriveFile>]
|
||||
@ -52822,7 +52842,7 @@ def printShowFilePaths(users):
|
||||
csvPF.writeCSVfile('Drive File Paths')
|
||||
|
||||
# gam <UserTypeEntity> print filecounts [todrive <ToDriveAttribute>*]
|
||||
# [((query <QueryDriveFile>) | (fullquery <QueryDriveFile>) | <DriveFileQueryShortcut>) (querytime.* <Time>)*]
|
||||
# [((query <QueryDriveFile>) | (fullquery <QueryDriveFile>) | <DriveFileQueryShortcut>) (querytime<String> <Time>)*]
|
||||
# [corpora <CorporaAttribute>]
|
||||
# [select <SharedDriveEntity>]
|
||||
# [anyowner|(showownedby any|me|others)]
|
||||
@ -52832,7 +52852,7 @@ def printShowFilePaths(users):
|
||||
# [excludetrashed]
|
||||
# [summary none|only|plus] [summaryuser <String>] [showsize]
|
||||
# gam <UserTypeEntity> show filecounts
|
||||
# [((query <QueryDriveFile>) | (fullquery <QueryDriveFile>) | <DriveFileQueryShortcut>) (querytime.* <Time>)*]
|
||||
# [((query <QueryDriveFile>) | (fullquery <QueryDriveFile>) | <DriveFileQueryShortcut>) (querytime<String> <Time>)*]
|
||||
# [corpora <CorporaAttribute>]
|
||||
# [select <SharedDriveEntity>]
|
||||
# [anyowner|(showownedby any|me|others)]
|
||||
@ -54765,7 +54785,8 @@ def _getUniqueFilename(destFilename, mimeType, targetChildren):
|
||||
|
||||
def _copyPermissions(drive, user, i, count, j, jcount,
|
||||
entityType, fileId, fileTitle, newFileId, newFileTitle,
|
||||
statistics, stat, copyMoveOptions, atTop, copyInherited, copyNonInherited):
|
||||
statistics, stat, copyMoveOptions, atTop, copyInherited, copyNonInherited,
|
||||
updateOwner):
|
||||
def getPermissions(fid):
|
||||
permissions = {}
|
||||
try:
|
||||
@ -54800,12 +54821,14 @@ def _copyPermissions(drive, user, i, count, j, jcount,
|
||||
|
||||
def isPermissionCopyable(kvList, permission):
|
||||
role = permission['role']
|
||||
if permission['type'] in {'group', 'user'}:
|
||||
emailAddress = permission.get('emailAddress', '')
|
||||
domain = ''
|
||||
if copyMoveOptions['excludePermissionsFromDomains'] or copyMoveOptions['includePermissionsFromDomains']:
|
||||
if permission['type'] in {'group', 'user'}:
|
||||
atLoc = permission.get('emailAddress', '').find('@')
|
||||
atLoc = emailAddress.find('@')
|
||||
if atLoc > 0:
|
||||
domain = permission['emailAddress'][atLoc+1:]
|
||||
domain = emailAddress[atLoc+1:]
|
||||
elif permission['type'] == 'domain':
|
||||
domain = permission.get('domain', '')
|
||||
if permission['inherited'] and not copyMoveOptions[copyInherited]:
|
||||
@ -54813,7 +54836,13 @@ def _copyPermissions(drive, user, i, count, j, jcount,
|
||||
elif not permission['inherited'] and copyMoveOptions[copyNonInherited] == COPY_NONINHERITED_PERMISSIONS_NEVER:
|
||||
notCopiedMessage = 'noninherited not selected'
|
||||
elif role == 'owner':
|
||||
if emailAddress == user or copyMoveOptions['destDriveId'] or not updateOwner:
|
||||
notCopiedMessage = f'role {role} copy not required/appropriate'
|
||||
else:
|
||||
permission['role'] = 'writer'
|
||||
return True
|
||||
elif updateOwner and emailAddress == user:
|
||||
notCopiedMessage = 'user is now owner'
|
||||
elif domain and domain in copyMoveOptions['excludePermissionsFromDomains']:
|
||||
notCopiedMessage = f'domain {domain} excluded'
|
||||
elif domain and copyMoveOptions['includePermissionsFromDomains'] and domain not in copyMoveOptions['includePermissionsFromDomains']:
|
||||
@ -55301,7 +55330,8 @@ def copyDriveFile(users):
|
||||
statistics, STAT_FOLDER_PERMISSIONS_FAILED,
|
||||
copyMoveOptions, True,
|
||||
'copyTopFolderInheritedPermissions',
|
||||
copyFolderNonInheritedPermissions)
|
||||
copyFolderNonInheritedPermissions,
|
||||
True)
|
||||
return (newParentId, newParentName, True)
|
||||
# Merge parent folders
|
||||
if copyMoveOptions['duplicateFolders'] == DUPLICATE_FOLDER_MERGE:
|
||||
@ -55330,7 +55360,8 @@ def copyDriveFile(users):
|
||||
statistics, STAT_FOLDER_PERMISSIONS_FAILED,
|
||||
copyMoveOptions, atTop,
|
||||
['copySubFolderInheritedPermissions', 'copyTopFolderInheritedPermissions'][atTop],
|
||||
copyFolderNonInheritedPermissions)
|
||||
copyFolderNonInheritedPermissions,
|
||||
False)
|
||||
return (newFolderId, newFolderName, True)
|
||||
entityActionFailedWarning(kvList+[Ent.DRIVE_FOLDER, newParentNameId], Msg.NOT_WRITABLE, j, jcount)
|
||||
_incrStatistic(statistics, STAT_FOLDER_NOT_WRITABLE)
|
||||
@ -55375,7 +55406,8 @@ def copyDriveFile(users):
|
||||
statistics, STAT_FOLDER_PERMISSIONS_FAILED,
|
||||
copyMoveOptions, False,
|
||||
['copySubFolderInheritedPermissions', 'copyTopFolderInheritedPermissions'][atTop],
|
||||
['copySubFolderNonInheritedPermissions', 'copyTopFolderNonInheritedPermissions'][atTop])
|
||||
['copySubFolderNonInheritedPermissions', 'copyTopFolderNonInheritedPermissions'][atTop],
|
||||
True)
|
||||
return (newFolderId, newFolderName, False)
|
||||
except (GAPI.forbidden, GAPI.insufficientFilePermissions, GAPI.insufficientParentPermissions,
|
||||
GAPI.internalError, GAPI.storageQuotaExceeded, GAPI.teamDriveHierarchyTooDeep, GAPI.badRequest) as e:
|
||||
@ -55570,7 +55602,8 @@ def copyDriveFile(users):
|
||||
statistics, STAT_FILE_PERMISSIONS_FAILED,
|
||||
copyMoveOptions, False,
|
||||
'copySheetProtectedRangesInheritedPermissions',
|
||||
'copySheetProtectedRangesNonInheritedPermissions')
|
||||
'copySheetProtectedRangesNonInheritedPermissions',
|
||||
True)
|
||||
_updateSheetProtectedRanges(sheet, user, i, count, k, kcount, result['id'], result['name'], protectedSheetRanges,
|
||||
statistics, STAT_FILE_PROTECTEDRANGES_FAILED)
|
||||
elif copyMoveOptions['copyFilePermissions']:
|
||||
@ -55579,7 +55612,8 @@ def copyDriveFile(users):
|
||||
statistics, STAT_FILE_PERMISSIONS_FAILED,
|
||||
copyMoveOptions, False,
|
||||
'copyFileInheritedPermissions',
|
||||
'copyFileNonInheritedPermissions')
|
||||
'copyFileNonInheritedPermissions',
|
||||
True)
|
||||
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions,
|
||||
GAPI.insufficientParentPermissions, GAPI.unknownError,
|
||||
GAPI.invalid, GAPI.cannotCopyFile, GAPI.badRequest, GAPI.responsePreparationFailure, GAPI.fileNeverWritable, GAPI.fieldNotWritable,
|
||||
@ -55830,7 +55864,8 @@ def copyDriveFile(users):
|
||||
statistics, STAT_FILE_PERMISSIONS_FAILED,
|
||||
copyMoveOptions, False,
|
||||
'copySheetProtectedRangesInheritedPermissions',
|
||||
'copySheetProtectedRangesNonInheritedPermissions')
|
||||
'copySheetProtectedRangesNonInheritedPermissions',
|
||||
True)
|
||||
_updateSheetProtectedRanges(sheet, user, i, count, j, jcount, result['id'], result['name'], protectedSheetRanges,
|
||||
statistics, STAT_FILE_PROTECTEDRANGES_FAILED)
|
||||
elif copyMoveOptions['copyFilePermissions']:
|
||||
@ -55839,7 +55874,8 @@ def copyDriveFile(users):
|
||||
statistics, STAT_FILE_PERMISSIONS_FAILED,
|
||||
copyMoveOptions, False,
|
||||
'copyFileInheritedPermissions',
|
||||
'copyFileNonInheritedPermissions')
|
||||
'copyFileNonInheritedPermissions',
|
||||
True)
|
||||
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions,
|
||||
GAPI.insufficientParentPermissions, GAPI.unknownError,
|
||||
GAPI.invalid, GAPI.badRequest, GAPI.cannotCopyFile, GAPI.responsePreparationFailure, GAPI.fileNeverWritable, GAPI.fieldNotWritable,
|
||||
@ -56072,7 +56108,8 @@ def moveDriveFile(users):
|
||||
statistics, STAT_FOLDER_PERMISSIONS_FAILED,
|
||||
copyMoveOptions, True,
|
||||
'copyTopFolderInheritedPermissions',
|
||||
copyFolderNonInheritedPermissions)
|
||||
copyFolderNonInheritedPermissions,
|
||||
False)
|
||||
source.pop('oldparents', None)
|
||||
return (newParentId, newParentName, True)
|
||||
# Merge parent folders
|
||||
@ -56101,7 +56138,8 @@ def moveDriveFile(users):
|
||||
statistics, STAT_FOLDER_PERMISSIONS_FAILED,
|
||||
copyMoveOptions, atTop,
|
||||
['copySubFolderInheritedPermissions', 'copyTopFolderInheritedPermissions'][atTop],
|
||||
copyFolderNonInheritedPermissions)
|
||||
copyFolderNonInheritedPermissions,
|
||||
False)
|
||||
return (newFolderId, newFolderName, True)
|
||||
entityActionFailedWarning(kvList+[Ent.DRIVE_FOLDER, newParentNameId], Msg.NOT_WRITABLE, j, jcount)
|
||||
_incrStatistic(statistics, STAT_FOLDER_NOT_WRITABLE)
|
||||
@ -56187,7 +56225,8 @@ def moveDriveFile(users):
|
||||
statistics, STAT_FOLDER_PERMISSIONS_FAILED,
|
||||
copyMoveOptions, False,
|
||||
['copySubFolderInheritedPermissions', 'copyTopFolderInheritedPermissions'][atTop],
|
||||
['copySubFolderNonInheritedPermissions', 'copyTopFolderNonInheritedPermissions'][atTop])
|
||||
['copySubFolderNonInheritedPermissions', 'copyTopFolderNonInheritedPermissions'][atTop],
|
||||
True)
|
||||
return (newFolderId, newFolderName, False)
|
||||
except (GAPI.forbidden, GAPI.insufficientFilePermissions, GAPI.insufficientParentPermissions,
|
||||
GAPI.internalError, GAPI.storageQuotaExceeded, GAPI.teamDriveHierarchyTooDeep,
|
||||
@ -59575,7 +59614,7 @@ def doInfoDriveFileACLs():
|
||||
infoDriveFileACLs([_getAdminEmail()], True)
|
||||
|
||||
DRIVEFILE_BASIC_PERMISSION_FIELDS = [
|
||||
'id', 'emailAddress', 'domain', 'role', 'type',
|
||||
'displayName', 'id', 'emailAddress', 'domain', 'role', 'type',
|
||||
'allowFileDiscovery', 'expirationTime', 'deleted'
|
||||
]
|
||||
|
||||
@ -60929,7 +60968,8 @@ def copySyncSharedDriveACLs(users, useDomainAdminAccess=False):
|
||||
statistics, STAT_FOLDER_PERMISSIONS_FAILED,
|
||||
copyMoveOptions, True,
|
||||
'copyTopFolderInheritedPermissions',
|
||||
'copyTopFolderNonInheritedPermissions')
|
||||
'copyTopFolderNonInheritedPermissions',
|
||||
False)
|
||||
|
||||
def doCopySyncSharedDriveACLs():
|
||||
copySyncSharedDriveACLs([_getAdminEmail()], True)
|
||||
@ -62162,58 +62202,16 @@ def printShowUserGroups(users):
|
||||
# [(domain <DomainName>)|(customerid <CustomerID>)]
|
||||
# [roles <GroupRoleList>]
|
||||
# [showparentsaslist [<Boolean>]] [delimiter <Character>]
|
||||
# [formatjson [quotechar <Character>]]
|
||||
# gam <UserTypeEntity> show grouptree
|
||||
# [(domain <DomainName>)|(customerid <CustomerID>)]
|
||||
# [roles <GroupRoleList>]
|
||||
# [formatjson]
|
||||
def printShowGroupTree(users):
|
||||
def getGroupParents(groupEmail, groupName):
|
||||
groupParents[groupEmail] = {'name': groupName, 'parents': []}
|
||||
_setUserGroupArgs(groupEmail, kwargs)
|
||||
try:
|
||||
entityList = callGAPIpages(cd.groups(), 'list', 'groups',
|
||||
throwReasons=GAPI.GROUP_LIST_USERKEY_THROW_REASONS,
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
orderBy='email', fields='nextPageToken,groups(email,name)', **kwargs)
|
||||
for parentGroup in entityList:
|
||||
groupParents[groupEmail]['parents'].append(parentGroup['email'])
|
||||
if parentGroup['email'] not in groupParents:
|
||||
getGroupParents(parentGroup['email'], parentGroup['name'])
|
||||
except (GAPI.invalidMember, GAPI.invalidInput):
|
||||
badRequestWarning(Ent.GROUP, Ent.MEMBER, groupEmail)
|
||||
except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.forbidden, GAPI.badRequest):
|
||||
accessErrorExit(cd)
|
||||
|
||||
def showGroupParents(groupEmail, role, i, count):
|
||||
kvList = [groupEmail, f'{groupParents[groupEmail]["name"]}']
|
||||
if role:
|
||||
kvList.extend([Ent.Singular(Ent.ROLE), role])
|
||||
printKeyValueListWithCount(kvList, i, count)
|
||||
Ind.Increment()
|
||||
for parentEmail in groupParents[groupEmail]['parents']:
|
||||
showGroupParents(parentEmail, None, 0, 0)
|
||||
Ind.Decrement()
|
||||
|
||||
def printGroupParents(groupEmail, row):
|
||||
if groupParents[groupEmail]['parents']:
|
||||
for parentEmail in groupParents[groupEmail]['parents']:
|
||||
row['parents'].append({'email': parentEmail, 'name': groupParents[parentEmail]['name']})
|
||||
printGroupParents(parentEmail, row)
|
||||
del row['parents'][-1]
|
||||
else:
|
||||
if not showParentsAsList:
|
||||
csvPF.WriteRowTitles(flattenJSON(row))
|
||||
else:
|
||||
crow = {'User': row['User'], 'Group': row['Group'], 'Name': row['Name']}
|
||||
if rolesSet:
|
||||
crow['Role'] = row['Role']
|
||||
crow['ParentsCount'] = len(row['parents'])
|
||||
crow['Parents'] = delimiter.join([parent['email'] for parent in row['parents']])
|
||||
crow['ParentsName'] = delimiter.join([parent['name'] for parent in row['parents']])
|
||||
csvPF.WriteRow(flattenJSON(crow))
|
||||
|
||||
cd = buildGAPIObject(API.DIRECTORY)
|
||||
kwargs = {'customer': GC.Values[GC.CUSTOMER_ID]}
|
||||
csvPF = CSVPrintFile(['User', 'Group', 'Name']) if Act.csvFormat() else None
|
||||
FJQC = FormatJSONQuoteChar(csvPF)
|
||||
delimiter = GC.Values[GC.CSV_OUTPUT_FIELD_DELIMITER]
|
||||
showParentsAsList = False
|
||||
rolesSet = set()
|
||||
@ -62234,14 +62232,19 @@ def printShowGroupTree(users):
|
||||
elif csvPF and myarg == 'showparentsaslist':
|
||||
showParentsAsList = getBoolean()
|
||||
else:
|
||||
unknownArgumentExit()
|
||||
FJQC.GetFormatJSONQuoteChar(myarg, False)
|
||||
if csvPF:
|
||||
if rolesSet:
|
||||
csvPF.AddTitles('Role')
|
||||
if not FJQC.formatJSON:
|
||||
if not showParentsAsList:
|
||||
csvPF.SetIndexedTitles(['parents'])
|
||||
else:
|
||||
csvPF.AddTitles(['ParentsCount', 'Parents', 'ParentsName'])
|
||||
else:
|
||||
if rolesSet:
|
||||
csvPF.AddJSONTitles('Role')
|
||||
csvPF.AddJSONTitles('JSON')
|
||||
allRoles = rolesSet == ALL_GROUP_ROLES
|
||||
groupParents = {}
|
||||
i, count, users = getEntityArgument(users)
|
||||
@ -62259,7 +62262,7 @@ def printShowGroupTree(users):
|
||||
continue
|
||||
j = 0
|
||||
jcount = len(groups)
|
||||
if not csvPF:
|
||||
if not csvPF and not FJQC.formatJSON:
|
||||
if allRoles:
|
||||
entityPerformActionNumItems([Ent.USER, user], jcount, Ent.GROUP_TREE, i, count)
|
||||
else:
|
||||
@ -62269,7 +62272,7 @@ def printShowGroupTree(users):
|
||||
j += 1
|
||||
groupEmail = group['email']
|
||||
if groupEmail not in groupParents:
|
||||
getGroupParents(groupEmail, group['name'])
|
||||
getGroupParents(cd, groupParents, groupEmail, group['name'], kwargs)
|
||||
if rolesSet:
|
||||
try:
|
||||
result = callGAPI(cd.members(), 'get',
|
||||
@ -62287,13 +62290,30 @@ def printShowGroupTree(users):
|
||||
continue
|
||||
else:
|
||||
role = None
|
||||
if not FJQC.formatJSON:
|
||||
if not csvPF:
|
||||
showGroupParents(groupEmail, role, j, jcount)
|
||||
showGroupParents(groupParents, groupEmail, role, j, jcount)
|
||||
else:
|
||||
row = {'User': user, 'Group': groupEmail, 'Name': group['name'], 'parents': []}
|
||||
if role is not None:
|
||||
row['Role'] = role
|
||||
printGroupParents(groupParents, groupEmail, row, csvPF, delimiter, showParentsAsList)
|
||||
else:
|
||||
groupInfo = {'email': groupEmail, 'name': group['name'], 'parents': []}
|
||||
if role is not None:
|
||||
groupInfo['role'] = role
|
||||
addJsonGroupParents(groupParents, groupInfo, groupEmail)
|
||||
if not csvPF:
|
||||
printLine(json.dumps(cleanJSON(groupInfo), ensure_ascii=False, sort_keys=True))
|
||||
else:
|
||||
row = flattenJSON(groupInfo)
|
||||
if csvPF.CheckRowTitles(row):
|
||||
row = {'User': user, 'Group': groupEmail, 'Name': group['name']}
|
||||
if rolesSet:
|
||||
row['Role'] = role
|
||||
printGroupParents(groupEmail, row)
|
||||
row['JSON'] = json.dumps(cleanJSON(groupInfo),
|
||||
ensure_ascii=False, sort_keys=True)
|
||||
csvPF.WriteRowNoFilter(row)
|
||||
Ind.Decrement()
|
||||
if csvPF:
|
||||
csvPF.writeCSVfile('User Group Trees')
|
||||
@ -64599,7 +64619,8 @@ MESSAGES_MAX_TO_KEYWORDS = {
|
||||
|
||||
def _initMessageThreadParameters(entityType, doIt, maxToProcess):
|
||||
listType = 'messages' if entityType == Ent.MESSAGE else 'threads'
|
||||
return {'currLabelOp': 'and', 'prevLabelOp': 'and', 'labelGroupOpen': False, 'query': '',
|
||||
return {'currLabelOp': 'and', 'prevLabelOp': 'and', 'labelGroupOpen': False,
|
||||
'query': '', 'queryTimes': {},
|
||||
'entityType': entityType, 'messageEntity': None, 'doIt': doIt, 'quick': True,
|
||||
'labelMatchPattern': None, 'senderMatchPattern': None,
|
||||
'maxToProcess': maxToProcess, 'maxItems': 0,
|
||||
@ -64611,6 +64632,8 @@ LABEL_QUERY_REPLACEMENT_CHARACTERS = ' &()"|{}/'
|
||||
def _getMessageSelectParameters(myarg, parameters):
|
||||
if myarg == 'query':
|
||||
parameters['query'] += f' ({getString(Cmd.OB_QUERY)})'
|
||||
elif myarg.startswith('querytime'):
|
||||
parameters['queryTimes'][myarg] = getDateOrDeltaFromNow().replace('-', '/')
|
||||
elif myarg == 'matchlabel':
|
||||
labelTemp = getString(Cmd.OB_LABEL_NAME).lower()
|
||||
labelName = ''
|
||||
@ -64667,6 +64690,9 @@ def _finalizeMessageSelectParameters(parameters, queryOrIdsRequired):
|
||||
if parameters['query']:
|
||||
if parameters['labelGroupOpen']:
|
||||
parameters['query'] += ')'
|
||||
if parameters['queryTimes']:
|
||||
for queryTimeName, queryTimeValue in iter(parameters['queryTimes'].items()):
|
||||
parameters['query'] = parameters['query'].replace(f'#{queryTimeName}#', queryTimeValue)
|
||||
_mapMessageQueryDates(parameters)
|
||||
elif queryOrIdsRequired and parameters['messageEntity'] is None:
|
||||
missingArgumentExit('query|matchlabel|ids')
|
||||
@ -64675,7 +64701,7 @@ def _finalizeMessageSelectParameters(parameters, queryOrIdsRequired):
|
||||
parameters['maxItems'] = parameters['maxToProcess'] if parameters['quick'] and not parameters['labelMatchPattern'] else 0
|
||||
|
||||
# gam <UserTypeEntity> archive messages <GroupItem>
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_archive <Number>])|(ids <MessageIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_archive <Number>])|(ids <MessageIDEntity>)
|
||||
def archiveMessages(users):
|
||||
entityType = Ent.MESSAGE
|
||||
parameters = _initMessageThreadParameters(entityType, False, 0)
|
||||
@ -64905,30 +64931,30 @@ def _processMessagesThreads(users, entityType):
|
||||
Ind.Decrement()
|
||||
|
||||
# gam <UserTypeEntity> delete message|messages
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_delete <Number>])|(ids <MessageIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_delete <Number>])|(ids <MessageIDEntity>)
|
||||
# gam <UserTypeEntity> modify message|messages
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_modify <Number>])|(ids <MessageIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_modify <Number>])|(ids <MessageIDEntity>)
|
||||
# (addlabel <LabelName>)* (removelabel <LabelName>)*
|
||||
# gam <UserTypeEntity> spam message|messages
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_spam <Number>])|(ids <MessageIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_spam <Number>])|(ids <MessageIDEntity>)
|
||||
# gam <UserTypeEntity> trash message|messages
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_trash <Number>])|(ids <MessageIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_trash <Number>])|(ids <MessageIDEntity>)
|
||||
# gam <UserTypeEntity> untrash message|messages
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_untrash <Number>])|(ids <MessageIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_untrash <Number>])|(ids <MessageIDEntity>)
|
||||
def processMessages(users):
|
||||
_processMessagesThreads(users, Ent.MESSAGE)
|
||||
|
||||
# gam <UserTypeEntity> delete thread|threads
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_delete <Number>])|(ids <ThreadIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_delete <Number>])|(ids <ThreadIDEntity>)
|
||||
# gam <UserTypeEntity> modify thread|threads
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_modify <Number>])|(ids <ThreadIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_modify <Number>])|(ids <ThreadIDEntity>)
|
||||
# (addlabel <LabelName>)* (removelabel <LabelName>)*
|
||||
# gam <UserTypeEntity> spam thread|threads
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_spam <Number>])|(ids <ThreadIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_spam <Number>])|(ids <ThreadIDEntity>)
|
||||
# gam <UserTypeEntity> trash thread|threads
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_trash <Number>])|(ids <MessageIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_trash <Number>])|(ids <MessageIDEntity>)
|
||||
# gam <UserTypeEntity> untrash thread|threads
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_untrash <Number>])|(ids <ThreadIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_untrash <Number>])|(ids <ThreadIDEntity>)
|
||||
def processThreads(users):
|
||||
_processMessagesThreads(users, Ent.THREAD)
|
||||
|
||||
@ -65038,13 +65064,13 @@ def exportMessagesThreads(users, entityType):
|
||||
Ind.Decrement()
|
||||
|
||||
# gam <UserTypeEntity> export message|messages
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_export <Number>])|(ids <MessageIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_export <Number>])|(ids <MessageIDEntity>)
|
||||
# [targetfolder <FilePath>] [targetname <FileName>] [overwrite [<Boolean>]]
|
||||
def exportMessages(users):
|
||||
exportMessagesThreads(users, Ent.MESSAGE)
|
||||
|
||||
# gam <UserTypeEntity> export thread|threads
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_export <Number>])|(ids <ThreadIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_export <Number>])|(ids <ThreadIDEntity>)
|
||||
# [targetfolder <FilePath>] [targetname <FileName>] [overwrite [<Boolean>]]
|
||||
def exportThreads(users):
|
||||
exportMessagesThreads(users, Ent.THREAD)
|
||||
@ -65064,10 +65090,10 @@ def _decodeHeader(header):
|
||||
return header
|
||||
|
||||
# gam <UserTypeEntity> forward message|messages recipient|to <RecipientEntity>
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_forward <Number>])|(ids <MessageIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_forward <Number>])|(ids <MessageIDEntity>)
|
||||
# [subject <String>] [altcharset <String>]
|
||||
# gam <UserTypeEntity> forward thread|threads recipient|to <RecipientEntity>
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_forward <Number>])|(ids <ThreadIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_forward <Number>])|(ids <ThreadIDEntity>)
|
||||
# [subject <String>] [altcharset <String>]
|
||||
def forwardMessagesThreads(users, entityType):
|
||||
def getRecipients():
|
||||
@ -65371,7 +65397,7 @@ def _draftImportInsertMessage(users, operation):
|
||||
emlFile = True
|
||||
internalDateSource = 'dateHeader'
|
||||
elif myarg == 'replace':
|
||||
_getTagReplacement(tagReplacements, False)
|
||||
_getTagReplacement(tagReplacements, True)
|
||||
elif operation in IMPORT_INSERT and myarg == 'addlabel':
|
||||
addLabelNames.append(getString(Cmd.OB_LABEL_NAME, minLen=1))
|
||||
elif operation in IMPORT_INSERT and myarg == 'labels':
|
||||
@ -66184,7 +66210,7 @@ def printShowMessagesThreads(users, entityType):
|
||||
csvPF.writeCSVfile('Message Counts' if not show_labels else 'Message Label Counts')
|
||||
|
||||
# gam <UserTypeEntity> print message|messages
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_print <Number>] [includespamtrash])|(ids <MessageIDEntity>)
|
||||
# (((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]
|
||||
@ -66192,7 +66218,7 @@ def printShowMessagesThreads(users, entityType):
|
||||
# [convertcrnl] [delimiter <Character>] [todrive <ToDriveAttribute>*]
|
||||
# [countsonly|positivecountsonly] [useronly]
|
||||
# gam <UserTypeEntity> show message|messages
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_show <Number>] [includespamtrash])|(ids <MessageIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_show <Number>] [includespamtrash])|(ids <MessageIDEntity>)
|
||||
# [labelmatchpattern <RegularExpression>] [sendermatchpattern <RegularExpression>]
|
||||
# [headers all|<SMTPHeaderList>] [dateheaderformat iso|rfc2822|<String>] [dateheaderconverttimezone [<Boolean>]]
|
||||
# [showlabels] [showbody] [showdate] [showsize] [showsnippet]
|
||||
@ -66203,7 +66229,7 @@ def printShowMessages(users):
|
||||
printShowMessagesThreads(users, Ent.MESSAGE)
|
||||
|
||||
# gam <UserTypeEntity> print thread|threads
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_print <Number>] [includespamtrash])|(ids <ThreadIDEntity>)
|
||||
# (((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]
|
||||
@ -66211,7 +66237,7 @@ def printShowMessages(users):
|
||||
# [convertcrnl] [delimiter <Character>] [todrive <ToDriveAttribute>*]
|
||||
# [countsonly|positivecountsonly] [useronly]
|
||||
# gam <UserTypeEntity> show thread|threads
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_show <Number>] [includespamtrash])|(ids <ThreadIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_show <Number>] [includespamtrash])|(ids <ThreadIDEntity>)
|
||||
# [labelmatchpattern <RegularExpression>]
|
||||
# [headers all|<SMTPHeaderList>] [dateheaderformat iso|rfc2822|<String>] [dateheaderconverttimezone [<Boolean>]]
|
||||
# [showlabels] [showbody] [showdate] [showsize] [showsnippet]
|
||||
@ -67169,10 +67195,10 @@ EMAILSETTINGS_FORWARD_POP_ACTION_CHOICE_MAP = {
|
||||
}
|
||||
|
||||
# gam <UserTypeEntity> forward message|messages recipient|to <RecipientEntity>
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_forward <Number>])|(ids <MessageIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_forward <Number>])|(ids <MessageIDEntity>)
|
||||
# [subject <String>]
|
||||
# gam <UserTypeEntity> forward thread|threads recipient|to <RecipientEntity>
|
||||
# (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_forward <Number>])|(ids <ThreadIDEntity>)
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_forward <Number>])|(ids <ThreadIDEntity>)
|
||||
# [subject <String>]
|
||||
# gam <UserTypeEntity> forward <FalseValues>
|
||||
# gam <UserTypeEntity> forward <TrueValues> keep|leaveininbox|archive|delete|trash|markread <EmailAddress>
|
||||
|
@ -438,6 +438,7 @@ STRING_LENGTH = 'string length'
|
||||
SUBKEY_FIELD_MISMATCH = 'subkeyfield {0} does not match saved subkeyfield {1}'
|
||||
SUBSCRIPTION_NOT_FOUND = 'Could not find subscription'
|
||||
SUFFIX_NOT_ALLOWED_WITH_CUSTOMLANGUAGE = 'Suffix {0} not allowed with customLanguage {1}'
|
||||
TASKLIST_TITLE_NOT_FOUND = 'Task list title not found'
|
||||
THREAD = 'thread'
|
||||
THREADS = 'threads'
|
||||
TO = 'To'
|
||||
|
Reference in New Issue
Block a user