mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-18 05:01:37 +00:00
Compare commits
40 Commits
20250606.0
...
v7.10.03
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e875acf428 | ||
|
|
5d213e9951 | ||
|
|
35d61da0a0 | ||
|
|
da04ead86d | ||
|
|
5526c987ea | ||
|
|
d9795b3f83 | ||
|
|
39a17bacb1 | ||
|
|
af94ea6e54 | ||
|
|
c220f41cbe | ||
|
|
8a32e53652 | ||
|
|
372f86a79a | ||
|
|
7f307254bf | ||
|
|
2ae7b4a4b5 | ||
|
|
6dde273ee9 | ||
|
|
b66f6f60fe | ||
|
|
01fcefc647 | ||
|
|
a59e3008c5 | ||
|
|
eb82da4ff2 | ||
|
|
c4aa399446 | ||
|
|
f1713ec685 | ||
|
|
74924c9c0e | ||
|
|
8d3b65f5f1 | ||
|
|
260f2d3f5c | ||
|
|
475275add7 | ||
|
|
d71832096a | ||
|
|
f12d3abfc1 | ||
|
|
474aa069b7 | ||
|
|
c49708cbae | ||
|
|
43ecba07bb | ||
|
|
51f8ebe8e2 | ||
|
|
28edce3aca | ||
|
|
fe1f0285f8 | ||
|
|
da83121d0d | ||
|
|
f58a69e374 | ||
|
|
2f40a164c5 | ||
|
|
58a3fa7313 | ||
|
|
39ce5b7349 | ||
|
|
860d44d819 | ||
|
|
5e90ff143e | ||
|
|
28e05bf09a |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -126,7 +126,7 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
cache.tar.xz
|
||||
key: gam-${{ matrix.jid }}-20250603
|
||||
key: gam-${{ matrix.jid }}-20250611
|
||||
|
||||
- name: Untar Cache archive
|
||||
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
This document describes the GAM command line syntax in modified BNF, see https://en.wikipedia.org/wiki/Backus-Naur_Form
|
||||
his document describes the GAM command line syntax in modified BNF, see https://en.wikipedia.org/wiki/Backus-Naur_Form
|
||||
Skip the History section and start reading at Introduction.
|
||||
|
||||
Items on the command line are space separated, when an actual space character is required, it will be indicated by <Space>.
|
||||
@@ -380,6 +380,8 @@ If an item contains spaces, it should be surrounded by ".
|
||||
domain:<DomainName>|domain|default
|
||||
<CalendarItem> ::= <EmailAddress>
|
||||
<ChannelCustomerID> ::= <String>
|
||||
<ChatEmojiName> ::= :<String>:
|
||||
<ChatEmoji> ::= emojiname <ChatEmojiName> | customemojis/<String>
|
||||
<ChatMember> ::= spaces/<String>/members/<String>
|
||||
<ChatMessage> ::= spaces/<String>/messages/<String>
|
||||
<ChatSpace> ::= spaces/<String> | space <String> | space spaces/<String>
|
||||
@@ -664,6 +666,7 @@ If an item contains spaces, it should be surrounded by ".
|
||||
(gdoc|ghtml <UserGoogleDoc>)|
|
||||
(gcsdoc|gcshtml <StorageBucketObjectName>)
|
||||
<YouTubeChannelID> ::= <String>
|
||||
|
||||
## Lists of basic items
|
||||
|
||||
<APIScopeURLList> ::= "<APIScopeURL>(,<APIScopeURL>)*"
|
||||
@@ -2725,6 +2728,7 @@ gam print chromschemas [todrive <ToDriveAttribute>*]
|
||||
<ChromePolicySchemaFieldName>* [fields <ChromePolicySchemaFieldNameList>]
|
||||
[[formatjson [quotechar <Character>]]
|
||||
|
||||
gam info chromeschema std <SchemaName>
|
||||
gam show chromeschemas std
|
||||
[filter <String>]
|
||||
|
||||
@@ -4436,13 +4440,14 @@ gam report usage customer [todrive <ToDriveAttribute>*]
|
||||
calendar|calendars|
|
||||
chat|
|
||||
chrome|
|
||||
classroom|
|
||||
contextawareaccess|
|
||||
currents|gplus|google+|
|
||||
datastudio|
|
||||
devices|mobile|
|
||||
domain|
|
||||
drive|doc|docs|
|
||||
gcp|
|
||||
gcp|cloud|
|
||||
gemini|geminiforworkspace|
|
||||
groups|group|
|
||||
groupsenterprise|enterprisegroups|
|
||||
@@ -4461,7 +4466,7 @@ gam report <ActivityApplicationName> [todrive <ToDriveAttribute>*]
|
||||
[(user all|<UserItem>)|(orgunit|org|ou <OrgUnitPath> [showorgunit])|(select <UserTypeEntity>)]
|
||||
[([start <Time>] [end <Time>])|(range <Time> <Time>)|
|
||||
yesterday|today|thismonth|(previousmonths <Integer>)]
|
||||
[filtertime.* <Time>] [filter|filters <String>]
|
||||
[filtertime.String> <Time>] [filter|filters <String>]
|
||||
[event|events <EventNameList>] [ip <String>]
|
||||
[groupidfilter <String>]
|
||||
[maxactivities <Number>] [maxevents <Number>] [maxresults <Number>]
|
||||
@@ -5030,18 +5035,18 @@ gam <UserTypeEntity> delete permissions <SharedDriveEntityAdmin> <DriveFilePermi
|
||||
|
||||
In these commands, the Google administrator named in oauth2.txt is used.
|
||||
|
||||
gam copy teamdriveacls <SharedDriveEntity> to <SharedDriveEntity>
|
||||
gam copy shareddriveacls <SharedDriveEntity> to <SharedDriveEntity>
|
||||
[adminaccess|asadmin]
|
||||
[showpermissionsmessages [<Boolean>]]
|
||||
[excludepermissionsfromdomains|includepermissionsfromdomains <DomainNameList>]
|
||||
(mappermissionsdomain <DomainName> <DomainName>)*
|
||||
gam sync teamdriveacls <SharedDriveEntity> with <SharedDriveEntity>
|
||||
gam sync shareddriveacls <SharedDriveEntity> with <SharedDriveEntity>
|
||||
[adminaccess|asadmin]
|
||||
[showpermissionsmessages [<Boolean>]]
|
||||
[excludepermissionsfromdomains|includepermissionsfromdomains <DomainNameList>]
|
||||
(mappermissionsdomain <DomainName> <DomainName>)*
|
||||
|
||||
gam print teamdriveacls [todrive <ToDriveAttribute>*]
|
||||
gam print shareddriveacls [todrive <ToDriveAttribute>*]
|
||||
[teamdriveadminquery|query <QueryTeamDrive>]
|
||||
[matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>]
|
||||
[user|group <EmailAddress> [checkgroups]] (role|roles <SharedDriveACLRoleList>)*
|
||||
@@ -5049,7 +5054,7 @@ gam print teamdriveacls [todrive <ToDriveAttribute>*]
|
||||
[oneitemperrow] [<DrivePermissionsFieldName>*|(fields <DrivePermissionsFieldNameList>)]
|
||||
(addcsvdata <FieldName> <String>)*
|
||||
[formatjson [quotechar <Character>]]
|
||||
gam show teamdriveacls
|
||||
gam show shareddriveacls
|
||||
[teamdriveadminquery|query <QueryTeamDrive>]
|
||||
[matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>]
|
||||
[user|group <EmailAddress> [checkgroups]] (role|roles <SharedDriveACLRoleList>)*
|
||||
@@ -5059,18 +5064,18 @@ gam show teamdriveacls
|
||||
|
||||
In these commands, you specify an administrator and then indicate that you want domain administrator access with the adminaccess option.
|
||||
|
||||
gam <UserTypeEntity> copy teamdriveacls <SharedDriveEntity> to <SharedDriveEntity>
|
||||
gam <UserTypeEntity> copy shareddriveacls <SharedDriveEntity> to <SharedDriveEntity>
|
||||
[adminaccess|asadmin]
|
||||
[showpermissionsmessages [<Boolean>]]
|
||||
[excludepermissionsfromdomains|includepermissionsfromdomains <DomainNameList>]
|
||||
(mappermissionsdomain <DomainName> <DomainName>)*
|
||||
gam <UserTypeEntity> sync teamdriveacls <SharedDriveEntity> with <SharedDriveEntity>
|
||||
gam <UserTypeEntity> sync shareddriveacls <SharedDriveEntity> with <SharedDriveEntity>
|
||||
[adminaccess|asadmin]
|
||||
[showpermissionsmessages [<Boolean>]]
|
||||
[excludepermissionsfromdomains|includepermissionsfromdomains <DomainNameList>]
|
||||
(mappermissionsdomain <DomainName> <DomainName>)*
|
||||
|
||||
gam <UserTypeEntity> print teamdriveacls [todrive <ToDriveAttribute>*]
|
||||
gam <UserTypeEntity> print shareddriveacls [todrive <ToDriveAttribute>*]
|
||||
[adminaccess|asadmin] [teamdriveadminquery|query <QueryTeamDrive>]
|
||||
[matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>]
|
||||
[user|group <EmailAddress> [checkgroups]] (role|roles <SharedDriveACLRoleList>)*
|
||||
@@ -5079,7 +5084,7 @@ gam <UserTypeEntity> print teamdriveacls [todrive <ToDriveAttribute>*]
|
||||
[shownopermissionsdrives false|true|only]
|
||||
(addcsvdata <FieldName> <String>)*
|
||||
[formatjson [quotechar <Character>]]
|
||||
gam <UserTypeEntity> show teamdriveacls
|
||||
gam <UserTypeEntity> show shareddriveacls
|
||||
[adminaccess|asadmin] [teamdriveadminquery|query <QueryTeamDrive>]
|
||||
[matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>]
|
||||
[user|group <EmailAddress> [checkgroups]] (role|roles <SharedDriveACLRoleList>)*
|
||||
@@ -6435,6 +6440,22 @@ gam <UserTypeEntity> print chatevents [todrive <ToDriveAttribute>*]
|
||||
filter <String>
|
||||
[formatjson [quotechar <Character>]]
|
||||
|
||||
<ChatEmojiName> ::= :[0-9a-z_-]+:
|
||||
<ChatEmoji> ::= emojiname <ChatEmojiName> | customemojis/<String>
|
||||
|
||||
gam <UserTypeEntity> create chatemoji <ChatEmojiName>
|
||||
([drivedir|(sourcefolder <FilePath>)] [filename <FileNamePattern>])
|
||||
[formatjson]
|
||||
gam <UserTypeEntity> delete chatemoji <ChatEmoji>
|
||||
gam <UserTypeEntity> info chatemoji <ChatEmoji>
|
||||
[formatjson]
|
||||
gam <UserTypeEntity> show chatemojis
|
||||
[showcreatedby any|me|others]
|
||||
[formatjson]
|
||||
gam <UserTypeEntity> print chatemojis [todrive <ToDriveAttribute>*]
|
||||
[showcreatedby any|me|others]
|
||||
[formatjson [quotechar <Character>]]
|
||||
|
||||
# Users - Drive
|
||||
|
||||
<DriveFileOrderByFieldName> ::=
|
||||
@@ -7203,7 +7224,8 @@ gam <UserTypeEntity> show filesharecounts
|
||||
owners|
|
||||
parents|
|
||||
size|
|
||||
trashed
|
||||
trashed|
|
||||
webviewlink
|
||||
<FileTreeFieldNameList> ::= "<FileTreeFieldName>(,<FileTreeFieldName>)*"
|
||||
|
||||
gam <UserTypeEntity> print filetree [todrive <ToDriveAttribute>*]
|
||||
@@ -7396,10 +7418,12 @@ gam <UserTypeEntity> print filters [labelidsonly] [todrive <ToDriveAttribute>*]
|
||||
|
||||
gam <UserTypeEntity> create form
|
||||
title <String> [description <String>] [isquiz [<Boolean>]] [<JSONData>]
|
||||
[ispublished [<Boolean>] isacceptingresponses [<Boolean>]]
|
||||
[drivefilename <DriveFileName>] [<DriveFileParentAttribute>]
|
||||
[(csv [todrive <ToDriveAttribute>*]) | returnidonly]
|
||||
gam <UserTypeEntity> update form <DriveFileEntity>
|
||||
[title <String>] [description <String>] [isquiz [<Boolean>]] [<JSONData>]
|
||||
[ispublished [<Boolean>] isacceptingresponses [<Boolean>]]
|
||||
|
||||
gam <UserTypeEntity> print forms <DriveFileEntity> [todrive <ToDriveAttribute>*]
|
||||
(addcsvdata <FieldName> <String>)*
|
||||
@@ -7591,48 +7615,61 @@ gam <UserTypeEntity> insert message
|
||||
|
||||
gam <UserTypeEntity> archive messages <GroupItem>
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_archive <Number>])|(ids <MessageIDEntity>)
|
||||
[csv [todrive <ToDriveAttribute>*]]
|
||||
gam <UserTypeEntity> delete messages|threads
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_delete <Number>])|(ids <MessageIDEntity>)
|
||||
[csv [todrive <ToDriveAttribute>*]]
|
||||
gam <UserTypeEntity> modify messages|threads
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_modify <Number>])|(ids <MessageIDEntity>)
|
||||
((addlabel <LabelName>)|(removelabel <LabelName>))+
|
||||
[csv [todrive <ToDriveAttribute>*]]
|
||||
gam <UserTypeEntity> spam messages|threads
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_spam <Number>])|(ids <MessageIDEntity>)
|
||||
[csv [todrive <ToDriveAttribute>*]]
|
||||
gam <UserTypeEntity> trash messages|threads
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_trash <Number>])|(ids <MessageIDEntity>)
|
||||
[csv [todrive <ToDriveAttribute>*]]
|
||||
gam <UserTypeEntity> untrash messages|threads
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_untrash <Number>])|(ids <MessageIDEntity>)
|
||||
[csv [todrive <ToDriveAttribute>*]]
|
||||
|
||||
gam <UserTypeEntity> export message|messages
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_export <Number>])|(ids <MessageIDEntity>)
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_export <Number>])|(ids <MessageIDEntity>)
|
||||
[targetfolder <FilePath>] [targetname <FileName>] [overwrite [<Boolean>]]
|
||||
gam <UserTypeEntity> export thread|threads
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_export <Number>])|(ids <ThreadIDEntity>)
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[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> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_forward <Number>])|(ids <MessageIDEntity>)
|
||||
[subject <String>] [addorigfieldstosubject [<Boolean>]] [altcharset <String>]
|
||||
gam <UserTypeEntity> forward thread|thtreads recipient|to <RecipientEntity>
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
quick|notquick] [doit] [max_to_forward <Number>])|(ids <ThreadIDEntity>)
|
||||
[subject <String>] [addorigfieldstosubject [<Boolean>]] [altcharset <String>]
|
||||
|
||||
gam <UserTypeEntity> show messages|threads
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])*
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [max_to_show <Number>] [includespamtrash])|(ids <MessageIDEntity>)
|
||||
[labelmatchpattern <REMatchPattern>] [sendermatchpattern <REMatchPattern>]
|
||||
[countsonly|positivecountsonly] [useronly]
|
||||
@@ -7645,6 +7682,7 @@ gam <UserTypeEntity> show messages|threads
|
||||
[uploadattachments [<DriveFileParentAttribute>]]]
|
||||
gam <UserTypeEntity> print messages|threads [todrive <ToDriveAttribute>*]
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])*
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [max_to_print <Number>] [includespamtrash])|(ids <MessageIDEntity>)
|
||||
[labelmatchpattern <REMatchPattern>] [sendermatchpattern <REMatchPattern>]
|
||||
[countsonly|positivecountsonly] [useronly]
|
||||
|
||||
@@ -1,3 +1,70 @@
|
||||
7.10.03
|
||||
|
||||
Fixed bug in commands that modify messages where the `labelids <LabelIdList>` option
|
||||
was not being applied.
|
||||
|
||||
7.10.02
|
||||
|
||||
Added option `labelids <LabelIdList>` to all commands that process messages;
|
||||
this option causes GAM to only return messages with labels that match all of the specified label IDs.
|
||||
|
||||
Updated `gam <UserTypeEntity> print|show forms` to always display `isPublished` and
|
||||
`isAcceptingResponses` in `publishSettings/publishState` regardless of their value;
|
||||
the API doesn't return these values when they are False.
|
||||
|
||||
7.10.01
|
||||
|
||||
Added options `ispublished [<Boolean>]` and `isacceptingresponses [<Boolean>]` to
|
||||
`gam <UserTypeEntity> create|update form`.
|
||||
|
||||
7.10.00
|
||||
|
||||
Added commands to manage/display Chat Custom Emojis.
|
||||
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Users-Chat#manage-chat-emojis
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Users-Chat#display-chat-emojis
|
||||
|
||||
Updated `gam <UserItem> print|show chatspaces|chatmembers asadmin` to display
|
||||
the spaces in ascending display name order.
|
||||
|
||||
7.09.07
|
||||
|
||||
Added `webviewlink` to `<FileTreeFieldName>` for use in `gam <UserTypeEntity> print|show filetree`.
|
||||
|
||||
7.09.06
|
||||
|
||||
Upddated `gam print|show shareddrives`, `gam print|show shareddriveacls`, `gam print shareddriveorganizers`
|
||||
to display the Shared Drives in ascending name order; the API returns them in an unidentifiable order.
|
||||
|
||||
7.09.05
|
||||
|
||||
Improved output of `gam info|show chromeschemas [std]` to more accurately display the schemas.
|
||||
|
||||
Fixed bugs in `gam update chromepolicy` that caused invalid error messaages.
|
||||
|
||||
7.09.04
|
||||
|
||||
Fixed bug in `gam whatis <EmailItem>` where the check for an invitable user always failed.
|
||||
|
||||
Fixed bug in `gam print shareddriveorganizers` where no organizers were displayed when `domain` in `gam.cfg` was blank.
|
||||
|
||||
Updated to Python 3.13.5
|
||||
|
||||
7.09.03
|
||||
|
||||
Updated `gam <UserTypeEntity> create focustime|outofoffice ... timerange <Time> <Time>` to check
|
||||
that the first `<Time>` is less than the second `Time`; previously the event was not created.
|
||||
|
||||
For new installs the `enforce_expansive_access` Boolean variable in `gam.cfg` now defaults to True.
|
||||
For existing installations, if `enforce_expansive_access` has not been added to `gam.cfg`,
|
||||
a default value of True will be used.
|
||||
|
||||
7.09.02
|
||||
|
||||
Added command `gam info chromeschema std <SchemaName>` to display a Chrome policy schema in the same format as Legacy GAM.
|
||||
|
||||
Improved output of `gam show chromeschemas [std]` and `gam info chromeschema [std]` to more accurately display the schemas.
|
||||
|
||||
7.09.01
|
||||
|
||||
Fixed bug in `gam <UserTypeEntity> print diskusage` where the `ownedByMe` column was
|
||||
|
||||
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
|
||||
"""
|
||||
|
||||
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
|
||||
__version__ = '7.09.01'
|
||||
__version__ = '7.10.03'
|
||||
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
||||
|
||||
#pylint: disable=wrong-import-position
|
||||
@@ -12353,7 +12353,8 @@ def checkServiceAccount(users):
|
||||
Ind.Increment()
|
||||
try:
|
||||
key = callGAPI(iam.projects().serviceAccounts().keys(), 'get',
|
||||
throwReasons=[GAPI.BAD_REQUEST, GAPI.INVALID, GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED],
|
||||
throwReasons=[GAPI.BAD_REQUEST, GAPI.INVALID, GAPI.NOT_FOUND,
|
||||
GAPI.PERMISSION_DENIED, GAPI.SERVICE_NOT_AVAILABLE],
|
||||
name=name, fields='validAfterTime')
|
||||
key_created, _ = iso8601.parse_date(key['validAfterTime'])
|
||||
key_age = todaysTime()-key_created
|
||||
@@ -12366,6 +12367,10 @@ def checkServiceAccount(users):
|
||||
Ent.SVCACCT, GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['client_email']],
|
||||
str(e))
|
||||
printPassFail(Msg.SERVICE_ACCOUNT_PRIVATE_KEY_AGE.format('UNKNOWN'), testWarn)
|
||||
except GAPI.serviceNotAvailable as e:
|
||||
entityActionFailedExit([Ent.PROJECT, GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['project_id'],
|
||||
Ent.SVCACCT, GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['client_email']],
|
||||
str(e))
|
||||
else:
|
||||
printPassFail(Msg.SERVICE_ACCOUNT_SKIPPING_KEY_AGE_CHECK.format(key_type), testPass)
|
||||
Ind.Decrement()
|
||||
@@ -13138,7 +13143,7 @@ def doWhatIs():
|
||||
entityUnknownWarning(Ent.EMAIL, email)
|
||||
setSysExitRC(ENTITY_IS_UKNOWN_RC)
|
||||
return
|
||||
if not invitableCheck or not getSvcAcctCredentials(API.CLOUDIDENTITY_USERINVITATIONS, _getAdminEmail(), softErrors=True):
|
||||
if not invitableCheck:
|
||||
isInvitableUser = False
|
||||
else:
|
||||
isInvitableUser, ci = _getIsInvitableUser(None, email)
|
||||
@@ -13551,7 +13556,10 @@ REPORT_CHOICE_MAP = {
|
||||
'calendars': 'calendar',
|
||||
'chat': 'chat',
|
||||
'chrome': 'chrome',
|
||||
'classroom': 'classroom',
|
||||
'cloud': 'gcp',
|
||||
'contextawareaccess': 'context_aware_access',
|
||||
'currents': 'gplus',
|
||||
'customer': 'customer',
|
||||
'customers': 'customer',
|
||||
'datastudio': 'data_studio',
|
||||
@@ -22781,7 +22789,7 @@ def _processPeopleContactPhotos(users, function):
|
||||
if function == 'GetContactPhoto' and not os.path.isdir(targetFolder):
|
||||
os.makedirs(targetFolder)
|
||||
elif myarg == 'filename':
|
||||
filenamePattern = getString(Cmd.OB_PHOTO_FILENAME_PATTERN)
|
||||
filenamePattern = getString(Cmd.OB_FILE_NAME_PATTERN)
|
||||
else:
|
||||
unknownArgumentExit()
|
||||
subForContactId = filenamePattern.find('#contactid#') != -1
|
||||
@@ -25947,7 +25955,7 @@ def exitIfChatNotConfigured(chat, kvList, errMsg, i, count):
|
||||
if (('No bot associated with this project.' in errMsg) or
|
||||
('Invalid project number.' in errMsg) or
|
||||
('Google Chat app not found.' in errMsg)):
|
||||
systemErrorExit(API_ACCESS_DENIED_RC, Msg.TO_SET_UP_GOOGLE_CHAT.format(setupChatURL(chat)))
|
||||
systemErrorExit(API_ACCESS_DENIED_RC, Msg.TO_SET_UP_GOOGLE_CHAT.format(setupChatURL(chat), GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['project_id']))
|
||||
entityActionFailedWarning(kvList, errMsg, i, count)
|
||||
|
||||
def _getChatAdminAccess(adminAPI, userAPI):
|
||||
@@ -25985,6 +25993,8 @@ def _printChatItem(user, citem, parent, entityType, csvPF, FJQC, addCSVData=None
|
||||
if entityType == Ent.CHAT_SPACE:
|
||||
_cleanChatSpace(citem)
|
||||
baserow = {'User': user} if user is not None else {}
|
||||
elif entityType == Ent.CHAT_EMOJI:
|
||||
baserow = {'User': user, 'name': citem['name'], 'emojiName': citem['emojiName']}
|
||||
else:
|
||||
if user is not None:
|
||||
baserow = {'User': user, 'space.name': parent['name'], 'space.displayName': parent['displayName']}
|
||||
@@ -26004,6 +26014,190 @@ def _printChatItem(user, citem, parent, entityType, csvPF, FJQC, addCSVData=None
|
||||
'JSON': json.dumps(cleanJSON(citem, timeObjects=CHAT_TIME_OBJECTS), ensure_ascii=False, sort_keys=True)})
|
||||
csvPF.WriteRowNoFilter(row)
|
||||
|
||||
def _getValidateEmojiName():
|
||||
name = getString(Cmd.OB_CHAT_EMOJI_NAME)
|
||||
if re.match(r'^:[0-9a-z_-]+:$', name):
|
||||
return name
|
||||
Cmd.Backup()
|
||||
usageErrorExit(Msg.INVALID_EMOJI_NAME.format(name))
|
||||
|
||||
# gam <UserTypeEntity> create chatemoji <ChatEmojiName>
|
||||
# ([drivedir|(sourcefolder <FilePath>)] [filename <FileNamePattern>])
|
||||
# [formatjson]
|
||||
def createChatEmoji(users):
|
||||
FJQC = FormatJSONQuoteChar()
|
||||
name = _getValidateEmojiName()
|
||||
body = {'emojiName': name, 'payload': {'filename': '', 'fileContent': ''}}
|
||||
sourceFolder = os.getcwd()
|
||||
filenamePattern = '#email#.jpg'
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if myarg == 'drivedir':
|
||||
sourceFolder = GC.Values[GC.DRIVE_DIR]
|
||||
elif myarg == 'sourcefolder':
|
||||
sourceFolder = os.path.expanduser(getString(Cmd.OB_FILE_PATH))
|
||||
if not os.path.isdir(sourceFolder):
|
||||
entityDoesNotExistExit(Ent.DIRECTORY, sourceFolder)
|
||||
elif myarg == 'filename':
|
||||
filenamePattern = getString(Cmd.OB_FILE_NAME_PATTERN)
|
||||
else:
|
||||
FJQC.GetFormatJSON(myarg)
|
||||
i, count, users = getEntityArgument(users)
|
||||
for user in users:
|
||||
i += 1
|
||||
user, chat, kvList = buildChatServiceObject(API.CHAT_CUSTOM_EMOJIS, user, i, count, [Ent.CHAT_EMOJI, name])
|
||||
if not chat:
|
||||
continue
|
||||
user, userName, _ = splitEmailAddressOrUID(user)
|
||||
filename = _substituteForUser(filenamePattern, user, userName)
|
||||
if sourceFolder is not None:
|
||||
filename = os.path.join(sourceFolder, filename)
|
||||
filename = os.path.expanduser(filename)
|
||||
try:
|
||||
with open(filename, 'rb') as f:
|
||||
image_data = f.read()
|
||||
except (OSError, IOError) as e:
|
||||
entityActionFailedWarning([Ent.USER, user, Ent.CHAT_EMOJI, filename], str(e), i, count)
|
||||
continue
|
||||
body['payload'] = {'filename': os.path.basename(filename),
|
||||
'fileContent':base64.urlsafe_b64encode(image_data).decode(UTF8)}
|
||||
try:
|
||||
emoji = callGAPI(chat.customEmojis(), 'create',
|
||||
throwReasons=[GAPI.ALREADY_EXISTS, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.FAILED_PRECONDITION],
|
||||
body=body)
|
||||
_showChatItem(emoji, Ent.CHAT_EMOJI, FJQC, i, count)
|
||||
except (GAPI.alreadyExists, GAPI.invalidArgument, GAPI.permissionDenied) as e:
|
||||
exitIfChatNotConfigured(chat, kvList, str(e), i, count)
|
||||
except GAPI.failedPrecondition:
|
||||
userChatServiceNotEnabledWarning(user, i, count)
|
||||
|
||||
def getEmojiName(myarg):
|
||||
if myarg == 'emojiname':
|
||||
name = _getValidateEmojiName()
|
||||
return 'customEmojis/'+name
|
||||
_, chatEmoji = Cmd.Previous().split('/', 1)
|
||||
return 'customEmojis/'+chatEmoji
|
||||
|
||||
# gam <UserTypeEntity> delete chatemoji <ChatEmoji>
|
||||
def deleteChatEmoji(users):
|
||||
name = None
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if myarg == 'emojiname':
|
||||
name = getEmojiName(myarg)
|
||||
elif myarg.startswith('customemojis/'):
|
||||
name = getEmojiName(myarg)
|
||||
else:
|
||||
unknownArgumentExit()
|
||||
if not name:
|
||||
missingArgumentExit('ChatEmoji')
|
||||
i, count, users = getEntityArgument(users)
|
||||
for user in users:
|
||||
i += 1
|
||||
user, chat, kvList = buildChatServiceObject(API.CHAT_CUSTOM_EMOJIS, user, i, count, [Ent.CHAT_EMOJI, name])
|
||||
if not chat:
|
||||
continue
|
||||
try:
|
||||
callGAPI(chat.customEmojis(), 'delete',
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.FAILED_PRECONDITION],
|
||||
name=name)
|
||||
entityActionPerformed(kvList, i, count)
|
||||
except (GAPI.notFound, GAPI.invalidArgument, GAPI.permissionDenied) as e:
|
||||
exitIfChatNotConfigured(chat, kvList, str(e), i, count)
|
||||
except GAPI.failedPrecondition:
|
||||
userChatServiceNotEnabledWarning(user, i, count)
|
||||
|
||||
# gam <UserTypeEntity> info chatemoji <ChatEmoji>
|
||||
# [formatjson]
|
||||
def infoChatEmoji(users):
|
||||
FJQC = FormatJSONQuoteChar()
|
||||
name = None
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if myarg == 'emojiname':
|
||||
name = getEmojiName(myarg)
|
||||
elif myarg.startswith('customemojis/'):
|
||||
name = getEmojiName(myarg)
|
||||
else:
|
||||
FJQC.GetFormatJSON(myarg)
|
||||
if not name:
|
||||
missingArgumentExit('ChatEmoji')
|
||||
i, count, users = getEntityArgument(users)
|
||||
for user in users:
|
||||
i += 1
|
||||
user, chat, kvList = buildChatServiceObject(API.CHAT_CUSTOM_EMOJIS, user, i, count, [Ent.CHAT_EMOJI, name])
|
||||
if not chat:
|
||||
continue
|
||||
try:
|
||||
emoji = callGAPI(chat.customEmojis(), 'get',
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.FAILED_PRECONDITION],
|
||||
name=name)
|
||||
if not FJQC.formatJSON:
|
||||
entityPerformAction(kvList, i, count)
|
||||
_showChatItem(emoji, Ent.CHAT_EMOJI, FJQC, i, count)
|
||||
except (GAPI.notFound, GAPI.invalidArgument, GAPI.permissionDenied) as e:
|
||||
exitIfChatNotConfigured(chat, kvList, str(e), i, count)
|
||||
except GAPI.failedPrecondition:
|
||||
userChatServiceNotEnabledWarning(user, i, count)
|
||||
|
||||
CHAT_EMOJI_SHOW_CREATED_BY_CHOICE_MAP = {
|
||||
'any': None,
|
||||
'me': 'creator("users/me")',
|
||||
'others': 'NOT creator("users/me")'
|
||||
}
|
||||
|
||||
# gam <UserTypeEntity> show chatemojis
|
||||
# [showcreatedby any|me|others]
|
||||
# [formatjson]
|
||||
# gam <UserTypeEntity> print chatemojis [todrive <ToDriveAttribute>*]
|
||||
# [showcreatedby any|me|others]
|
||||
# [formatjson [quotechar <Character>]]
|
||||
def printShowChatEmojis(users):
|
||||
csvPF = CSVPrintFile(['User', 'name', 'emojiName']) if Act.csvFormat() else None
|
||||
FJQC = FormatJSONQuoteChar(csvPF)
|
||||
pfilter = CHAT_EMOJI_SHOW_CREATED_BY_CHOICE_MAP['me']
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if csvPF and myarg == 'todrive':
|
||||
csvPF.GetTodriveParameters()
|
||||
elif myarg =='showcreatedby':
|
||||
pfilter = getChoice(CHAT_EMOJI_SHOW_CREATED_BY_CHOICE_MAP, mapChoice=True)
|
||||
else:
|
||||
FJQC.GetFormatJSONQuoteChar(myarg, True)
|
||||
i, count, users = getEntityArgument(users)
|
||||
for user in users:
|
||||
i += 1
|
||||
user, chat, kvList = buildChatServiceObject(API.CHAT_CUSTOM_EMOJIS, user, i, count, [Ent.CHAT_EMOJI, None])
|
||||
if not chat:
|
||||
continue
|
||||
try:
|
||||
emojis = callGAPIpages(chat.customEmojis(), 'list', 'customEmojis',
|
||||
pageMessage=_getChatPageMessage(Ent.CHAT_EMOJI, user, i, count, pfilter),
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
pageSize=CHAT_PAGE_SIZE, filter=pfilter)
|
||||
except (GAPI.notFound, GAPI.invalidArgument, GAPI.permissionDenied) as e:
|
||||
exitIfChatNotConfigured(chat, kvList, str(e), i, count)
|
||||
continue
|
||||
except GAPI.failedPrecondition:
|
||||
userChatServiceNotEnabledWarning(user, i, count)
|
||||
break
|
||||
if not csvPF:
|
||||
jcount = len(emojis)
|
||||
if not FJQC.formatJSON:
|
||||
entityPerformActionNumItems(kvList, jcount, Ent.CHAT_EMOJI, i, count)
|
||||
Ind.Increment()
|
||||
j = 0
|
||||
for emoji in sorted(emojis, key=lambda k: k['emojiName']):
|
||||
j += 1
|
||||
_showChatItem(emoji, Ent.CHAT_EMOJI, FJQC, j, jcount)
|
||||
Ind.Decrement()
|
||||
else:
|
||||
for emoji in sorted(emojis, key=lambda k: k['emojiName']):
|
||||
_printChatItem(user, emoji, '', Ent.CHAT_EMOJI, csvPF, FJQC)
|
||||
if csvPF:
|
||||
csvPF.writeCSVfile('Chat Custom Emojis')
|
||||
|
||||
# gam setup chat
|
||||
def doSetupChat():
|
||||
checkForExtraneousArguments()
|
||||
@@ -26467,6 +26661,9 @@ def printShowChatSpaces(users):
|
||||
substituteQueryTimes(queries, queryTimes)
|
||||
pfilter = kwargsCS['query'] = queries[0]
|
||||
kwargsCS['useAdminAccess'] = True
|
||||
sortName = 'displayName'
|
||||
else:
|
||||
sortName = 'name'
|
||||
for user in users:
|
||||
i += 1
|
||||
user, chat, kvList = buildChatServiceObject(api, user, i, count, None, useAdminAccess)
|
||||
@@ -26494,12 +26691,12 @@ def printShowChatSpaces(users):
|
||||
entityPerformActionNumItems(kvList, jcount, Ent.CHAT_SPACE, i, count)
|
||||
Ind.Increment()
|
||||
j = 0
|
||||
for space in spaces:
|
||||
for space in sorted(spaces, key=lambda k: k[sortName]):
|
||||
j += 1
|
||||
_showChatItem(space, Ent.CHAT_SPACE, FJQC, j, jcount)
|
||||
Ind.Decrement()
|
||||
else:
|
||||
for space in spaces:
|
||||
for space in sorted(spaces, key=lambda k: k[sortName]):
|
||||
_printChatItem(user, space, None, Ent.CHAT_SPACE, csvPF, FJQC)
|
||||
if csvPF:
|
||||
csvPF.writeCSVfile('Chat Spaces')
|
||||
@@ -27134,6 +27331,9 @@ def printShowChatMembers(users):
|
||||
i, count, users = getEntityArgument(users)
|
||||
if useAdminAccess:
|
||||
_chkChatAdminAccess(count)
|
||||
sortName = 'displayName'
|
||||
else:
|
||||
sortName = 'name'
|
||||
for user in users:
|
||||
i += 1
|
||||
user, chat, kvList = buildChatServiceObject(api, user, i, count, [Ent.CHAT_SPACE, None], useAdminAccess)
|
||||
@@ -27156,7 +27356,7 @@ def printShowChatMembers(users):
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
fields="nextPageToken,spaces(name,displayName,spaceType,membershipCount)", pageSize=CHAT_PAGE_SIZE,
|
||||
**kwargsCS)
|
||||
for space in spaces:
|
||||
for space in sorted(spaces, key=lambda k: k[sortName]):
|
||||
if space['spaceType'] == 'SPACE' and 'membershipCount' in space:
|
||||
parentList.append({'name': space['name'], 'displayName': space.get('displayName', 'None')})
|
||||
except (GAPI.notFound, GAPI.invalidArgument, GAPI.internalError,
|
||||
@@ -27173,7 +27373,7 @@ def printShowChatMembers(users):
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
fields="nextPageToken,spaces(name,displayName,spaceType,membershipCount)", pageSize=CHAT_PAGE_SIZE,
|
||||
**kwargsCS)
|
||||
for space in spaces:
|
||||
for space in sorted(spaces, key=lambda k: k[sortName]):
|
||||
# if 'membershipCount' in space:
|
||||
# parentList.append({'name': space['name'], 'displayName': space.get('displayName', 'None')})
|
||||
parentList.append({'name': space['name'], 'displayName': space.get('displayName', 'None')})
|
||||
@@ -28111,25 +28311,21 @@ def commonprefix(m):
|
||||
return s1[:i]
|
||||
return s1
|
||||
|
||||
def simplifyChromeSchema(schema):
|
||||
SCHEMA_TYPE_MESSAGE_MAP = {
|
||||
'NullableDuration': {'type': 'TYPE_INT64', 'namedType': 'duration'},
|
||||
'NullableLong': {'type': 'TYPE_INT64', 'namedType': 'value'},
|
||||
'SystemTimezone': {'type': 'TYPE_STRING', 'namedType': 'value'}
|
||||
}
|
||||
|
||||
def simplifyChromeSchemaUpdate(schema):
|
||||
schema_name = schema['name'].split('/')[-1]
|
||||
schema_dict = {'name': schema_name,
|
||||
'description': schema.get('policyDescription', ''),
|
||||
'settings': {}
|
||||
}
|
||||
fieldDescriptions = schema['fieldDescriptions']
|
||||
savedSettingName = ''
|
||||
schema_dict = {'name': schema_name, 'settings': {}}
|
||||
for mtype in schema['definition']['messageType']:
|
||||
if mtype['name'] in SCHEMA_TYPE_MESSAGE_MAP:
|
||||
continue
|
||||
for setting in mtype['field']:
|
||||
setting_name = setting['name']
|
||||
setting_dict = {'name': setting_name,
|
||||
'constraints': None,
|
||||
'descriptions': [],
|
||||
'type': setting['type'],
|
||||
}
|
||||
if setting_dict['type'] == 'TYPE_INT64' and savedSettingName:
|
||||
setting_dict['name'] = savedSettingName
|
||||
savedSettingName = ''
|
||||
setting_dict = {'name': setting_name, 'type': setting['type'], 'namedType': ''}
|
||||
if setting_dict['type'] == 'TYPE_STRING' and setting.get('label') == 'LABEL_REPEATED':
|
||||
setting_dict['type'] = 'TYPE_LIST'
|
||||
if setting_dict['type'] == 'TYPE_ENUM':
|
||||
@@ -28140,28 +28336,83 @@ def simplifyChromeSchema(schema):
|
||||
setting_dict['enum_prefix'] = commonprefix(setting_dict['enums'])
|
||||
prefix_len = len(setting_dict['enum_prefix'])
|
||||
setting_dict['enums'] = [enum[prefix_len:] for enum in setting_dict['enums'] if not enum.endswith('UNSPECIFIED')]
|
||||
setting_dict['descriptions'] = ['']*len(setting_dict['enums'])
|
||||
for i, an in enumerate(setting_dict['enums']):
|
||||
elif setting_dict['type'] == 'TYPE_MESSAGE':
|
||||
type_name = setting['typeName']
|
||||
if type_name not in SCHEMA_TYPE_MESSAGE_MAP:
|
||||
continue
|
||||
setting_dict['type'] = SCHEMA_TYPE_MESSAGE_MAP[type_name]['type']
|
||||
setting_dict['namedType'] = SCHEMA_TYPE_MESSAGE_MAP[type_name]['namedType']
|
||||
schema_dict['settings'][setting_name.lower()] = setting_dict
|
||||
return(schema_name, schema_dict)
|
||||
|
||||
def simplifyChromeSchemaDisplay(schema):
|
||||
schema_name = schema['name'].split('/')[-1]
|
||||
schema_dict = {'name': schema_name, 'description': schema.get('policyDescription', '')}
|
||||
fieldDescriptions = schema['fieldDescriptions']
|
||||
enumDict = {}
|
||||
for enumType in schema['definition'].get('enumType', []):
|
||||
enumEntry = {}
|
||||
enumEntry['enums'] = [enum['name'] for enum in enumType['value']]
|
||||
enumEntry['enum_prefix'] = commonprefix(enumEntry['enums'])
|
||||
enumEntry['enum_prefix_len'] = prefix_len = len(enumEntry['enum_prefix'])
|
||||
enumEntry['enums'] = [enum[prefix_len:] for enum in enumEntry['enums'] if not enum.endswith('UNSPECIFIED')]
|
||||
enumDict[enumType['name']] = enumEntry.copy()
|
||||
mesgDict = {}
|
||||
mesgPops = set()
|
||||
for mesgType in schema['definition']['messageType']:
|
||||
mtypeEntry = {'field': {}, 'subfield': False}
|
||||
for mfield in mesgType['field']:
|
||||
mfield.pop('number')
|
||||
mtypeEntry['field'][mfield.pop('name')] = mfield
|
||||
mesgDict[mesgType['name']] = mtypeEntry.copy()
|
||||
for _, mtypeEntry in mesgDict.items():
|
||||
for mfieldName, mfield in mtypeEntry['field'].items():
|
||||
mfield['descriptions'] = []
|
||||
if mfield['type'] == 'TYPE_STRING' and mfield.get('label') == 'LABEL_REPEATED':
|
||||
mfield['type'] = 'TYPE_LIST'
|
||||
if mfield['type'] == 'TYPE_ENUM':
|
||||
mfield['subtype'] = enumDict[mfield['typeName']]
|
||||
for an_enum in schema['definition']['enumType']:
|
||||
if an_enum['name'] == mfield['typeName']:
|
||||
mfield['descriptions'] = ['']*len(mfield['subtype']['enums'])
|
||||
for i, an in enumerate(mfield['subtype']['enums']):
|
||||
for fdesc in fieldDescriptions:
|
||||
if fdesc.get('field') == setting_name:
|
||||
if fdesc.get('field') == mfieldName:
|
||||
for d in fdesc.get('knownValueDescriptions', []):
|
||||
if d['value'][prefix_len:] == an:
|
||||
setting_dict['descriptions'][i] = d.get('description', '')
|
||||
if d['value'][mfield['subtype']['enum_prefix_len']:] == an:
|
||||
mfield['descriptions'][i] = d.get('description', '')
|
||||
break
|
||||
break
|
||||
break
|
||||
elif setting_dict['type'] == 'TYPE_MESSAGE':
|
||||
savedSettingName = setting_name
|
||||
elif mfield['type'] == 'TYPE_MESSAGE':
|
||||
subfield = mfield['typeName']
|
||||
if subfield not in SCHEMA_TYPE_MESSAGE_MAP:
|
||||
mesgDict[subfield]['subfield'] = True
|
||||
mfield['subtype'] = mesgDict[subfield]
|
||||
else:
|
||||
mfield['type'] = SCHEMA_TYPE_MESSAGE_MAP[subfield]['type']
|
||||
mesgPops.add(subfield)
|
||||
continue
|
||||
else:
|
||||
setting_dict['enums'] = None
|
||||
for fdesc in schema['fieldDescriptions']:
|
||||
if fdesc['field'] == setting_name:
|
||||
for fdesc in fieldDescriptions:
|
||||
if fdesc['field'] == mfieldName:
|
||||
if 'knownValueDescriptions' in fdesc:
|
||||
setting_dict['descriptions'] = fdesc['knownValueDescriptions']
|
||||
if isinstance(fdesc['knownValueDescriptions'], list):
|
||||
for kvd in fdesc['knownValueDescriptions']:
|
||||
if isinstance(kvd, dict):
|
||||
if 'description' in kvd:
|
||||
mfield['descriptions'].append(f"{kvd['value']}: {kvd['description']}")
|
||||
else:
|
||||
mfield['descriptions'].append(f"{kvd['value']}")
|
||||
else:
|
||||
mfield['descriptions'].extend(kvd)
|
||||
else:
|
||||
mfield['descriptions'].append(kvd)
|
||||
elif 'description' in fdesc:
|
||||
setting_dict['descriptions'] = [fdesc['description']]
|
||||
schema_dict['settings'][setting_name.lower()] = setting_dict
|
||||
mfield['descriptions'].append(fdesc['description'])
|
||||
for pfield in mesgPops:
|
||||
mesgDict.pop(pfield)
|
||||
schema_dict['settings'] = mesgDict
|
||||
return(schema_name, schema_dict)
|
||||
|
||||
def _getPolicyOrgUnitTarget(cd, cp, myarg, groupEmail):
|
||||
@@ -28310,7 +28561,16 @@ CHROME_SCHEMA_SPECIAL_CASES = {
|
||||
'chrome.users.RelaunchNotificationWithDurationV2':
|
||||
{'relaunchnotificationperiodduration':
|
||||
{'casedField': 'relaunchNotificationPeriodDuration',
|
||||
'type': 'duration', 'minVal': -1, 'maxVal': None}},
|
||||
'type': 'duration', 'minVal': 1, 'maxVal': 168},
|
||||
'relaunchinitialquietperiodduration':
|
||||
{'casedField': 'relaunchInitialQuietPeriodDuration',
|
||||
'type': 'duration', 'minVal': 0, 'maxVal': None},
|
||||
'relaunchwindowstarttime':
|
||||
{'casedField': 'relaunchWindowStartTime',
|
||||
'type': 'timeOfDay'},
|
||||
'relaunchwindowdurationmin':
|
||||
{'casedField': 'relaunchWindowDurationMin',
|
||||
'type': 'duration', 'minVal': 1, 'maxVal': 1440}},
|
||||
'chrome.users.SecurityTokenSessionSettingsV2':
|
||||
{'securitytokensessionnotificationseconds':
|
||||
{'casedField': 'securityTokenSessionNotificationSeconds',
|
||||
@@ -28472,7 +28732,7 @@ def doUpdateChromePolicy():
|
||||
return value
|
||||
#if vtype == timeOfDay:
|
||||
hours, minutes = value.split(':')
|
||||
return {vtype: {'hours': hours, 'minutes': minutes}}
|
||||
return {vtype: {'hours': int(hours), 'minutes': int(minutes)}}
|
||||
|
||||
cp = buildGAPIObject(API.CHROMEPOLICY)
|
||||
cd = buildGAPIObject(API.DIRECTORY)
|
||||
@@ -28495,7 +28755,7 @@ def doUpdateChromePolicy():
|
||||
elif myarg == 'convertcrnl':
|
||||
convertCRsNLs = True
|
||||
else:
|
||||
schemaName, schema = simplifyChromeSchema(_getChromePolicySchema(cp, Cmd.Previous(), '*'))
|
||||
schemaName, schema = simplifyChromeSchemaUpdate(_getChromePolicySchema(cp, Cmd.Previous(), '*'))
|
||||
body['requests'].append({'policyValue': {'policySchema': schemaName, 'value': {}},
|
||||
'updateMask': ''})
|
||||
schemaNameList.append(schemaName)
|
||||
@@ -28581,8 +28841,9 @@ def doUpdateChromePolicy():
|
||||
if field not in schema['settings']:
|
||||
Cmd.Backup()
|
||||
missingChoiceExit(schema['settings'])
|
||||
casedField = schema['settings'][field]['name']
|
||||
vtype = schema['settings'][field]['type']
|
||||
field_settings = schema['settings'][field]
|
||||
casedField = field_settings['name']
|
||||
vtype = field_settings['type']
|
||||
value = getString(Cmd.OB_STRING, minLen=0 if vtype in {'TYPE_STRING', 'TYPE_LIST'} else 1)
|
||||
if vtype in ['TYPE_INT64', 'TYPE_INT32', 'TYPE_UINT64']:
|
||||
if not value.isnumeric():
|
||||
@@ -28599,8 +28860,8 @@ def doUpdateChromePolicy():
|
||||
invalidChoiceExit(value, TRUE_FALSE, True)
|
||||
elif vtype == 'TYPE_ENUM':
|
||||
value = value.upper()
|
||||
prefix = schema['settings'][field]['enum_prefix']
|
||||
enum_values = schema['settings'][field]['enums']
|
||||
prefix = field_settings['enum_prefix']
|
||||
enum_values = field_settings['enums']
|
||||
if value in enum_values:
|
||||
value = f'{prefix}{value}'
|
||||
elif value.replace(prefix, '') in enum_values:
|
||||
@@ -28627,7 +28888,10 @@ def doUpdateChromePolicy():
|
||||
elif value and not CHROME_TARGET_VERSION_PATTERN.match(value):
|
||||
Cmd.Backup()
|
||||
invalidArgumentExit(Msg.CHROME_TARGET_VERSION_FORMAT)
|
||||
body['requests'][-1]['policyValue']['value'][casedField] = value
|
||||
if field_settings['namedType']:
|
||||
body['requests'][-1]['policyValue']['value'][casedField] = {field_settings['namedType']: value}
|
||||
else:
|
||||
body['requests'][-1]['policyValue']['value'][casedField] = value
|
||||
body['requests'][-1]['updateMask'] += f'{casedField},'
|
||||
checkPolicyArgs(targetResource, printer_id, app_id)
|
||||
count = len(body['requests'])
|
||||
@@ -28928,7 +29192,9 @@ def _showChromePolicySchema(schema, FJQC, i=0, count=0):
|
||||
return
|
||||
printEntity([Ent.CHROME_POLICY_SCHEMA, schema['name']], i, count)
|
||||
Ind.Increment()
|
||||
showJSON(None, schema)
|
||||
showJSON(None, schema,
|
||||
dictObjectsKey={'messageType': 'name', 'field': 'name',
|
||||
'fieldDescriptions': 'field', 'knownValueDescriptions': 'value'})
|
||||
Ind.Decrement()
|
||||
|
||||
CHROME_POLICY_SCHEMA_FIELDS_CHOICE_MAP = {
|
||||
@@ -28951,6 +29217,9 @@ CHROME_POLICY_SCHEMA_FIELDS_CHOICE_MAP = {
|
||||
# [formatjson]
|
||||
def doInfoChromePolicySchemas():
|
||||
cp = buildGAPIObject(API.CHROMEPOLICY)
|
||||
if checkArgumentPresent('std'):
|
||||
doInfoChromePolicySchemasStd(cp)
|
||||
return
|
||||
FJQC = FormatJSONQuoteChar()
|
||||
fieldsList = []
|
||||
name = _getChromePolicySchemaName()
|
||||
@@ -28979,7 +29248,7 @@ def doInfoChromePolicySchemas():
|
||||
# [filter <String>]
|
||||
# <ChromePolicySchemaFieldName>* [fields <ChromePolicySchemaFieldNameList>]
|
||||
# [[formatjson [quotechar <Character>]]
|
||||
def doPrintShowChromeSchemas():
|
||||
def doPrintShowChromePolicySchemas():
|
||||
def _printChromePolicySchema(schema):
|
||||
row = flattenJSON(schema)
|
||||
if not FJQC.formatJSON:
|
||||
@@ -28993,10 +29262,12 @@ def doPrintShowChromeSchemas():
|
||||
row['JSON'] = json.dumps(cleanJSON(schema), ensure_ascii=False, sort_keys=True)
|
||||
csvPF.WriteRowNoFilter(row)
|
||||
|
||||
if checkArgumentPresent('std'):
|
||||
doShowChromeSchemasStd()
|
||||
return
|
||||
cp = buildGAPIObject(API.CHROMEPOLICY)
|
||||
if checkArgumentPresent('std'):
|
||||
if not Act.csvFormat():
|
||||
doShowChromePolicySchemasStd(cp)
|
||||
return
|
||||
unknownArgumentExit()
|
||||
parent = _getCustomersCustomerIdWithC()
|
||||
csvPF = CSVPrintFile(['name', 'schemaName', 'policyDescription',
|
||||
'policyApiLifecycle.policyApiLifecycleStage',
|
||||
@@ -29056,9 +29327,55 @@ def doPrintShowChromeSchemas():
|
||||
if csvPF:
|
||||
csvPF.writeCSVfile('Chrome Policy Schemas')
|
||||
|
||||
def _showChromePolicySchemaStd(schema):
|
||||
def _printEntry(mtypeName, mtypeEntry):
|
||||
vtype = mtypeEntry['type']
|
||||
if vtype != 'TYPE_MESSAGE':
|
||||
printKeyValueList([f'{mtypeName}', f'{vtype}'])
|
||||
else:
|
||||
printKeyValueList([f'{mtypeName}'])
|
||||
Ind.Increment()
|
||||
if vtype == 'TYPE_ENUM':
|
||||
enums = mtypeEntry['subtype']['enums']
|
||||
descriptions = mtypeEntry['descriptions']
|
||||
for i in range(len(enums)):
|
||||
printKeyValueList([f'{enums[i]}', f'{descriptions[i]}'])
|
||||
elif vtype == 'TYPE_MESSAGE':
|
||||
for mfieldName, mfield in mtypeEntry['subtype']['field'].items():
|
||||
# managedBookmarks is recursive
|
||||
if mtypeName != 'entries':
|
||||
_printEntry(mfieldName, mfield)
|
||||
else:
|
||||
for description in mtypeEntry.get('descriptions', []):
|
||||
printKeyValueList([description])
|
||||
Ind.Decrement()
|
||||
|
||||
printKeyValueList([f'{schema.get("name")}', f'{schema.get("description")}'])
|
||||
Ind.Increment()
|
||||
for _, mtypeEntry in schema['settings'].items():
|
||||
if mtypeEntry['subfield']:
|
||||
continue
|
||||
for mfieldName, mfield in mtypeEntry['field'].items():
|
||||
_printEntry(mfieldName, mfield)
|
||||
Ind.Decrement()
|
||||
|
||||
# gam info chromeschema std <SchemaName>
|
||||
def doInfoChromePolicySchemasStd(cp):
|
||||
name = _getChromePolicySchemaName()
|
||||
checkForExtraneousArguments()
|
||||
try:
|
||||
schema = callGAPI(cp.customers().policySchemas(), 'get',
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN],
|
||||
name=name)
|
||||
_, schema_dict = simplifyChromeSchemaDisplay(schema)
|
||||
_showChromePolicySchemaStd(schema_dict)
|
||||
except GAPI.notFound:
|
||||
entityUnknownWarning(Ent.CHROME_POLICY_SCHEMA, name)
|
||||
except (GAPI.badRequest, GAPI.forbidden):
|
||||
accessErrorExit(None)
|
||||
|
||||
# gam show chromeschemas std [filter <String>]
|
||||
def doShowChromeSchemasStd():
|
||||
cp = buildGAPIObject(API.CHROMEPOLICY)
|
||||
def doShowChromePolicySchemasStd(cp):
|
||||
sfilter = None
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
@@ -29072,35 +29389,10 @@ def doShowChromeSchemasStd():
|
||||
parent=parent, filter=sfilter)
|
||||
schemas = {}
|
||||
for schema in result:
|
||||
schema_name, schema_dict = simplifyChromeSchema(schema)
|
||||
schema_name, schema_dict = simplifyChromeSchemaDisplay(schema)
|
||||
schemas[schema_name.lower()] = schema_dict
|
||||
for _, value in sorted(iter(schemas.items())):
|
||||
printKeyValueList([f'{value.get("name")}', f'{value.get("description")}'])
|
||||
Ind.Increment()
|
||||
for val in value['settings'].values():
|
||||
vtype = val.get('type')
|
||||
printKeyValueList([f'{val.get("name")}', f'{vtype}'])
|
||||
Ind.Increment()
|
||||
if vtype == 'TYPE_ENUM':
|
||||
enums = val.get('enums', [])
|
||||
descriptions = val.get('descriptions', [])
|
||||
for i in range(len(val.get('enums', []))):
|
||||
printKeyValueList([f'{enums[i]}', f'{descriptions[i]}'])
|
||||
elif vtype == 'TYPE_BOOL':
|
||||
pvs = val.get('descriptions')
|
||||
for pvi in pvs:
|
||||
if isinstance(pvi, dict):
|
||||
pvalue = pvi.get('value')
|
||||
pdescription = pvi.get('description')
|
||||
printKeyValueList([f'{pvalue}', f'{pdescription}'])
|
||||
elif isinstance(pvi, list):
|
||||
printKeyValueList([f'{pvi[0]}'])
|
||||
else:
|
||||
description = val.get('descriptions')
|
||||
if len(description) > 0:
|
||||
printKeyValueList([f'{description[0]}'])
|
||||
Ind.Decrement()
|
||||
Ind.Decrement()
|
||||
for _, schema in sorted(iter(schemas.items())):
|
||||
_showChromePolicySchemaStd(schema)
|
||||
printBlankLine()
|
||||
|
||||
# gam create chromenetwork
|
||||
@@ -51561,6 +51853,9 @@ def getStatusEventDateTime(dateType, dateList):
|
||||
if dateType == 'timerange':
|
||||
startTime = getTimeOrDeltaFromNow(returnDateTime=True)[0]
|
||||
endTime = getTimeOrDeltaFromNow(returnDateTime=True)[0]
|
||||
if startTime >= endTime:
|
||||
Cmd.Backup()
|
||||
usageErrorExit(Msg.INVALID_EVENT_TIMERANGE.format(dateType, startTime, endTime))
|
||||
recurrence = []
|
||||
while checkArgumentPresent(['recurrence']):
|
||||
recurrence.append(getString(Cmd.OB_RECURRENCE))
|
||||
@@ -57518,9 +57813,10 @@ FILETREE_FIELDS_CHOICE_MAP = {
|
||||
'parents': 'parents',
|
||||
'size': 'size',
|
||||
'trashed': 'trashed',
|
||||
'webviewlink': 'webViewLink',
|
||||
}
|
||||
|
||||
FILETREE_FIELDS_PRINT_ORDER = ['id', 'parents', 'owners', 'mimeType', 'size', 'explicitlyTrashed', 'trashed']
|
||||
FILETREE_FIELDS_PRINT_ORDER = ['id', 'parents', 'owners', 'mimeType', 'size', 'explicitlyTrashed', 'trashed', 'webViewLink']
|
||||
|
||||
# gam <UserTypeEntity> print filetree [todrive <ToDriveAttribute>*]
|
||||
# [select <DriveFileEntity> [selectsubquery <QueryDriveFile>] [depth <Number>]]
|
||||
@@ -57685,7 +57981,7 @@ def printShowFileTree(users):
|
||||
else:
|
||||
unknownArgumentExit()
|
||||
fieldsList = ['driveId', 'id', 'name', 'parents', 'mimeType', 'ownedByMe', 'owners(emailAddress)',
|
||||
'shared', sizeField, 'explicitlyTrashed', 'trashed']
|
||||
'shared', sizeField, 'explicitlyTrashed', 'trashed', 'webViewLink']
|
||||
if csvPF:
|
||||
if not GC.Values[GC.DRIVE_V3_NATIVE_NAMES]:
|
||||
fileNameTitle = 'title'
|
||||
@@ -65675,13 +65971,13 @@ def printShowSharedDrives(users, useDomainAdminAccess=False):
|
||||
entityPerformActionNumItems([Ent.USER, user], jcount, Ent.SHAREDDRIVE, i, count)
|
||||
Ind.Increment()
|
||||
j = 0
|
||||
for shareddrive in matchedFeed:
|
||||
for shareddrive in sorted(matchedFeed, key=lambda k: k['name']):
|
||||
j += 1
|
||||
shareddrive = stripNonShowFields(shareddrive)
|
||||
_showSharedDrive(user, shareddrive, j, jcount, FJQC)
|
||||
Ind.Decrement()
|
||||
else:
|
||||
for shareddrive in matchedFeed:
|
||||
for shareddrive in sorted(matchedFeed, key=lambda k: k['name']):
|
||||
shareddrive = stripNonShowFields(shareddrive)
|
||||
if FJQC.formatJSON:
|
||||
row = {'User': user, 'id': shareddrive['id'], 'name': shareddrive['name']}
|
||||
@@ -66056,7 +66352,7 @@ def printShowSharedDriveACLs(users, useDomainAdminAccess=False):
|
||||
entityPerformActionNumItems([Ent.USER, user], jcount, Ent.SHAREDDRIVE, i, count)
|
||||
Ind.Increment()
|
||||
j = 0
|
||||
for shareddrive in matchFeed:
|
||||
for shareddrive in sorted(matchFeed, key=lambda k: k['name']):
|
||||
j += 1
|
||||
if not FJQC.formatJSON:
|
||||
_showDriveFilePermissions(Ent.SHAREDDRIVE, f'{shareddrive["name"]} ({shareddrive["id"]}) - {shareddrive["createdTime"]}',
|
||||
@@ -66070,7 +66366,7 @@ def printShowSharedDriveACLs(users, useDomainAdminAccess=False):
|
||||
Ind.Decrement()
|
||||
elif matchFeed:
|
||||
if oneItemPerRow:
|
||||
for shareddrive in matchFeed:
|
||||
for shareddrive in sorted(matchFeed, key=lambda k: k['name']):
|
||||
baserow = {'User': user, 'id': shareddrive['id'], 'name': shareddrive['name'], 'createdTime': shareddrive['createdTime']}
|
||||
if addCSVData:
|
||||
baserow.update(addCSVData)
|
||||
@@ -66091,7 +66387,7 @@ def printShowSharedDriveACLs(users, useDomainAdminAccess=False):
|
||||
baserow['JSON'] = json.dumps({})
|
||||
csvPF.WriteRowNoFilter(baserow)
|
||||
else:
|
||||
for shareddrive in matchFeed:
|
||||
for shareddrive in sorted(matchFeed, key=lambda k: k['name']):
|
||||
baserow = {'User': user, 'id': shareddrive['id'], 'name': shareddrive['name'], 'createdTime': shareddrive['createdTime']}
|
||||
if addCSVData:
|
||||
baserow.update(addCSVData)
|
||||
@@ -66141,7 +66437,7 @@ def printSharedDriveOrganizers(users, useDomainAdminAccess=False):
|
||||
showNoOrganizerDrives = SHOW_NO_PERMISSIONS_DRIVES_CHOICE_MAP['false']
|
||||
fieldsList = ['role', 'type', 'emailAddress']
|
||||
cd = entityList = orgUnitId = query = matchPattern = None
|
||||
domainList = [GC.Values[GC.DOMAIN]]
|
||||
domainList = set([(GC.Values[GC.DOMAIN] if GC.Values[GC.DOMAIN] else _getValueFromOAuth('hd'))])
|
||||
oneOrganizer = True
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
@@ -66292,7 +66588,7 @@ def printSharedDriveOrganizers(users, useDomainAdminAccess=False):
|
||||
pass
|
||||
if len(matchFeed) == 0:
|
||||
setSysExitRC(NO_ENTITIES_FOUND_RC)
|
||||
for shareddrive in matchFeed:
|
||||
for shareddrive in sorted(matchFeed, key=lambda k: k['name']):
|
||||
row = {'id': shareddrive['id'], 'name': shareddrive['name'],
|
||||
'organizers': delimiter.join(shareddrive['organizers']),
|
||||
'createdTime': shareddrive['createdTime']}
|
||||
@@ -67770,7 +68066,7 @@ def updatePhoto(users):
|
||||
baseFileIdEntity = drive = owner = None
|
||||
sourceFolder = os.getcwd()
|
||||
if Cmd.NumArgumentsRemaining() == 1:
|
||||
filenamePattern = getString(Cmd.OB_PHOTO_FILENAME_PATTERN)
|
||||
filenamePattern = getString(Cmd.OB_FILE_NAME_PATTERN)
|
||||
else:
|
||||
filenamePattern = '#email#.jpg'
|
||||
while Cmd.ArgumentsRemaining():
|
||||
@@ -67782,7 +68078,7 @@ def updatePhoto(users):
|
||||
if not os.path.isdir(sourceFolder):
|
||||
entityDoesNotExistExit(Ent.DIRECTORY, sourceFolder)
|
||||
elif myarg == 'filename':
|
||||
filenamePattern = getString(Cmd.OB_PHOTO_FILENAME_PATTERN)
|
||||
filenamePattern = getString(Cmd.OB_FILE_NAME_PATTERN)
|
||||
elif myarg == 'gphoto':
|
||||
owner, drive = buildGAPIServiceObject(API.DRIVE3, getEmailAddress())
|
||||
if not drive:
|
||||
@@ -67883,7 +68179,7 @@ def getPhoto(users, profileMode):
|
||||
if not os.path.isdir(targetFolder):
|
||||
os.makedirs(targetFolder)
|
||||
elif myarg == 'filename':
|
||||
filenamePattern = getString(Cmd.OB_PHOTO_FILENAME_PATTERN)
|
||||
filenamePattern = getString(Cmd.OB_FILE_NAME_PATTERN)
|
||||
elif myarg == 'nofile':
|
||||
writeFileData = False
|
||||
elif myarg == 'noshow':
|
||||
@@ -69837,6 +70133,7 @@ def _initMessageThreadParameters(entityType, doIt, maxToProcess):
|
||||
'query': '', 'queryTimes': {},
|
||||
'entityType': entityType, 'messageEntity': None, 'doIt': doIt, 'quick': True,
|
||||
'labelMatchPattern': None, 'senderMatchPattern': None,
|
||||
'labelIds': [],
|
||||
'maxToProcess': maxToProcess, 'maxItems': 0, 'maxMessagesPerThread': 0,
|
||||
'maxToKeywords': [MESSAGES_MAX_TO_KEYWORDS[Act.Get()], 'maxtoprocess'],
|
||||
'listType': listType, 'fields': f'nextPageToken,{listType}(id)'}
|
||||
@@ -69869,6 +70166,8 @@ def _getMessageSelectParameters(myarg, parameters):
|
||||
parameters['labelMatchPattern'] = getREPattern(re.IGNORECASE)
|
||||
elif myarg == 'sendermatchpattern':
|
||||
parameters['senderMatchPattern'] = getREPattern(re.IGNORECASE)
|
||||
elif myarg == 'labelids':
|
||||
parameters['labelIds'].extend(getEntityList(Cmd.OB_LABEL_ID_LIST))
|
||||
elif myarg == 'ids':
|
||||
parameters['messageEntity'] = getUserObjectEntity(Cmd.OB_MESSAGE_ID, parameters['entityType'])
|
||||
elif myarg == 'quick':
|
||||
@@ -69968,7 +70267,8 @@ def archiveMessages(users):
|
||||
listResult = callGAPIpages(service, 'list', parameters['listType'],
|
||||
pageMessage=getPageMessageForWhom(), maxItems=parameters['maxItems'],
|
||||
throwReasons=GAPI.GMAIL_THROW_REASONS+GAPI.GMAIL_LIST_THROW_REASONS,
|
||||
userId='me', q=parameters['query'], fields=parameters['fields'],
|
||||
userId='me', q=parameters['query'], labelIds=parameters['labelIds'],
|
||||
fields=parameters['fields'],
|
||||
maxResults=GC.Values[GC.MESSAGE_MAX_RESULTS])
|
||||
messageIds = [message['id'] for message in listResult]
|
||||
except (GAPI.failedPrecondition, GAPI.permissionDenied, GAPI.invalid, GAPI.invalidArgument) as e:
|
||||
@@ -70157,7 +70457,8 @@ def _processMessagesThreads(users, entityType):
|
||||
listResult = callGAPIpages(service, 'list', parameters['listType'],
|
||||
pageMessage=getPageMessageForWhom(), maxItems=parameters['maxItems'],
|
||||
throwReasons=GAPI.GMAIL_THROW_REASONS+GAPI.GMAIL_LIST_THROW_REASONS,
|
||||
userId='me', q=parameters['query'], fields=parameters['fields'], includeSpamTrash=includeSpamTrash,
|
||||
userId='me', q=parameters['query'], labelIds=parameters['labelIds'],
|
||||
fields=parameters['fields'], includeSpamTrash=includeSpamTrash,
|
||||
maxResults=GC.Values[GC.MESSAGE_MAX_RESULTS])
|
||||
messageIds = [message['id'] for message in listResult]
|
||||
else:
|
||||
@@ -70273,7 +70574,8 @@ def exportMessagesThreads(users, entityType):
|
||||
listResult = callGAPIpages(service, 'list', parameters['listType'],
|
||||
pageMessage=getPageMessageForWhom(), maxItems=parameters['maxItems'],
|
||||
throwReasons=GAPI.GMAIL_THROW_REASONS+GAPI.GMAIL_LIST_THROW_REASONS,
|
||||
userId='me', q=parameters['query'], fields=parameters['fields'], includeSpamTrash=includeSpamTrash,
|
||||
userId='me', q=parameters['query'], labelIds=parameters['labelIds'],
|
||||
fields=parameters['fields'], includeSpamTrash=includeSpamTrash,
|
||||
maxResults=GC.Values[GC.MESSAGE_MAX_RESULTS])
|
||||
entityIds = [entity['id'] for entity in listResult]
|
||||
except (GAPI.failedPrecondition, GAPI.permissionDenied, GAPI.invalid, GAPI.invalidArgument) as e:
|
||||
@@ -70408,7 +70710,8 @@ def forwardMessagesThreads(users, entityType):
|
||||
listResult = callGAPIpages(service, 'list', parameters['listType'],
|
||||
pageMessage=getPageMessageForWhom(), maxItems=parameters['maxItems'],
|
||||
throwReasons=GAPI.GMAIL_THROW_REASONS+GAPI.GMAIL_LIST_THROW_REASONS,
|
||||
userId='me', q=parameters['query'], fields=parameters['fields'], includeSpamTrash=includeSpamTrash,
|
||||
userId='me', q=parameters['query'], labelIds=parameters['labelIds'],
|
||||
fields=parameters['fields'], includeSpamTrash=includeSpamTrash,
|
||||
maxResults=GC.Values[GC.MESSAGE_MAX_RESULTS])
|
||||
entityIds = [entity['id'] for entity in listResult]
|
||||
except (GAPI.failedPrecondition, GAPI.permissionDenied, GAPI.invalid, GAPI.invalidArgument) as e:
|
||||
@@ -71513,7 +71816,8 @@ def printShowMessagesThreads(users, entityType):
|
||||
listResult = callGAPIpages(service, 'list', parameters['listType'],
|
||||
pageMessage=getPageMessageForWhom(), maxItems=parameters['maxItems'],
|
||||
throwReasons=GAPI.GMAIL_THROW_REASONS+GAPI.GMAIL_LIST_THROW_REASONS,
|
||||
userId='me', q=parameters['query'], fields=parameters['fields'], includeSpamTrash=includeSpamTrash,
|
||||
userId='me', q=parameters['query'], labelIds=parameters['labelIds'],
|
||||
fields=parameters['fields'], includeSpamTrash=includeSpamTrash,
|
||||
maxResults=GC.Values[GC.MESSAGE_MAX_RESULTS])
|
||||
messageIds = [message['id'] for message in listResult]
|
||||
else:
|
||||
@@ -72310,8 +72614,28 @@ def updateFormRequestUpdateMasks(ubody):
|
||||
v['updateMask'] = ','.join(v['updateMask'])
|
||||
break
|
||||
|
||||
def _initPublishSettings():
|
||||
return {'publishSettings': {'publishState': {}}, 'updateMask': ''}
|
||||
|
||||
def _getPublishSettings(myarg, pbody):
|
||||
if myarg == 'ispublished':
|
||||
bval = getBoolean()
|
||||
pbody['publishSettings']['publishState']['isPublished'] = bval
|
||||
if not bval:
|
||||
pbody['publishSettings']['publishState']['isAcceptingResponses'] = bval
|
||||
elif myarg == 'isacceptingresponses':
|
||||
bval = getBoolean()
|
||||
pbody['publishSettings']['publishState']['isAcceptingResponses'] = bval
|
||||
if bval:
|
||||
pbody['publishSettings']['publishState']['isPublished'] = bval
|
||||
else:
|
||||
return False
|
||||
pbody['updateMask'] = 'publishState'
|
||||
return True
|
||||
|
||||
# gam <UserTypeEntity> create form
|
||||
# title <String> [description <String>] [isquiz [<Boolean>]] [<JSONData>]
|
||||
# [ispublished [<Boolean>] isacceptingresponses [<Boolean>]]
|
||||
# [drivefilename <DriveFileName>] [<DriveFileParentAttribute>]
|
||||
# [(csv [todrive <ToDriveAttribute>*]) | returnidonly]
|
||||
def createForm(users):
|
||||
@@ -72320,6 +72644,7 @@ def createForm(users):
|
||||
title = ''
|
||||
body = {'mimeType': MIMETYPE_GA_FORM}
|
||||
ubody = {'includeFormInResponse': True, 'requests': []}
|
||||
pbody = _initPublishSettings()
|
||||
parentParms = initDriveFileAttributes()
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
@@ -72333,6 +72658,8 @@ def createForm(users):
|
||||
elif myarg == 'json':
|
||||
jsonData = getJSON([])
|
||||
ubody['requests'].extend(jsonData.get('requests', []))
|
||||
elif _getPublishSettings(myarg, pbody):
|
||||
pass
|
||||
elif myarg == 'drivefilename':
|
||||
body['name'] = getString(Cmd.OB_DRIVE_FILE_NAME)
|
||||
elif getDriveFileParentAttribute(myarg, parentParms):
|
||||
@@ -72373,6 +72700,10 @@ def createForm(users):
|
||||
form = callGAPI(gform.forms(), 'batchUpdate',
|
||||
throwReasons=[GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
|
||||
formId=formId, body=ubody)
|
||||
if pbody['updateMask']:
|
||||
callGAPI(gform.forms(), 'setPublishSettings',
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
|
||||
formId=formId, body=pbody)
|
||||
if returnIdOnly:
|
||||
writeStdout(f'{formId}\n')
|
||||
elif not csvPF:
|
||||
@@ -72397,8 +72728,10 @@ def createForm(users):
|
||||
|
||||
# gam <UserTypeEntity> update form <DriveFileEntity>
|
||||
# [title <String>] [description <String>] [isquiz [Boolean>]] [<JSONData>]
|
||||
# [ispublished [<Boolean>] isacceptingresponses [<Boolean>]]
|
||||
def updateForm(users):
|
||||
ubody = {'includeFormInResponse': False, 'requests': []}
|
||||
pbody = _initPublishSettings()
|
||||
fileIdEntity = getDriveFileEntity()
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
@@ -72411,10 +72744,12 @@ def updateForm(users):
|
||||
elif myarg == 'json':
|
||||
jsonData = getJSON([])
|
||||
ubody['requests'].extend(jsonData.get('requests', []))
|
||||
elif _getPublishSettings(myarg, pbody):
|
||||
pass
|
||||
else:
|
||||
unknownArgumentExit()
|
||||
updateFormRequestUpdateMasks(ubody)
|
||||
if not ubody['requests']:
|
||||
if not ubody['requests'] and not pbody['updateMask']:
|
||||
return
|
||||
i, count, users = getEntityArgument(users)
|
||||
for user in users:
|
||||
@@ -72430,9 +72765,14 @@ def updateForm(users):
|
||||
for formId in fileIdEntity['list']:
|
||||
j += 1
|
||||
try:
|
||||
callGAPI(gform.forms(), 'batchUpdate',
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
|
||||
formId=formId, body=ubody)
|
||||
if ubody['requests']:
|
||||
callGAPI(gform.forms(), 'batchUpdate',
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
|
||||
formId=formId, body=ubody)
|
||||
if pbody['updateMask']:
|
||||
callGAPI(gform.forms(), 'setPublishSettings',
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
|
||||
formId=formId, body=pbody)
|
||||
entityActionPerformed([Ent.USER, user, Ent.FORM, formId], j, jcount)
|
||||
except (GAPI.notFound, GAPI.invalidArgument) as e:
|
||||
entityActionFailedWarning([Ent.USER, user, Ent.FORM, formId], str(e), j, jcount)
|
||||
@@ -72481,6 +72821,9 @@ def printShowForms(users):
|
||||
result = callGAPI(gform.forms(), 'get',
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED],
|
||||
formId=formId)
|
||||
if 'publishSettings' in result and 'publishState' in result['publishSettings']:
|
||||
result['publishSettings']['publishState'].setdefault('isPublished', False)
|
||||
result['publishSettings']['publishState'].setdefault('isAcceptingResponses', False)
|
||||
if not csvPF:
|
||||
if not FJQC.formatJSON:
|
||||
printEntity([Ent.FORM, result['formId']], j, jcount)
|
||||
@@ -76137,7 +76480,7 @@ MAIN_COMMANDS_WITH_OBJECTS = {
|
||||
Cmd.ARG_CHROMENEEDSATTN: doPrintShowChromeNeedsAttn,
|
||||
Cmd.ARG_CHROMEPOLICY: doPrintShowChromePolicies,
|
||||
Cmd.ARG_CHROMEPROFILE: doPrintShowChromeProfiles,
|
||||
Cmd.ARG_CHROMESCHEMA: doPrintShowChromeSchemas,
|
||||
Cmd.ARG_CHROMESCHEMA: doPrintShowChromePolicySchemas,
|
||||
Cmd.ARG_CHROMESNVALIDITY: doPrintChromeSnValidity,
|
||||
Cmd.ARG_CHROMEVERSIONS: doPrintShowChromeVersions,
|
||||
Cmd.ARG_CIGROUP: doPrintCIGroups,
|
||||
@@ -76269,7 +76612,7 @@ MAIN_COMMANDS_WITH_OBJECTS = {
|
||||
Cmd.ARG_CHROMENEEDSATTN: doPrintShowChromeNeedsAttn,
|
||||
Cmd.ARG_CHROMEPOLICY: doPrintShowChromePolicies,
|
||||
Cmd.ARG_CHROMEPROFILE: doPrintShowChromeProfiles,
|
||||
Cmd.ARG_CHROMESCHEMA: doPrintShowChromeSchemas,
|
||||
Cmd.ARG_CHROMESCHEMA: doPrintShowChromePolicySchemas,
|
||||
Cmd.ARG_CHROMEVERSIONS: doPrintShowChromeVersions,
|
||||
Cmd.ARG_CIGROUPMEMBERS: doShowCIGroupMembers,
|
||||
Cmd.ARG_CIPOLICY: doPrintShowCIPolicies,
|
||||
@@ -76882,6 +77225,7 @@ USER_ADD_CREATE_FUNCTIONS = {
|
||||
Cmd.ARG_CALENDAR: addCreateCalendars,
|
||||
Cmd.ARG_GROUP: addUserToGroups,
|
||||
Cmd.ARG_CALENDARACL: createCalendarACLs,
|
||||
Cmd.ARG_CHATEMOJI: createChatEmoji,
|
||||
Cmd.ARG_CHATMEMBER: createChatMember,
|
||||
Cmd.ARG_CHATMESSAGE: createChatMessage,
|
||||
Cmd.ARG_CHATSPACE: createChatSpace,
|
||||
@@ -76998,6 +77342,7 @@ USER_COMMANDS_WITH_OBJECTS = {
|
||||
Cmd.ARG_BACKUPCODE: deleteBackupCodes,
|
||||
Cmd.ARG_CALENDAR: deleteCalendars,
|
||||
Cmd.ARG_CALENDARACL: deleteCalendarACLs,
|
||||
Cmd.ARG_CHATEMOJI: deleteChatEmoji,
|
||||
Cmd.ARG_CHATMEMBER: deleteUpdateChatMember,
|
||||
Cmd.ARG_CHATMESSAGE: deleteChatMessage,
|
||||
Cmd.ARG_CHATSPACE: deleteChatSpace,
|
||||
@@ -77102,6 +77447,7 @@ USER_COMMANDS_WITH_OBJECTS = {
|
||||
(Act.INFO,
|
||||
{Cmd.ARG_CALENDAR: infoCalendars,
|
||||
Cmd.ARG_CALENDARACL: infoCalendarACLs,
|
||||
Cmd.ARG_CHATEMOJI: infoChatEmoji,
|
||||
Cmd.ARG_CHATEVENT: infoChatEvent,
|
||||
Cmd.ARG_CHATMEMBER: infoChatMember,
|
||||
Cmd.ARG_CHATMESSAGE: infoChatMessage,
|
||||
@@ -77174,6 +77520,7 @@ USER_COMMANDS_WITH_OBJECTS = {
|
||||
Cmd.ARG_CALENDAR: printShowCalendars,
|
||||
Cmd.ARG_CALENDARACL: printShowCalendarACLs,
|
||||
Cmd.ARG_CALSETTINGS: printShowCalSettings,
|
||||
Cmd.ARG_CHATEMOJI: printShowChatEmojis,
|
||||
Cmd.ARG_CHATEVENT: printShowChatEvents,
|
||||
Cmd.ARG_CHATMEMBER: printShowChatMembers,
|
||||
Cmd.ARG_CHATMESSAGE: printShowChatMessages,
|
||||
@@ -77281,6 +77628,7 @@ USER_COMMANDS_WITH_OBJECTS = {
|
||||
Cmd.ARG_CALENDAR: printShowCalendars,
|
||||
Cmd.ARG_CALENDARACL: printShowCalendarACLs,
|
||||
Cmd.ARG_CALSETTINGS: printShowCalSettings,
|
||||
Cmd.ARG_CHATEMOJI: printShowChatEmojis,
|
||||
Cmd.ARG_CHATEVENT: printShowChatEvents,
|
||||
Cmd.ARG_CHATMEMBER: printShowChatMembers,
|
||||
Cmd.ARG_CHATMESSAGE: printShowChatMessages,
|
||||
@@ -77497,6 +77845,7 @@ USER_COMMANDS_OBJ_ALIASES = {
|
||||
Cmd.ARG_CLASSIFICATIONLABELPERMISSION: Cmd.ARG_DRIVELABELPERMISSION,
|
||||
Cmd.ARG_CLASSIFICATIONLABELPERMISSIONS: Cmd.ARG_DRIVELABELPERMISSION,
|
||||
Cmd.ARG_CLASSROOMINVITATIONS: Cmd.ARG_CLASSROOMINVITATION,
|
||||
Cmd.ARG_CHATEMOJIS: Cmd.ARG_CHATEMOJI,
|
||||
Cmd.ARG_CHATEVENTS: Cmd.ARG_CHATEVENT,
|
||||
Cmd.ARG_CHATMEMBERS: Cmd.ARG_CHATMEMBER,
|
||||
Cmd.ARG_CHATMESSAGES: Cmd.ARG_CHATMESSAGE,
|
||||
|
||||
@@ -26,6 +26,7 @@ ANALYTICS_ADMIN = 'analyticsadmin'
|
||||
CALENDAR = 'calendar'
|
||||
CBCM = 'cbcm'
|
||||
CHAT = 'chat'
|
||||
CHAT_CUSTOM_EMOJIS = 'chatcustomemojis'
|
||||
CHAT_EVENTS = 'chatevents'
|
||||
CHAT_MEMBERSHIPS = 'chatmemberships'
|
||||
CHAT_MEMBERSHIPS_ADMIN = 'chatmembershipsadmin'
|
||||
@@ -210,6 +211,7 @@ _INFO = {
|
||||
CALENDAR: {'name': 'Calendar API', 'version': 'v3', 'v2discovery': True, 'mappedAPI': 'calendar-json'},
|
||||
CBCM: {'name': 'Chrome Browser Cloud Management API', 'version': 'v1.1beta1', 'v2discovery': True, 'localjson': True},
|
||||
CHAT: {'name': 'Chat API', 'version': 'v1', 'v2discovery': True},
|
||||
CHAT_CUSTOM_EMOJIS: {'name': 'Chat API - Custom Emojis', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_EVENTS: {'name': 'Chat API - Events', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_MEMBERSHIPS: {'name': 'Chat API - Memberships', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_MEMBERSHIPS_ADMIN: {'name': 'Chat API - Memberships Admin', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
@@ -544,6 +546,10 @@ _SVCACCT_SCOPES = [
|
||||
'api': CALENDAR,
|
||||
'subscopes': READONLY,
|
||||
'scope': 'https://www.googleapis.com/auth/calendar'},
|
||||
{'name': 'Chat API - Custom Emojis',
|
||||
'api': CHAT_CUSTOM_EMOJIS,
|
||||
'subscopes': READONLY,
|
||||
'scope': 'https://www.googleapis.com/auth/chat.customemojis'},
|
||||
{'name': 'Chat API - Memberships',
|
||||
'api': CHAT_MEMBERSHIPS,
|
||||
'subscopes': READONLY,
|
||||
@@ -644,7 +650,7 @@ _SVCACCT_SCOPES = [
|
||||
'api': GMAIL,
|
||||
'subscopes': [],
|
||||
'scope': 'https://www.googleapis.com/auth/gmail.modify'},
|
||||
{'name': 'Gmail API - Basic Settings (Filters,IMAP, Language, POP, Vacation) - read/write, Sharing Settings (Delegates, Forwarding, SendAs) - read',
|
||||
{'name': 'Gmail API - Basic Settings (Filters, IMAP, Language, POP, Vacation) - read/write, Sharing Settings (Delegates, Forwarding, SendAs) - read',
|
||||
'api': GMAIL,
|
||||
'subscopes': [],
|
||||
'scope': 'https://www.googleapis.com/auth/gmail.settings.basic'},
|
||||
|
||||
@@ -379,7 +379,7 @@ Defaults = {
|
||||
DEVICE_MAX_RESULTS: '200',
|
||||
DOMAIN: '',
|
||||
DRIVE_DIR: '',
|
||||
ENFORCE_EXPANSIVE_ACCESS: FALSE,
|
||||
ENFORCE_EXPANSIVE_ACCESS: TRUE,
|
||||
DRIVE_MAX_RESULTS: '1000',
|
||||
DRIVE_V3_BETA: FALSE,
|
||||
DRIVE_V3_NATIVE_NAMES: TRUE,
|
||||
|
||||
@@ -461,6 +461,8 @@ class GamCLArgs():
|
||||
ARG_CHANNELSKU = 'channelsku'
|
||||
ARG_CHANNELSKUS = 'channelskus'
|
||||
ARG_CHAT = 'chat'
|
||||
ARG_CHATEMOJI = 'chatemoji'
|
||||
ARG_CHATEMOJIS = 'chatemojis'
|
||||
ARG_CHATEVENT = 'chatevent'
|
||||
ARG_CHATEVENTS = 'chatevents'
|
||||
ARG_CHATMEMBER = 'chatmember'
|
||||
@@ -843,6 +845,8 @@ class GamCLArgs():
|
||||
OB_CHARACTER = 'Character'
|
||||
OB_CHAR_SET = 'CharacterSet'
|
||||
OG_CHAT_ATTACHMENT = 'ChatAttachment'
|
||||
OB_CHAT_EMOJI = 'ChatEmoji'
|
||||
OB_CHAT_EMOJI_NAME = 'ChatEmojiName'
|
||||
OB_CHAT_EVENT = 'ChatEvent'
|
||||
OB_CHAT_MEMBER = 'ChatMember'
|
||||
OB_CHAT_MESSAGE = 'ChatMessage'
|
||||
@@ -930,6 +934,7 @@ class GamCLArgs():
|
||||
OB_FILE_NAME = 'FileName'
|
||||
OB_FILE_NAME_FIELD_NAME = OB_FILE_NAME+'(:'+OB_FIELD_NAME+')+'
|
||||
OB_FILE_NAME_OR_URL = 'FileName|URL'
|
||||
OB_FILE_NAME_PATTERN = 'FileNamePattern'
|
||||
OB_FILE_PATH = 'FilePath'
|
||||
OB_FILTER_ID_ENTITY = 'FilterIDEntity'
|
||||
OB_FORMAT_LIST = 'FormatList'
|
||||
@@ -975,7 +980,6 @@ class GamCLArgs():
|
||||
OB_PERMISSION_ID_LIST = 'PermissionIDList'
|
||||
OB_PERMISSION_ROLE_LIST = 'PermissionRoleList'
|
||||
OB_PERMISSION_TYPE_LIST = 'PermissionTypeList'
|
||||
OB_PHOTO_FILENAME_PATTERN = 'FilenameNamePattern'
|
||||
OB_PRINTER_ID = 'PrinterID'
|
||||
OB_PRIVILEGE_LIST = 'PrivilegeList'
|
||||
OB_PRODUCT_ID = 'ProductID'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2024 Ross Scroggs All Rights Reserved.
|
||||
# Copyright (C) 2025 Ross Scroggs All Rights Reserved.
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
@@ -86,6 +86,7 @@ class GamEntity():
|
||||
CHANNEL_SKU = 'chsk'
|
||||
CHAT_BOT = 'chbo'
|
||||
CHAT_ADMIN = 'chad'
|
||||
CHAT_EMOJI = 'chem'
|
||||
CHAT_EVENT = 'chev'
|
||||
CHAT_MANAGER_USER = 'chgu'
|
||||
CHAT_MEMBER = 'chme'
|
||||
@@ -436,6 +437,7 @@ class GamEntity():
|
||||
CHANNEL_SKU: ['Channel SKUs', 'Channel SKU'],
|
||||
CHAT_BOT: ['Chat BOTs', 'Chat BOT'],
|
||||
CHAT_ADMIN: ['Chat Admins', 'Chat Admin'],
|
||||
CHAT_EMOJI: ['Chat Emojis', 'Chat Emoji'],
|
||||
CHAT_EVENT: ['Chat Events', 'Chat Event'],
|
||||
CHAT_MANAGER_USER: ['Chat User Managers', 'Chat User Manager'],
|
||||
CHAT_MESSAGE: ['Chat Messages', 'Chat Message'],
|
||||
|
||||
@@ -309,7 +309,9 @@ INVALID_ALIAS = 'Invalid Alias'
|
||||
INVALID_ATTENDEE_CHANGE = 'Invalid attendee change "{0}"'
|
||||
INVALID_CHARSET = 'Invalid charset "{0}"'
|
||||
INVALID_DATE_TIME_RANGE = '{0} {1} must be greater than/equal to {2} {3}'
|
||||
INVALID_EMOJI_NAME = '{0} does not match pattern :[0-9a-z_-]:'
|
||||
INVALID_ENTITY = 'Invalid {0}, {1}'
|
||||
INVALID_EVENT_TIMERANGE = '{0} {1} must be less than {2}'
|
||||
INVALID_FILE_SELECTION_WITH_ADMIN_ACCESS = 'Invalid file selection with adminaccess|asadmin'
|
||||
INVALID_GROUP = 'Invalid Group'
|
||||
INVALID_HTTP_HEADER = 'Invalid http header data: {0}'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2023 Ross Scroggs All Rights Reserved.
|
||||
# Copyright (C) 2025 Ross Scroggs All Rights Reserved.
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2023 Ross Scroggs All Rights Reserved.
|
||||
# Copyright (C) 2025 Ross Scroggs All Rights Reserved.
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
banana|basil|blueberry|flamingo|graphite|grape|
|
||||
lavender|peacock|sage|tangerine|tomato
|
||||
<FileFormat> ::=
|
||||
csv|doc|dot|docx|dotx|epub|html|jpeg|jpg|mht|odp|ods|odt|
|
||||
csv|doc|dot|docx|dotx|epub|html|jpeg|jpg|json|mht|odp|ods|odt|
|
||||
pdf|png|ppt|pot|potx|pptx|rtf|svg|tsv|txt|xls|xlt|xlsx|xltx|zip|
|
||||
ms|microsoft|openoffice|
|
||||
<LabelColorHex> ::=
|
||||
@@ -278,6 +278,8 @@
|
||||
domain:<DomainName>|domain|default
|
||||
<CalendarItem> ::= <EmailAddress>
|
||||
<ChannelCustomerID> ::= <String>
|
||||
<ChatEmojiName> ::= :[0-9a-z_-]+:
|
||||
<ChatEmoji> ::= emojiname <ChatEmojiName> | customemojis/<String>
|
||||
<ChatMember> ::= spaces/<String>/members/<String>
|
||||
<ChatMessage> ::= spaces/<String>/messages/<String>
|
||||
<ChatSpace> ::= spaces/<String> | space <String> | space spaces/<String>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,79 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
|
||||
|
||||
See [Downloads-Installs-GAM7](https://github.com/GAM-team/GAM/wiki/Downloads-Installs) for Windows or other options, including manual installation
|
||||
|
||||
### 7.10.02
|
||||
|
||||
Added option `labelids <LabelIdList>` to all commands that process messages;
|
||||
this option causes GAM to only return messages with labels that match all of the specified label IDs.
|
||||
|
||||
Updated `gam <UserTypeEntity> print|show forms` to always display `isPublished` and
|
||||
`isAcceptingResponses` in `publishSettings/publishState` regardless of their value;
|
||||
the API doesn't return these values when they are False.
|
||||
|
||||
### 7.10.01
|
||||
|
||||
Added options `ispublished [<Boolean>]` and `isacceptingresponses [<Boolean>]` to
|
||||
`gam <UserTypeEntity> create|update form`.
|
||||
|
||||
### 7.10.00
|
||||
|
||||
Added commands to manage/display Chat Custom Emojis.
|
||||
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Users-Chat#manage-chat-emojis
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Users-Chat#display-chat-emojis
|
||||
|
||||
Updated `gam <UserItem> print|show chatspaces|chatmembers asadmin` to display
|
||||
the spaces in ascending display name order.
|
||||
|
||||
### 7.09.07
|
||||
|
||||
Added `webviewlink` to `<FileTreeFieldName>` for use in `gam <UserTypeEntity> print|show filetree`.
|
||||
|
||||
### 7.09.06
|
||||
|
||||
Upddated `gam print|show shareddrives`, `gam print|show shareddriveacls`, `gam print shareddriveorganizers`
|
||||
to display the Shared Drives in ascending name order; the API returns them in an unidentifiable order.
|
||||
|
||||
### 7.09.05
|
||||
|
||||
Improved output of `gam info|show chromeschemas [std]` to more accurately display the schemas.
|
||||
|
||||
Fixed bugs in `gam update chromepolicy` that caused invalid error messaages.
|
||||
|
||||
### 7.09.04
|
||||
|
||||
Fixed bug in `gam whatis <EmailItem>` where the check for an invitable user always failed.
|
||||
|
||||
Fixed bug in `gam print shareddriveorganizers` where no organizers were displayed when `domain` in `gam.cfg` was blank.
|
||||
|
||||
Updated to Python 3.13.5
|
||||
|
||||
### 7.09.03
|
||||
|
||||
Updated `gam <UserTypeEntity> create focustime|outofoffice ... timerange <Time> <Time>` to check
|
||||
that the first `<Time>` is less than the second `Time`; previously the event was not created.
|
||||
|
||||
For new installs the `enforce_expansive_access` Boolean variable in `gam.cfg` now defaults to True.
|
||||
For existing installations, if `enforce_expansive_access` has not been added to `gam.cfg`,
|
||||
a default value of True will be used.
|
||||
|
||||
### 7.09.02
|
||||
|
||||
Added command `gam info chromeschema std <SchemaName>` to display a Chrome policy schema in the same format as Legacy GAM.
|
||||
|
||||
Improved output of `gam show chromeschemas [std]` and `gam info chromeschema [std]` to more accurately display the schemas.
|
||||
|
||||
### 7.09.01
|
||||
|
||||
Fixed bug in `gam <UserTypeEntity> print diskusage` where the `ownedByMe` column was
|
||||
blank for the top folder.
|
||||
|
||||
Fixed bug in `gam update chromepolicy` where the following error was generated
|
||||
when updating policies with simple numerical values.
|
||||
```
|
||||
ERROR: Missing argument: Expected <value>"
|
||||
```
|
||||
|
||||
### 7.09.00
|
||||
|
||||
Removed the overly broad service account `IAM and Access Management API` scope `https://www.googleapis.com/auth/cloud-platform`
|
||||
|
||||
@@ -152,7 +152,7 @@ gam update group|groups <GroupEntity> create|add [<GroupRole>]
|
||||
[preview] [actioncsv]
|
||||
<UserItem>|<UserTypeEntity>
|
||||
```
|
||||
To add a group as a memmber of another group, just specify its email address.
|
||||
To add a group as a member of another group, just specify its email address.
|
||||
```
|
||||
gam update group group1@domain.com add member group2@domain.com
|
||||
```
|
||||
@@ -208,7 +208,7 @@ gam update group|groups <GroupEntity> delete|remove [<GroupRole>]
|
||||
```
|
||||
`<GroupRole>` is ignored, deletions take place regardless of role.
|
||||
|
||||
To remove a group as a memmber of another group, just specify its email address.
|
||||
To remove a group as a member of another group, just specify its email address.
|
||||
```
|
||||
gam update group group1@domain.com remove group2@domain.com
|
||||
```
|
||||
|
||||
@@ -251,9 +251,9 @@ writes the credentials into the file oauth2.txt.
|
||||
admin@server:/Users/admin$ rm -f /Users/admin/GAMConfig/oauth2.txt
|
||||
admin@server:/Users/admin$ gam version
|
||||
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
|
||||
GAM 7.09.00 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.10.02 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.4 64-bit final
|
||||
Python 3.13.5 64-bit final
|
||||
MacOS Sequoia 15.5 x86_64
|
||||
Path: /Users/admin/bin/gam7
|
||||
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
|
||||
@@ -989,9 +989,9 @@ writes the credentials into the file oauth2.txt.
|
||||
C:\>del C:\GAMConfig\oauth2.txt
|
||||
C:\>gam version
|
||||
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
|
||||
GAM 7.09.00 - https://github.com/GAM-team/GAM - pythonsource
|
||||
GAM 7.10.02 - https://github.com/GAM-team/GAM - pythonsource
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.4 64-bit final
|
||||
Python 3.13.5 64-bit final
|
||||
Windows-10-10.0.17134 AMD64
|
||||
Path: C:\GAM7
|
||||
Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
- [Synchronize licenses](#synchronize-licenses)
|
||||
|
||||
## API documentation
|
||||
* [License Manager API](https://developers.google.com/admin-sdk/licensing/rest/v1/licenseAssignments)
|
||||
* [License Manager API](https://developers.google.com/workspace/admin/licensing/reference/rest/v1/licenseAssignments)
|
||||
|
||||
## License Products and SKUs
|
||||
* [Product and SKU IDs](https://developers.google.com/admin-sdk/licensing/v1/how-tos/products)
|
||||
|
||||
@@ -44,13 +44,14 @@ config csv_output_row_filter "'\"accounts:used_quota_in_mb\":count>15000'"
|
||||
calendar|calendars|
|
||||
chat|
|
||||
chrome|
|
||||
classroom|
|
||||
contextawareaccess|
|
||||
currents|gplus|google+|
|
||||
datastudio|
|
||||
devices|mobile|
|
||||
domain|
|
||||
drive|doc|docs|
|
||||
gcp|
|
||||
gcp|cloud|
|
||||
gemini|geminiforworkspace|
|
||||
groups|group|
|
||||
groupsenterprise|enterprisegroups|
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
- [Manage Chat Messages](#manage-chat-messages)
|
||||
- [Display Chat Messages](#display-chat-messages)
|
||||
- [Display Chat Events](#display-chat-events)
|
||||
- [Manage Chat Emojis](#manage-chat-emojis)
|
||||
- [Display Chat Emojis](#display-chat-emojis)
|
||||
- [Bulk Operations](#bulk-operations)
|
||||
|
||||
## Introduction
|
||||
@@ -19,6 +21,7 @@ To use these commands you must update your service account authorization.
|
||||
```
|
||||
gam user user@domain.com update serviceaccount
|
||||
|
||||
[*] 3) Chat API - Custom Emojis (supports readonly)
|
||||
[*] 4) Chat API - Memberships (supports readonly)
|
||||
[*] 5) Chat API - Memberships Admin (supports readonly)
|
||||
[*] 6) Chat API - Messages (supports readonly)
|
||||
@@ -51,10 +54,12 @@ Google requires that you have a Chat Bot configured in order to use the Chat API
|
||||
## API documentation
|
||||
* [Overview](https://developers.google.com/workspace/chat/overview)
|
||||
* [Chat API](https://developers.google.com/workspace/chat/api/reference/rest)
|
||||
* [Chat API - Custom Emojis](https://developers.google.com/workspace/chat/api/reference/rest/v1/customEmojis)
|
||||
* [Chat API - Members](https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.members/list)
|
||||
* [Chat API - Messages](https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.messages/list)
|
||||
* [Chat API - Events](https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.spaceEvents/list)
|
||||
* [Apps in Google Chat](https://support.google.com/chat/answer/7655820)
|
||||
* [Manage customemoji permissions](https://support.google.com/a/answer/12850085)
|
||||
* [Manage Spaces in Admin Console](https://support.google.com/a/answer/13369245)
|
||||
* [Predefined permission settings](https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces#Space.FIELDS.predefined_permission_settings)
|
||||
|
||||
@@ -83,6 +88,8 @@ Google requires that you have a Chat Bot configured in order to use the Chat API
|
||||
(gdoc <UserGoogleDoc>)|
|
||||
(gcsdoc <StorageBucketObjectName>))
|
||||
|
||||
<ChatEmojiName> ::= :[0-9a-z_-]+:
|
||||
<ChatEmoji> ::= emojiname <ChatEmojiName> | customemojis/<String>
|
||||
<ChatEvent> ::= spaces/<String>/spaceEvents/<String>
|
||||
<ChatMember> ::= spaces/<String>/members/<String>
|
||||
<ChatMemberList> ::= "<ChatMember>(,<ChatMember>)*"
|
||||
@@ -896,6 +903,75 @@ filter 'start_time=\"2024-03-15T11:30:00-04:00\" AND event_types:\"google.worksp
|
||||
filter 'start_time=\"2024-03-15T11:30:00+00:00\" AND end_time=\"2024-03-3100:00:00+00:00\" AND event_types:\"google.workspace.chat.message.v1.created\"'
|
||||
```
|
||||
|
||||
## Manage Chat Emojis
|
||||
|
||||
### Create a Chat Emoji
|
||||
```
|
||||
gam <UserTypeEntity> create chatemoji <ChatEmojiName>
|
||||
([drivedir|(sourcefolder <FilePath>)] [filename <FileNamePattern>])
|
||||
[formatjson]
|
||||
```
|
||||
Emoji names must start and end with colons, must be lowercase and can only contain alphanumeric characters, hyphens, and underscores.
|
||||
Hyphens and underscores should be used to separate words and cannot be used consecutively.
|
||||
|
||||
By default, the emoji file will be uploaded from the current working directory.
|
||||
* `drivedir` - The emoji file will be uploaded from the directory specified by `drive_dir` in gam.cfg
|
||||
* `sourcefolder <FilePath>` - The emoji file will be uploaded from `<FilePath>`
|
||||
|
||||
Specify the emoji file name; the following substitutions will be made:
|
||||
* `#email#` and `#user#` will be replaced by the user's full email address
|
||||
* `#username#` will be replaced by the local part of the user's email address
|
||||
|
||||
### Delete a Chat Emoji
|
||||
Deletes the given Chat emoji.
|
||||
|
||||
```
|
||||
gam <UserTypeEntity> delete chatemoji <Chatemoji>
|
||||
```
|
||||
|
||||
## Display Chat Emojis
|
||||
### Display a specific Chat emoji
|
||||
|
||||
```
|
||||
gam <UserTypeEntity> info chatemoji <Chatemoji>
|
||||
[formatjson]
|
||||
```
|
||||
By default, Gam displays the information as an indented list of keys and values.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
|
||||
### Display information about all chat emojis
|
||||
```
|
||||
gam <UserTypeEntity> show chatemojis
|
||||
[showcreatedby any|me|others]
|
||||
[formatjson]
|
||||
```
|
||||
Select emojis to display:
|
||||
* `showcreatedby any` - Display all emojis regardless of creator
|
||||
* `showcreatedby ` - Display all emojis created by the user; this is the default
|
||||
* `showcreatedby others` - Display all emojis not created by the user
|
||||
|
||||
By default, Gam displays the information as an indented list of keys and values.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
|
||||
```
|
||||
gam <UserTypeEntity> print chatemojis [todrive <ToDriveAttribute>*]
|
||||
[showcreatedby any|me|others]
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
Select emojis to display:
|
||||
* `showcreatedby any` - Display all emojis regardless of creator
|
||||
* `showcreatedby ` - Display all emojis created by the user; this is the default
|
||||
* `showcreatedby others` - Display all emojis not created by the user
|
||||
|
||||
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format,
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
|
||||
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
|
||||
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
|
||||
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.
|
||||
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
|
||||
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
|
||||
|
||||
## Bulk Operations
|
||||
### Display information about all chat spaces for a collection of users
|
||||
```
|
||||
|
||||
@@ -968,7 +968,8 @@ Display a list of file/folder names indented to show structure.
|
||||
owners|
|
||||
parents|
|
||||
size|
|
||||
trashed
|
||||
trashed|
|
||||
webviewlink
|
||||
<FileTreeFieldNameList> ::= "<FileTreeFieldName>(,<FileTreeFieldName>)*"
|
||||
|
||||
gam <UserTypeEntity> print filetree [todrive <ToDriveAttribute>*]
|
||||
|
||||
@@ -49,10 +49,19 @@ gam user user@domain.com update serviceaccount
|
||||
```
|
||||
gam <UserTypeEntity> create form
|
||||
title <String> [description <String>] [isquiz [Boolean>]] [<JSONData>]
|
||||
[ispublished [<Boolean>] isacceptingresponses [<Boolean>]]
|
||||
[drivefilename <DriveFileName>] [<DriveFileParentAttribute>]
|
||||
[(csv [todrive <ToDriveAttribute>*]) | returnidonly]
|
||||
```
|
||||
|
||||
The valid combinations of `ispublished` and `isacceptingresponses` are:
|
||||
* `ispublished true isacceptingresponses true`
|
||||
* `ispublished true isacceptingresponses false`
|
||||
* `ispublished false isacceptingresponses false`
|
||||
* `ispublished false` - Sets `isacceptingresponses false`
|
||||
* `isacceptingresponses false` - Sets `ispublished false`
|
||||
* `isacceptingresponses true` - Sets `ispublished true`
|
||||
|
||||
`<JSONData>` is a list of form update requests.
|
||||
|
||||
* See: https://developers.google.com/forms/api/reference/rest/v1/forms/batchUpdate
|
||||
@@ -79,15 +88,24 @@ Select forms with `<DriveFileEntity>`:
|
||||
```
|
||||
gam <UserTypeEntity> update form <DriveFileEntity>
|
||||
[title <String>] [description <String>] [isquiz [Boolean>]] [<JSONData>]
|
||||
[ispublished [<Boolean>] isacceptingresponses [<Boolean>]]
|
||||
```
|
||||
|
||||
The valid combinations of `ispublished` and `isacceptingresponses` are:
|
||||
* `ispublished true isacceptingresponses true`
|
||||
* `ispublished true isacceptingresponses false`
|
||||
* `ispublished false isacceptingresponses false`
|
||||
* `ispublished false` - Sets `isacceptingresponses false`
|
||||
* `isacceptingresponses false` - Sets `ispublished false`
|
||||
* `isacceptingresponses true` - Sets `ispublished true`
|
||||
|
||||
`<JSONData>` is a list of form update requests.
|
||||
|
||||
* See: https://developers.google.com/forms/api/reference/rest/v1/forms/batchUpdate
|
||||
|
||||
## Extended Example
|
||||
|
||||
This example illustrates the use of JSN data to create and update forms
|
||||
This example illustrates the use of JSON data to create and update forms
|
||||
concerning student classtoom attendance.
|
||||
The form has two items: Absences and Notes.
|
||||
In `Absences`, the teacher can check `All present.` or check individual student absences.
|
||||
|
||||
@@ -72,6 +72,8 @@ This table and other suggestions came from:
|
||||
<EmailAddress> ::= <String>@<DomainName>
|
||||
<UniqueID> ::= id:<String>
|
||||
<GroupItem> ::= <EmailAddress>|<UniqueID>|<String>
|
||||
<LabelID> ::= <String>
|
||||
<LabelIDList> ::= "<LabelID>(,<LabelID)*"
|
||||
<LabelName> ::= <String>
|
||||
<QueryGmail> ::= <String> See: https://support.google.com/mail/answer/7190
|
||||
<Time> ::=
|
||||
@@ -389,6 +391,7 @@ Your command line will have: `embedimage file1.jpg image1` embedimage file2.jpg
|
||||
```
|
||||
gam <UserTypeEntity> archive messages <GroupItem>
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_archive <Number>])|(ids <MessageIDEntity>)
|
||||
[csv [todrive <ToDriveAttribute>*]]
|
||||
```
|
||||
@@ -400,6 +403,7 @@ Messages are archived to the group specified by `<GroupItem>`.
|
||||
|
||||
### Archive a selected set of messages
|
||||
* `((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+` - Criteria to select messages
|
||||
* `labelids <LabelIDList>` - Select messages with labels that match all of the specified label IDs.
|
||||
* `max_to_archive` - Limit the number of messages that will be archived; use a value of 0 for no limit
|
||||
* `doit` - No messages are archived unless you specify `doit`. By not specifying `doit`, you can preview the messages selected to verify that the results match your expectations.
|
||||
|
||||
@@ -432,10 +436,14 @@ See below for message selection.
|
||||
Export messages in EML format.
|
||||
```
|
||||
gam <UserTypeEntity> export message|messages
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [max_to_export <Number>])|(ids <MessageIDEntity>)
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [max_to_export <Number>])|(ids <MessageIDEntity>)
|
||||
[targetfolder <FilePath>] [targetname <FileName>] [overwrite [<Boolean>]]
|
||||
gam <UserTypeEntity> export thread|threads
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [max_to_export <Number>])|(ids <ThreadIDEntity>)
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [max_to_export <Number>])|(ids <MessageIDEntity>)
|
||||
[targetfolder <FilePath>] [targetname <FileName>] [overwrite [<Boolean>]]
|
||||
```
|
||||
|
||||
@@ -459,10 +467,12 @@ See below for message selection.
|
||||
```
|
||||
gam <UserTypeEntity> forward message|messages recipient|to <RecipientEntity>
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_forward <Number>])|(ids <MessageIDEntity>)
|
||||
[subject <String>] [addorigfieldstosubject]
|
||||
gam <UserTypeEntity> forward thread|threads recipient|to <RecipientEntity>
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_forward <Number>])|(ids <ThreadIDEntity>)
|
||||
[subject <String>] [addorigfieldstosubject]
|
||||
```
|
||||
@@ -482,23 +492,28 @@ See below for message selection.
|
||||
```
|
||||
gam <UserTypeEntity> delete messages|threads
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_delete <Number>])|(ids <MessageIDEntity>)
|
||||
[csv [todrive <ToDriveAttribute>*]]
|
||||
gam <UserTypeEntity> modify messages|threads
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_modify <Number>])|(ids <MessageIDEntity>)
|
||||
((addlabel <LabelName>)|(removelabel <LabelName>))+
|
||||
[csv [todrive <ToDriveAttribute>*]]
|
||||
gam <UserTypeEntity> spam messages|threads
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_spam <Number>])|(ids <MessageIDEntity>)
|
||||
[csv [todrive <ToDriveAttribute>*]]
|
||||
gam <UserTypeEntity> trash messages|threads
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_trash <Number>])|(ids <MessageIDEntity>)
|
||||
[csv [todrive <ToDriveAttribute>*]]
|
||||
gam <UserTypeEntity> untrash messages|threads
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_untrash <Number>])|(ids <MessageIDEntity>)
|
||||
[csv [todrive <ToDriveAttribute>*]]
|
||||
```
|
||||
@@ -522,6 +537,7 @@ user@domain.com,18e9fc58c5491f4c,Deleted,
|
||||
|
||||
### Manage a selected set of messages
|
||||
* `((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+` - Criteria to select messages
|
||||
* `labelids <LabelIDList>` - Select messages with labels that match all of the specified label IDs.
|
||||
* `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.
|
||||
|
||||
@@ -570,6 +586,7 @@ gam config auto_batch_min 1 groups_inde EastOffice delete message query "rfc822m
|
||||
```
|
||||
gam <UserTypeEntity> show messages|threads
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])*
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [max_to_show <Number>] [includespamtrash])|(ids <MessageIDEntity>)
|
||||
[labelmatchpattern <REMatchPattern>] [sendermatchpattern <REMatchPattern>]
|
||||
[countsonly|positivecountsonly] [useronly]
|
||||
@@ -581,6 +598,7 @@ gam <UserTypeEntity> show messages|threads
|
||||
[targetfolder <FilePath>] [overwrite [<Boolean>]]
|
||||
gam <UserTypeEntity> print messages|threads [todrive <ToDriveAttribute>*]
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])*
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [max_to_print <Number>] [includespamtrash])|(ids <MessageIDEntity>)
|
||||
[labelmatchpattern <REMatchPattern>] [sendermatchpattern <REMatchPattern>]
|
||||
[countsonly|positivecountsonly] [useronly]
|
||||
@@ -607,6 +625,7 @@ gam user user@domain.com print|show threads maxmessagesperthread 1
|
||||
|
||||
## Display a selected set of messages
|
||||
* `((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+` - Criteria to select messages
|
||||
* `labelids <LabelIDList>` - Select messages with labels that match all of the specified label IDs.
|
||||
* `max_to_xxx` - Limit the number of messages that will be displayed
|
||||
* `includespamtrash` - Include messages in the Spam and Trash folders
|
||||
* `labelmatchpattern <REMatchPattern>` - Only display messages with some label that matches `<REMatchPattern>`
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
Print the current version of Gam with details
|
||||
```
|
||||
gam version
|
||||
GAM 7.09.00 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.10.02 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.4 64-bit final
|
||||
Python 3.13.5 64-bit final
|
||||
MacOS Sequoia 15.5 x86_64
|
||||
Path: /Users/Admin/bin/gam7
|
||||
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
|
||||
@@ -15,9 +15,9 @@ Time: 2023-06-02T21:10:00-07:00
|
||||
Print the current version of Gam with details and time offset information
|
||||
```
|
||||
gam version timeoffset
|
||||
GAM 7.09.00 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.10.02 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.4 64-bit final
|
||||
Python 3.13.5 64-bit final
|
||||
MacOS Sequoia 15.5 x86_64
|
||||
Path: /Users/Admin/bin/gam7
|
||||
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
|
||||
@@ -27,9 +27,9 @@ Your system time differs from www.googleapis.com by less than 1 second
|
||||
Print the current version of Gam with extended details and SSL information
|
||||
```
|
||||
gam version extended
|
||||
GAM 7.09.00 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.10.02 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.4 64-bit final
|
||||
Python 3.13.5 64-bit final
|
||||
MacOS Sequoia 15.5 x86_64
|
||||
Path: /Users/Admin/bin/gam7
|
||||
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
|
||||
@@ -64,7 +64,7 @@ MacOS High Sierra 10.13.6 x86_64
|
||||
Path: /Users/Admin/bin/gam7
|
||||
Version Check:
|
||||
Current: 5.35.08
|
||||
Latest: 7.09.00
|
||||
Latest: 7.10.02
|
||||
echo $?
|
||||
1
|
||||
```
|
||||
@@ -72,7 +72,7 @@ echo $?
|
||||
Print the current version number without details
|
||||
```
|
||||
gam version simple
|
||||
7.09.00
|
||||
7.10.02
|
||||
```
|
||||
In Linux/MacOS you can do:
|
||||
```
|
||||
@@ -82,9 +82,9 @@ echo $VER
|
||||
Print the current version of Gam and address of this Wiki
|
||||
```
|
||||
gam help
|
||||
GAM 7.09.00 - https://github.com/GAM-team/GAM
|
||||
GAM 7.10.02 - https://github.com/GAM-team/GAM
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.4 64-bit final
|
||||
Python 3.13.5 64-bit final
|
||||
MacOS Sequoia 15.5 x86_64
|
||||
Path: /Users/Admin/bin/gam7
|
||||
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
|
||||
|
||||
@@ -337,7 +337,7 @@ enforce_expansive_access
|
||||
gam <UserTypeEntity> move drivefile
|
||||
gam <UserTypeEntity> transfer ownership
|
||||
gam <UserTypeEntity> claim ownership
|
||||
Default: False
|
||||
Default: True
|
||||
event_max_results
|
||||
When retrieving lists of Calendar events from API,
|
||||
how many should be retrieved in each API call
|
||||
|
||||
Reference in New Issue
Block a user