mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-07 07:41:38 +00:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c5f747c36 | ||
|
|
826619857c | ||
|
|
9a2880e411 | ||
|
|
95caeaba5e | ||
|
|
d8ad1b27a4 | ||
|
|
fefeae7c60 | ||
|
|
65f7b82d53 | ||
|
|
bebafb428d | ||
|
|
5e59363a0c | ||
|
|
4b2e0db720 | ||
|
|
938b2bf5a4 | ||
|
|
34ff0329c4 | ||
|
|
bed610405b | ||
|
|
1b0c8b75cb | ||
|
|
6eb7e59d56 | ||
|
|
5b4cf97702 | ||
|
|
997bd56bd6 | ||
|
|
e66db1a117 | ||
|
|
e3a5f33981 | ||
|
|
877465a82f | ||
|
|
7e9477c6ea | ||
|
|
1b2fc06f6f | ||
|
|
3d3b3eac85 | ||
|
|
882b930928 | ||
|
|
4d804177c4 | ||
|
|
de71baff60 | ||
|
|
79de854440 |
2
.github/workflows/pushwiki.yml
vendored
2
.github/workflows/pushwiki.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
cd GAM.wiki
|
||||
git config --local user.email "action@github.com"
|
||||
git config --local user.name "GitHub Action"
|
||||
git add *.md
|
||||
git add -A
|
||||
git commit -m "[no ci] Push Wiki changes"
|
||||
git status
|
||||
git push
|
||||
|
||||
@@ -565,6 +565,7 @@ If an item contains spaces, it should be surrounded by ".
|
||||
See: https://support.google.com/mail/answer/7190
|
||||
<QueryGroup> ::= <String>
|
||||
See: https://developers.google.com/admin-sdk/directory/v1/guides/search-groups
|
||||
<QueryItem> ::= <UniqueID>|<String>
|
||||
<QueryMemberRestrictions> ::= <String>
|
||||
See: https://cloud.google.com/identity/docs/reference/rest/v1beta1/SecuritySettings#MemberRestriction
|
||||
<QueryMobile> ::= <String>
|
||||
@@ -728,6 +729,7 @@ If an item contains spaces, it should be surrounded by ".
|
||||
<DomainNameList> ::= "<DomainName>(,<DomainName>)*"
|
||||
<DriveFileACLRoleList> ::= "<DriveFileACLRole>(,<DriveFileACLRole>)*"
|
||||
<DriveFileACLTypeList> ::= "<DriveFileACLType>(,<DriveFileACLType>)*"
|
||||
<DriveFileIDList> ::= "<DriveFileID>(,<DriveFileID>)*"
|
||||
<DriveFileList> ::= "<DriveFileItem>(,<DriveFileItem>)*"
|
||||
<DriveFilePermissionList> ::= "<DriveFilePermission>(,<DriveFilePermission>)*"
|
||||
<DriveFilePermissionIDList> ::= "<DriveFilePermissionID>(,<DriveFilePermissionID>)*"
|
||||
@@ -3381,6 +3383,7 @@ gam print course-materials [todrive <ToDriveAttribute>*]
|
||||
(orderby <CourseMaterialOrderByFieldName> [ascending|descending])*)
|
||||
[showcreatoremails|creatoremail] [showtopicnames] [fields <CourseMaterialFieldNameList>]
|
||||
[timefilter creationtime|updatetime|scheduledtime] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
|
||||
[oneitemperrow]
|
||||
[countsonly] [formatjson [quotechar <Character>]]
|
||||
gam print course-submissions [todrive <ToDriveAttribute>*]
|
||||
(course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] states <CourseStateList>])
|
||||
@@ -3402,6 +3405,7 @@ gam print course-works [todrive <ToDriveAttribute>*]
|
||||
[showcreatoremails|creatoremail] [showtopicnames] [fields <CourseWorkFieldNameList>]
|
||||
[showstudentsaslist [<Boolean>]] [delimiter <Character>]
|
||||
[timefilter creationtime|updatetime|scheduledtime] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
|
||||
[oneitemperrow]
|
||||
[countsonly] [formatjson [quotechar <Character>]]
|
||||
|
||||
# Classroom - Student Groups
|
||||
@@ -5410,34 +5414,48 @@ gam show vaultmatters|matters [matterstate <MatterStateList>]
|
||||
[formatjson]
|
||||
|
||||
gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
matter <MatterItem> corpus mail|groups
|
||||
[(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone]
|
||||
[(shareddrives|teamdrives (<SharedDriveIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
(rooms (<ChatSpaceList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
(sitesurl (<URLList>||(select <FileSelector>|<CSVFileSelector>)))]
|
||||
matter <MatterItem> <QueryItem>
|
||||
[wait <Integer>]
|
||||
gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
matter <MatterItem>
|
||||
corpus mail|groups
|
||||
[scope [all_data|held_data|unprocessed_data]]
|
||||
[(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone]
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
|
||||
[excludedrafts <Boolean>]
|
||||
[<JSONData>]
|
||||
[wait <Integer>]
|
||||
gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
matter <MatterItem> operation <String> [wait <Integer>]
|
||||
|
||||
gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
|
||||
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
(shareddrives|teamdrives (<SharedDriveIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
(rooms (<ChatSpaceList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
(sitesurl (<URLList>||(select <FileSelector>|<CSVFileSelector>)))
|
||||
gam create vaultexport|export matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[driveclientsideencryption any|encrypted|unencrypted]
|
||||
[includeaccessinfo <Boolean>]
|
||||
[excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
|
||||
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
[format ics|mbox|pst|xml]
|
||||
[region any|europe|us] [showdetails|returnidonly]
|
||||
|
||||
gam create vaultexport|export matter <MatterItem> [name <String>]
|
||||
corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
|
||||
[scope all_data|held_data|unprocessed_data]
|
||||
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
(documentids (<DriveFileIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
(shareddrives|teamdrives (<SharedDriveIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
[(includeshareddrives <Boolean>)|(shareddrivesoption included|included_if_account_is_not_a_member|not_included)]
|
||||
(sitesurl (<URLList>||(select <FileSelector>|<CSVFileSelector>)))
|
||||
[driveversiondate <Date>|<Time>]
|
||||
[includerooms <Boolean>]
|
||||
(rooms (<ChatSpaceList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
|
||||
[locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
|
||||
[responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
|
||||
[(includeshareddrives <Boolean>)|(shareddrivesoption included|included_if_account_is_not_a_member|not_included)]
|
||||
[driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
|
||||
(covereddata calllogs|textmessages|voicemails)*
|
||||
[driveclientsideencryption any|encrypted|unencrypted]
|
||||
[includerooms <Boolean>]
|
||||
[includeaccessinfo <Boolean>]
|
||||
[excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
|
||||
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
[covereddata calllogs|textmessages|voicemails]
|
||||
[format ics|mbox|pst|xml]
|
||||
[region any|europe|us] [showdetails|returnidonly]
|
||||
gam delete vaultexport|export <ExportItem> matter <MatterItem>
|
||||
@@ -5493,18 +5511,21 @@ gam show vaultexports|exports
|
||||
[fields <VaultExportFieldNameList>] [shownames]
|
||||
[formatjson]
|
||||
|
||||
gam create vaulthold|hold matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[showdetails|returnidonly]
|
||||
gam create vaulthold|hold matter <MatterItem> [name <String>] corpus calendar|drive|mail|groups|hangouts_chat|voice
|
||||
[(accounts|groups|users <EmailItemList>) | (orgunit|org|ou <OrgUnit>)]
|
||||
[query <QueryVaultCorpus>]
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
|
||||
[includerooms <Boolean>] [covereddata calllogs|textmessages|voicemails]
|
||||
[includerooms <Boolean>] (covereddata calllogs|textmessages|voicemails)*
|
||||
[includeshareddrives <Boolean>]
|
||||
[showdetails|returnidonly]
|
||||
gam update vaulthold|hold <HoldItem> matter <MatterItem>
|
||||
[([addaccounts|addgroups|addusers <EmailItemList>] [removeaccounts|removegroups|removeusers <EmailItemList>]) | (orgunit|org|ou <OrgUnit>)]
|
||||
[query <QueryVaultCorpus>]
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
|
||||
[includerooms <Boolean>] [covereddata calllogs|textmessages|voicemails]
|
||||
[includerooms <Boolean>] (covereddata calllogs|textmessages|voicemails)*
|
||||
[includeshareddrives <Boolean>]
|
||||
[showdetails]
|
||||
gam delete vaulthold|hold <HoldItem> matter <MatterItem>
|
||||
@@ -5544,6 +5565,32 @@ gam show vaultholds|holds [matters <MatterItemList>]
|
||||
gam <UserTypeEntity> print vaultholds|holds [todrive <ToDriveAttribute>*]
|
||||
gam <UserTypeEntity> show vaultholds|holds
|
||||
|
||||
gam create vaultquery <MatterItem> [name <String>]
|
||||
corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
|
||||
[scope all_data|held_data|unprocessed_data]
|
||||
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
(documentids (<DriveFileIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
(shareddrives|teamdrives (<SharedDriveIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
[(includeshareddrives <Boolean>)|(shareddrivesoption included|included_if_account_is_not_a_member|not_included)]
|
||||
(sitesurl (<URLList>||(select <FileSelector>|<CSVFileSelector>)))
|
||||
[driveversiondate <Date>|<Time>]
|
||||
[includerooms <Boolean>]
|
||||
(rooms (<ChatSpaceList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
|
||||
[locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
|
||||
[responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
|
||||
(covereddata calllogs|textmessages|voicemails)*
|
||||
[<JSONData>]
|
||||
[shownames]
|
||||
[showdetails|returnidonly|formatjson]
|
||||
|
||||
gam copy vaultquery <MatterItem> <QueryItem> [targetmatter <MatterItem>] [name <String>]
|
||||
[shownames]
|
||||
[showdetails|returnidonly|formatjson]
|
||||
|
||||
gam delete vaultquery <QueryItem> matter <MatterItem>
|
||||
gam delete vaultquery <MatterItem> <QueryItem>
|
||||
|
||||
<VaultQueryFieldName> ::=
|
||||
createtime |
|
||||
displayname |
|
||||
|
||||
@@ -1,7 +1,95 @@
|
||||
7.23.01
|
||||
|
||||
Added option `oneitemperrow` to 'gam print course-materials|course-work` to have each of a
|
||||
course's materials displayed on a separate row with all of the other course fields.
|
||||
This produces a CSV file that can be used in subsequent commands to process the materials without further script processing.
|
||||
|
||||
7.23.00
|
||||
|
||||
Added `chat_max_results` variable to `gam.cfg`.
|
||||
```
|
||||
chat_max_results
|
||||
When retrieving lists of Chat items from API,
|
||||
how many should be retrieved in each API call
|
||||
Default: 100
|
||||
Range: 1 - 1000
|
||||
```
|
||||
Previously, this vaule was always set to 1000 which could cause errors.
|
||||
|
||||
7.22.07
|
||||
|
||||
Added options `showdetails` and `returnidonly` to `gam create|copy vaultquery`.
|
||||
|
||||
Added option `<JSONData>` to `gam create vaultexport|vaultquery` and `gam print vaultcounts`.
|
||||
|
||||
7.22.06
|
||||
|
||||
Added commands to create, copy and delete Vault saved queries.
|
||||
```
|
||||
gam create vaultquery <MatterItem> [name <String>]
|
||||
corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
|
||||
[scope all_data|held_data|unprocessed_data]
|
||||
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
(documentids (<DriveFileIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
(shareddrives|teamdrives (<SharedDriveIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
[(includeshareddrives <Boolean>)|(shareddrivesoption included|included_if_account_is_not_a_member|not_included)]
|
||||
(sitesurl (<URLList>||(select <FileSelector>|<CSVFileSelector>)))
|
||||
[driveversiondate <Date>|<Time>]
|
||||
[includerooms <Boolean>]
|
||||
(rooms (<ChatSpaceList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
|
||||
[locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
|
||||
[responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
|
||||
(covereddata calllogs|textmessages|voicemails)*
|
||||
[shownames] [formatjson]
|
||||
|
||||
gam copy vaultquery <MatterItem> <QueryItem> [targetmatter <MatterItem>] [name <String>]
|
||||
[shownames] [formatjson]
|
||||
|
||||
gam delete vaultquery <QueryItem> matter <MatterItem>
|
||||
gam delete vaultquery <MatterItem> <QueryItem>
|
||||
```
|
||||
|
||||
Added a variant of `gam print vaultcounts` that gets its query parameters from a saved Vault query.
|
||||
```
|
||||
gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
matter <MatterItem> <QueryItem>
|
||||
[wait <Integer>]
|
||||
```
|
||||
|
||||
7.22.05
|
||||
|
||||
Added a variant of `gam create vaultexport` that gets its query parameters from a saved Vault query.
|
||||
|
||||
```
|
||||
gam create vaultexport|export matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[driveclientsideencryption any|encrypted|unencrypted]
|
||||
[includeaccessinfo <Boolean>]
|
||||
[excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
|
||||
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
[format ics|mbox|pst|xml]
|
||||
[region any|europe|us] [showdetails|returnidonly]
|
||||
```
|
||||
|
||||
7.22.04
|
||||
|
||||
Added a variant of `gam create vaulthold` that gets its parameters from a saved Vault query.
|
||||
```
|
||||
gam create vaulthold matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[showdetails|returnidonly]
|
||||
```
|
||||
|
||||
7.22.03
|
||||
|
||||
Fix backwards compatability bug introduced in 7.22.00 for `gam print users` that changed `suspended`
|
||||
from a field name to a query option; it is now correctly interpreted as a field name.
|
||||
|
||||
7.22.02
|
||||
|
||||
An update to the httplib2 library caused GAM proxy connections to fail; this has been fixed
|
||||
by includinbg the pysocks library needed by the latest httplib2 library.
|
||||
by including the pysocks library needed by the latest httplib2 library.
|
||||
|
||||
7.22.00
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
|
||||
"""
|
||||
|
||||
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
|
||||
__version__ = '7.22.02'
|
||||
__version__ = '7.23.00'
|
||||
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
||||
|
||||
#pylint: disable=wrong-import-position
|
||||
@@ -18989,10 +18989,10 @@ def doPrintAliases():
|
||||
pass
|
||||
elif myarg == 'select':
|
||||
_, users = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS)
|
||||
elif myarg in SUSPENDED_ARGUMENTS:
|
||||
isSuspended = _getIsSuspended(myarg)
|
||||
elif myarg in ARCHIVED_ARGUMENTS:
|
||||
isArchived = _getIsArchived(myarg)
|
||||
elif myarg == 'issuspended':
|
||||
isSuspended = getBoolean()
|
||||
elif myarg == 'isarchived':
|
||||
isArchived = getBoolean()
|
||||
elif myarg in {'user','users'}:
|
||||
users.extend(convertEntityToList(getString(Cmd.OB_EMAIL_ADDRESS_LIST, minLen=0)))
|
||||
elif myarg in {'group', 'groups'}:
|
||||
@@ -26579,7 +26579,7 @@ def printShowChatEmojis(users):
|
||||
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)
|
||||
pageSize=GC.Values[GC.CHAT_MAX_RESULTS], filter=pfilter)
|
||||
except (GAPI.notFound, GAPI.invalidArgument, GAPI.permissionDenied) as e:
|
||||
exitIfChatNotConfigured(chat, kvList, str(e), i, count)
|
||||
continue
|
||||
@@ -26649,7 +26649,14 @@ def getChatSpaceParameters(myarg, body, typeChoicesMap, updateMask):
|
||||
|
||||
CHAT_MEMBER_ROLE_MAP = {
|
||||
'member': 'ROLE_MEMBER',
|
||||
'manager': 'ROLE_MANAGER'
|
||||
'manager': 'ROLE_MANAGER',
|
||||
'owner': 'ROLE_OWNER',
|
||||
}
|
||||
|
||||
CHAT_ROLE_ENTITY_TYPE_MAP = {
|
||||
'ROLE_MEMBER': Ent.CHAT_MEMBER_USER,
|
||||
'ROLE_MANAGER': Ent.CHAT_MANAGER_USER,
|
||||
'ROLE_OWNER': Ent.CHAT_OWNER_USER,
|
||||
}
|
||||
|
||||
CHAT_MEMBER_TYPE_MAP = {
|
||||
@@ -27006,7 +27013,6 @@ def _getChatSpaceSearchParms(myarg, queries, queryTimes, OBY):
|
||||
return False
|
||||
return True
|
||||
|
||||
CHAT_PAGE_SIZE = 1000
|
||||
CHAT_SPACES_ADMIN_ORDERBY_CHOICE_MAP = {
|
||||
'createtime': 'createTime',
|
||||
'lastactivetime': 'lastActiveTime',
|
||||
@@ -27086,7 +27092,7 @@ def printShowChatSpaces(users):
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.INTERNAL_ERROR,
|
||||
GAPI.PERMISSION_DENIED, GAPI.FAILED_PRECONDITION],
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
fields=fields, pageSize=CHAT_PAGE_SIZE, **kwargsCS)
|
||||
fields=fields, pageSize=GC.Values[GC.CHAT_MAX_RESULTS], **kwargsCS)
|
||||
if showAccessSettings:
|
||||
for space in spaces:
|
||||
if space['spaceType'] == 'SPACE':
|
||||
@@ -27152,7 +27158,7 @@ def _getChatSpaceMembers(cd, chatSpace, ciGroupName):
|
||||
pageMessage=_getChatPageMessage(Ent.CHAT_MEMBER, user, 0, 0, qfilter),
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
parent=chatSpace, fields=fields, pageSize=CHAT_PAGE_SIZE, **kwargsUAA)
|
||||
parent=chatSpace, fields=fields, pageSize=GC.Values[GC.CHAT_MAX_RESULTS], **kwargsUAA)
|
||||
for member in members:
|
||||
_getChatMemberEmail(cd, member)
|
||||
gmember = {}
|
||||
@@ -27289,7 +27295,7 @@ def createChatMember(users):
|
||||
missingArgumentExit('space')
|
||||
if not userList and not groupList:
|
||||
missingArgumentExit('user|members|group|groups')
|
||||
userEntityType = Ent.CHAT_MEMBER_USER if role == 'ROLE_MEMBER' else Ent.CHAT_MANAGER_USER
|
||||
userEntityType = CHAT_ROLE_ENTITY_TYPE_MAP[role]
|
||||
userMembers = []
|
||||
for user in userList:
|
||||
userMembers.append({'member': {'name': f'users/{user}', 'type': mtype}})
|
||||
@@ -27546,7 +27552,7 @@ def syncChatMembers(users):
|
||||
unknownArgumentExit()
|
||||
if not parent:
|
||||
missingArgumentExit('space')
|
||||
userEntityType = Ent.CHAT_MEMBER_USER if role == 'ROLE_MEMBER' else Ent.CHAT_MANAGER_USER
|
||||
userEntityType = CHAT_ROLE_ENTITY_TYPE_MAP[role]
|
||||
userMembers = {}
|
||||
syncUsersSet = set()
|
||||
for user in userList:
|
||||
@@ -27576,7 +27582,7 @@ def syncChatMembers(users):
|
||||
pageMessage=_getChatPageMessage(Ent.CHAT_MEMBER, user, i, count, qfilter),
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.FAILED_PRECONDITION],
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
parent=parent, showGroups=groupsSpecified, pageSize=CHAT_PAGE_SIZE, **kwargs, **kwargsUAA)
|
||||
parent=parent, showGroups=groupsSpecified, pageSize=GC.Values[GC.CHAT_MAX_RESULTS], **kwargs, **kwargsUAA)
|
||||
for member in members:
|
||||
if 'member' in member:
|
||||
if member['member']['type'] == mtype and member['role'] == role:
|
||||
@@ -27777,7 +27783,7 @@ def printShowChatMembers(users):
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.INTERNAL_ERROR,
|
||||
GAPI.PERMISSION_DENIED, GAPI.FAILED_PRECONDITION],
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
fields="nextPageToken,spaces(name,displayName,spaceType,membershipCount)", pageSize=CHAT_PAGE_SIZE,
|
||||
fields="nextPageToken,spaces(name,displayName,spaceType,membershipCount)", pageSize=GC.Values[GC.CHAT_MAX_RESULTS],
|
||||
**kwargsCS)
|
||||
for space in sorted(spaces, key=lambda k: k[sortName]):
|
||||
if space['spaceType'] == 'SPACE' and 'membershipCount' in space:
|
||||
@@ -27794,7 +27800,7 @@ def printShowChatMembers(users):
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.INTERNAL_ERROR,
|
||||
GAPI.PERMISSION_DENIED, GAPI.FAILED_PRECONDITION],
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
fields="nextPageToken,spaces(name,displayName,spaceType,membershipCount)", pageSize=CHAT_PAGE_SIZE,
|
||||
fields="nextPageToken,spaces(name,displayName,spaceType,membershipCount)", pageSize=GC.Values[GC.CHAT_MAX_RESULTS],
|
||||
**kwargsCS)
|
||||
for space in sorted(spaces, key=lambda k: k[sortName]):
|
||||
# if 'membershipCount' in space:
|
||||
@@ -27825,7 +27831,7 @@ def printShowChatMembers(users):
|
||||
pageMessage=_getChatPageMessage(Ent.CHAT_MEMBER, user, j, jcount, qfilter),
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
parent=parentName, fields=fields, pageSize=CHAT_PAGE_SIZE, **kwargs, **kwargsUAA)
|
||||
parent=parentName, fields=fields, pageSize=GC.Values[GC.CHAT_MAX_RESULTS], **kwargs, **kwargsUAA)
|
||||
for member in members:
|
||||
_getChatMemberEmail(cd, member)
|
||||
except (GAPI.notFound, GAPI.invalidArgument, GAPI.permissionDenied) as e:
|
||||
@@ -28139,7 +28145,7 @@ def printShowChatMessages(users):
|
||||
pageMessage=_getChatPageMessage(Ent.CHAT_MESSAGE, user, i, count, qfilter),
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
pageSize=CHAT_PAGE_SIZE, parent=parentName, filter=pfilter, showDeleted=showDeleted,
|
||||
pageSize=GC.Values[GC.CHAT_MAX_RESULTS], parent=parentName, filter=pfilter, showDeleted=showDeleted,
|
||||
fields=fields)
|
||||
for message in messages:
|
||||
if 'sender' in message:
|
||||
@@ -28257,7 +28263,7 @@ def printShowChatEvents(users):
|
||||
pageMessage=_getChatPageMessage(Ent.CHAT_EVENT, user, i, count, qfilter),
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
pageSize=CHAT_PAGE_SIZE, parent=parentName, filter=pfilter)
|
||||
pageSize=GC.Values[GC.CHAT_MAX_RESULTS], parent=parentName, filter=pfilter)
|
||||
except (GAPI.notFound, GAPI.invalidArgument, GAPI.permissionDenied) as e:
|
||||
exitIfChatNotConfigured(chat, kvList, str(e), i, count)
|
||||
continue
|
||||
@@ -41654,7 +41660,7 @@ def convertQueryNameToID(v, nameOrId, matterId, matterNameId):
|
||||
query = callGAPI(v.matters().savedQueries(), 'get',
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
|
||||
matterId=matterId, savedQueryId=cg.group(1))
|
||||
return (query['savedQueryId'], query['displayName'], formatVaultNameId(query['savedQueryId'], query['displayName']))
|
||||
return (query['savedQueryId'], query['displayName'], formatVaultNameId(query['savedQueryId'], query['displayName']), query['query'])
|
||||
except (GAPI.notFound, GAPI.badRequest):
|
||||
entityDoesNotHaveItemExit([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_QUERY, nameOrId])
|
||||
except (GAPI.forbidden, GAPI.invalidArgument) as e:
|
||||
@@ -41663,12 +41669,12 @@ def convertQueryNameToID(v, nameOrId, matterId, matterNameId):
|
||||
try:
|
||||
queries = callGAPIpages(v.matters().savedQueries(), 'list', 'savedQueries',
|
||||
throwReasons=[GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
|
||||
matterId=matterId, fields='savedQueries(savedQueryId,displayName),nextPageToken')
|
||||
matterId=matterId, fields='savedQueries(savedQueryId,displayName,query),nextPageToken')
|
||||
except (GAPI.forbidden, GAPI.invalidArgument) as e:
|
||||
ClientAPIAccessDeniedExit(str(e))
|
||||
for query in queries:
|
||||
if query['displayName'].lower() == nameOrIdlower:
|
||||
return (query['savedQueryId'], query['displayName'], formatVaultNameId(query['savedQueryId'], query['displayName']))
|
||||
return (query['savedQueryId'], query['displayName'], formatVaultNameId(query['savedQueryId'], query['displayName']), query['query'])
|
||||
entityDoesNotHaveItemExit([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_QUERY, nameOrId])
|
||||
|
||||
def getMatterItem(v, state=None):
|
||||
@@ -41716,6 +41722,7 @@ VAULT_SEARCH_METHODS_MAP = {
|
||||
'accounts': 'ACCOUNT',
|
||||
'chatspace': 'ROOM',
|
||||
'chatspaces': 'ROOM',
|
||||
'documentids': 'DRIVE_DOCUMENT',
|
||||
'entireorg': 'ENTIRE_ORG',
|
||||
'everyone': 'ENTIRE_ORG',
|
||||
'org': 'ORG_UNIT',
|
||||
@@ -41813,11 +41820,13 @@ VAULT_QUERY_ARGS = [
|
||||
# drive
|
||||
'driveclientsideencryption', 'driveversiondate', 'includeshareddrives', 'includeteamdrives', 'shareddrivesoption',
|
||||
# hangoutsChat
|
||||
'includerooms',
|
||||
'includerooms',
|
||||
# mail
|
||||
'mailclientsideencryption', 'excludedrafts',
|
||||
# voice
|
||||
'covereddata',
|
||||
# all
|
||||
'json',
|
||||
] + list(VAULT_SEARCH_METHODS_MAP.keys())
|
||||
|
||||
def _buildVaultQuery(myarg, query, corpusArgumentMap):
|
||||
@@ -41831,12 +41840,14 @@ def _buildVaultQuery(myarg, query, corpusArgumentMap):
|
||||
query['dataScope'] = 'ALL_DATA'
|
||||
if myarg == 'corpus':
|
||||
query['corpus'] = getChoice(corpusArgumentMap, mapChoice=True)
|
||||
elif myarg == 'scope':
|
||||
query['dataScope'] = getChoice(VAULT_EXPORT_DATASCOPE_MAP, mapChoice=True)
|
||||
elif myarg in VAULT_SEARCH_METHODS_MAP:
|
||||
if query.get('searchMethod'):
|
||||
if query.get('method'):
|
||||
Cmd.Backup()
|
||||
usageErrorExit(Msg.MULTIPLE_SEARCH_METHODS_SPECIFIED.format(formatChoiceList(VAULT_SEARCH_METHODS_MAP)))
|
||||
searchMethod = VAULT_SEARCH_METHODS_MAP[myarg]
|
||||
query['searchMethod'] = searchMethod
|
||||
query['method'] = searchMethod
|
||||
if searchMethod == 'ACCOUNT':
|
||||
query['accountInfo'] = {'emails': getNormalizedEmailAddressEntity()}
|
||||
elif searchMethod == 'ORG_UNIT':
|
||||
@@ -41851,8 +41862,8 @@ def _buildVaultQuery(myarg, query, corpusArgumentMap):
|
||||
query['hangoutsChatInfo'] = {'roomId': roomIds}
|
||||
elif searchMethod == 'SITES_URL':
|
||||
query['sitesUrlInfo'] = {'urls': _getQueryList(Cmd.OB_URL_LIST)}
|
||||
elif myarg == 'scope':
|
||||
query['dataScope'] = getChoice(VAULT_EXPORT_DATASCOPE_MAP, mapChoice=True)
|
||||
elif searchMethod == 'DRIVE_DOCUMENT':
|
||||
query['driveDocumentInfo'] = {'documentIds': {'ids': _getQueryList(Cmd.OB_DRIVE_FILE_ID_LIST)}}
|
||||
elif myarg == 'terms':
|
||||
query['terms'] = getString(Cmd.OB_STRING)
|
||||
elif myarg in {'start', 'starttime'}:
|
||||
@@ -41891,50 +41902,73 @@ def _buildVaultQuery(myarg, query, corpusArgumentMap):
|
||||
query['hangoutsChatOptions'] = {'includeRooms': getBoolean()}
|
||||
# mail
|
||||
elif myarg == 'excludedrafts':
|
||||
query['mailOptions'] = {'excludeDrafts': getBoolean()}
|
||||
query.setdefault('mailOptions', {})['excludeDrafts'] = getBoolean()
|
||||
elif myarg == 'mailclientsideencryption':
|
||||
query.setdefault('mailOptions', {})['clientSideEncryptedOption'] = getChoice(VAULT_CSE_OPTION_MAP, mapChoice=True)
|
||||
# voice
|
||||
elif myarg == 'covereddata':
|
||||
query['voiceOptions'] = {'coveredData': getChoice(VAULT_VOICE_COVERED_DATA_MAP, mapChoice=True)}
|
||||
query.setdefault('voiceOptions', {'coveredData': []})
|
||||
query['voiceOptions']['coveredData'].append(getChoice(VAULT_VOICE_COVERED_DATA_MAP, mapChoice=True))
|
||||
# all
|
||||
elif myarg == 'json':
|
||||
jsonData = getJSON([])
|
||||
if 'query' in jsonData:
|
||||
query.update(jsonData['query'])
|
||||
else:
|
||||
query.update(jsonData)
|
||||
|
||||
|
||||
def _validateVaultQuery(body, corpusArgumentMap):
|
||||
if 'corpus' not in body['query']:
|
||||
missingArgumentExit(f'corpus {formatChoiceList(corpusArgumentMap)}')
|
||||
if 'searchMethod' not in body['query']:
|
||||
if 'method' not in body['query']:
|
||||
missingArgumentExit(formatChoiceList(VAULT_SEARCH_METHODS_MAP))
|
||||
if 'exportOptions' in body:
|
||||
for corpus, options in VAULT_CORPUS_OPTIONS_MAP.items():
|
||||
if body['query']['corpus'] != corpus:
|
||||
body['exportOptions'].pop(options, None)
|
||||
|
||||
# gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
|
||||
# (accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
# gam create vaultexport|export matter <MatterItem> [name <String>]
|
||||
# vaultquery <QueryItem>
|
||||
# [driveclientsideencryption any|encrypted|unencrypted]
|
||||
# [includeaccessinfo <Boolean>]
|
||||
# [excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
|
||||
# [showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
# [format ics|mbox|pst|xml]
|
||||
# [region any|europe|us] [showdetails|returnidonly]
|
||||
# gam create vaultexport|export matter <MatterItem> [name <String>]
|
||||
# corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
|
||||
# [scope all_data|held_data|unprocessed_data]
|
||||
# (accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone|entireorg
|
||||
# (documentids (<DriveFileIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
# (shareddrives|teamdrives (<SharedDriveIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
# (rooms (<ChatSpaceList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
# (sitesurl (<URLList>||(select <FileSelector>|<CSVFileSelector>)))
|
||||
# [scope <all_data|held_data|unprocessed_data>]
|
||||
# [(includeshareddrives <Boolean>)|(shareddrivesoption included|included_if_account_is_not_a_member|not_included)]
|
||||
# (sitesurl (<URLList>||(select <FileSelector>|<CSVFileSelector>)))
|
||||
# [driveversiondate <Date>|<Time>]
|
||||
# [includerooms <Boolean>]
|
||||
# (rooms (<ChatSpaceList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
# [terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
|
||||
# [locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
|
||||
# [responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
|
||||
# [(includeshareddrives <Boolean>)|(shareddrivesoption included|included_if_account_is_not_a_member|not_included)]
|
||||
# [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
|
||||
# (covereddata calllogs|textmessages|voicemails)*
|
||||
# [<JSONData>]
|
||||
# [driveclientsideencryption any|encrypted|unencrypted]
|
||||
# [includerooms <Boolean>]
|
||||
# [includeaccessinfo <Boolean>]
|
||||
# [excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
|
||||
# [showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
# [covereddata calllogs|textmessages|voicemails]
|
||||
# [format ics|mbox|pst|xml]
|
||||
# [region any|europe|us] [showdetails|returnidonly]
|
||||
def doCreateVaultExport():
|
||||
v = buildGAPIObject(API.VAULT)
|
||||
matterId = None
|
||||
body = {'query': {'dataScope': 'ALL_DATA'}, 'exportOptions': {}}
|
||||
includeAccessInfo = None
|
||||
exportFormat = None
|
||||
formatLocation = None
|
||||
useNewExport = None
|
||||
showConfidentialModeContent = None
|
||||
exportLinkedDriveFiles = None
|
||||
returnIdOnly = showDetails = False
|
||||
useNewExport = None
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if myarg == 'matter':
|
||||
@@ -41942,22 +41976,23 @@ def doCreateVaultExport():
|
||||
body['matterId'] = matterId
|
||||
elif myarg == 'name':
|
||||
body['name'] = getString(Cmd.OB_STRING)
|
||||
elif matterId is not None and myarg == 'vaultquery':
|
||||
_, _, _, body['query'] = convertQueryNameToID(v, getString(Cmd.OB_QUERY_ITEM), matterId, matterNameId)
|
||||
elif myarg in VAULT_QUERY_ARGS:
|
||||
_buildVaultQuery(myarg, body['query'], VAULT_CORPUS_ARGUMENT_MAP)
|
||||
elif myarg == 'includeaccessinfo':
|
||||
includeAccessInfo = getBoolean()
|
||||
elif myarg == 'format':
|
||||
formatLocation = Cmd.Location()
|
||||
exportFormat = getChoice(VAULT_EXPORT_FORMAT_MAP, mapChoice=True)
|
||||
elif myarg == 'usenewexport':
|
||||
useNewExport = getBoolean()
|
||||
elif myarg == 'format':
|
||||
exportFormat = getChoice(VAULT_EXPORT_FORMAT_MAP, mapChoice=True)
|
||||
elif myarg == 'showconfidentialmodecontent':
|
||||
showConfidentialModeContent = getBoolean()
|
||||
elif myarg == 'exportlinkeddrivefiles':
|
||||
exportLinkedDriveFiles = getBoolean()
|
||||
elif myarg == 'region':
|
||||
body['exportOptions']['region'] = getChoice(VAULT_EXPORT_REGION_MAP, mapChoice=True)
|
||||
elif myarg == 'includeaccessinfo':
|
||||
body['exportOptions'].setdefault('driveOptions', {})['includeAccessInfo'] = getBoolean()
|
||||
elif myarg == 'covereddata':
|
||||
body['exportOptions'].setdefault('voiceOptions', {})['coveredData'] = getChoice(VAULT_VOICE_COVERED_DATA_MAP, mapChoice=True)
|
||||
elif myarg == 'showdetails':
|
||||
showDetails = True
|
||||
returnIdOnly = False
|
||||
@@ -41969,15 +42004,19 @@ def doCreateVaultExport():
|
||||
if not matterId:
|
||||
missingArgumentExit('matter')
|
||||
_validateVaultQuery(body, VAULT_CORPUS_ARGUMENT_MAP)
|
||||
if exportFormat is not None:
|
||||
if not exportFormat in VAULT_CORPUS_EXPORT_FORMATS[body['query']['corpus']]:
|
||||
invalidChoiceExit(exportFormat, VAULT_CORPUS_EXPORT_FORMATS[body['query']['corpus']], False)
|
||||
elif body['query']['corpus'] != 'DRIVE':
|
||||
exportFormat = VAULT_CORPUS_EXPORT_FORMATS[body['query']['corpus']][0]
|
||||
if 'name' not in body:
|
||||
body['name'] = f'GAM {body["query"]["corpus"]} Export - {ISOformatTimeStamp(todaysTime())}'
|
||||
optionsField = VAULT_CORPUS_OPTIONS_MAP[body['query']['corpus']]
|
||||
if body['query']['corpus'] != 'DRIVE':
|
||||
if body['query']['corpus'] == 'DRIVE':
|
||||
if includeAccessInfo is not None:
|
||||
body['exportOptions'][optionsField] = {'includeAccessInfo': includeAccessInfo}
|
||||
else:
|
||||
if exportFormat is not None:
|
||||
if not exportFormat in VAULT_CORPUS_EXPORT_FORMATS[body['query']['corpus']]:
|
||||
Cmd.SetLocation(formatLocation)
|
||||
invalidChoiceExit(exportFormat, VAULT_CORPUS_EXPORT_FORMATS[body['query']['corpus']], False)
|
||||
else:
|
||||
exportFormat = VAULT_CORPUS_EXPORT_FORMATS[body['query']['corpus']][0]
|
||||
body['exportOptions'][optionsField] = {'exportFormat': exportFormat}
|
||||
if body['query']['corpus'] == 'MAIL':
|
||||
if showConfidentialModeContent is not None:
|
||||
@@ -42459,6 +42498,34 @@ def _showVaultHold(matterNameId, hold, cd, FJQC, k=0, kcount=0):
|
||||
showJSON(None, hold, timeObjects=VAULT_HOLD_TIME_OBJECTS)
|
||||
Ind.Decrement()
|
||||
|
||||
def _useVaultQueryForHold(v, matterId, matterNameId, body):
|
||||
_, _, _, query = convertQueryNameToID(v, getString(Cmd.OB_QUERY_ITEM), matterId, matterNameId)
|
||||
body['corpus'] = query['corpus']
|
||||
method = query.get('method')
|
||||
if method == 'ACCOUNT':
|
||||
body['accounts'] = []
|
||||
for email in query['accountInfo']['emails']:
|
||||
body['accounts'].append({'email': email})
|
||||
elif method == 'ORG_UNIT':
|
||||
body['orgUnit'] = {'orgUnitId': query['orgUnitInfo']['orgUnitId']}
|
||||
queryType = VAULT_CORPUS_QUERY_MAP[query['corpus']]
|
||||
if queryType is None:
|
||||
return
|
||||
body['query'] = {queryType: {}}
|
||||
if query['corpus'] == 'DRIVE':
|
||||
body['query'][queryType]['includeSharedDriveFiles'] = query['driveOptions'].get('includeSharedDrives', False)
|
||||
elif query['corpus'] in {'GROUPS', 'MAIL'}:
|
||||
if query.get('terms'):
|
||||
body['query'][queryType]['terms'] = query['terms']
|
||||
if query.get('startTime'):
|
||||
body['query'][queryType]['startTime'] = query['startTime']
|
||||
if query.get('endTime'):
|
||||
body['query'][queryType]['endTime'] = query['endTime']
|
||||
elif query['corpus'] == 'HANGOUTS_CHAT':
|
||||
body['query'][queryType]['includeRooms'] = query['hangoutsChatOptions'].get('includeRooms', False)
|
||||
elif query['corpus'] == 'VOICE':
|
||||
body['query'][queryType]['coveredData'] = query['voiceOptions']['coveredData']
|
||||
|
||||
def _getHoldQueryParameters(myarg, queryParameters):
|
||||
if myarg == 'query':
|
||||
queryParameters['queryLocation'] = Cmd.Location()
|
||||
@@ -42474,7 +42541,8 @@ def _getHoldQueryParameters(myarg, queryParameters):
|
||||
elif myarg in {'includeshareddrives', 'includeteamdrives'}:
|
||||
queryParameters['includeSharedDriveFiles'] = getBoolean()
|
||||
elif myarg == 'covereddata':
|
||||
queryParameters['coveredData'] = getChoice(VAULT_VOICE_COVERED_DATA_MAP, mapChoice=True)
|
||||
queryParameters.setdefault('coveredData', [])
|
||||
queryParameters['coveredData'].append(getChoice(VAULT_VOICE_COVERED_DATA_MAP, mapChoice=True))
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
@@ -42509,7 +42577,11 @@ def _setHoldQuery(body, queryParameters):
|
||||
if queryParameters.get('coveredData'):
|
||||
body['query'][queryType]['coveredData'] = queryParameters['coveredData']
|
||||
|
||||
# gam create vaulthold|hold matter <MatterItem> [name <String>] corpus calendar|drive|mail|groups|hangouts_chat|voice
|
||||
# gam create vaulthold|hold matter <MatterItem> [name <String>]
|
||||
# vaultquery <QueryItem>
|
||||
# [showdetails|returnidonly]
|
||||
# gam create vaulthold|hold matter <MatterItem> [name <String>]
|
||||
# corpus calendar|drive|mail|groups|hangouts_chat|voice
|
||||
# [(accounts|groups|users <EmailItemList>) | (orgunit|org|ou <OrgUnit>)]
|
||||
# [query <QueryVaultCorpus>]
|
||||
# [terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
|
||||
@@ -42523,13 +42595,16 @@ def doCreateVaultHold():
|
||||
matterId = None
|
||||
accounts = []
|
||||
queryParameters = {}
|
||||
returnIdOnly = showDetails = False
|
||||
returnIdOnly = showDetails = usedVaultQuery = False
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if myarg == 'matter':
|
||||
matterId, matterNameId = getMatterItem(v)
|
||||
elif myarg == 'name':
|
||||
body['name'] = getString(Cmd.OB_STRING)
|
||||
elif matterId is not None and myarg == 'vaultquery':
|
||||
_useVaultQueryForHold(v, matterId, matterNameId, body)
|
||||
usedVaultQuery = True
|
||||
elif myarg == 'corpus':
|
||||
body['corpus'] = getChoice(VAULT_CORPUS_ARGUMENT_MAP, mapChoice=True)
|
||||
elif myarg in {'accounts', 'users', 'groups'}:
|
||||
@@ -42553,7 +42628,8 @@ def doCreateVaultHold():
|
||||
missingArgumentExit(f'corpus {"|".join(VAULT_CORPUS_ARGUMENT_MAP)}')
|
||||
if 'name' not in body:
|
||||
body['name'] = f'GAM {body["corpus"]} Hold - {ISOformatTimeStamp(todaysTime())}'
|
||||
_setHoldQuery(body, queryParameters)
|
||||
if not usedVaultQuery:
|
||||
_setHoldQuery(body, queryParameters)
|
||||
if accounts:
|
||||
body['accounts'] = []
|
||||
cd = buildGAPIObject(API.DIRECTORY)
|
||||
@@ -42986,6 +43062,116 @@ def _showVaultQuery(matterNameId, query, cd, drive, FJQC, k=0, kcount=0):
|
||||
showJSON(None, query, timeObjects=VAULT_QUERY_TIME_OBJECTS)
|
||||
Ind.Decrement()
|
||||
|
||||
def doCreateCopyVaultQuery(copyCmd):
|
||||
v = buildGAPIObject(API.VAULT)
|
||||
body = {'query': {'dataScope': 'ALL_DATA'}, 'displayName': ''}
|
||||
matterId, matterNameId = getMatterItem(v)
|
||||
if copyCmd:
|
||||
_, queryName, _, body['query'] = convertQueryNameToID(v, getString(Cmd.OB_QUERY_ITEM), matterId, matterNameId)
|
||||
targetId = None
|
||||
cd = drive = None
|
||||
FJQC = FormatJSONQuoteChar()
|
||||
returnIdOnly = showDetails = False
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if myarg == 'name':
|
||||
body['displayName'] = getString(Cmd.OB_STRING)
|
||||
elif copyCmd and myarg == 'targetmatter':
|
||||
targetId, targetNameId = getMatterItem(v)
|
||||
elif not copyCmd and myarg in VAULT_QUERY_ARGS:
|
||||
_buildVaultQuery(myarg, body['query'], VAULT_CORPUS_ARGUMENT_MAP)
|
||||
elif myarg == 'shownames':
|
||||
cd = buildGAPIObject(API.DIRECTORY)
|
||||
_, drive = buildGAPIServiceObject(API.DRIVE3, _getAdminEmail())
|
||||
if drive is None:
|
||||
return
|
||||
elif myarg == 'showdetails':
|
||||
showDetails = True
|
||||
returnIdOnly = False
|
||||
elif myarg == 'returnidonly':
|
||||
returnIdOnly = True
|
||||
showDetails = False
|
||||
else:
|
||||
FJQC.GetFormatJSON(myarg)
|
||||
if copyCmd:
|
||||
if targetId is None:
|
||||
targetId = matterId
|
||||
targetNameId = matterNameId
|
||||
if not body['displayName']:
|
||||
body['displayName'] = f'Copy of {queryName}' if matterId == targetId else queryName
|
||||
resultId = targetId
|
||||
resultNameId = targetNameId
|
||||
else:
|
||||
_validateVaultQuery(body, VAULT_CORPUS_ARGUMENT_MAP)
|
||||
if not body['displayName']:
|
||||
body['displayName'] = 'GAM {body["query"]["corpus"]} Query - {ISOformatTimeStamp(todaysTime())}'
|
||||
resultId = matterId
|
||||
resultNameId = matterNameId
|
||||
try:
|
||||
result = callGAPI(v.matters().savedQueries(), 'create',
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT, GAPI.ALREADY_EXISTS],
|
||||
matterId=resultId, body=body)
|
||||
if not returnIdOnly:
|
||||
if not FJQC.formatJSON:
|
||||
entityActionPerformed([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_QUERY, formatVaultNameId(result['displayName'], result['savedQueryId'])])
|
||||
if showDetails or FJQC.formatJSON:
|
||||
_showVaultQuery(resultNameId, result, cd, drive, FJQC)
|
||||
else:
|
||||
writeStdout(f'{result["savedQueryId"]}\n')
|
||||
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument, GAPI.alreadyExists) as e:
|
||||
entityActionFailedWarning([Ent.VAULT_MATTER, resultNameId, Ent.VAULT_QUERY, body['displayName']], str(e))
|
||||
|
||||
# gam create vaultquery <MatterItem> [name <String>]
|
||||
# corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
|
||||
# [scope all_data|held_data|unprocessed_data]
|
||||
# (accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone|entireorg
|
||||
# (documentids (<DriveFileIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
# (shareddrives|teamdrives (<SharedDriveIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
# [(includeshareddrives <Boolean>)|(shareddrivesoption included|included_if_account_is_not_a_member|not_included)]
|
||||
# (sitesurl (<URLList>||(select <FileSelector>|<CSVFileSelector>)))
|
||||
# [driveversiondate <Date>|<Time>]
|
||||
# [includerooms <Boolean>]
|
||||
# (rooms (<ChatSpaceList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
# [terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
|
||||
# [locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
|
||||
# [responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
|
||||
# (covereddata calllogs|textmessages|voicemails)*
|
||||
# [<JSONData>]
|
||||
# [shownames]
|
||||
# [showdetails|returnidonly|formatjson]
|
||||
def doCreateVaultQuery():
|
||||
doCreateCopyVaultQuery(False)
|
||||
|
||||
# gam copy vaultquery <MatterItem> <QueryItem> [targetmatter <MatterItem>] [name <String>]
|
||||
# [shownames]
|
||||
# [showdetails|returnidonly|formatjson]
|
||||
def doCopyVaultQuery():
|
||||
doCreateCopyVaultQuery(True)
|
||||
|
||||
# gam delete vaultquery <QueryItem> matter <MatterItem>
|
||||
# gam delete vaultquery <MatterItem> <QueryItem>
|
||||
def doDeleteVaultQuery():
|
||||
v = buildGAPIObject(API.VAULT)
|
||||
if not Cmd.ArgumentIsAhead('matter'):
|
||||
matterId, matterNameId = getMatterItem(v)
|
||||
queryId, queryName, queryNameId, _ = convertQueryNameToID(v, getString(Cmd.OB_QUERY_ITEM), matterId, matterNameId)
|
||||
else:
|
||||
queryName = getString(Cmd.OB_QUERY_ITEM)
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if myarg == 'matter':
|
||||
matterId, matterNameId = getMatterItem(v)
|
||||
queryId, queryName, queryNameId, _ = convertQueryNameToID(v, queryName, matterId, matterNameId)
|
||||
else:
|
||||
unknownArgumentExit()
|
||||
try:
|
||||
callGAPI(v.matters().savedQueries(), 'delete',
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
|
||||
matterId=matterId, savedQueryId=queryId)
|
||||
entityActionPerformed([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_QUERY, queryNameId])
|
||||
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument) as e:
|
||||
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_QUERY, queryNameId], str(e))
|
||||
|
||||
VAULT_QUERY_FIELDS_CHOICE_MAP = {
|
||||
'createtime': 'createTime',
|
||||
'displayname': 'displayName',
|
||||
@@ -43006,7 +43192,7 @@ def doInfoVaultQuery():
|
||||
v = buildGAPIObject(API.VAULT)
|
||||
if not Cmd.ArgumentIsAhead('matter'):
|
||||
matterId, matterNameId = getMatterItem(v)
|
||||
queryId, queryName, queryNameId = convertQueryNameToID(v, getString(Cmd.OB_QUERY_ITEM), matterId, matterNameId)
|
||||
queryId, queryName, queryNameId, _ = convertQueryNameToID(v, getString(Cmd.OB_QUERY_ITEM), matterId, matterNameId)
|
||||
else:
|
||||
queryName = getString(Cmd.OB_QUERY_ITEM)
|
||||
cd = drive = None
|
||||
@@ -43016,7 +43202,7 @@ def doInfoVaultQuery():
|
||||
myarg = getArgument()
|
||||
if myarg == 'matter':
|
||||
matterId, matterNameId = getMatterItem(v)
|
||||
queryId, queryName, queryNameId = convertQueryNameToID(v, queryName, matterId, matterNameId)
|
||||
queryId, queryName, queryNameId, _ = convertQueryNameToID(v, queryName, matterId, matterNameId)
|
||||
elif myarg == 'shownames':
|
||||
cd = buildGAPIObject(API.DIRECTORY)
|
||||
_, drive = buildGAPIServiceObject(API.DRIVE3, _getAdminEmail())
|
||||
@@ -43471,14 +43657,16 @@ def doPrintShowVaultMatters():
|
||||
PRINT_VAULT_COUNTS_TITLES = ['account', 'count', 'error']
|
||||
|
||||
# gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
# matter <MatterItem> corpus mail|groups
|
||||
# (accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
# (shareddrives|teamdrives (<SharedDriveIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
# (rooms (<ChatSpaceList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
# (sitesurl (<URLList>||(select <FileSelector>|<CSVFileSelector>)))
|
||||
# [scope <all_data|held_data|unprocessed_data>]
|
||||
# matter <MatterItem> <QueryItem>
|
||||
# [wait <Integer>]
|
||||
# gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
# matter <MatterItem>
|
||||
# corpus mail|groups
|
||||
# [scope all_data|held_data|unprocessed_data]
|
||||
# (accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone|entireorg
|
||||
# [terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
|
||||
# [excludedrafts <Boolean>]
|
||||
# [<JSONData>]
|
||||
# [wait <Integer>]
|
||||
# gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
# matter <MatterItem> operation <String> [wait <Integer>]
|
||||
@@ -43487,18 +43675,19 @@ def doPrintVaultCounts():
|
||||
csvPF = CSVPrintFile(PRINT_VAULT_COUNTS_TITLES, 'sortall')
|
||||
matterId = name = None
|
||||
operationWait = 15
|
||||
body = {'view': 'ALL'}
|
||||
query = {}
|
||||
body = {'view': 'ALL', 'query': {}}
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if csvPF and myarg == 'todrive':
|
||||
csvPF.GetTodriveParameters()
|
||||
elif myarg == 'matter':
|
||||
matterId, _ = getMatterItem(v)
|
||||
matterId, matterNameId = getMatterItem(v)
|
||||
elif matterId is not None and myarg == 'vaultquery':
|
||||
_, _, _, body['query'] = convertQueryNameToID(v, getString(Cmd.OB_QUERY_ITEM), matterId, matterNameId)
|
||||
elif myarg == 'operation':
|
||||
name = getString(Cmd.OB_STRING)
|
||||
elif myarg in VAULT_QUERY_ARGS:
|
||||
_buildVaultQuery(myarg, query, VAULT_COUNTS_CORPUS_ARGUMENT_MAP)
|
||||
_buildVaultQuery(myarg, body['query'], VAULT_COUNTS_CORPUS_ARGUMENT_MAP)
|
||||
elif myarg == 'wait':
|
||||
operationWait = getInteger(minVal=1)
|
||||
else:
|
||||
@@ -43509,7 +43698,6 @@ def doPrintVaultCounts():
|
||||
operation = {'name': name}
|
||||
doWait = False
|
||||
else:
|
||||
body['query'] = query
|
||||
_validateVaultQuery(body, VAULT_COUNTS_CORPUS_ARGUMENT_MAP)
|
||||
try:
|
||||
operation = callGAPI(v.matters(), 'count',
|
||||
@@ -43533,7 +43721,7 @@ def doPrintVaultCounts():
|
||||
doWait = True
|
||||
response = operation.get('response', {})
|
||||
query = operation['metadata']['query']
|
||||
search_method = query.get('searchMethod')
|
||||
search_method = query.get('method')
|
||||
# ARGH count results don't include accounts with zero items.
|
||||
# so we keep track of which accounts we searched and can report
|
||||
# zero data for them.
|
||||
@@ -45754,71 +45942,81 @@ def doPrintUsers(entityList=None):
|
||||
csvPF.WriteRowNoFilter(row)
|
||||
|
||||
def _printUser(userEntity, i, count):
|
||||
if isSuspended is None or isSuspended == userEntity.get('suspended', isSuspended):
|
||||
if showValidColumn:
|
||||
userEntity[showValidColumn] = True
|
||||
userEmail = userEntity['primaryEmail']
|
||||
if printOptions['emailParts']:
|
||||
if userEmail.find('@') != -1:
|
||||
userEntity['primaryEmailLocal'], userEntity['primaryEmailDomain'] = splitEmailAddress(userEmail)
|
||||
if 'languages' in userEntity and not FJQC.formatJSON:
|
||||
userEntity['languages'] = _formatLanguagesList(userEntity.pop('languages'), delimiter)
|
||||
for location in userEntity.get('locations', []):
|
||||
location['buildingName'] = _getBuildingNameById(cd, location.get('buildingId', ''))
|
||||
if quotePlusPhoneNumbers:
|
||||
for phone in userEntity.get('phones', []):
|
||||
phoneNumber = phone.get('value', '')
|
||||
if phoneNumber.startswith('+'):
|
||||
phone['value'] = "'"+phoneNumber
|
||||
if schemaParms['selectedSchemaFields']:
|
||||
_filterSchemaFields(userEntity, schemaParms)
|
||||
if printOptions['getGroupFeed']:
|
||||
printGettingAllEntityItemsForWhom(Ent.GROUP_MEMBERSHIP, userEmail, i, count)
|
||||
try:
|
||||
groups = callGAPIpages(cd.groups(), 'list', 'groups',
|
||||
pageMessage=getPageMessageForWhom(),
|
||||
throwReasons=GAPI.GROUP_LIST_USERKEY_THROW_REASONS,
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
userKey=userEmail, orderBy='email', fields='nextPageToken,groups(email)')
|
||||
numGroups = len(groups)
|
||||
if not printOptions['groupsInColumns']:
|
||||
userEntity['GroupsCount'] = numGroups
|
||||
userEntity['Groups'] = delimiter.join([groupname['email'] for groupname in groups])
|
||||
else:
|
||||
if numGroups > printOptions['maxGroups']:
|
||||
printOptions['maxGroups'] = numGroups
|
||||
userEntity['Groups'] = numGroups
|
||||
for j, group in enumerate(groups):
|
||||
userEntity[f'Groups{GC.Values[GC.CSV_OUTPUT_SUBFIELD_DELIMITER]}{j}'] = group['email']
|
||||
except (GAPI.invalidMember, GAPI.invalidInput):
|
||||
badRequestWarning(Ent.GROUP, Ent.MEMBER, userEmail)
|
||||
except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.forbidden, GAPI.badRequest):
|
||||
accessErrorExit(cd)
|
||||
if aliasMatchPattern and 'aliases' in userEntity:
|
||||
userEntity['aliases'] = [alias for alias in userEntity['aliases'] if aliasMatchPattern.match(alias)]
|
||||
if printOptions['getLicenseFeed'] or printOptions['getLicenseFeedByUser']:
|
||||
if printOptions['getLicenseFeed']:
|
||||
u_licenses = licenses.get(userEmail.lower(), [])
|
||||
if (isSuspended is None and isArchived is None):
|
||||
showUser = True
|
||||
elif (isSuspended is not None and isArchived is None):
|
||||
showUser = isSuspended == userEntity.get('suspended', isSuspended)
|
||||
elif (isSuspended is None and isArchived is not None):
|
||||
showUser = isArchived == userEntity.get('archived', isArchived)
|
||||
else:
|
||||
showUser = ((isSuspended == userEntity.get('suspended', isSuspended)) or
|
||||
(isArchived == userEntity.get('archived', isArchived)))
|
||||
if not showUser:
|
||||
return
|
||||
if showValidColumn:
|
||||
userEntity[showValidColumn] = True
|
||||
userEmail = userEntity['primaryEmail']
|
||||
if printOptions['emailParts']:
|
||||
if userEmail.find('@') != -1:
|
||||
userEntity['primaryEmailLocal'], userEntity['primaryEmailDomain'] = splitEmailAddress(userEmail)
|
||||
if 'languages' in userEntity and not FJQC.formatJSON:
|
||||
userEntity['languages'] = _formatLanguagesList(userEntity.pop('languages'), delimiter)
|
||||
for location in userEntity.get('locations', []):
|
||||
location['buildingName'] = _getBuildingNameById(cd, location.get('buildingId', ''))
|
||||
if quotePlusPhoneNumbers:
|
||||
for phone in userEntity.get('phones', []):
|
||||
phoneNumber = phone.get('value', '')
|
||||
if phoneNumber.startswith('+'):
|
||||
phone['value'] = "'"+phoneNumber
|
||||
if schemaParms['selectedSchemaFields']:
|
||||
_filterSchemaFields(userEntity, schemaParms)
|
||||
if printOptions['getGroupFeed']:
|
||||
printGettingAllEntityItemsForWhom(Ent.GROUP_MEMBERSHIP, userEmail, i, count)
|
||||
try:
|
||||
groups = callGAPIpages(cd.groups(), 'list', 'groups',
|
||||
pageMessage=getPageMessageForWhom(),
|
||||
throwReasons=GAPI.GROUP_LIST_USERKEY_THROW_REASONS,
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
userKey=userEmail, orderBy='email', fields='nextPageToken,groups(email)')
|
||||
numGroups = len(groups)
|
||||
if not printOptions['groupsInColumns']:
|
||||
userEntity['GroupsCount'] = numGroups
|
||||
userEntity['Groups'] = delimiter.join([groupname['email'] for groupname in groups])
|
||||
else:
|
||||
u_licenses = getUserLicenses(lic, userEntity, skus)
|
||||
if not oneLicensePerRow:
|
||||
userEntity['LicensesCount'] = len(u_licenses)
|
||||
if u_licenses:
|
||||
userEntity['Licenses'] = delimiter.join(u_licenses)
|
||||
userEntity['LicensesDisplay'] = delimiter.join([SKU.skuIdToDisplayName(skuId) for skuId in u_licenses])
|
||||
if numGroups > printOptions['maxGroups']:
|
||||
printOptions['maxGroups'] = numGroups
|
||||
userEntity['Groups'] = numGroups
|
||||
for j, group in enumerate(groups):
|
||||
userEntity[f'Groups{GC.Values[GC.CSV_OUTPUT_SUBFIELD_DELIMITER]}{j}'] = group['email']
|
||||
except (GAPI.invalidMember, GAPI.invalidInput):
|
||||
badRequestWarning(Ent.GROUP, Ent.MEMBER, userEmail)
|
||||
except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.forbidden, GAPI.badRequest):
|
||||
accessErrorExit(cd)
|
||||
if aliasMatchPattern and 'aliases' in userEntity:
|
||||
userEntity['aliases'] = [alias for alias in userEntity['aliases'] if aliasMatchPattern.match(alias)]
|
||||
if printOptions['getLicenseFeed'] or printOptions['getLicenseFeedByUser']:
|
||||
if printOptions['getLicenseFeed']:
|
||||
u_licenses = licenses.get(userEmail.lower(), [])
|
||||
else:
|
||||
u_licenses = []
|
||||
u_licenses = getUserLicenses(lic, userEntity, skus)
|
||||
if not oneLicensePerRow:
|
||||
_writeUserEntity(userEntity)
|
||||
else:
|
||||
userEntity['LicensesCount'] = len(u_licenses)
|
||||
if u_licenses:
|
||||
for skuId in u_licenses:
|
||||
userEntity['License'] = skuId
|
||||
userEntity['LicenseDisplay'] = SKU.skuIdToDisplayName(skuId)
|
||||
_writeUserEntity(userEntity)
|
||||
else:
|
||||
userEntity['License'] = userEntity['LicenseDisplay'] = ''
|
||||
userEntity['Licenses'] = delimiter.join(u_licenses)
|
||||
userEntity['LicensesDisplay'] = delimiter.join([SKU.skuIdToDisplayName(skuId) for skuId in u_licenses])
|
||||
else:
|
||||
u_licenses = []
|
||||
if not oneLicensePerRow:
|
||||
_writeUserEntity(userEntity)
|
||||
else:
|
||||
if u_licenses:
|
||||
for skuId in u_licenses:
|
||||
userEntity['License'] = skuId
|
||||
userEntity['LicenseDisplay'] = SKU.skuIdToDisplayName(skuId)
|
||||
_writeUserEntity(userEntity)
|
||||
else:
|
||||
userEntity['License'] = userEntity['LicenseDisplay'] = ''
|
||||
_writeUserEntity(userEntity)
|
||||
|
||||
def _updateDomainCounts(emailAddress):
|
||||
nonlocal domainCounts
|
||||
@@ -45911,10 +46109,10 @@ def doPrintUsers(entityList=None):
|
||||
showDeleted = True
|
||||
elif entityList is None and myarg == 'select':
|
||||
_, entityList = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS)
|
||||
elif myarg in SUSPENDED_ARGUMENTS:
|
||||
isSuspended = _getIsSuspended(myarg)
|
||||
elif myarg in ARCHIVED_ARGUMENTS:
|
||||
isArchived = _getIsArchived(myarg)
|
||||
elif myarg == 'issuspended':
|
||||
isSuspended = getBoolean()
|
||||
elif myarg == 'isarchived':
|
||||
isArchived = getBoolean()
|
||||
elif myarg == 'orderby':
|
||||
orderBy, sortOrder = getOrderBySortOrder(USERS_ORDERBY_CHOICE_MAP)
|
||||
elif myarg == 'userview':
|
||||
@@ -46092,6 +46290,8 @@ def doPrintUsers(entityList=None):
|
||||
# If no individual fields were specified (allfields, basic, full) or individual fields other than primaryEmail were specified, look up each user
|
||||
if isSuspended is not None and fieldsList:
|
||||
fieldsList.append('suspended')
|
||||
if isArchived is not None and fieldsList:
|
||||
fieldsList.append('archived')
|
||||
if projectionSet or len(set(fieldsList)) > 1 or showValidColumn:
|
||||
jcount = len(entityList)
|
||||
fields = getFieldsFromFieldsList(fieldsList)
|
||||
@@ -49273,6 +49473,16 @@ def doPrintCourseWM(entityIDType, entityStateType):
|
||||
pass
|
||||
return topicNames
|
||||
|
||||
def _printCourseWMrow(course, courseWM):
|
||||
row = flattenJSON(courseWM, flattened={'courseId': course['id'], 'courseName': course['name']}, timeObjects=TimeObjects,
|
||||
simpleLists=['studentIds'] if showStudentsAsList else None, delimiter=delimiter)
|
||||
if not FJQC.formatJSON:
|
||||
csvPF.WriteRowTitles(row)
|
||||
elif csvPF.CheckRowTitles(row):
|
||||
csvPF.WriteRowNoFilter({'courseId': course['id'], 'courseName': course['name'],
|
||||
'JSON': json.dumps(cleanJSON(courseWM, timeObjects=TimeObjects),
|
||||
ensure_ascii=False, sort_keys=True)})
|
||||
|
||||
def _printCourseWM(course, courseWM, i, count):
|
||||
if applyCourseItemFilter and not _courseItemPassesFilter(courseWM, courseItemFilter):
|
||||
return
|
||||
@@ -49284,14 +49494,13 @@ def doPrintCourseWM(entityIDType, entityStateType):
|
||||
topicId = courseWM.get('topicId')
|
||||
if topicId:
|
||||
courseWM['topicName'] = topicNames.get(topicId, topicId)
|
||||
row = flattenJSON(courseWM, flattened={'courseId': course['id'], 'courseName': course['name']}, timeObjects=TimeObjects,
|
||||
simpleLists=['studentIds'] if showStudentsAsList else None, delimiter=delimiter)
|
||||
if not FJQC.formatJSON:
|
||||
csvPF.WriteRowTitles(row)
|
||||
elif csvPF.CheckRowTitles(row):
|
||||
csvPF.WriteRowNoFilter({'courseId': course['id'], 'courseName': course['name'],
|
||||
'JSON': json.dumps(cleanJSON(courseWM, timeObjects=TimeObjects),
|
||||
ensure_ascii=False, sort_keys=True)})
|
||||
if not oneItemPerRow or not courseWM.get('materials', []):
|
||||
_printCourseWMrow(course, courseWM)
|
||||
else:
|
||||
courseMaterials = courseWM.pop('materials')
|
||||
for courseMaterial in courseMaterials:
|
||||
courseWM['materials'] = courseMaterial
|
||||
_printCourseWMrow(course, courseWM)
|
||||
|
||||
croom = buildGAPIObject(API.CLASSROOM)
|
||||
if entityIDType == Ent.COURSE_WORK_ID:
|
||||
@@ -49329,7 +49538,7 @@ def doPrintCourseWM(entityIDType, entityStateType):
|
||||
courseShowProperties = _initCourseShowProperties(['name'])
|
||||
OBY = OrderBy(OrderbyChoiceMap)
|
||||
creatorEmails = {}
|
||||
showCreatorEmail = showTopicNames = False
|
||||
oneItemPerRow = showCreatorEmail = showTopicNames = False
|
||||
delimiter = GC.Values[GC.CSV_OUTPUT_FIELD_DELIMITER]
|
||||
countsOnly = showStudentsAsList = False
|
||||
while Cmd.ArgumentsRemaining():
|
||||
@@ -49346,6 +49555,9 @@ def doPrintCourseWM(entityIDType, entityStateType):
|
||||
pass
|
||||
elif myarg == 'orderby':
|
||||
OBY.GetChoice()
|
||||
elif myarg == 'oneitemperrow':
|
||||
oneItemPerRow = True
|
||||
csvPF.RemoveIndexedTitles('materials')
|
||||
elif myarg in {'showcreatoremails', 'creatoremail'}:
|
||||
showCreatorEmail = True
|
||||
elif myarg == 'showtopicnames':
|
||||
@@ -49426,6 +49638,7 @@ def doPrintCourseWM(entityIDType, entityStateType):
|
||||
# (orderby <CourseMaterialsOrderByFieldName> [ascending|descending])*)
|
||||
# [showcreatoremails|creatoremail] [showtopicnames] [fields <CourseMaterialFieldNameList>]
|
||||
# [timefilter creationtime|updatetime|scheduledtime] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
|
||||
# [oneitemperrow]
|
||||
# [countsonly] [formatjson [quotechar <Character>]]
|
||||
def doPrintCourseMaterials():
|
||||
doPrintCourseWM(Ent.COURSE_MATERIAL_ID, Ent.COURSE_MATERIAL_STATE)
|
||||
@@ -49437,6 +49650,7 @@ def doPrintCourseMaterials():
|
||||
# [showcreatoremails|creatoremail] [showtopicnames] [fields <CourseWorkFieldNameList>]
|
||||
# [showstudentsaslist [<Boolean>]] [delimiter <Character>]
|
||||
# [timefilter creationtime|updatetime] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
|
||||
# [oneitemperrow]
|
||||
# [countsonly] [formatjson [quotechar <Character>]]
|
||||
def doPrintCourseWork():
|
||||
doPrintCourseWM(Ent.COURSE_WORK_ID, Ent.COURSE_WORK_STATE)
|
||||
@@ -77912,6 +78126,7 @@ MAIN_ADD_CREATE_FUNCTIONS = {
|
||||
Cmd.ARG_VAULTEXPORT: doCreateVaultExport,
|
||||
Cmd.ARG_VAULTHOLD: doCreateVaultHold,
|
||||
Cmd.ARG_VAULTMATTER: doCreateVaultMatter,
|
||||
Cmd.ARG_VAULTQUERY: doCreateVaultQuery,
|
||||
Cmd.ARG_VERIFY: doCreateSiteVerification,
|
||||
}
|
||||
|
||||
@@ -77969,6 +78184,7 @@ MAIN_COMMANDS_WITH_OBJECTS = {
|
||||
{Cmd.ARG_SHAREDDRIVEACLS: doCopySyncSharedDriveACLs,
|
||||
Cmd.ARG_STORAGEBUCKET: doCopyCloudStorageBucket,
|
||||
Cmd.ARG_VAULTEXPORT: doCopyVaultExport,
|
||||
Cmd.ARG_VAULTQUERY: doCopyVaultQuery,
|
||||
}
|
||||
),
|
||||
'create':
|
||||
@@ -78033,6 +78249,7 @@ MAIN_COMMANDS_WITH_OBJECTS = {
|
||||
Cmd.ARG_VAULTEXPORT: doDeleteVaultExport,
|
||||
Cmd.ARG_VAULTHOLD: doDeleteVaultHold,
|
||||
Cmd.ARG_VAULTMATTER: doDeleteVaultMatter,
|
||||
Cmd.ARG_VAULTQUERY: doDeleteVaultQuery,
|
||||
}
|
||||
),
|
||||
'download':
|
||||
|
||||
@@ -69,6 +69,8 @@ CACHE_DISCOVERY_ONLY = 'cache_discovery_only'
|
||||
CHANNEL_CUSTOMER_ID = 'channel_customer_id'
|
||||
# Character set of batch, csv, data files
|
||||
CHARSET = 'charset'
|
||||
# When retrieving lists of Chat items from API, how many should be retrieved in each chunk
|
||||
CHAT_MAX_RESULTS = 'chat_max_results'
|
||||
# When retrieving lists of Google Classroom items from API, how many should be retrieved in each chunk
|
||||
CLASSROOM_MAX_RESULTS = 'classroom_max_results'
|
||||
# Path to client_secrets.json
|
||||
@@ -335,6 +337,7 @@ Defaults = {
|
||||
CACHE_DISCOVERY_ONLY: TRUE,
|
||||
CHARSET: DEFAULT_CHARSET,
|
||||
CHANNEL_CUSTOMER_ID: '',
|
||||
CHAT_MAX_RESULTS: '100',
|
||||
CLASSROOM_MAX_RESULTS: '0',
|
||||
CLIENT_SECRETS_JSON: FN_CLIENT_SECRETS_JSON,
|
||||
CLOCK_SKEW_IN_SECONDS: '10',
|
||||
@@ -502,6 +505,7 @@ VAR_INFO = {
|
||||
CACHE_DISCOVERY_ONLY: {VAR_TYPE: TYPE_BOOLEAN, VAR_SIGFILE: 'allcache.txt', VAR_SFFT: (TRUE, FALSE)},
|
||||
CHARSET: {VAR_TYPE: TYPE_STRING, VAR_ENVVAR: 'GAM_CHARSET', VAR_LIMITS: (1, None)},
|
||||
CHANNEL_CUSTOMER_ID: {VAR_TYPE: TYPE_STRING, VAR_LIMITS: (0, None)},
|
||||
CHAT_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 1000)},
|
||||
CLASSROOM_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (0, 1000)},
|
||||
CLIENT_SECRETS_JSON: {VAR_TYPE: TYPE_FILE, VAR_ENVVAR: 'CLIENTSECRETS', VAR_ACCESS: os.R_OK},
|
||||
CLOCK_SKEW_IN_SECONDS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (10, 3600)},
|
||||
|
||||
@@ -1216,6 +1216,7 @@ class GamCLArgs():
|
||||
OB_DOMAIN_NAME_LIST = 'DomainNameList'
|
||||
OB_DRIVE_FILE_ENTITY = 'DriveFileEntity'
|
||||
OB_DRIVE_FILE_ID = 'DriveFileID'
|
||||
OB_DRIVE_FILE_ID_LIST = 'DriveFileIDList'
|
||||
OB_DRIVE_FILE_NAME = 'DriveFileName'
|
||||
OB_DRIVE_FILE_PERMISSION_ENTITY = 'DriveFilePermissionEntity'
|
||||
OB_DRIVE_FILE_PERMISSION_ID = 'DriveFilePermissionID'
|
||||
|
||||
@@ -96,6 +96,7 @@ class GamEntity():
|
||||
CHAT_MEMBER_USER = 'chmu'
|
||||
CHAT_MESSAGE = 'chms'
|
||||
CHAT_MESSAGE_ID = 'chmi'
|
||||
CHAT_OWNER_USER = 'chou'
|
||||
CHAT_SPACE = 'chsp'
|
||||
CHAT_THREAD = 'chth'
|
||||
CHILD_ORGANIZATIONAL_UNIT = 'corg'
|
||||
@@ -462,6 +463,7 @@ class GamEntity():
|
||||
CHAT_MEMBER: ['Chat Members', 'Chat Member'],
|
||||
CHAT_MEMBER_GROUP: ['Chat Group Members', 'Chat Group Member'],
|
||||
CHAT_MEMBER_USER: ['Chat User Members', 'Chat User Member'],
|
||||
CHAT_OWNER_USER: ['Chat User Owners', 'Chat User Owner'],
|
||||
CHAT_SPACE: ['Chat Spaces', 'Chat Space'],
|
||||
CHAT_THREAD: ['Chat Threads', 'Chat Thread'],
|
||||
CHILD_ORGANIZATIONAL_UNIT: ['Child Organizational Units', 'Child Organizational Unit'],
|
||||
|
||||
@@ -462,6 +462,7 @@
|
||||
See: https://support.google.com/mail/answer/7190
|
||||
<QueryGroup> ::= <String>
|
||||
See: https://developers.google.com/admin-sdk/directory/v1/guides/search-groups
|
||||
<QueryItem> ::= <UniqueID>|<String>
|
||||
<QueryMemberRestrictions> ::= <String>
|
||||
See: https://cloud.google.com/identity/docs/reference/rest/v1beta1/SecuritySettings#MemberRestriction
|
||||
<QueryMobile> ::= <String>
|
||||
|
||||
@@ -10,9 +10,92 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
|
||||
|
||||
See [Downloads-Installs-GAM7](https://github.com/GAM-team/GAM/wiki/Downloads-Installs) for Windows or other options, including manual installation
|
||||
|
||||
### 7.22.01
|
||||
### 7.23.00
|
||||
|
||||
An update to the httplib2 library caused GAM proxy connections to fail; this has been fixed.
|
||||
Added `chat_max_results` variable to `gam.cfg`.
|
||||
```
|
||||
chat_max_results
|
||||
When retrieving lists of Chat items from API,
|
||||
how many should be retrieved in each API call
|
||||
Default: 100
|
||||
Range: 1 - 1000
|
||||
```
|
||||
Previously, this vaule was always set to 1000 which could cause errors.
|
||||
|
||||
### 7.22.07
|
||||
|
||||
Added options `showdetails` and `returnidonly` to `gam create|copy vaultquery`.
|
||||
|
||||
Added option `<JSONData>` to `gam create vaultexport|vaultquery and `gam print vaultcounts``.
|
||||
|
||||
### 7.22.06
|
||||
|
||||
Added commands to create, copy and delete Vault saved queries.
|
||||
```
|
||||
gam create vaultquery <MatterItem> [name <String>]
|
||||
corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
|
||||
[scope all_data|held_data|unprocessed_data]
|
||||
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
(documentids (<DriveFileIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
(shareddrives|teamdrives (<SharedDriveIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
[(includeshareddrives <Boolean>)|(shareddrivesoption included|included_if_account_is_not_a_member|not_included)]
|
||||
(sitesurl (<URLList>||(select <FileSelector>|<CSVFileSelector>)))
|
||||
[driveversiondate <Date>|<Time>]
|
||||
[includerooms <Boolean>]
|
||||
(rooms (<ChatSpaceList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
|
||||
[locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
|
||||
[responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
|
||||
(covereddata calllogs|textmessages|voicemails)*
|
||||
[shownames] [formatjson]
|
||||
|
||||
gam copy vaultquery <MatterItem> <QueryItem> [targetmatter <MatterItem"] [name <String>]
|
||||
[shownames] [formatjson]
|
||||
|
||||
gam delete vaultquery <QueryItem> matter <MatterItem>
|
||||
gam delete vaultquery <MatterItem> <QueryItem>
|
||||
```
|
||||
|
||||
Added a variant of `gam print vaultcounts` that gets its query parameters from a saved Vault query.
|
||||
```
|
||||
gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
matter <MatterItem> <QueryItem>
|
||||
[wait <Integer>]
|
||||
```
|
||||
|
||||
### 7.22.05
|
||||
|
||||
Added a variant of `gam create vaultexport` that gets its query parameters from a saved Vault query.
|
||||
|
||||
```
|
||||
gam create vaultexport|export matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[driveclientsideencryption any|encrypted|unencrypted]
|
||||
[includeaccessinfo <Boolean>]
|
||||
[excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
|
||||
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
[format ics|mbox|pst|xml]
|
||||
[region any|europe|us] [showdetails|returnidonly]
|
||||
```
|
||||
|
||||
### 7.22.04
|
||||
|
||||
Added a variant of `gam create vaulthold` that gets its parameters from a saved Vault query.
|
||||
```
|
||||
gam create vaulthold matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[showdetails|returnidonly]
|
||||
```
|
||||
|
||||
### 7.22.03
|
||||
|
||||
Fix backwards compatability bug introduced in 7.22.00 for `gam print users` that changed `suspended`
|
||||
from a field name to a query option; it is now correctly interpreted as a field name.
|
||||
|
||||
### 7.22.02
|
||||
|
||||
An update to the httplib2 library caused GAM proxy connections to fail; this has been fixed
|
||||
by including the pysocks library needed by the latest httplib2 library.
|
||||
|
||||
### 7.22.00
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ 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.22.01 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.23.00 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.7 64-bit final
|
||||
MacOS Sequoia 15.6.1 x86_64
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
<DomainNameList> ::= "<DomainName>(,<DomainName>)*"
|
||||
<DriveFileACLRoleList> ::= "<DriveFileACLRole>(,<DriveFileACLRole>)*"
|
||||
<DriveFileACLTypeList> ::= "<DriveFileACLType>(,<DriveFileACLType>)*"
|
||||
<DriveFileIDList> ::= "<DriveFileID>(,<DriveFileID>)*"
|
||||
<DriveFileList> ::= "<DriveFileItem>(,<DriveFileItem>)*"
|
||||
<DriveFilePermissionList> ::= "<DriveFilePermission>(,<DriveFilePermission>)*"
|
||||
<DriveFilePermissionIDList> ::= "<DriveFilePermissionID>(,<DriveFilePermissionID>)*"
|
||||
|
||||
@@ -378,7 +378,7 @@ Select the users for whom information is desired.
|
||||
* `showorgunit` - Add a column labelled `orgUnitPath` to the output; an additional API call is made to get the email addresses of the users in `<OrgUnitPath>`
|
||||
* `select <UserTypeEntity>` - A selected collection of users, e.g., `select group staff@domain.com`; there is one API call per user
|
||||
|
||||
By default, when `user all` is specified (or no user specification in supplied), GAM backs up looking for data with a (basically) random user. If the randaom
|
||||
By default, when `user all` is specified (or no user specification in supplied), GAM backs up looking for data with a (basically) random user. If the random
|
||||
doesn't have any data, the command reports that no data was found. Use `allverifyuser <UserItem>` to specify a specific user to use to search for data.
|
||||
|
||||
Specify the report date; the default is today's date.
|
||||
|
||||
@@ -570,17 +570,12 @@ gam config auto_batch_min 1 csv_output_row_filter "owners.0.emailAddress:notrege
|
||||
### Multiple parents
|
||||
No existing parents are copied for source top/sub files/folders.
|
||||
|
||||
### Removed options
|
||||
The following options will generate an error; they were removed in 6.23.00:
|
||||
* `copysubfileparents` and `copysubfolderparents`.
|
||||
|
||||
### Move Folder Permissions
|
||||
When a folder is moved by recreating it, its permissions are not copied; these options control copying permissions for folders.
|
||||
When a folder is moved by recreating it, its permissions are not copied by the Drive API; these options control copying permissions for folders.
|
||||
|
||||
For options of the form `option [<Boolean>]`; if `<Boolean>` is omitted, `true` is assumed.
|
||||
|
||||
When recreated, a target folder inherits the permissions of its parent folder; these options control whether/how GAM copies the existing source folder permissions;
|
||||
The default values of options introduced in version 6.14.00 are set to match the behavior of earlier versions.
|
||||
|
||||
When `mergewithparent` is `true`:
|
||||
* `copymergewithparentfolderpermissions false` - The permissions of the source top folder are not not copied to the target folder; this is the default action.
|
||||
@@ -594,7 +589,7 @@ When `duplicatefolders` is `merge` and a sub folder is a duplicate:
|
||||
* `copymergedsubfolderpermissions false` - The permissions of the source sub folder are not not copied to the target folder.
|
||||
* `copymergedsubfolderpermissions true` - The permissions of the source sub folder are copied to the target folder; this is the default action.
|
||||
|
||||
When `duplicatefolders` is `duplicatename` or `uniquename` and a top/sub folder is not a duplicate:
|
||||
When `duplicatefolders` is `merge` or `duplicatename` or `uniquename` and a top/sub folder is not a duplicate:
|
||||
* `copytopfolderpermissions true` - The permissions of the source top folder are copied to the target folder; this is the default action.
|
||||
* `copytopfolderpermissions false` - The permissions of the source top folder are not not copied to the target folder.
|
||||
* `copysubfolderpermissions true` - The permissions of the source sub folders are copied to the target folder; this is the default action.
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
```
|
||||
<DomainName> ::= <String>(.<String>)+
|
||||
<EmailAddress> ::= <String>@<DomainName>
|
||||
<JSONData> ::= (json [charset <Charset>] <String>) | (json file <FileName> [charset <Charset>]) |
|
||||
<UniqueID> ::= id:<String>
|
||||
<UserItem> ::= <EmailAddress>|<UniqueID>|<String>
|
||||
|
||||
@@ -424,12 +425,12 @@ gam config auto_batch_min 1 num_threads 20 redirect csv ./MyDriveShares.csv mult
|
||||
|
||||
Delete those My Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
Add My Drive ACLs with a different email address and the same role.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./AddMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" add drivefleacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
gam config num_threads 20 redirect stdout ./AddMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" add drivefileacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
```
|
||||
|
||||
### Shared Drives
|
||||
@@ -447,12 +448,12 @@ gam config num_threads 20 csv_input_row_filter "organizers:regex:^.+$" redirect
|
||||
|
||||
Delete those Shared Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
Add Shared Drive ACLs with a different email address and the same role.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./ReplaceSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" add drivefleacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
gam config num_threads 20 redirect stdout ./ReplaceSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" add drivefileacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
```
|
||||
|
||||
## Remove ACLs for all users-groups in external domains
|
||||
@@ -469,18 +470,22 @@ Replace `<Types>` as required:
|
||||
Replace `<Domains>` with specification of external domain(s)
|
||||
* `domain domain.com` - A single external domain
|
||||
* `domainlist domain1.com,domain2.com,domain3.com...` - A list of external domains
|
||||
|
||||
If you want domains other than your internal domain(s)
|
||||
* `notdomain domain.com` - A single internal domain
|
||||
* `notdomainlist domain1.com,domain2.com,domain3.com...` - A list of internal domains
|
||||
```
|
||||
gam config auto_batch_min 1 num_threads 20 redirect csv ./MyDriveShares.csv multiprocess redirect stderr - multiprocess all users print filelist fields id,name,mimetype,basicpermissions pm notrole owner <Types> <Domains> em pmfilter oneitemperrow
|
||||
```
|
||||
|
||||
Delete those My Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
Add My Drive ACLs with a different email address and the same role.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./AddMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" add drivefleacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
gam config num_threads 20 redirect stdout ./AddMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" add drivefileacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
```
|
||||
|
||||
### Shared Drives
|
||||
@@ -499,18 +504,22 @@ Replace `<Types>` as required:
|
||||
Replace `<Domains>` with specification of external domain(s)
|
||||
* `domain domain.com` - A single external domain
|
||||
* `domainlist domain1.com,domain2.com,domain3.com...` - A list of external domains
|
||||
|
||||
If you want domains other than your internal domain(s)
|
||||
* `notdomain domain.com` - A single internal domain
|
||||
* `notdomainlist domain1.com,domain2.com,domain3.com...` - A list of internal domains
|
||||
```
|
||||
gam config num_threads 20 csv_input_row_filter "organizers:regex:^.+$" redirect csv ./SharedDriveShares.csv multiprocess redirect stderr - multiprocess csv SharedDriveOrganizers.csv gam user "~organizers" print filelist select shareddriveid "~id" fields id,name,mimetype,basicpermissions,driveid showdrivename pm <Types> <Domains> inherited false em pmfilter oneitemperrow
|
||||
```
|
||||
|
||||
Delete those Shared Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
Add Shared Drive ACLs with a different email address and the same role.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./ReplaceSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" add drivefleacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
gam config num_threads 20 redirect stdout ./ReplaceSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" add drivefileacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
```
|
||||
|
||||
## Remove domainCanFind-domainWithLink ACLs for internal domain
|
||||
@@ -529,7 +538,7 @@ gam config auto_batch_min 1 num_threads 20 redirect csv ./MyDriveShares.csv mult
|
||||
|
||||
Delete those My Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
### Shared Drives
|
||||
@@ -546,7 +555,7 @@ gam config num_threads 20 csv_input_row_filter "organizers:regex:^.+$" redirect
|
||||
|
||||
Delete those Shared Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
## Remove My Drive ACLs for external domains
|
||||
@@ -558,13 +567,17 @@ Get My Drive ACLs sharing to external domain(s)
|
||||
Replace `<Domains>` with specification of external domain(s)
|
||||
* `domain domain.com` - A single external domain
|
||||
* `domainlist domain1.com,domain2.com,domain3.com...` - A list of external domains
|
||||
|
||||
If you want domains other than your internal domain(s)
|
||||
* `notdomain domain.com` - A single internal domain
|
||||
* `notdomainlist domain1.com,domain2.com,domain3.com...` - A list of internal domains
|
||||
```
|
||||
gam config auto_batch_min 1 num_threads 20 redirect csv ./MyDriveShares.csv multiprocess redirect stderr - multiprocess all users print filelist fields id,name,mimetype,basicpermissions pm type domain <Domains> em pmfilter oneitemperrow
|
||||
```
|
||||
|
||||
Delete those My Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
## Remove anyoneCanFind-anyoneWithLink ACLs
|
||||
@@ -583,7 +596,7 @@ gam config auto_batch_min 1 num_threads 20 redirect csv ./MyDriveShares.csv mult
|
||||
|
||||
Delete those My Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
### Shared Drives
|
||||
@@ -599,5 +612,5 @@ gam config num_threads 20 csv_input_row_filter "organizers:regex:^.+$" redirect
|
||||
|
||||
Delete those Shared Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
- [Query documentation](#query-documentation)
|
||||
- [Python Regular Expressions](Python-Regular-Expressions) Match function
|
||||
- [Definitions](#definitions)
|
||||
- [Special quoting](#special-quoting)
|
||||
- [Vault Matters](#vault-matters)
|
||||
- [Create Vault Matters](#create-vault-matters)
|
||||
- [Manage Vault Matters](#manage-vault-matters)
|
||||
@@ -21,6 +22,9 @@
|
||||
- [Display Vault Holds](#display-vault-holds)
|
||||
- [Display Vault Holds Affecting a User](#display-vault-holds-affecting-a-user)
|
||||
- [Vault Saved Queries](#vault-saved-queries)
|
||||
- [Create Vault Saved Queries](#create-vault-saved-queries)
|
||||
- [Copy Vault Saved Queries](#copy-vault-saved-queries)
|
||||
- [Delete Vault Saved Queries](#delete-vault-saved-queries)
|
||||
- [Display Vault Saved Queries](#display-vault-saved-queries)
|
||||
- [Takeout](#takeout)
|
||||
- [Copy a Takeout Bucket](#copy-a-takeoutbucket)
|
||||
@@ -54,6 +58,7 @@
|
||||
<EmailAddressList> ::= "<EmailAddess>(,<EmailAddress>)*"
|
||||
<EmailAddressEntity> ::= <EmailAddressList> | <FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVDataSelector>
|
||||
See: https://github.com/GAM-team/GAM/wiki/Collections-of-Items
|
||||
<JSONData> ::= (json [charset <Charset>] <String>) | (json file <FileName> [charset <Charset>]) |
|
||||
<TimeZone> ::= <String>
|
||||
See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||
<UniqueID> ::= id:<String>
|
||||
@@ -66,13 +71,17 @@
|
||||
|
||||
<ChatSpace> ::= spaces/<String> | space/<String> | <String>
|
||||
<ChatSpaceList> ::= "<ChatSpace>(,<ChatSpace>)*"
|
||||
<DriveFileID> ::= <String>
|
||||
<DriveFileIDList> ::= "<DriveFileID>(,<DriveFileID>)*"
|
||||
<ExportItem> ::= <UniqueID>|<String>
|
||||
<ExportStatus> ::= completed|failed|inprogrsss
|
||||
<ExportStatusList> ::= "<ExportStatus>(,<ExportStatus>)*"
|
||||
<HoldItem> ::= <UniqueID>|<String>
|
||||
<MatterItem> ::= <UniqueID>|<String>
|
||||
<MatterItemList> ::= "<MatterItem>(,<MatterItem>)*"
|
||||
<MatterState> ::= open|closed|deleted
|
||||
<MatterStateList> ::= "<MatterState>(,<MatterState>)*"
|
||||
<QueryItem> ::= <UniqueID>|<String>
|
||||
<SharedDriveID> ::= <String>
|
||||
<SharedDriveIDList> ::= "<SharedDriveID>(,<SharedDriveID>)*"
|
||||
<URL> ::= <String>
|
||||
@@ -135,9 +144,29 @@
|
||||
<VaultQueryFieldNameList> ::= "<VaultQueryFieldName>(,<VaultQueryFieldName>)*"
|
||||
|
||||
```
|
||||
|
||||
You specify matters, exports and holds by ID (`<UniqueID>`) or name (`<String>`). The API requires an ID, so if you specify a name,
|
||||
GAM has to make additional API calls to convert the name to an ID.
|
||||
|
||||
## Special quoting
|
||||
You specify a single matter with `matter <MatterItem>` and a list of matters with `matters <MatterItemList>`.
|
||||
|
||||
As matter names can contain spaces, some care must be used when entering `<MatterItem>` and `<MatterItemList>` with names.
|
||||
|
||||
Suppose you have a matter `Foo Bar`. To get information about a specific export: `gam info vaultexport "Foo Bar" <ExportItem>`
|
||||
|
||||
The shell strips the `"` leaving a single argument `Foo Bar`; gam correctly processes the argument.
|
||||
|
||||
Suppose you enter the command: `gam show vaultexports matters "Foo Bar"`
|
||||
|
||||
The shell strips the `"` leaving a single argument `Foo Bar`; gam splits the argument on space leaving two items and then tries to process `Foo` and `Bar`, not what you want.
|
||||
|
||||
You must enter: `gam info show vaultexports matters "'Foo Bar'"`
|
||||
|
||||
The shell strips the `"` leaving a single argument `'Foo Bar'`; gam splits the argument on space while honoring the `'` leaving one item `Foo Bar` and correctly processes the item.
|
||||
|
||||
For quoting rules, see: [List Quoting Rules](Command-Line-Parsing)
|
||||
|
||||
## Vault Matters
|
||||
## Create Vault Matters
|
||||
Create a Google Vault matter.
|
||||
@@ -201,11 +230,18 @@ Select fields to display:
|
||||
* `fields <VaultMatterFieldNameList>` - Display selected fields; `matterId` and `name` are always displayed
|
||||
|
||||
## Display Vault Counts
|
||||
Display item counts retained in Vault for the given users or groups.
|
||||
### Display item counts retained in Vault using a saved Vault query.
|
||||
```
|
||||
gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
matter <MatterItem> <QueryItem>
|
||||
[wait <Integer>]
|
||||
```
|
||||
|
||||
### Display item counts retained in Vault for the given users or groups.
|
||||
* The required argument `matter` specifies the matter name or ID (prefix with id:) where the count should be performed.
|
||||
* The required argument `corpus` specifies whether Gmail mailbox data or Google Groups archives are queried.
|
||||
* You need to specify one argument of accounts, orgunit or everyone to determine which users/groups to query.
|
||||
* The `scope` argument specifies the data to be queried, `all_data` is the default and is recommended.
|
||||
* You need to specify one argument of accounts, orgunit or everyone to determine which users/groups to query.
|
||||
|
||||
The command may take some time to complete; GAM makes repeated API calls until the operation is complete. By default,
|
||||
GAM waits 15 seconds between API calls; use the `wait <Integer>` option to specify a different wait period.
|
||||
@@ -213,26 +249,28 @@ GAM waits 15 seconds between API calls; use the `wait <Integer>` option to speci
|
||||
This command can be useful for discovering legacy former employee accounts which no longer have any mail data retained by Vault.
|
||||
```
|
||||
gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
matter <MatterItem> corpus mail|groups
|
||||
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
[(shareddrives|teamdrives (<TeamDriveIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
(rooms (<ChatSpaceList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
(sitesurl (<URLList>||(select <FileSelector>|<CSVFileSelector>)))]
|
||||
[scope <all_data|held_data|unprocessed_data>]
|
||||
matter <MatterItem>
|
||||
corpus mail|groups
|
||||
[scope all_data|held_data|unprocessed_data]
|
||||
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone|entireorg
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
|
||||
[excludedrafts <Boolean>]
|
||||
[<JSONData>]
|
||||
[wait <Integer>]
|
||||
```
|
||||
Specify the search method, this is optional:
|
||||
* `accounts <EmailAddressEntity>` - Search all accounts specified in `<EmailAddressEntity>`
|
||||
* `orgunit|org|ou <OrgUnitPath>` - Search all accounts in the OU `<OrgUnitPath>`
|
||||
* `everyone` - Search for all accounts in the organization
|
||||
* `shareddrives|teamdrives <SharedDriveIDList>` - Search for all accounts in the Shared Drives specified in `<SharedDriveIDList>`
|
||||
* `shareddrives|teamdrives select <FileSelector>|<CSVFileSelector>` - Search for all accounts in the Shared Drives specified in `<FileSelector>|<CSVFileSelector>`
|
||||
* `rooms <ChatSpaceList>` - Search in the Room specified in the chat rooms specified in `<ChatSpaceList>`
|
||||
* `rooms <ChatSpaceList>` - Search in the Room specified in the chat rooms specified in `<FileSelector>|<CSVFileSelector>`
|
||||
* `sitesurl <URLList>` - Search the published site URLs of new Google Sites in `<URLList>`
|
||||
* `sitesurl <URLList>` - Search the published site URLs of new Google Sites specified in `<FileSelector>|<CSVFileSelector>`
|
||||
* `everyone|entireorg` - Search for all accounts in the organization
|
||||
|
||||
For `corpus mail|group`, you can specify search terms to limit the search.
|
||||
* `terms <String>` - [Vault search](https://support.google.com/vault/answer/2474474)
|
||||
|
||||
For `corpus mail|group`, you can specify time limits on the search:
|
||||
* `start|starttime <Date>|<Time>` - The start time range for the search query. These timestamps are in GMT and rounded down to the start of the given date.
|
||||
* `end|endtime <Date>|<Time>` - The end time range for the search query. These timestamps are in GMT and rounded down to the start of the given date.
|
||||
|
||||
You can specify query options with `<JSONData>`.
|
||||
|
||||
Check the status of a previous count operation with the name from a previous command.
|
||||
```
|
||||
@@ -242,32 +280,48 @@ gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
|
||||
## Vault Exports
|
||||
## Create Vault Exports
|
||||
Create a Google Vault export request.
|
||||
### Create a Google Vault export request using a saved Vault query.
|
||||
```
|
||||
gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
|
||||
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
(shareddrives|teamdrives (<TeamDriveIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
(rooms (<ChatSpaceList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
(sitesurl (<URLList>||(select <FileSelector>|<CSVFileSelector>)))
|
||||
gam create vaultexport|export matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[driveclientsideencryption any|encrypted|unencrypted]
|
||||
[includeaccessinfo <Boolean>]
|
||||
[excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
|
||||
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
[format ics|mbox|pst|xml]
|
||||
[region any|europe|us] [showdetails|returnidonly]
|
||||
```
|
||||
|
||||
Create a Google Vault export request by specifying the query parameters.
|
||||
```
|
||||
gam create vaultexport|export matter <MatterItem> [name <String>]
|
||||
corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
|
||||
[scope all_data|held_data|unprocessed_data]
|
||||
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
(documentids (<DriveFileIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
(shareddrives|teamdrives (<SharedDriveIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
[(includeshareddrives <Boolean>)|(shareddrivesoption included|included_if_account_is_not_a_member|not_included)]
|
||||
(sitesurl (<URLList>||(select <FileSelector>|<CSVFileSelector>)))
|
||||
[driveversiondate <Date>|<Time>]
|
||||
[includerooms <Boolean>]
|
||||
(rooms (<ChatSpaceList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
|
||||
[locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
|
||||
[responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
|
||||
[(includeshareddrives <Boolean>)|(shareddrivesoption included|included_if_account_is_not_a_member|not_included)]
|
||||
[driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
|
||||
(covereddata calllogs|textmessages|voicemails)*
|
||||
[<JSONData>]
|
||||
[driveclientsideencryption any|encrypted|unencrypted]
|
||||
[includerooms <Boolean>]
|
||||
[includeaccessinfo <Boolean>]
|
||||
[excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
|
||||
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
[covereddata calllogs|textmessages|voicemails]
|
||||
[format ics|mbox|pst|xml]
|
||||
[region any|europe|us] [showdetails|returnidonly]
|
||||
```
|
||||
<MatterItem> specifies the matter name or ID the export should be associated with.
|
||||
|
||||
Specify the name of the export:
|
||||
* `name <String>` - The export will be named `<String>`
|
||||
* `default` - The export will be named `GAM <corpus> Export - <Time>`
|
||||
If `name <String>` is omitted, the export will be named `GAM <corpus> Export - <Time>`
|
||||
|
||||
## Vault Query options
|
||||
|
||||
Specify the corpus of data, this option is required:
|
||||
* `calendar`
|
||||
@@ -281,13 +335,15 @@ Specify the corpus of data, this option is required:
|
||||
Specify the search method, this option is required:
|
||||
* `accounts <EmailAddressEntity>` - Search all accounts specified in `<EmailAddressEntity>`
|
||||
* `orgunit|org|ou <OrgUnitPath>` - Search all accounts in the OU `<OrgUnitPath>`
|
||||
* `everyone` - Search for all accounts in the organization
|
||||
* `everyone|entireorg` - Search for all accounts in the organization
|
||||
* `documentids <DriveFileIDList>` - Search for all drive files specified in `<DriveFileIDList>`
|
||||
* `documentids select <FileSelector>|<CSVFileSelector>` - Search for all drive files specified in `<FileSelector>|<CSVFileSelector>`
|
||||
* `shareddrives|teamdrives <SharedDriveIDList>` - Search for all accounts in the Shared Drives specified in `<SharedDriveIDList>`
|
||||
* `shareddrives|teamdrives select <FileSelector>|<CSVFileSelector>` - Search for all accounts in the Shared Drives specified in `<FileSelector>|<CSVFileSelector>`
|
||||
* `rooms <ChatSpaceList>` - Search in the Room specified in the chat rooms specified in `<ChatSpaceList>`
|
||||
* `rooms <ChatSpaceList>` - Search in the Room specified in the chat rooms specified in `<FileSelector>|<CSVFileSelector>`
|
||||
* `sitesurl <URLList>` - Search the published site URLs of new Google Sites in `<URLList>`
|
||||
* `sitesurl <URLList>` - Search the published site URLs of new Google Sites specified in `<FileSelector>|<CSVFileSelector>`
|
||||
* `rooms <ChatSpaceList>` - Search in the Room specified in the chat rooms specified in `<ChatSpaceList>`
|
||||
* `rooms <ChatSpaceList>` - Search in the Room specified in the chat rooms specified in `<FileSelector>|<CSVFileSelector>`
|
||||
|
||||
Specify the scope of data to include in the export:
|
||||
* `all_data` - All available data; this is the default
|
||||
@@ -320,10 +376,6 @@ For `corpus calendar`, you can specify advanced search options:
|
||||
* Search the current version of the Calendar event, but export the contents of the last version saved before 12:00 AM UTC on the specified date.
|
||||
* Enter the date in UTC.
|
||||
|
||||
For `corpus calendar`, you can specify the format of the exported data:
|
||||
* `format ics` - Export in ICS format, this is the default
|
||||
* `format pst` - Export in PST format
|
||||
|
||||
For `corpus drive`, you can specify advanced search options:
|
||||
* `driveversiondate <Date>|<Time>` - Search the versions of the Drive file as of the reference date. These timestamps are in GMT and rounded down to the given date.
|
||||
* `includeshareddrives False` - Mapped to `sharedrivesoption included_if_account_is_not_a_member`
|
||||
@@ -331,6 +383,16 @@ For `corpus drive`, you can specify advanced search options:
|
||||
* `sharedrivesoption included` - Resources in shared drives are included in the search
|
||||
* `sharedrivesoption included_if_account_is_not_a_member` - Resources in shared drives where account is not a member are included in the search, this is the default
|
||||
* `sharedrivesoption not_included` - Resources in shared drives are not included in the search
|
||||
|
||||
For `corpus hangouts_chat` you can specify advanced search options:
|
||||
* `includerooms False` - Do not include rooms, this is the default
|
||||
* `includerooms True` - Include rooms
|
||||
|
||||
You can specify query options with `<JSONData>`.
|
||||
|
||||
## Vault Export options
|
||||
|
||||
For `corpus drive`, you can specify advanced search options:
|
||||
* `driveclientsideencryption any` - Include both client-side encrypted and unencrypted content in search, this is the default.
|
||||
* `driveclientsideencryption encrypted` - Include client-side encrypted content only in search.
|
||||
* `driveclientsideencryption unencrypted` - Include client-side unencrypted content only in search.
|
||||
@@ -339,10 +401,6 @@ For `corpus drive`, you can specify whether to include access information for us
|
||||
* `includeaccessinfo False` - Do not include access information for users with indirect access, this is the default
|
||||
* `includeaccessinfo True` - Include access information for users with indirect access
|
||||
|
||||
For `corpus hangouts_chat` you can specify advanced search options:
|
||||
* `includerooms False` - Do not include rooms, this is the default
|
||||
* `includerooms True` - Include rooms
|
||||
|
||||
For `corpus mail`, you can specify advanced search options:
|
||||
* `excludedrafts False` - Do not exclude drafts, this is the default
|
||||
* `excludedrafts True` - Exclude drafts
|
||||
@@ -365,18 +423,18 @@ For `corpus mail`, you can specify whether to enable exporting linked Drive file
|
||||
See: https://support.google.com/vault/answer/4388708#new_gmail_export&zippy=%2Cfebruary-new-gmail-export-system-available
|
||||
|
||||
For `corpus calendar`, you can specify the format of the exported data:
|
||||
* `format ics - Export in ICS format, this is the default
|
||||
* `format ics` - Export in ICS format, this is the default
|
||||
* `format pst` - Export in PST format
|
||||
|
||||
For `corpus drive`, you can not specify the format of the exported data,
|
||||
|
||||
For `corpus gemini`, `format xml` is the only format of the exported data,
|
||||
For `corpus gemini`, `format xml` is the only supported format of the exported data,
|
||||
|
||||
For `corpus groups`, `corpus hangouts_chat`, `corpus mail` and `corpus voice`, you can specify the format of the exported data:
|
||||
* `format mbox` - Export in MBOX format, this is the default
|
||||
* `format pst` - Export in PST format
|
||||
|
||||
For `corpus voice` you can specify thet data covered by the export:
|
||||
For `corpus voice` you can specify the data covered by the export, multiple values are allowed.:
|
||||
* `covereddata calllogs` - Call logs
|
||||
* `covereddata textmessages` - Voice text messages
|
||||
* `covereddata voicemail` - Voicemail
|
||||
@@ -606,13 +664,29 @@ The `shownames` argument controls whether account and org unit names are display
|
||||
|
||||
## Vault Holds
|
||||
## Create Vault Holds
|
||||
### Create a hold from a saved Vault query.
|
||||
```
|
||||
gam create vaulthold|hold matter <MatterItem> [name <String>] corpus calendar|drive|mail|groups|hangouts_chat|voice
|
||||
gam create vaulthold|hold matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[showdetails|returnidonly]
|
||||
```
|
||||
Specify the name of the hold:
|
||||
* `name <String>` - The hold will be named `<String>`
|
||||
* `default` - The hold will be named `GAM <corpus> Hold - <Time>`
|
||||
|
||||
Use the `showdetails` option to have the full details of the hold displayed.
|
||||
|
||||
Use the `returnidonly` option to have only the hold ID displayed.
|
||||
|
||||
### Create a hold from parameters.
|
||||
```
|
||||
gam create vaulthold|hold matter <MatterItem> [name <String>]
|
||||
corpus calendar|drive|mail|groups|hangouts_chat|voice
|
||||
[(accounts|groups|users <EmailItemList>) | (orgunit|org|ou <OrgUnit>)]
|
||||
[query <QueryVaultCorpus>]
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
|
||||
[includerooms <Boolean>]
|
||||
[covereddata calllogs|textmessages|voicemails]
|
||||
(covereddata calllogs|textmessages|voicemails)*
|
||||
[includeshareddrives <Boolean>]
|
||||
[showdetails|returnidonly]
|
||||
```
|
||||
@@ -638,10 +712,10 @@ For `corpus drive`, you can specify advanced search options:
|
||||
* `includeshareddrives False` - Files in shared drives are not included in the hold, this is the default
|
||||
* `includeshareddrives True` - Files in shared drives are included in the hold
|
||||
|
||||
For `corpus mail`, you can specify search terms to limit the search.
|
||||
For `corpus mail|group`, you can specify search terms to limit the search.
|
||||
* `terms <String>` - [Vault search](https://support.google.com/vault/answer/2474474)
|
||||
|
||||
For `corpus mail`, you can specify time limits on the search:
|
||||
For `corpus mail|group`, you can specify time limits on the search:
|
||||
* `start|starttime <Date>|<Time>` - The start time range for the search query. These timestamps are in GMT and rounded down to the start of the given date.
|
||||
* `end|endtime <Date>|<Time>` - The end time range for the search query. These timestamps are in GMT and rounded down to the start of the given date.
|
||||
|
||||
@@ -649,7 +723,8 @@ For `corpus hangouts_chat` you can specify advanced search options:
|
||||
* `includerooms False` - Do not include rooms, this is the default
|
||||
* `includerooms True` - Include rooms
|
||||
|
||||
For `corpus voice` you can specify the data covered by the hold:
|
||||
For `corpus voice` you can specify the data covered by the hold,
|
||||
multiple values are allowed.:
|
||||
* `covereddata calllogs` - Call logs
|
||||
* `covereddata textmessages` - Voice text messages
|
||||
* `covereddata voicemail` - Voicemail
|
||||
@@ -665,7 +740,7 @@ gam update vaulthold|hold <HoldItem> matter <MatterItem>
|
||||
[query <QueryVaultCorpus>]
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
|
||||
[includerooms <Boolean>]
|
||||
[covereddata calllogs|textmessages|voicemails]
|
||||
(covereddata calllogs|textmessages|voicemails)*
|
||||
[includeshareddrives <Boolean>]
|
||||
[showdetails]
|
||||
```
|
||||
@@ -673,10 +748,10 @@ For a hold with `corpus drive`, you can specify advanced search options:
|
||||
* `includeshareddrives False` - Files in shared drives are not included in the hold, this is the default
|
||||
* `includeshareddrives True` - Files in shared drives are included in the hold
|
||||
|
||||
For a hold with `corpus mail`, you can specify search terms to limit the search.
|
||||
For a hold with `corpus mail|groups`, you can specify search terms to limit the search.
|
||||
* `terms <String>` - [Vault search](https://support.google.com/vault/answer/2474474)
|
||||
|
||||
For a hold with `corpus mail`, you can specify time limits on the search:
|
||||
For a hold with `corpus mai|groupsl`, you can specify time limits on the search:
|
||||
* `start|starttime <Date>|<Time>` - The start time range for the search query. These timestamps are in GMT and rounded down to the start of the given date.
|
||||
* `end|endtime <Date>|<Time>` - The end time range for the search query. These timestamps are in GMT and rounded down to the start of the given date.
|
||||
|
||||
@@ -684,7 +759,8 @@ For a hold with `corpus hangouts_chat` you can specify advanced search options:
|
||||
* `includerooms False` - Do not include rooms, this is the default
|
||||
* `includerooms True` - Include rooms
|
||||
|
||||
For a hold with `corpus voice` you can specify the data covered by the hold:
|
||||
For a hold with `corpus voice` you can specify the data covered by the hold,
|
||||
multiple values are allowed.:
|
||||
* `covereddata calllogs` - Call logs
|
||||
* `covereddata textmessages` - Voice text messages
|
||||
* `covereddata voicemail` - Voicemail
|
||||
@@ -752,6 +828,67 @@ gam <UserTypeEntity> show vaultholds|holds
|
||||
```
|
||||
|
||||
## Vault Saved Queries
|
||||
## Create Vault Saved Queries
|
||||
```
|
||||
gam create vaultquery <MatterItem> [name <String>]
|
||||
corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
|
||||
[scope all_data|held_data|unprocessed_data]
|
||||
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
(documentids (<DriveFileIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
(shareddrives|teamdrives (<SharedDriveIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
[(includeshareddrives <Boolean>)|(shareddrivesoption included|included_if_account_is_not_a_member|not_included)]
|
||||
(sitesurl (<URLList>||(select <FileSelector>|<CSVFileSelector>)))
|
||||
[driveversiondate <Date>|<Time>]
|
||||
[includerooms <Boolean>]
|
||||
(rooms (<ChatSpaceList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
|
||||
[locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
|
||||
[responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
|
||||
(covereddata calllogs|textmessages|voicemails)*
|
||||
[<JSONData>]
|
||||
[shownames]
|
||||
[showdetails|returnidonly|formatjson]
|
||||
``
|
||||
|
||||
If `name <String>` is omitted, the query is named `GAM <corpus> Query - <Time>`
|
||||
|
||||
The `shownames` argument controls whether org unit and shared drive names are displayed in queries; additional API calls are required to get the names.
|
||||
|
||||
See: [Vault Query options](#vault-query-options)
|
||||
|
||||
Use the `showdetails` option to have the full details of the saved query displayed.
|
||||
|
||||
Use the `returnidonly` option to have only the saved query ID displayed.
|
||||
|
||||
Use the `formatjson` option to have only the saved query JSON displayed.
|
||||
|
||||
## Copy Vault Saved Queries
|
||||
```
|
||||
gam copy vaultquery <MatterItem> <QueryItem> [targetmatter <MatterItem>] [name <String>]
|
||||
[shownames]
|
||||
[showdetails|returnidonly|formatjson]
|
||||
```
|
||||
|
||||
If `targetmatter <MatterItem>` is omitted, the query is copied in the source matter.
|
||||
|
||||
If `name <String>` is omitted:
|
||||
* `targetmatter <MatterItem>` specified - The copied query has the same name as the source query
|
||||
* `targetmatter <MatterItem>` omitted - The copied query is named `Copy of Source Query name`
|
||||
|
||||
The `shownames` argument controls whether org unit and shared drive names are displayed in queries; additional API calls are required to get the names.
|
||||
|
||||
Use the `showdetails` option to have the full details of the saved query displayed.
|
||||
|
||||
Use the `returnidonly` option to have only the saved query ID displayed.
|
||||
|
||||
Use the `formatjson` option to have only the saved query JSON displayed.
|
||||
|
||||
## Delete Vault Saved Queries
|
||||
```
|
||||
gam delete vaultquery <QueryItem> matter <MatterItem>
|
||||
gam delete vaultquery <MatterItem> <QueryItem>
|
||||
```
|
||||
|
||||
## Display Vault Saved Queries
|
||||
```
|
||||
gam info vaultquery <QueryItem> matter <MatterItem>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Print the current version of Gam with details
|
||||
```
|
||||
gam version
|
||||
GAM 7.22.01 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.23.00 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.7 64-bit final
|
||||
macOS Sequoia 15.7 x86_64
|
||||
@@ -15,7 +15,7 @@ Time: 2023-06-02T21:10:00-07:00
|
||||
Print the current version of Gam with details and time offset information
|
||||
```
|
||||
gam version timeoffset
|
||||
GAM 7.22.01 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.23.00 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.7 64-bit final
|
||||
macOS Sequoia 15.7 x86_64
|
||||
@@ -27,7 +27,7 @@ Your system time differs from www.googleapis.com by less than 1 second
|
||||
Print the current version of Gam with extended details and SSL information
|
||||
```
|
||||
gam version extended
|
||||
GAM 7.22.01 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.23.00 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.7 64-bit final
|
||||
macOS Sequoia 15.7 x86_64
|
||||
|
||||
@@ -180,29 +180,3 @@ Service Account Access
|
||||
* [Users - Tasks](Users-Tasks)
|
||||
* [Users - YouTube](Users-YouTube)
|
||||
* [Users - Web Resources and Sites](Users-Web-Resources-and-Sites)
|
||||
|
||||
GAM Tutorials
|
||||
* [Account Auditing](l-ExamplesAccountAuditing)
|
||||
* [Calendar Settings](l-CalendarExamples)
|
||||
* [Chat Bot commands](Chat-Bot)
|
||||
* [Chrome Browser Management](l-Chrome-Browser-Management)
|
||||
* [Chrome Policy Settings](l-Chrome-Policy-Settings)
|
||||
* [Context Aware Access levels](Context-Aware-Access-Levels)
|
||||
* [Data Transfers](l-Data-Transfers)
|
||||
* [Domain Verification](l-DomainVerification)
|
||||
* [Google Drive Management](l-GoogleDriveManagement)
|
||||
* [Group Settings](l-GAM3GroupSettings)
|
||||
* [Inbound SSO Settings](l-Inbound-SSO-Settings)
|
||||
* [Managing Admins](l-Managing-Admins)
|
||||
* [Managing Classroom](l-Managing-Google-Classroom)
|
||||
* [Managing Custom User Schemas](l-Custom-Schemas)
|
||||
* [Managing Devices](l-Managing-Devices)
|
||||
* [Managing Organizations](l-ExamplesOrganizations)
|
||||
* [Managing Product Licenses](l-LicenseExamples)
|
||||
* [Managing Users, Groups, Aliases, Domains, Mobile and Chrome Devices, and Resource Calendars](l-GAM3DirectoryCommands)
|
||||
* [OAuth Authentication Related Commands](l-OAuthKeyManagement)
|
||||
* [Print Users, Groups, Aliases, Mobile and Chrome OS devices, OUs, Licenses and Reports](l-GAM3CSVListings)
|
||||
* [Printers](l-Printers)
|
||||
* [Unmanaged Users and Invitations](l-UnmanagedUsersExamples)
|
||||
* [User Email Settings](l-ExamplesEmailSettings)
|
||||
* [User Security Settings](l-SecurityExamples)
|
||||
|
||||
@@ -109,6 +109,11 @@ charset
|
||||
Character set of gam batch, gam csv, gam loop files.
|
||||
Default: utf-8
|
||||
Environment variable: GAM_CHARSET
|
||||
chat_max_results
|
||||
When retrieving lists of Chat items from API,
|
||||
how many should be retrieved in each API call
|
||||
Default: 100
|
||||
Range: 1 - 1000
|
||||
classroom_max_results
|
||||
When retrieving lists of Google Classroom items from API,
|
||||
how many should be retrieved in each API call
|
||||
|
||||
Reference in New Issue
Block a user