Handle issues in update alias/message

This commit is contained in:
Ross Scroggs
2023-12-19 20:04:06 -08:00
parent 80fc40a9c7
commit f89f730957
8 changed files with 139 additions and 62 deletions

View File

@@ -55,13 +55,18 @@ gam create alias bob[@yourdomain.com] user robert[@yourdomain.com]
The existing alias is deleted and a new alias is created. The existing alias is deleted and a new alias is created.
``` ```
gam update alias|aliases <EmailAddressEntity> user|group|target <UniqueID>|<EmailAddress> gam update alias|aliases <EmailAddressEntity> user|group|target <UniqueID>|<EmailAddress>
[notargetverify] [notargetverify] [waitafterdelete <Integer>]
``` ```
`<EmailAddressEntity>` are the aliases, `<EmailAddress>` is the target. `<EmailAddressEntity>` are the aliases, `<EmailAddress>` is the target.
By default, GAM makes additional API calls to verify that the target email address exists before updating the alias; By default, GAM makes additional API calls to verify that the target email address exists before updating the alias;
if you know that the target exists, you can suppress the verification with `notargetverify. if you know that the target exists, you can suppress the verification with `notargetverify.
GAM updates an alias to point to a new target by deleting the alias and then recreates the alias pointing to the new target.
Unfortunately, if these commands are executed back-to-back; Google generates the `Update Failed: Duplicate` error.
Now, GAM waits 2 seconds between the delete and the insert which seems to eliminate the problem. If the problem persists,
use the option `waitafterdelete <Integer>` to increase the wait time to a maximum of 10 seconds.
## Delete an alias regardless of the target ## Delete an alias regardless of the target
``` ```
gam delete alias|aliases [user|group|target] <EmailAddressEntity> gam delete alias|aliases [user|group|target] <EmailAddressEntity>

View File

@@ -10,6 +10,25 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
See [Downloads](https://github.com/taers232c/GAMADV-XTD3/wiki/Downloads) for Windows or other options, including manual installation See [Downloads](https://github.com/taers232c/GAMADV-XTD3/wiki/Downloads) for Windows or other options, including manual installation
### 6.66.14
Updated `gam <UserTypeEntity> modify messages` to recognize the following error:
```
ERROR: 400: invalid - Invalid label: SENT
```
Updated `gam update alias <EmailAddressEntity> user|group|target <EmailAddress>`
to avoid the following problem.
```
$ gam update alias testalias@domain.com user testuser
User Alias: testalias@domain.com, Deleted
User Alias: testalias@domain.com, User: testuser@domain.com, Update Failed: Duplicate, Email Address: testalias@domain.com
```
GAM updates an alias to point to a new target by deleting the alias and then recreating the alias pointing to the new target.
Unfortunately, if these commands are executed back-to-back; Google generates the `Update Failed: Duplicate` error.
Now, GAM waits 2 seconds between the delete and the insert which seems to eliminate the problem. If the problem persists,
the option `waitafterdelete <Integer>` can be used to increase the wait time to a maximum of 10 seconds.
### 6.66.13 ### 6.66.13
Updated functionality of option `preservefiletimes` in `gam <UserTypeEntity> update drivefile <DriveFileEntity>`. Updated functionality of option `preservefiletimes` in `gam <UserTypeEntity> update drivefile <DriveFileEntity>`.

View File

@@ -334,7 +334,7 @@ writes the credentials into the file oauth2.txt.
admin@server:/Users/admin/bin/gamadv-xtd3$ rm -f /Users/admin/GAMConfig/oauth2.txt admin@server:/Users/admin/bin/gamadv-xtd3$ rm -f /Users/admin/GAMConfig/oauth2.txt
admin@server:/Users/admin/bin/gamadv-xtd3$ ./gam version admin@server:/Users/admin/bin/gamadv-xtd3$ ./gam version
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
GAMADV-XTD3 6.66.13 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource GAMADV-XTD3 6.66.14 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com> Ross Scroggs <ross.scroggs@gmail.com>
Python 3.10.8 64-bit final Python 3.10.8 64-bit final
MacOS High Sierra 10.13.6 x86_64 MacOS High Sierra 10.13.6 x86_64
@@ -1002,7 +1002,7 @@ writes the credentials into the file oauth2.txt.
C:\GAMADV-XTD3>del C:\GAMConfig\oauth2.txt C:\GAMADV-XTD3>del C:\GAMConfig\oauth2.txt
C:\GAMADV-XTD3>gam version C:\GAMADV-XTD3>gam version
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
GAMADV-XTD3 6.66.13 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource GAMADV-XTD3 6.66.14 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com> Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.0 64-bit final Python 3.12.0 64-bit final
Windows-10-10.0.17134 AMD64 Windows-10-10.0.17134 AMD64

View File

@@ -4,7 +4,7 @@
Print the current version of Gam with details Print the current version of Gam with details
``` ```
gam version gam version
GAMADV-XTD3 6.66.13 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource GAMADV-XTD3 6.66.14 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com> Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.0 64-bit final Python 3.12.0 64-bit final
MacOS Monterey 12.7 x86_64 MacOS Monterey 12.7 x86_64
@@ -16,7 +16,7 @@ Time: 2023-06-02T21:10:00-07:00
Print the current version of Gam with details and time offset information Print the current version of Gam with details and time offset information
``` ```
gam version timeoffset gam version timeoffset
GAMADV-XTD3 6.66.13 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource GAMADV-XTD3 6.66.14 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com> Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.0 64-bit final Python 3.12.0 64-bit final
MacOS Monterey 12.7 x86_64 MacOS Monterey 12.7 x86_64
@@ -28,7 +28,7 @@ Your system time differs from www.googleapis.com by less than 1 second
Print the current version of Gam with extended details and SSL information Print the current version of Gam with extended details and SSL information
``` ```
gam version extended gam version extended
GAMADV-XTD3 6.66.13 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource GAMADV-XTD3 6.66.14 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com> Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.0 64-bit final Python 3.12.0 64-bit final
MacOS Monterey 12.7 x86_64 MacOS Monterey 12.7 x86_64
@@ -65,7 +65,7 @@ MacOS High Sierra 10.13.6 x86_64
Path: /Users/Admin/bin/gamadv-xtd3 Path: /Users/Admin/bin/gamadv-xtd3
Version Check: Version Check:
Current: 5.35.08 Current: 5.35.08
Latest: 6.66.13 Latest: 6.66.14
echo $? echo $?
1 1
``` ```
@@ -73,7 +73,7 @@ echo $?
Print the current version number without details Print the current version number without details
``` ```
gam version simple gam version simple
6.66.13 6.66.14
``` ```
In Linux/MacOS you can do: In Linux/MacOS you can do:
``` ```
@@ -83,7 +83,7 @@ echo $VER
Print the current version of Gam and address of this Wiki Print the current version of Gam and address of this Wiki
``` ```
gam help gam help
GAM 6.66.13 - https://github.com/taers232c/GAMADV-XTD3 GAM 6.66.14 - https://github.com/taers232c/GAMADV-XTD3
Ross Scroggs <ross.scroggs@gmail.com> Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.0 64-bit final Python 3.12.0 64-bit final
MacOS Monterey 12.7 x86_64 MacOS Monterey 12.7 x86_64

View File

@@ -1457,7 +1457,7 @@ gam print alertfeedback [todrive <ToDriveAttribute>*] [alert <AlertID>] [filter
gam create|add alias|aliases <EmailAddressEntity> user|group|target <UniqueID>|<EmailAddress> gam create|add alias|aliases <EmailAddressEntity> user|group|target <UniqueID>|<EmailAddress>
[verifynotinvitable] [verifynotinvitable]
gam update alias|aliases <EmailAddressEntity> user|group|target <UniqueID>|<EmailAddress> gam update alias|aliases <EmailAddressEntity> user|group|target <UniqueID>|<EmailAddress>
[notargetverify] [notargetverify] [waitafterdelete <Integer>]
gam delete alias|aliases [user|group|target] <EmailAddressEntity> gam delete alias|aliases [user|group|target] <EmailAddressEntity>
gam remove aliases|nicknames <EmailAddress> user|group <EmailAddressEntity> gam remove aliases|nicknames <EmailAddress> user|group <EmailAddressEntity>
gam <UserTypeEntity> delete alias|aliases gam <UserTypeEntity> delete alias|aliases

View File

@@ -2,6 +2,25 @@
Merged GAM-Team version Merged GAM-Team version
6.66.14
Updated `gam <UserTypeEntity> modify messages` to recognize the following error:
```
ERROR: 400: invalid - Invalid label: SENT
```
Updated `gam update alias <EmailAddressEntity> user|group|target <EmailAddress>`
to avoid the following problem.
```
$ gam update alias testalias@domain.com user testuser
User Alias: testalias@domain.com, Deleted
User Alias: testalias@domain.com, User: testuser@domain.com, Update Failed: Duplicate, Email Address: testalias@domain.com
```
GAM updates an alias to point to a new target by deleting the alias and then recreating the alias pointing to the new target.
Unfortunately, if these commands are executed back-to-back; Google generates the `Update Failed: Duplicate` error.
Now, GAM waits 2 seconds between the delete and the insert which seems to eliminate the problem. If the problem persists,
the option `waitafterdelete <Integer>` can be used to increase the wait time to a maximum of 10 seconds.
6.66.13 6.66.13
Updated functionality of option `preservefiletimes` in `gam <UserTypeEntity> update drivefile <DriveFileEntity>`. Updated functionality of option `preservefiletimes` in `gam <UserTypeEntity> update drivefile <DriveFileEntity>`.

View File

@@ -17333,7 +17333,7 @@ ALIAS_TARGET_TYPES = ['user', 'group', 'target']
# gam create aliases|nicknames <EmailAddressEntity> user|group|target <UniqueID>|<EmailAddress> # gam create aliases|nicknames <EmailAddressEntity> user|group|target <UniqueID>|<EmailAddress>
# [verifynotinvitable] # [verifynotinvitable]
# gam update aliases|nicknames <EmailAddressEntity> user|group|target <UniqueID>|<EmailAddress> # gam update aliases|nicknames <EmailAddressEntity> user|group|target <UniqueID>|<EmailAddress>
# [notargetverify] # [notargetverify] [waitafterdelete <Integer>]
def doCreateUpdateAliases(): def doCreateUpdateAliases():
def verifyAliasTargetExists(): def verifyAliasTargetExists():
if targetType != 'group': if targetType != 'group':
@@ -17355,6 +17355,42 @@ def doCreateUpdateAliases():
GAPI.badRequest, GAPI.invalid, GAPI.systemError): GAPI.badRequest, GAPI.invalid, GAPI.systemError):
return None return None
def deleteAliasOnUpdate():
# User alias
if targetType != 'group':
try:
callGAPI(cd.users().aliases(), 'delete',
throwReasons=[GAPI.USER_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.INVALID, GAPI.FORBIDDEN, GAPI.INVALID_RESOURCE,
GAPI.CONDITION_NOT_MET],
userKey=aliasEmail, alias=aliasEmail)
printEntityKVList([Ent.USER_ALIAS, aliasEmail], [Act.PerformedName(Act.DELETE)], i, count)
time.sleep(waitAfterDelete)
return True
except GAPI.conditionNotMet as e:
entityActionFailedWarning([Ent.USER_ALIAS, aliasEmail], str(e), i, count)
return False
except (GAPI.userNotFound, GAPI.badRequest, GAPI.invalid, GAPI.forbidden, GAPI.invalidResource):
if targetType == 'user':
entityUnknownWarning(Ent.USER_ALIAS, aliasEmail, i, count)
return False
# Group alias
try:
callGAPI(cd.groups().aliases(), 'delete',
throwReasons=[GAPI.GROUP_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.INVALID, GAPI.FORBIDDEN, GAPI.INVALID_RESOURCE,
GAPI.CONDITION_NOT_MET],
groupKey=aliasEmail, alias=aliasEmail)
time.sleep(waitAfterDelete)
return True
except GAPI.conditionNotMet as e:
entityActionFailedWarning([Ent.GROUP_ALIAS, aliasEmail], str(e), i, count)
return False
except GAPI.forbidden:
entityUnknownWarning(Ent.GROUP_ALIAS, aliasEmail, i, count)
return False
except (GAPI.groupNotFound, GAPI.badRequest, GAPI.invalid, GAPI.invalidResource):
entityUnknownWarning(Ent.GROUP_ALIAS, aliasEmail, i, count)
return False
cd = buildGAPIObject(API.DIRECTORY) cd = buildGAPIObject(API.DIRECTORY)
ci = None ci = None
updateCmd = Act.Get() == Act.UPDATE updateCmd = Act.Get() == Act.UPDATE
@@ -17364,12 +17400,15 @@ def doCreateUpdateAliases():
entityLists = targetEmails if isinstance(targetEmails, dict) else None entityLists = targetEmails if isinstance(targetEmails, dict) else None
verifyNotInvitable = False verifyNotInvitable = False
verifyTarget = updateCmd verifyTarget = updateCmd
waitAfterDelete = 2
while Cmd.ArgumentsRemaining(): while Cmd.ArgumentsRemaining():
myarg = getArgument() myarg = getArgument()
if (not updateCmd) and myarg == 'verifynotinvitable': if (not updateCmd) and myarg == 'verifynotinvitable':
verifyNotInvitable = True verifyNotInvitable = True
elif updateCmd and myarg == 'notargetverify': elif updateCmd and myarg == 'notargetverify':
verifyTarget = False verifyTarget = False
elif updateCmd and myarg == 'waitafterdelete':
waitAfterDelete = getInteger(minVal=2, maxVal=10)
else: else:
unknownArgumentExit() unknownArgumentExit()
i = 0 i = 0
@@ -17394,30 +17433,9 @@ def doCreateUpdateAliases():
if targetType is None: if targetType is None:
entityUnknownWarning(Ent.ALIAS_TARGET, targetEmail, i, count) entityUnknownWarning(Ent.ALIAS_TARGET, targetEmail, i, count)
continue continue
if updateCmd: if updateCmd and not deleteAliasOnUpdate():
try:
callGAPI(cd.users().aliases(), 'delete',
throwReasons=[GAPI.USER_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.INVALID, GAPI.FORBIDDEN, GAPI.INVALID_RESOURCE,
GAPI.CONDITION_NOT_MET],
userKey=aliasEmail, alias=aliasEmail)
printEntityKVList([Ent.USER_ALIAS, aliasEmail], [Act.PerformedName(Act.DELETE)], i, count)
except GAPI.conditionNotMet as e:
entityActionFailedWarning([Ent.USER_ALIAS, aliasEmail], str(e), i, count)
continue continue
except (GAPI.userNotFound, GAPI.badRequest, GAPI.invalid, GAPI.forbidden, GAPI.invalidResource): # User alias
try:
callGAPI(cd.groups().aliases(), 'delete',
throwReasons=[GAPI.GROUP_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.INVALID, GAPI.FORBIDDEN, GAPI.INVALID_RESOURCE,
GAPI.CONDITION_NOT_MET],
groupKey=aliasEmail, alias=aliasEmail)
except GAPI.conditionNotMet as e:
entityActionFailedWarning([Ent.GROUP_ALIAS, aliasEmail], str(e), i, count)
continue
except GAPI.forbidden:
entityUnknownWarning(Ent.GROUP_ALIAS, aliasEmail, i, count)
continue
except (GAPI.groupNotFound, GAPI.badRequest, GAPI.invalid, GAPI.invalidResource):
entityUnknownWarning(Ent.ALIAS, aliasEmail, i, count)
if targetType != 'group': if targetType != 'group':
try: try:
callGAPI(cd.users().aliases(), 'insert', callGAPI(cd.users().aliases(), 'insert',
@@ -17440,6 +17458,7 @@ def doCreateUpdateAliases():
if targetType == 'user': if targetType == 'user':
entityUnknownWarning(Ent.ALIAS_TARGET, targetEmail, i, count) entityUnknownWarning(Ent.ALIAS_TARGET, targetEmail, i, count)
continue continue
# Group alias
try: try:
callGAPI(cd.groups().aliases(), 'insert', callGAPI(cd.groups().aliases(), 'insert',
throwReasons=[GAPI.GROUP_NOT_FOUND, GAPI.USER_NOT_FOUND, GAPI.BAD_REQUEST, throwReasons=[GAPI.GROUP_NOT_FOUND, GAPI.USER_NOT_FOUND, GAPI.BAD_REQUEST,
@@ -25169,16 +25188,18 @@ def createChatMember(users):
entityPerformActionNumItems(kvList, jcount, entityType, i, count) entityPerformActionNumItems(kvList, jcount, entityType, i, count)
if jcount == 0: if jcount == 0:
return return
kvList.extend([entityType, ''])
Ind.Increment() Ind.Increment()
j = 0 j = 0
for body in members: for body in members:
j += 1
kvList[-1] = body[field]['name'] kvList[-1] = body[field]['name']
try: try:
member = callGAPI(chat.spaces().members(), 'create', member = callGAPI(chat.spaces().members(), 'create',
bailOnInternalError=True, bailOnInternalError=True,
throwReasons=[GAPI.ALREADY_EXISTS, GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.INTERNAL_ERROR], throwReasons=[GAPI.ALREADY_EXISTS, GAPI.NOT_FOUND, GAPI.INVALID, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.INTERNAL_ERROR],
parent=parent, body=body) parent=parent, body=body)
if role != 'ROLE_MEMBER': if role != 'ROLE_MEMBER' and entityType == Ent.CHAT_MANAGER_USER:
member = callGAPI(chat.spaces().members(), 'patch', member = callGAPI(chat.spaces().members(), 'patch',
bailOnInternalError=True, bailOnInternalError=True,
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.INTERNAL_ERROR], throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.INTERNAL_ERROR],
@@ -25193,7 +25214,7 @@ def createChatMember(users):
Ind.Decrement() Ind.Decrement()
else: else:
writeStdout(f'{member["name"]}\n') writeStdout(f'{member["name"]}\n')
except (GAPI.alreadyExists, GAPI.notFound, GAPI.invalidArgument, GAPI.permissionDenied, GAPI.internalError) as e: except (GAPI.alreadyExists, GAPI.notFound, GAPI.invalid, GAPI.invalidArgument, GAPI.permissionDenied, GAPI.internalError) as e:
entityActionFailedWarning(kvList, str(e)) entityActionFailedWarning(kvList, str(e))
Ind.Decrement() Ind.Decrement()
@@ -25230,6 +25251,7 @@ def createChatMember(users):
missingArgumentExit('space') missingArgumentExit('space')
if not userList and not groupList: if not userList and not groupList:
missingArgumentExit('user|members|group|groups') missingArgumentExit('user|members|group|groups')
userEntityType = Ent.CHAT_MEMBER_USER if role == 'ROLE_MEMBER' else Ent.CHAT_MANAGER_USER
userMembers = [] userMembers = []
for user in userList: for user in userList:
name = normalizeEmailAddressOrUID(user) name = normalizeEmailAddressOrUID(user)
@@ -25244,10 +25266,12 @@ def createChatMember(users):
user, chat, kvList = buildChatServiceObject(API.CHAT_MEMBERSHIPS, user, i, count, [Ent.CHAT_SPACE, parent]) user, chat, kvList = buildChatServiceObject(API.CHAT_MEMBERSHIPS, user, i, count, [Ent.CHAT_SPACE, parent])
if not chat: if not chat:
continue continue
Ind.Increment()
if userMembers: if userMembers:
addMembers(userMembers, 'member', Ent.CHAT_MEMBER_USER, i, count) addMembers(userMembers, 'member', userEntityType, i, count)
if groupMembers: if groupMembers:
addMembers(groupMembers, 'groupMember', Ent.CHAT_MEMBER_GROUP, i, count) addMembers(groupMembers, 'groupMember', Ent.CHAT_MEMBER_GROUP, i, count)
Ind.Decrement()
def _deleteChatMembers(chat, kvList, jcount, memberNames, i, count): def _deleteChatMembers(chat, kvList, jcount, memberNames, i, count):
j = 0 j = 0
@@ -25323,7 +25347,7 @@ def deleteUpdateChatMember(users):
i, count, users = getEntityArgument(users) i, count, users = getEntityArgument(users)
for user in users: for user in users:
i += 1 i += 1
user, chat, kvList = buildChatServiceObject(API.CHAT_MEMBERSHIPS, user, i, count) user, chat, kvList = buildChatServiceObject(API.CHAT_MEMBERSHIPS, user, i, count, [Ent.CHAT_SPACE, parent] if parent is not None else None)
if not chat: if not chat:
continue continue
jcount = len(memberNames) jcount = len(memberNames)
@@ -25360,12 +25384,12 @@ CHAT_SYNC_PREVIEW_TITLES = ['space', 'member', 'role', 'action', 'message']
# [preview [actioncsv]] # [preview [actioncsv]]
# (users <UserTypeEntity>)* (groups <GroupEntity>)* # (users <UserTypeEntity>)* (groups <GroupEntity>)*
def syncChatMembers(users): def syncChatMembers(users):
def _previewAction(members, jcount, action): def _previewAction(members, entityType, jcount, action):
Ind.Increment() Ind.Increment()
j = 0 j = 0
for member in members: for member in members:
j += 1 j += 1
entityActionPerformed([Ent.CHAT_SPACE, parent, Ent.CHAT_MEMBER, member, Ent.ROLE, role], j, jcount) entityActionPerformed([Ent.CHAT_SPACE, parent, entityType, member, Ent.ROLE, role], j, jcount)
Ind.Decrement() Ind.Decrement()
if csvPF: if csvPF:
for member in members: for member in members:
@@ -25373,11 +25397,11 @@ def syncChatMembers(users):
def addMembers(memberNames, members, entityType, i, count): def addMembers(memberNames, members, entityType, i, count):
jcount = len(memberNames) jcount = len(memberNames)
entityPerformActionNumItems(kvList, jcount, Ent.CHAT_MEMBER, i, count) entityPerformActionNumItems(kvList, jcount, entityType, i, count)
if jcount == 0: if jcount == 0:
return return
if preview: if preview:
_previewAction(memberNames, jcount, Act.REMOVE) _previewAction(memberNames, entityType, jcount, Act.REMOVE)
return return
kvList.extend([entityType, '']) kvList.extend([entityType, ''])
Ind.Increment() Ind.Increment()
@@ -25389,26 +25413,26 @@ def syncChatMembers(users):
try: try:
callGAPI(chat.spaces().members(), 'create', callGAPI(chat.spaces().members(), 'create',
bailOnInternalError=True, bailOnInternalError=True,
throwReasons=[GAPI.ALREADY_EXISTS, GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.INTERNAL_ERROR], throwReasons=[GAPI.ALREADY_EXISTS, GAPI.NOT_FOUND, GAPI.INVALID, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.INTERNAL_ERROR],
parent=parent, body=body) parent=parent, body=body)
if role != 'ROLE_MEMBER': if role != 'ROLE_MEMBER' and entityType == Ent.CHAT_MANAGER_USER:
callGAPI(chat.spaces().members(), 'patch', callGAPI(chat.spaces().members(), 'patch',
bailOnInternalError=True, bailOnInternalError=True,
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.INTERNAL_ERROR], throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.INTERNAL_ERROR],
name=memberName, updateMask='role', body={'role': role}) name=memberName, updateMask='role', body={'role': role})
entityActionPerformed(kvList, j, jcount) entityActionPerformed(kvList, j, jcount)
except (GAPI.alreadyExists, GAPI.notFound, GAPI.invalidArgument, GAPI.permissionDenied, GAPI.internalError) as e: except (GAPI.alreadyExists, GAPI.notFound, GAPI.invalid, GAPI.invalidArgument, GAPI.permissionDenied, GAPI.internalError) as e:
entityActionFailedWarning(kvList, str(e), j, jcount) entityActionFailedWarning(kvList, str(e), j, jcount)
Ind.Decrement() Ind.Decrement()
del kvList[-2:] del kvList[-2:]
def deleteMembers(memberNames, entityType, i, count): def deleteMembers(memberNames, entityType, i, count):
jcount = len(memberNames) jcount = len(memberNames)
entityPerformActionNumItems(kvList, jcount, Ent.CHAT_MEMBER, i, count) entityPerformActionNumItems(kvList, jcount, entityType, i, count)
if jcount == 0: if jcount == 0:
return return
if preview: if preview:
_previewAction(memberNames, jcount, Act.ADD) _previewAction(memberNames, entityType, jcount, Act.ADD)
return return
kvList.extend([entityType, '']) kvList.extend([entityType, ''])
Ind.Increment() Ind.Increment()
@@ -25417,7 +25441,6 @@ def syncChatMembers(users):
del kvList[-2:] del kvList[-2:]
cd = buildGAPIObject(API.DIRECTORY) cd = buildGAPIObject(API.DIRECTORY)
kwargs = {}
parent = None parent = None
role = CHAT_MEMBER_ROLE_MAP['member'] role = CHAT_MEMBER_ROLE_MAP['member']
mtype = CHAT_MEMBER_TYPE_MAP['human'] mtype = CHAT_MEMBER_TYPE_MAP['human']
@@ -25456,6 +25479,7 @@ def syncChatMembers(users):
unknownArgumentExit() unknownArgumentExit()
if not parent: if not parent:
missingArgumentExit('space') missingArgumentExit('space')
userEntityType = Ent.CHAT_MEMBER_USER if role == 'ROLE_MEMBER' else Ent.CHAT_MANAGER_USER
userMembers = {} userMembers = {}
syncUsersSet = set() syncUsersSet = set()
for user in userList: for user in userList:
@@ -25470,12 +25494,11 @@ def syncChatMembers(users):
memberName = f'{parent}/members/{name}' memberName = f'{parent}/members/{name}'
groupMembers[memberName] = {'groupMember': {'name': f'groups/{name}'}} groupMembers[memberName] = {'groupMember': {'name': f'groups/{name}'}}
syncGroupsSet.add(memberName) syncGroupsSet.add(memberName)
kwargs['filter'] = f'member.type = "{mtype}" AND role = "{role}"' qfilter = f'{Ent.Singular(Ent.CHAT_SPACE)}: {parent}'
qfilter = f'{Ent.Singular(Ent.CHAT_SPACE)}: {parent}, {kwargs["filter"]}'
i, count, users = getEntityArgument(users) i, count, users = getEntityArgument(users)
for user in users: for user in users:
i += 1 i += 1
user, chat, kvList = buildChatServiceObject(API.CHAT_MEMBERSHIPS, user, i, count) user, chat, kvList = buildChatServiceObject(API.CHAT_MEMBERSHIPS, user, i, count, [Ent.CHAT_SPACE, parent])
if not chat: if not chat:
continue continue
currentUsersSet = set() currentUsersSet = set()
@@ -25484,12 +25507,14 @@ def syncChatMembers(users):
members = callGAPIpages(chat.spaces().members(), 'list', 'memberships', members = callGAPIpages(chat.spaces().members(), 'list', 'memberships',
pageMessage=_getChatPageMessage(Ent.CHAT_MEMBER, user, i, count, qfilter), pageMessage=_getChatPageMessage(Ent.CHAT_MEMBER, user, i, count, qfilter),
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED], throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
pageSize=CHAT_PAGE_SIZE, parent=parent, **kwargs) pageSize=CHAT_PAGE_SIZE, parent=parent, showGroups=groupsSpecified)
for member in members: for member in members:
_getChatMemberEmail(cd, member)
if 'member' in member: if 'member' in member:
if member['member']['type'] == mtype and member['role'] == role:
_getChatMemberEmail(cd, member)
currentUsersSet.add(f"{parent}/members/{member['member']['email']}") currentUsersSet.add(f"{parent}/members/{member['member']['email']}")
elif 'groupMember' in member: elif 'groupMember' in member:
_getChatMemberEmail(cd, member)
currentGroupsSet.add(f"{parent}/members/{member['groupMember']['email']}") currentGroupsSet.add(f"{parent}/members/{member['groupMember']['email']}")
except (GAPI.notFound, GAPI.invalidArgument, GAPI.permissionDenied) as e: except (GAPI.notFound, GAPI.invalidArgument, GAPI.permissionDenied) as e:
exitIfChatNotConfigured(chat, kvList, str(e), i, count) exitIfChatNotConfigured(chat, kvList, str(e), i, count)
@@ -25497,13 +25522,13 @@ def syncChatMembers(users):
if syncOperation != 'addonly': if syncOperation != 'addonly':
Act.Set([Act.REMOVE, Act.REMOVE_PREVIEW][preview]) Act.Set([Act.REMOVE, Act.REMOVE_PREVIEW][preview])
if usersSpecified: if usersSpecified:
deleteMembers(currentUsersSet-syncUsersSet, Ent.CHAT_MEMBER_USER, i, count) deleteMembers(currentUsersSet-syncUsersSet, userEntityType, i, count)
if groupsSpecified: if groupsSpecified:
deleteMembers(currentGroupsSet-syncGroupsSet, Ent.CHAT_MEMBER_GROUP, i, count) deleteMembers(currentGroupsSet-syncGroupsSet, Ent.CHAT_MEMBER_GROUP, i, count)
if syncOperation != 'removeonly': if syncOperation != 'removeonly':
Act.Set([Act.ADD, Act.ADD_PREVIEW][preview]) Act.Set([Act.ADD, Act.ADD_PREVIEW][preview])
if usersSpecified: if usersSpecified:
addMembers(syncUsersSet-currentUsersSet, userMembers, Ent.CHAT_MEMBER_USER, i, count) addMembers(syncUsersSet-currentUsersSet, userMembers, userEntityType, i, count)
if groupsSpecified: if groupsSpecified:
addMembers(syncGroupsSet-currentGroupsSet, groupMembers, Ent.CHAT_MEMBER_GROUP, i, count) addMembers(syncGroupsSet-currentGroupsSet, groupMembers, Ent.CHAT_MEMBER_GROUP, i, count)
if csvPF: if csvPF:
@@ -65484,20 +65509,27 @@ def _processMessagesThreads(users, entityType):
bcount = min(jcount-mcount, GC.Values[GC.MESSAGE_BATCH_SIZE]) bcount = min(jcount-mcount, GC.Values[GC.MESSAGE_BATCH_SIZE])
while bcount > 0: while bcount > 0:
body['ids'] = messageIds[mcount:mcount+bcount] body['ids'] = messageIds[mcount:mcount+bcount]
idsCount = min(5, bcount)
idsList = ','.join(body['ids'][0:idsCount])
if bcount > 5:
idsList += ',...'
try: try:
callGAPI(gmail.users().messages(), function, callGAPI(gmail.users().messages(), function,
throwReasons=GAPI.GMAIL_THROW_REASONS+[GAPI.INVALID_MESSAGE_ID, GAPI.FAILED_PRECONDITION], throwReasons=GAPI.GMAIL_THROW_REASONS+[GAPI.INVALID_MESSAGE_ID, GAPI.INVALID, GAPI.FAILED_PRECONDITION],
userId='me', body=body) userId='me', body=body)
for messageId in body['ids']: for messageId in body['ids']:
mcount += 1 mcount += 1
entityActionPerformed([Ent.USER, user, entityType, messageId], mcount, jcount) entityActionPerformed([Ent.USER, user, entityType, messageId], mcount, jcount)
except (GAPI.serviceNotAvailable, GAPI.badRequest): except (GAPI.serviceNotAvailable, GAPI.badRequest):
mcount += bcount mcount += bcount
except GAPI.invalid as e:
entityActionFailedWarning([Ent.USER, user, entityType, idsList], f'{str(e)} ({mcount+1}-{mcount+bcount}/{jcount})')
mcount += bcount
except GAPI.invalidMessageId: except GAPI.invalidMessageId:
entityActionFailedWarning([Ent.USER, user, entityType, Msg.BATCH], f'{Msg.INVALID_MESSAGE_ID} ({mcount+1}-{mcount+bcount}/{jcount})') entityActionFailedWarning([Ent.USER, user, entityType, idsList], f'{Msg.INVALID_MESSAGE_ID} ({mcount+1}-{mcount+bcount}/{jcount})')
mcount += bcount mcount += bcount
except GAPI.failedPrecondition: except GAPI.failedPrecondition:
entityActionFailedWarning([Ent.USER, user, entityType, Msg.BATCH], f'{Msg.FAILED_PRECONDITION} ({mcount+1}-{mcount+bcount}/{jcount})') entityActionFailedWarning([Ent.USER, user, entityType, idsList], f'{Msg.FAILED_PRECONDITION} ({mcount+1}-{mcount+bcount}/{jcount})')
mcount += bcount mcount += bcount
bcount = min(jcount-mcount, GC.Values[GC.MESSAGE_BATCH_SIZE]) bcount = min(jcount-mcount, GC.Values[GC.MESSAGE_BATCH_SIZE])

View File

@@ -84,6 +84,7 @@ class GamEntity():
CHANNEL_PRODUCT = 'chpr' CHANNEL_PRODUCT = 'chpr'
CHANNEL_SKU = 'chsk' CHANNEL_SKU = 'chsk'
CHAT_BOT = 'chbo' CHAT_BOT = 'chbo'
CHAT_MANAGER_USER = 'chgu'
CHAT_MEMBER = 'chme' CHAT_MEMBER = 'chme'
CHAT_MEMBER_GROUP = 'chmg' CHAT_MEMBER_GROUP = 'chmg'
CHAT_MEMBER_USER = 'chmu' CHAT_MEMBER_USER = 'chmu'
@@ -416,6 +417,7 @@ class GamEntity():
CHANNEL_PRODUCT: ['Channel Products', 'Channel Product'], CHANNEL_PRODUCT: ['Channel Products', 'Channel Product'],
CHANNEL_SKU: ['Channel SKUs', 'Channel SKU'], CHANNEL_SKU: ['Channel SKUs', 'Channel SKU'],
CHAT_BOT: ['Chat BOTs', 'Chat BOT'], CHAT_BOT: ['Chat BOTs', 'Chat BOT'],
CHAT_MANAGER_USER: ['Chat User Managers', 'Chat User Manager'],
CHAT_MESSAGE: ['Chat Messages', 'Chat Message'], CHAT_MESSAGE: ['Chat Messages', 'Chat Message'],
CHAT_MESSAGE_ID: ['Chat Message IDs', 'Chat Message ID'], CHAT_MESSAGE_ID: ['Chat Message IDs', 'Chat Message ID'],
CHAT_MEMBER: ['Chat Members', 'Chat Member'], CHAT_MEMBER: ['Chat Members', 'Chat Member'],