From aa1b3732450cf6447d40e2e4f7d2d2a1ba20402c Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Mon, 21 Jul 2025 14:07:03 -0700 Subject: [PATCH] Handle additional error when unsuspending a user ERROR: 412: adminCannotUnsuspend - Cannot restore a user suspended for abuse --- src/GamUpdate.txt | 10 ++++++++++ src/gam/__init__.py | 15 +++++++++------ src/gam/gamlib/glgapi.py | 4 ++++ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/GamUpdate.txt b/src/GamUpdate.txt index 4682ca7a..c7c943f9 100644 --- a/src/GamUpdate.txt +++ b/src/GamUpdate.txt @@ -1,3 +1,13 @@ +7.14.04 + +Updated `gam update user suspended off` and `gam unsuspend users` +to handle the following error that occurs when trying to unsuspend a user that has been suspended for abuse. +``` +ERROR: 412: adminCannotUnsuspend - Cannot restore a user suspended for abuse. +``` + +* See: https://support.google.com/a/answer/1110339 + 7.14.03 Fixed bug in `gam print cigroup-members includederivedmembership` that caused a trap. diff --git a/src/gam/__init__.py b/src/gam/__init__.py index 8e3a0a76..afce9062 100755 --- a/src/gam/__init__.py +++ b/src/gam/__init__.py @@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki """ __author__ = 'GAM Team ' -__version__ = '7.14.03' +__version__ = '7.14.04' __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)' #pylint: disable=wrong-import-position @@ -44425,7 +44425,7 @@ def updateUsers(entityList): try: result = callGAPI(cd.users(), 'update', throwReasons=[GAPI.CONDITION_NOT_MET, GAPI.USER_NOT_FOUND, GAPI.DOMAIN_NOT_FOUND, - GAPI.FORBIDDEN, GAPI.BAD_REQUEST, + GAPI.FORBIDDEN, GAPI.BAD_REQUEST, GAPI.ADMIN_CANNOT_UNSUSPEND, GAPI.INVALID, GAPI.INVALID_INPUT, GAPI.INVALID_PARAMETER, GAPI.INVALID_ORGUNIT, GAPI.INVALID_SCHEMA_VALUE, GAPI.DUPLICATE, GAPI.INSUFFICIENT_ARCHIVED_USER_LICENSES, GAPI.CONFLICT], @@ -44487,7 +44487,8 @@ def updateUsers(entityList): entityActionFailedWarning([Ent.USER, user, Ent.USER, body['primaryEmail']], str(e), i, count) except GAPI.invalidOrgunit: entityActionFailedWarning([Ent.USER, user], Msg.INVALID_ORGUNIT, i, count) - except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden, GAPI.badRequest, + except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, + GAPI.forbidden, GAPI.badRequest, GAPI.adminCannotUnsuspend, GAPI.invalid, GAPI.invalidInput, GAPI.invalidParameter, GAPI.insufficientArchivedUserLicenses, GAPI.conflict, GAPI.badRequest, GAPI.backendError, GAPI.systemError, GAPI.conditionNotMet) as e: entityActionFailedWarning([Ent.USER, user], str(e), i, count) @@ -44655,12 +44656,14 @@ def suspendUnsuspendUsers(entityList): try: callGAPI(cd.users(), 'update', throwReasons=[GAPI.USER_NOT_FOUND, GAPI.DOMAIN_NOT_FOUND, - GAPI.DOMAIN_CANNOT_USE_APIS, GAPI.FORBIDDEN, GAPI.BAD_REQUEST], + GAPI.DOMAIN_CANNOT_USE_APIS, GAPI.FORBIDDEN, GAPI.BAD_REQUEST, + GAPI.ADMIN_CANNOT_UNSUSPEND], userKey=user, body=body) entityActionPerformed([Ent.USER, user], i, count) except GAPI.userNotFound: entityUnknownWarning(Ent.USER, user, i, count) - except (GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden, GAPI.badRequest) as e: + except (GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden, + GAPI.badRequest, GAPI.adminCannotUnsuspend) as e: entityActionFailedWarning([Ent.USER, user], str(e), i, count) # gam suspend users [noactionifalias] @@ -49545,7 +49548,7 @@ def doCourseAddItems(courseIdList, getEntityListArg): addItems = getStringReturnInList(Cmd.OB_COURSE_ALIAS) elif addType == Ent.COURSE_TOPIC: addItems = getStringReturnInList(Cmd.OB_COURSE_TOPIC) - else: # addType == Ent.COURSE_ANNOUNCEMENT: + else: #elif addType == Ent.COURSE_ANNOUNCEMENT: addItems = [getCourseAnnouncement(True)] courseParticipantLists = None else: diff --git a/src/gam/gamlib/glgapi.py b/src/gam/gamlib/glgapi.py index 58cc44ed..56c1f2f1 100644 --- a/src/gam/gamlib/glgapi.py +++ b/src/gam/gamlib/glgapi.py @@ -23,6 +23,7 @@ ABORTED = 'aborted' ABUSIVE_CONTENT_RESTRICTION = 'abusiveContentRestriction' ACCESS_NOT_CONFIGURED = 'accessNotConfigured' +ADMIN_CANNOT_UNSUSPEND = 'adminCannotUnsuspend' ALREADY_EXISTS = 'alreadyExists' APPLY_LABEL_FORBIDDEN = 'applyLabelForbidden' AUTH_ERROR = 'authError' @@ -368,6 +369,8 @@ class abusiveContentRestriction(Exception): pass class accessNotConfigured(Exception): pass +class adminCannotUnsuspend(Exception): + pass class alreadyExists(Exception): pass class applyLabelForbidden(Exception): @@ -689,6 +692,7 @@ REASON_EXCEPTION_MAP = { ABORTED: aborted, ABUSIVE_CONTENT_RESTRICTION: abusiveContentRestriction, ACCESS_NOT_CONFIGURED: accessNotConfigured, + ADMIN_CANNOT_UNSUSPEND: adminCannotUnsuspend, ALREADY_EXISTS: alreadyExists, APPLY_LABEL_FORBIDDEN: applyLabelForbidden, AUTH_ERROR: authError,