gam7 7.11.0__py3-none-any.whl → 7.12.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of gam7 might be problematic. Click here for more details.

gam/__init__.py CHANGED
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
25
25
  """
26
26
 
27
27
  __author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
28
- __version__ = '7.11.00'
28
+ __version__ = '7.12.01'
29
29
  __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
30
30
 
31
31
  #pylint: disable=wrong-import-position
@@ -337,6 +337,7 @@ ENTITY_IS_A_GROUP_RC = 22
337
337
  ENTITY_IS_A_GROUP_ALIAS_RC = 23
338
338
  ENTITY_IS_AN_UNMANAGED_ACCOUNT_RC = 24
339
339
  ORGUNIT_NOT_EMPTY_RC = 25
340
+ USER_SUSPENDED_RC = 26
340
341
  CHECK_USER_GROUPS_ERROR_RC = 29
341
342
  ORPHANS_COLLECTED_RC = 30
342
343
  # Warnings/Errors
@@ -634,7 +635,8 @@ def accessErrorMessage(cd, errMsg=None):
634
635
  cd = buildGAPIObject(API.DIRECTORY)
635
636
  try:
636
637
  callGAPI(cd.customers(), 'get',
637
- throwReasons=[GAPI.BAD_REQUEST, GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
638
+ throwReasons=[GAPI.BAD_REQUEST, GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND,
639
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
638
640
  customerKey=GC.Values[GC.CUSTOMER_ID], fields='id')
639
641
  except (GAPI.badRequest, GAPI.invalidInput):
640
642
  return formatKeyValueList('',
@@ -671,14 +673,16 @@ def accessErrorExitNonDirectory(api, errMsg):
671
673
  ''))
672
674
 
673
675
  def ClientAPIAccessDeniedExit(errMsg=None):
674
- stderrErrorMsg(Msg.API_ACCESS_DENIED)
675
- if errMsg:
676
+ if errMsg is None:
677
+ stderrErrorMsg(Msg.API_ACCESS_DENIED)
678
+ missingScopes = API.getClientScopesSet(GM.Globals[GM.CURRENT_CLIENT_API])-GM.Globals[GM.CURRENT_CLIENT_API_SCOPES]
679
+ if missingScopes:
680
+ writeStderr(Msg.API_CHECK_CLIENT_AUTHORIZATION.format(GM.Globals[GM.OAUTH2_CLIENT_ID],
681
+ ','.join(sorted(missingScopes))))
682
+ systemErrorExit(API_ACCESS_DENIED_RC, None)
683
+ else:
676
684
  stderrErrorMsg(errMsg)
677
- missingScopes = API.getClientScopesSet(GM.Globals[GM.CURRENT_CLIENT_API])-GM.Globals[GM.CURRENT_CLIENT_API_SCOPES]
678
- if missingScopes:
679
- writeStderr(Msg.API_CHECK_CLIENT_AUTHORIZATION.format(GM.Globals[GM.OAUTH2_CLIENT_ID],
680
- ','.join(sorted(missingScopes))))
681
- systemErrorExit(API_ACCESS_DENIED_RC, None)
685
+ systemErrorExit(API_ACCESS_DENIED_RC, Msg.REAUTHENTICATION_IS_NEEDED)
682
686
 
683
687
  def SvcAcctAPIAccessDenied():
684
688
  _getSvcAcctData()
@@ -4458,6 +4462,8 @@ def handleOAuthTokenError(e, softErrors, displayError=False, i=0, count=0):
4458
4462
  errMsg.startswith('invalid_request: Invalid impersonation &quot;sub&quot; field')):
4459
4463
  if not GM.Globals[GM.CURRENT_SVCACCT_USER]:
4460
4464
  ClientAPIAccessDeniedExit()
4465
+ # 403 Forbidden, API disabled, user not enabled
4466
+ # 400 Bad Request, user not defined
4461
4467
  if softErrors:
4462
4468
  entityActionFailedWarning([Ent.USER, GM.Globals[GM.CURRENT_SVCACCT_USER], Ent.USER, None], errMsg, i, count)
4463
4469
  return None
@@ -4465,6 +4471,7 @@ def handleOAuthTokenError(e, softErrors, displayError=False, i=0, count=0):
4465
4471
  if errMsg in API.OAUTH2_UNAUTHORIZED_ERRORS:
4466
4472
  if not GM.Globals[GM.CURRENT_SVCACCT_USER]:
4467
4473
  ClientAPIAccessDeniedExit()
4474
+ # 401 Unauthorized, API disabled, user enabled
4468
4475
  if softErrors:
4469
4476
  if displayError:
4470
4477
  apiOrScopes = API.getAPIName(GM.Globals[GM.CURRENT_SVCACCT_API]) if GM.Globals[GM.CURRENT_SVCACCT_API] else ','.join(sorted(GM.Globals[GM.CURRENT_SVCACCT_API_SCOPES]))
@@ -6515,7 +6522,8 @@ def getItemsToModify(entityType, entity, memberRoles=None, isSuspended=None, isA
6515
6522
  printGettingAllEntityItemsForWhom(Ent.TEACHER, removeCourseIdScope(courseId), entityType=Ent.COURSE)
6516
6523
  result = callGAPIpages(courseInfo['croom'].courses().teachers(), 'list', 'teachers',
6517
6524
  pageMessage=getPageMessageForWhom(),
6518
- throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.BAD_REQUEST, GAPI.SERVICE_NOT_AVAILABLE],
6525
+ throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.SERVICE_NOT_AVAILABLE,
6526
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
6519
6527
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
6520
6528
  courseId=courseId, fields='nextPageToken,teachers/profile/emailAddress',
6521
6529
  pageSize=GC.Values[GC.CLASSROOM_MAX_RESULTS])
@@ -6528,7 +6536,8 @@ def getItemsToModify(entityType, entity, memberRoles=None, isSuspended=None, isA
6528
6536
  printGettingAllEntityItemsForWhom(Ent.STUDENT, removeCourseIdScope(courseId), entityType=Ent.COURSE)
6529
6537
  result = callGAPIpages(courseInfo['croom'].courses().students(), 'list', 'students',
6530
6538
  pageMessage=getPageMessageForWhom(),
6531
- throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.BAD_REQUEST, GAPI.SERVICE_NOT_AVAILABLE],
6539
+ throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.SERVICE_NOT_AVAILABLE,
6540
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
6532
6541
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
6533
6542
  courseId=courseId, fields='nextPageToken,students/profile/emailAddress',
6534
6543
  pageSize=GC.Values[GC.CLASSROOM_MAX_RESULTS])
@@ -6544,8 +6553,8 @@ def getItemsToModify(entityType, entity, memberRoles=None, isSuspended=None, isA
6544
6553
  entityActionNotPerformedWarning([Ent.COURSE, removeCourseIdScope(courseId)], str(e))
6545
6554
  GM.Globals[GM.CLASSROOM_SERVICE_NOT_AVAILABLE] = True
6546
6555
  break
6547
- except (GAPI.forbidden, GAPI.badRequest):
6548
- ClientAPIAccessDeniedExit()
6556
+ except (GAPI.forbidden, GAPI.permissionDenied, GAPI.badRequest) as e:
6557
+ ClientAPIAccessDeniedExit(str(e))
6549
6558
  elif entityType == Cmd.ENTITY_CROS:
6550
6559
  buildGAPIObject(API.DIRECTORY)
6551
6560
  result = convertEntityToList(entity)
@@ -9023,7 +9032,7 @@ class CSVPrintFile():
9023
9032
  normalizeSortHeaders()
9024
9033
  if self.outputTranspose:
9025
9034
  newRows = []
9026
- newTitlesList = [i for i in range(len(self.rows)+1)]
9035
+ newTitlesList = list(range(len(self.rows) + 1))
9027
9036
  for title in titlesList:
9028
9037
  i = 0
9029
9038
  newRow = {i: title}
@@ -15065,7 +15074,7 @@ def getRecipients():
15065
15074
  # (embedimage <FileName> <String>)*
15066
15075
  # [newuser <EmailAddress> firstname|givenname <String> lastname|familyname <string> password <Password>]
15067
15076
  # (<SMTPDateHeader> <Time>)* (<SMTPHeader> <String>)* (header <String> <String>)*
15068
- # gam <UserTypeEntity> sendemail recipient <RecipientEntity> [replyto <EmailAddress>]
15077
+ # gam <UserTypeEntity> sendemail recipient|to <RecipientEntity> [replyto <EmailAddress>]
15069
15078
  # [cc <RecipientEntity>] [bcc <RecipientEntity>] [singlemessage]
15070
15079
  # [subject <String>]
15071
15080
  # [<MessageContent>]
@@ -15098,11 +15107,12 @@ def doSendEmail(users=None):
15098
15107
  if checkArgumentPresent({'recipient', 'recipients', 'to'}):
15099
15108
  msgFroms = [normalizeEmailAddressOrUID(entity) for entity in entityList]
15100
15109
  recipients = getRecipients()
15101
- else:
15102
- if checkArgumentPresent({'from'}):
15103
- msgFroms = [getString(Cmd.OB_EMAIL_ADDRESS)]
15104
- count = 1
15110
+ elif checkArgumentPresent({'from'}):
15105
15111
  recipients = [normalizeEmailAddressOrUID(entity) for entity in entityList]
15112
+ msgFroms = [getString(Cmd.OB_EMAIL_ADDRESS)]
15113
+ count = 1
15114
+ else:
15115
+ missingArgumentExit('recipient|to|from')
15106
15116
  msgHeaders = {}
15107
15117
  ccRecipients = []
15108
15118
  bccRecipients = []
@@ -15319,6 +15329,7 @@ PLAN_NAME_MAP = {
15319
15329
  'annualmonthlypay': 'ANNUAL_MONTHLY_PAY',
15320
15330
  'annualyearlypay': 'ANNUAL_YEARLY_PAY',
15321
15331
  'flexible': 'FLEXIBLE',
15332
+ 'free': 'FREE',
15322
15333
  'trial': 'TRIAL',
15323
15334
  }
15324
15335
 
@@ -15402,7 +15413,7 @@ RENEWAL_TYPE_MAP = {
15402
15413
  # activate|suspend|startpaidservice|
15403
15414
  # (renewal auto_renew_monthly_pay|auto_renew_yearly_pay|cancel|renew_current_users_monthly_pay|renew_current_users_yearly_pay|switch_to_pay_as_you_go)|
15404
15415
  # (seats <Number>)|
15405
- # (plan annual_monthly_pay|annual_yearly_pay|flexible|trial [deal <String>] [purchaseorderid <String>] [seats <Number>])
15416
+ # (plan annual_monthly_pay|annual_yearly_pay|flexible|trial|free [deal <String>] [purchaseorderid <String>] [seats <Number>])
15406
15417
  def doUpdateResoldSubscription():
15407
15418
  def _getSeats():
15408
15419
  seats1 = getInteger(minVal=0)
@@ -16010,8 +16021,9 @@ def doCreateDomainAlias():
16010
16021
  checkForExtraneousArguments()
16011
16022
  try:
16012
16023
  callGAPI(cd.domainAliases(), 'insert',
16013
- throwReasons=[GAPI.DOMAIN_NOT_FOUND, GAPI.DUPLICATE, GAPI.INVALID, GAPI.BAD_REQUEST, GAPI.NOT_FOUND,
16014
- GAPI.FORBIDDEN, GAPI.CONFLICT],
16024
+ throwReasons=[GAPI.DOMAIN_NOT_FOUND, GAPI.DUPLICATE, GAPI.INVALID, GAPI.CONFLICT,
16025
+ GAPI.BAD_REQUEST, GAPI.NOT_FOUND,
16026
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16015
16027
  customer=GC.Values[GC.CUSTOMER_ID], body=body, fields='')
16016
16028
  entityActionPerformed([Ent.DOMAIN, body['parentDomainName'], Ent.DOMAIN_ALIAS, body['domainAliasName']])
16017
16029
  except GAPI.domainNotFound:
@@ -16020,8 +16032,10 @@ def doCreateDomainAlias():
16020
16032
  entityActionFailedWarning([Ent.DOMAIN, body['parentDomainName'], Ent.DOMAIN_ALIAS, body['domainAliasName']], Msg.DUPLICATE)
16021
16033
  except (GAPI.invalid, GAPI.conflict) as e:
16022
16034
  entityActionFailedWarning([Ent.DOMAIN, body['parentDomainName'], Ent.DOMAIN_ALIAS, body['domainAliasName']], str(e))
16023
- except (GAPI.badRequest, GAPI.notFound, GAPI.forbidden) as e:
16035
+ except (GAPI.badRequest, GAPI.notFound) as e:
16024
16036
  accessErrorExit(cd, str(e))
16037
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16038
+ ClientAPIAccessDeniedExit(str(e))
16025
16039
 
16026
16040
  # gam delete domainalias|aliasdomain <DomainAlias>
16027
16041
  def doDeleteDomainAlias():
@@ -16030,13 +16044,16 @@ def doDeleteDomainAlias():
16030
16044
  checkForExtraneousArguments()
16031
16045
  try:
16032
16046
  callGAPI(cd.domainAliases(), 'delete',
16033
- throwReasons=[GAPI.DOMAIN_ALIAS_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.NOT_FOUND, GAPI.FORBIDDEN],
16047
+ throwReasons=[GAPI.DOMAIN_ALIAS_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.NOT_FOUND,
16048
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16034
16049
  customer=GC.Values[GC.CUSTOMER_ID], domainAliasName=domainAliasName)
16035
16050
  entityActionPerformed([Ent.DOMAIN_ALIAS, domainAliasName])
16036
16051
  except GAPI.domainAliasNotFound:
16037
16052
  entityActionFailedWarning([Ent.DOMAIN_ALIAS, domainAliasName], Msg.DOES_NOT_EXIST)
16038
- except (GAPI.badRequest, GAPI.notFound, GAPI.forbidden) as e:
16053
+ except (GAPI.badRequest, GAPI.notFound) as e:
16039
16054
  accessErrorExit(cd, str(e))
16055
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16056
+ ClientAPIAccessDeniedExit(str(e))
16040
16057
 
16041
16058
  DOMAIN_TIME_OBJECTS = {'creationTime'}
16042
16059
  DOMAIN_ALIAS_PRINT_ORDER = ['parentDomainName', 'creationTime', 'verified']
@@ -16064,14 +16081,17 @@ def doInfoDomainAlias():
16064
16081
  FJQC = FormatJSONQuoteChar(formatJSONOnly=True)
16065
16082
  try:
16066
16083
  result = callGAPI(cd.domainAliases(), 'get',
16067
- throwReasons=[GAPI.DOMAIN_ALIAS_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.NOT_FOUND, GAPI.FORBIDDEN],
16084
+ throwReasons=[GAPI.DOMAIN_ALIAS_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.NOT_FOUND,
16085
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16068
16086
  customer=GC.Values[GC.CUSTOMER_ID], domainAliasName=domainAliasName)
16069
16087
  aliasSkipObjects = DOMAIN_ALIAS_SKIP_OBJECTS
16070
16088
  _showDomainAlias(result, FJQC, aliasSkipObjects)
16071
16089
  except GAPI.domainAliasNotFound:
16072
16090
  entityActionFailedWarning([Ent.DOMAIN_ALIAS, domainAliasName], Msg.DOES_NOT_EXIST)
16073
- except (GAPI.badRequest, GAPI.notFound, GAPI.forbidden) as e:
16091
+ except (GAPI.badRequest, GAPI.notFound) as e:
16074
16092
  accessErrorExit(cd, str(e))
16093
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16094
+ ClientAPIAccessDeniedExit(str(e))
16075
16095
 
16076
16096
  def _printDomain(domain, csvPF):
16077
16097
  row = {}
@@ -16107,7 +16127,8 @@ def doPrintShowDomainAliases():
16107
16127
  FJQC.GetFormatJSONQuoteChar(myarg, True)
16108
16128
  try:
16109
16129
  domainAliases = callGAPIitems(cd.domainAliases(), 'list', 'domainAliases',
16110
- throwReasons=[GAPI.BAD_REQUEST, GAPI.NOT_FOUND, GAPI.FORBIDDEN],
16130
+ throwReasons=[GAPI.BAD_REQUEST, GAPI.NOT_FOUND,
16131
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16111
16132
  customer=GC.Values[GC.CUSTOMER_ID])
16112
16133
  count = len(domainAliases)
16113
16134
  if showItemCountOnly:
@@ -16125,8 +16146,10 @@ def doPrintShowDomainAliases():
16125
16146
  csvPF.WriteRowNoFilter({'domainAliasName': domainAlias['domainAliasName'],
16126
16147
  'JSON': json.dumps(cleanJSON(domainAlias, timeObjects=DOMAIN_TIME_OBJECTS),
16127
16148
  ensure_ascii=False, sort_keys=True)})
16128
- except (GAPI.badRequest, GAPI.notFound, GAPI.forbidden) as e:
16149
+ except (GAPI.badRequest, GAPI.notFound) as e:
16129
16150
  accessErrorExit(cd, str(e))
16151
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16152
+ ClientAPIAccessDeniedExit(str(e))
16130
16153
  if csvPF:
16131
16154
  csvPF.writeCSVfile('Domain Aliases')
16132
16155
 
@@ -16137,15 +16160,19 @@ def doCreateDomain():
16137
16160
  checkForExtraneousArguments()
16138
16161
  try:
16139
16162
  callGAPI(cd.domains(), 'insert',
16140
- throwReasons=[GAPI.DUPLICATE, GAPI.DOMAIN_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.CONFLICT],
16163
+ throwReasons=[GAPI.DUPLICATE, GAPI.CONFLICT,
16164
+ GAPI.DOMAIN_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.NOT_FOUND,
16165
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16141
16166
  customer=GC.Values[GC.CUSTOMER_ID], body=body, fields='')
16142
16167
  entityActionPerformed([Ent.DOMAIN, body['domainName']])
16143
16168
  except GAPI.duplicate:
16144
16169
  entityDuplicateWarning([Ent.DOMAIN, body['domainName']])
16145
16170
  except GAPI.conflict as e:
16146
16171
  entityActionFailedWarning([Ent.DOMAIN, body['domainName']], str(e))
16147
- except (GAPI.domainNotFound, GAPI.badRequest, GAPI.notFound, GAPI.forbidden) as e:
16172
+ except (GAPI.domainNotFound, GAPI.badRequest, GAPI.notFound) as e:
16148
16173
  accessErrorExit(cd, str(e))
16174
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16175
+ ClientAPIAccessDeniedExit(str(e))
16149
16176
 
16150
16177
  # gam update domain <DomainName> primary
16151
16178
  def doUpdateDomain():
@@ -16162,13 +16189,17 @@ def doUpdateDomain():
16162
16189
  missingArgumentExit('primary')
16163
16190
  try:
16164
16191
  callGAPI(cd.customers(), 'update',
16165
- throwReasons=[GAPI.DOMAIN_NOT_VERIFIED_SECONDARY, GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID_INPUT],
16192
+ throwReasons=[GAPI.DOMAIN_NOT_VERIFIED_SECONDARY, GAPI.BAD_REQUEST,
16193
+ GAPI.RESOURCE_NOT_FOUND, GAPI.INVALID_INPUT,
16194
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16166
16195
  customerKey=GC.Values[GC.CUSTOMER_ID], body=body, fields='')
16167
16196
  entityActionPerformedMessage([Ent.DOMAIN, domainName], Msg.NOW_THE_PRIMARY_DOMAIN)
16168
16197
  except GAPI.domainNotVerifiedSecondary:
16169
16198
  entityActionFailedWarning([Ent.DOMAIN, domainName], Msg.DOMAIN_NOT_VERIFIED_SECONDARY)
16170
- except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden, GAPI.invalidInput) as e:
16199
+ except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.invalidInput) as e:
16171
16200
  accessErrorExit(cd, str(e))
16201
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16202
+ ClientAPIAccessDeniedExit(str(e))
16172
16203
 
16173
16204
  # gam delete domain <DomainName>
16174
16205
  def doDeleteDomain():
@@ -16177,11 +16208,14 @@ def doDeleteDomain():
16177
16208
  checkForExtraneousArguments()
16178
16209
  try:
16179
16210
  callGAPI(cd.domains(), 'delete',
16180
- throwReasons=[GAPI.BAD_REQUEST, GAPI.NOT_FOUND, GAPI.FORBIDDEN],
16211
+ throwReasons=[GAPI.BAD_REQUEST, GAPI.NOT_FOUND,
16212
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16181
16213
  customer=GC.Values[GC.CUSTOMER_ID], domainName=domainName)
16182
16214
  entityActionPerformed([Ent.DOMAIN, domainName])
16183
- except (GAPI.badRequest, GAPI.notFound, GAPI.forbidden) as e:
16215
+ except (GAPI.badRequest, GAPI.notFound) as e:
16184
16216
  accessErrorExit(cd, str(e))
16217
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16218
+ ClientAPIAccessDeniedExit(str(e))
16185
16219
 
16186
16220
  CUSTOMER_LICENSE_MAP = {
16187
16221
  'accounts:num_users': 'Total Users',
@@ -16210,7 +16244,7 @@ def _showCustomerLicenseInfo(customerInfo, FJQC):
16210
16244
  while True:
16211
16245
  try:
16212
16246
  result = callGAPI(rep.customerUsageReports(), 'get',
16213
- throwReasons=[GAPI.INVALID, GAPI.FORBIDDEN],
16247
+ throwReasons=[GAPI.INVALID, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16214
16248
  date=tryDate, customerId=customerInfo['id'],
16215
16249
  fields='warnings,usageReports', parameters=parameters)
16216
16250
  usageReports = numUsersAvailable(result)
@@ -16228,8 +16262,8 @@ def _showCustomerLicenseInfo(customerInfo, FJQC):
16228
16262
  if not tryDate:
16229
16263
  return
16230
16264
  continue
16231
- except GAPI.forbidden:
16232
- return
16265
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16266
+ ClientAPIAccessDeniedExit(str(e))
16233
16267
  if not FJQC.formatJSON:
16234
16268
  printKeyValueList([f'User counts as of {tryDate}:'])
16235
16269
  Ind.Increment()
@@ -16250,12 +16284,15 @@ def setTrueCustomerId(cd=None):
16250
16284
  cd = buildGAPIObject(API.DIRECTORY)
16251
16285
  try:
16252
16286
  customerInfo = callGAPI(cd.customers(), 'get',
16253
- throwReasons=[GAPI.BAD_REQUEST, GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
16287
+ throwReasons=[GAPI.BAD_REQUEST, GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND,
16288
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16254
16289
  customerKey=GC.MY_CUSTOMER,
16255
16290
  fields='id')
16256
16291
  GC.Values[GC.CUSTOMER_ID] = customerInfo['id']
16257
- except (GAPI.badRequest, GAPI.invalidInput, GAPI.resourceNotFound, GAPI.forbidden):
16292
+ except (GAPI.badRequest, GAPI.invalidInput, GAPI.resourceNotFound):
16258
16293
  pass
16294
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16295
+ ClientAPIAccessDeniedExit(str(e))
16259
16296
 
16260
16297
  def _getCustomerId():
16261
16298
  customerId = GC.Values[GC.CUSTOMER_ID]
@@ -16289,7 +16326,8 @@ def doInfoCustomer(returnCustomerInfo=None, FJQC=None):
16289
16326
  FJQC = FormatJSONQuoteChar(formatJSONOnly=True)
16290
16327
  try:
16291
16328
  customerInfo = callGAPI(cd.customers(), 'get',
16292
- throwReasons=[GAPI.BAD_REQUEST, GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
16329
+ throwReasons=[GAPI.BAD_REQUEST, GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND,
16330
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16293
16331
  customerKey=customerId)
16294
16332
  if 'customerCreationTime' in customerInfo:
16295
16333
  customerInfo['customerCreationTime'] = formatLocalTime(customerInfo['customerCreationTime'])
@@ -16298,7 +16336,8 @@ def doInfoCustomer(returnCustomerInfo=None, FJQC=None):
16298
16336
  primaryDomain = {'domainName': UNKNOWN, 'verified': UNKNOWN}
16299
16337
  try:
16300
16338
  domains = callGAPIitems(cd.domains(), 'list', 'domains',
16301
- throwReasons=[GAPI.BAD_REQUEST, GAPI.NOT_FOUND, GAPI.FORBIDDEN],
16339
+ throwReasons=[GAPI.BAD_REQUEST, GAPI.NOT_FOUND,
16340
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16302
16341
  customer=customerInfo['id'], fields='domains(creationTime,domainName,isPrimary,verified)')
16303
16342
  for domain in domains:
16304
16343
  if domain.get('isPrimary'):
@@ -16334,8 +16373,8 @@ def doInfoCustomer(returnCustomerInfo=None, FJQC=None):
16334
16373
  _showCustomerLicenseInfo(customerInfo, FJQC)
16335
16374
  except (GAPI.badRequest, GAPI.invalidInput, GAPI.domainNotFound, GAPI.notFound, GAPI.resourceNotFound):
16336
16375
  accessErrorExit(cd)
16337
- except GAPI.forbidden as e:
16338
- entityActionFailedExit([Ent.CUSTOMER_ID, customerId], str(e))
16376
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16377
+ ClientAPIAccessDeniedExit(str(e))
16339
16378
 
16340
16379
  # gam update customer [primary <DomainName>] [adminsecondaryemail|alternateemail <EmailAddress>] [language <LanguageCode] [phone|phonenumber <String>]
16341
16380
  # [contact|contactname <String>] [name|organizationname <String>]
@@ -16363,15 +16402,18 @@ def doUpdateCustomer():
16363
16402
  if body:
16364
16403
  try:
16365
16404
  callGAPI(cd.customers(), 'patch',
16366
- throwReasons=[GAPI.DOMAIN_NOT_VERIFIED_SECONDARY, GAPI.INVALID, GAPI.INVALID_INPUT, GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
16405
+ throwReasons=[GAPI.DOMAIN_NOT_VERIFIED_SECONDARY, GAPI.INVALID, GAPI.INVALID_INPUT, GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND,
16406
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16367
16407
  customerKey=customerId, body=body, fields='')
16368
16408
  entityActionPerformed([Ent.CUSTOMER_ID, GC.Values[GC.CUSTOMER_ID]])
16369
16409
  except GAPI.domainNotVerifiedSecondary:
16370
16410
  entityActionFailedWarning([Ent.CUSTOMER_ID, GC.Values[GC.CUSTOMER_ID], Ent.DOMAIN, body['customerDomain']], Msg.DOMAIN_NOT_VERIFIED_SECONDARY)
16371
16411
  except (GAPI.invalid, GAPI.invalidInput) as e:
16372
16412
  entityActionFailedWarning([Ent.CUSTOMER_ID, GC.Values[GC.CUSTOMER_ID]], str(e))
16373
- except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
16413
+ except (GAPI.badRequest, GAPI.resourceNotFound):
16374
16414
  accessErrorExit(cd)
16415
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16416
+ ClientAPIAccessDeniedExit(str(e))
16375
16417
 
16376
16418
  # gam info instance [formatjson]
16377
16419
  def doInfoInstance():
@@ -16418,13 +16460,16 @@ def doInfoDomain():
16418
16460
  FJQC = FormatJSONQuoteChar(formatJSONOnly=True)
16419
16461
  try:
16420
16462
  result = callGAPI(cd.domains(), 'get',
16421
- throwReasons=[GAPI.DOMAIN_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.NOT_FOUND, GAPI.FORBIDDEN],
16463
+ throwReasons=[GAPI.DOMAIN_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.NOT_FOUND,
16464
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16422
16465
  customer=GC.Values[GC.CUSTOMER_ID], domainName=domainName)
16423
16466
  _showDomain(result, FJQC)
16424
16467
  except GAPI.domainNotFound:
16425
16468
  entityActionFailedWarning([Ent.DOMAIN, domainName], Msg.DOES_NOT_EXIST)
16426
- except (GAPI.badRequest, GAPI.notFound, GAPI.forbidden):
16469
+ except (GAPI.badRequest, GAPI.notFound):
16427
16470
  accessErrorExit(cd)
16471
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16472
+ ClientAPIAccessDeniedExit(str(e))
16428
16473
 
16429
16474
  DOMAIN_SORT_TITLES = ['domainName', 'parentDomainName', 'creationTime', 'type', 'verified']
16430
16475
 
@@ -16472,8 +16517,10 @@ def doPrintShowDomains():
16472
16517
  csvPF.WriteRowNoFilter({'domainName': domain['domainName'],
16473
16518
  'JSON': json.dumps(cleanJSON(domain, timeObjects=DOMAIN_TIME_OBJECTS),
16474
16519
  ensure_ascii=False, sort_keys=True)})
16475
- except (GAPI.badRequest, GAPI.notFound, GAPI.forbidden, GAPI.domainNotFound) as e:
16520
+ except (GAPI.badRequest, GAPI.notFound, GAPI.domainNotFound) as e:
16476
16521
  accessErrorExit(cd, str(e))
16522
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16523
+ ClientAPIAccessDeniedExit(str(e))
16477
16524
  if csvPF:
16478
16525
  csvPF.writeCSVfile('Domains')
16479
16526
 
@@ -16483,10 +16530,13 @@ def _listPrivileges(cd):
16483
16530
  fields = f'items({",".join(PRINT_PRIVILEGES_FIELDS)})'
16484
16531
  try:
16485
16532
  return callGAPIitems(cd.privileges(), 'list', 'items',
16486
- throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND, GAPI.FORBIDDEN],
16533
+ throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND,
16534
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16487
16535
  customer=GC.Values[GC.CUSTOMER_ID], fields=fields)
16488
- except (GAPI.badRequest, GAPI.customerNotFound, GAPI.forbidden):
16536
+ except (GAPI.badRequest, GAPI.customerNotFound):
16489
16537
  accessErrorExit(cd)
16538
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16539
+ ClientAPIAccessDeniedExit(str(e))
16490
16540
 
16491
16541
  # gam print privileges [todrive <ToDriveAttribute>*]
16492
16542
  # gam show privileges
@@ -16532,12 +16582,15 @@ def makeRoleIdNameMap():
16532
16582
  cd = buildGAPIObject(API.DIRECTORY)
16533
16583
  try:
16534
16584
  result = callGAPIpages(cd.roles(), 'list', 'items',
16535
- throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND, GAPI.FORBIDDEN],
16585
+ throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND,
16586
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16536
16587
  customer=GC.Values[GC.CUSTOMER_ID],
16537
16588
  fields='nextPageToken,items(roleId,roleName)',
16538
16589
  maxResults=100)
16539
- except (GAPI.badRequest, GAPI.customerNotFound, GAPI.forbidden):
16590
+ except (GAPI.badRequest, GAPI.customerNotFound):
16540
16591
  accessErrorExit(cd)
16592
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16593
+ ClientAPIAccessDeniedExit(str(e))
16541
16594
  for role in result:
16542
16595
  GM.Globals[GM.MAP_ROLE_ID_TO_NAME][role['roleId']] = role['roleName']
16543
16596
  GM.Globals[GM.MAP_ROLE_NAME_TO_ID][role['roleName'].lower()] = role['roleId']
@@ -16627,19 +16680,23 @@ def doCreateUpdateAdminRoles():
16627
16680
  try:
16628
16681
  if not updateCmd:
16629
16682
  result = callGAPI(cd.roles(), 'insert',
16630
- throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND, GAPI.FORBIDDEN]+[GAPI.DUPLICATE],
16683
+ throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND,
16684
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED]+[GAPI.DUPLICATE],
16631
16685
  customer=GC.Values[GC.CUSTOMER_ID], body=body, fields='roleId,roleName')
16632
16686
  else:
16633
16687
  result = callGAPI(cd.roles(), 'patch',
16634
- throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND, GAPI.FORBIDDEN]+[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION, GAPI.CONFLICT],
16688
+ throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND,
16689
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED]+[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION, GAPI.CONFLICT],
16635
16690
  customer=GC.Values[GC.CUSTOMER_ID], roleId=roleId, body=body, fields='roleId,roleName')
16636
16691
  entityActionPerformed([Ent.ADMIN_ROLE, f"{result['roleName']}({result['roleId']})"])
16637
16692
  except GAPI.duplicate as e:
16638
16693
  entityActionFailedWarning([Ent.ADMIN_ROLE, f"{body['roleName']}"], str(e))
16639
- except (GAPI.notFound, GAPI.forbidden, GAPI.failedPrecondition, GAPI.conflict) as e:
16694
+ except (GAPI.notFound, GAPI.failedPrecondition, GAPI.conflict) as e:
16640
16695
  entityActionFailedWarning([Ent.ADMIN_ROLE, roleId], str(e))
16641
16696
  except (GAPI.badRequest, GAPI.customerNotFound):
16642
16697
  accessErrorExit(cd)
16698
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16699
+ ClientAPIAccessDeniedExit(str(e))
16643
16700
 
16644
16701
  # gam delete adminrole <RoleItem>
16645
16702
  def doDeleteAdminRole():
@@ -16648,13 +16705,16 @@ def doDeleteAdminRole():
16648
16705
  checkForExtraneousArguments()
16649
16706
  try:
16650
16707
  callGAPI(cd.roles(), 'delete',
16651
- throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND, GAPI.FORBIDDEN]+[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION],
16708
+ throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND,
16709
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED]+[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION],
16652
16710
  customer=GC.Values[GC.CUSTOMER_ID], roleId=roleId)
16653
16711
  entityActionPerformed([Ent.ADMIN_ROLE, f"{role}({roleId})"])
16654
- except (GAPI.notFound, GAPI.forbidden, GAPI.failedPrecondition) as e:
16712
+ except (GAPI.notFound, GAPI.failedPrecondition) as e:
16655
16713
  entityActionFailedWarning([Ent.ADMIN_ROLE, roleId], str(e))
16656
16714
  except (GAPI.badRequest, GAPI.customerNotFound):
16657
16715
  accessErrorExit(cd)
16716
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16717
+ ClientAPIAccessDeniedExit(str(e))
16658
16718
 
16659
16719
  PRINT_ADMIN_ROLES_FIELDS = ['roleId', 'roleName', 'roleDescription', 'isSuperAdminRole', 'isSystemRole']
16660
16720
 
@@ -16715,18 +16775,22 @@ def doInfoPrintShowAdminRoles():
16715
16775
  printGettingAllAccountEntities(Ent.ADMIN_ROLE)
16716
16776
  roles = callGAPIpages(cd.roles(), 'list', 'items',
16717
16777
  pageMessage=getPageMessage(),
16718
- throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND, GAPI.FORBIDDEN],
16778
+ throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND,
16779
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16719
16780
  customer=GC.Values[GC.CUSTOMER_ID], fields=fields)
16720
16781
  else:
16721
16782
  fields = getFieldsFromFieldsList(fieldsList)
16722
16783
  roles = [callGAPI(cd.roles(), 'get',
16723
- throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.FAILED_PRECONDITION,
16724
- GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND],
16784
+ throwReasons=[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION,
16785
+ GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND,
16786
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16725
16787
  customer=GC.Values[GC.CUSTOMER_ID], roleId=roleId, fields=fields)]
16726
- except (GAPI.notFound, GAPI.forbidden, GAPI.failedPrecondition) as e:
16788
+ except (GAPI.notFound, GAPI.failedPrecondition) as e:
16727
16789
  entityActionFailedWarning([Ent.ADMIN_ROLE, roleId], str(e))
16728
16790
  except (GAPI.badRequest, GAPI.customerNotFound):
16729
16791
  accessErrorExit(cd)
16792
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16793
+ ClientAPIAccessDeniedExit(str(e))
16730
16794
  for role in roles:
16731
16795
  role.setdefault('isSuperAdminRole', False)
16732
16796
  role.setdefault('isSystemRole', False)
@@ -16785,8 +16849,9 @@ def doCreateAdmin():
16785
16849
  try:
16786
16850
  result = callGAPI(cd.roleAssignments(), 'insert',
16787
16851
  throwReasons=[GAPI.INTERNAL_ERROR, GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND,
16788
- GAPI.FORBIDDEN, GAPI.CUSTOMER_EXCEEDED_ROLE_ASSIGNMENTS_LIMIT, GAPI.SERVICE_NOT_AVAILABLE,
16789
- GAPI.INVALID_ORGUNIT, GAPI.DUPLICATE, GAPI.CONDITION_NOT_MET],
16852
+ GAPI.CUSTOMER_EXCEEDED_ROLE_ASSIGNMENTS_LIMIT, GAPI.SERVICE_NOT_AVAILABLE,
16853
+ GAPI.INVALID_ORGUNIT, GAPI.DUPLICATE, GAPI.CONDITION_NOT_MET,
16854
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16790
16855
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
16791
16856
  customer=GC.Values[GC.CUSTOMER_ID], body=body, fields='roleAssignmentId,assigneeType')
16792
16857
  assigneeType = result.get('assigneeType')
@@ -16800,14 +16865,16 @@ def doCreateAdmin():
16800
16865
  f'{Ent.Singular(entityType)} {user}, {Ent.Singular(Ent.ADMIN_ROLE)} {role}, {Ent.Singular(Ent.SCOPE)} {scope}')
16801
16866
  except GAPI.internalError:
16802
16867
  pass
16803
- except (GAPI.badRequest, GAPI.customerNotFound):
16804
- accessErrorExit(cd)
16805
- except (GAPI.forbidden, GAPI.customerExceededRoleAssignmentsLimit, GAPI.serviceNotAvailable, GAPI.conditionNotMet) as e:
16868
+ except (GAPI.customerExceededRoleAssignmentsLimit, GAPI.serviceNotAvailable, GAPI.conditionNotMet) as e:
16806
16869
  entityActionFailedWarning([Ent.ADMINISTRATOR, user, Ent.ADMIN_ROLE, role], str(e))
16807
16870
  except GAPI.invalidOrgunit:
16808
16871
  entityActionFailedWarning([Ent.ADMINISTRATOR, user], Msg.INVALID_ORGUNIT)
16809
16872
  except GAPI.duplicate:
16810
16873
  entityActionFailedWarning([Ent.ADMINISTRATOR, user, Ent.ADMIN_ROLE, role], Msg.DUPLICATE)
16874
+ except (GAPI.badRequest, GAPI.customerNotFound):
16875
+ accessErrorExit(cd)
16876
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16877
+ ClientAPIAccessDeniedExit(str(e))
16811
16878
 
16812
16879
  # gam delete admin <RoleAssignmentId>
16813
16880
  def doDeleteAdmin():
@@ -16816,17 +16883,20 @@ def doDeleteAdmin():
16816
16883
  checkForExtraneousArguments()
16817
16884
  try:
16818
16885
  callGAPI(cd.roleAssignments(), 'delete',
16819
- throwReasons=[GAPI.NOT_FOUND, GAPI.OPERATION_NOT_SUPPORTED, GAPI.FORBIDDEN,
16886
+ throwReasons=[GAPI.NOT_FOUND, GAPI.OPERATION_NOT_SUPPORTED,
16820
16887
  GAPI.INVALID_INPUT, GAPI.SERVICE_NOT_AVAILABLE, GAPI.RESOURCE_NOT_FOUND,
16821
- GAPI.FAILED_PRECONDITION, GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND],
16888
+ GAPI.FAILED_PRECONDITION, GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND,
16889
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16822
16890
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
16823
16891
  customer=GC.Values[GC.CUSTOMER_ID], roleAssignmentId=roleAssignmentId)
16824
16892
  entityActionPerformed([Ent.ADMIN_ROLE_ASSIGNMENT, roleAssignmentId])
16825
- except (GAPI.notFound, GAPI.operationNotSupported, GAPI.forbidden,
16826
- GAPI.invalidInput, GAPI.serviceNotAvailable, GAPI.resourceNotFound, GAPI.failedPrecondition) as e:
16893
+ except (GAPI.notFound, GAPI.operationNotSupported, GAPI.invalidInput,
16894
+ GAPI.serviceNotAvailable, GAPI.resourceNotFound, GAPI.failedPrecondition) as e:
16827
16895
  entityActionFailedWarning([Ent.ADMIN_ROLE_ASSIGNMENT, roleAssignmentId], str(e))
16828
16896
  except (GAPI.badRequest, GAPI.customerNotFound):
16829
16897
  accessErrorExit(cd)
16898
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16899
+ ClientAPIAccessDeniedExit(str(e))
16830
16900
 
16831
16901
  ASSIGNEE_EMAILTYPE_TOFIELD_MAP = {
16832
16902
  'user': 'assignedToUser',
@@ -16850,17 +16920,20 @@ def doPrintShowAdmins():
16850
16920
  if roleId not in rolePrivileges:
16851
16921
  try:
16852
16922
  rolePrivileges[roleId] = callGAPI(cd.roles(), 'get',
16853
- throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.FAILED_PRECONDITION,
16854
- GAPI.SERVICE_NOT_AVAILABLE, GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND],
16923
+ throwReasons=[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION,
16924
+ GAPI.SERVICE_NOT_AVAILABLE, GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND,
16925
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16855
16926
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
16856
16927
  customer=GC.Values[GC.CUSTOMER_ID],
16857
16928
  roleId=roleId,
16858
16929
  fields='rolePrivileges')
16859
- except (GAPI.notFound, GAPI.forbidden, GAPI.failedPrecondition, GAPI.serviceNotAvailable) as e:
16930
+ except (GAPI.notFound, GAPI.failedPrecondition, GAPI.serviceNotAvailable) as e:
16860
16931
  entityActionFailedExit([Ent.USER, userKey, Ent.ADMIN_ROLE, admin['roleId']], str(e))
16861
16932
  rolePrivileges[roleId] = None
16862
16933
  except (GAPI.badRequest, GAPI.customerNotFound):
16863
16934
  accessErrorExit(cd)
16935
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
16936
+ ClientAPIAccessDeniedExit(str(e))
16864
16937
  return rolePrivileges[roleId]
16865
16938
 
16866
16939
  def _setNamesFromIds(admin, privileges):
@@ -16870,9 +16943,7 @@ def doPrintShowAdmins():
16870
16943
  if assignedTo not in assignedToIdEmailMap:
16871
16944
  assigneeType = admin.get('assigneeType')
16872
16945
  assignedToField = ASSIGNEE_EMAILTYPE_TOFIELD_MAP.get(assigneeType, None)
16873
- assigneeEmail, assigneeType = convertUIDtoEmailAddressWithType(f'uid:{assignedTo}',
16874
- cd,
16875
- sal,
16946
+ assigneeEmail, assigneeType = convertUIDtoEmailAddressWithType(f'uid:{assignedTo}', cd, sal,
16876
16947
  emailTypes=list(ASSIGNEE_EMAILTYPE_TOFIELD_MAP.keys()))
16877
16948
  if not assignedToField and assigneeType in ASSIGNEE_EMAILTYPE_TOFIELD_MAP:
16878
16949
  assignedToField = ASSIGNEE_EMAILTYPE_TOFIELD_MAP[assigneeType]
@@ -16929,16 +17000,19 @@ def doPrintShowAdmins():
16929
17000
  pageMessage=getPageMessage(),
16930
17001
  throwReasons=[GAPI.INVALID, GAPI.USER_NOT_FOUND,
16931
17002
  GAPI.FORBIDDEN, GAPI.SERVICE_NOT_AVAILABLE,
16932
- GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND],
17003
+ GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND,
17004
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
16933
17005
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
16934
17006
  customer=GC.Values[GC.CUSTOMER_ID], fields=fields, **kwargs)
16935
17007
  except (GAPI.invalid, GAPI.userNotFound):
16936
17008
  entityUnknownWarning(Ent.ADMINISTRATOR, userKey)
16937
17009
  return
16938
- except (GAPI.forbidden, GAPI.serviceNotAvailable) as e:
17010
+ except (GAPI.serviceNotAvailable) as e:
16939
17011
  entityActionFailedExit([Ent.ADMINISTRATOR, userKey, Ent.ADMIN_ROLE, roleId], str(e))
16940
17012
  except (GAPI.badRequest, GAPI.customerNotFound):
16941
17013
  accessErrorExit(cd)
17014
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
17015
+ ClientAPIAccessDeniedExit(str(e))
16942
17016
  if not csvPF:
16943
17017
  count = len(admins)
16944
17018
  performActionNumItems(count, Ent.ADMIN_ROLE_ASSIGNMENT)
@@ -21429,7 +21503,9 @@ def queryPeopleOtherContacts(people, contactQuery, fields, entityType, user, i=0
21429
21503
  return entityList
21430
21504
  except GAPI.permissionDenied as e:
21431
21505
  ClientAPIAccessDeniedExit(str(e))
21432
- except (GAPI.serviceNotAvailable, GAPI.forbidden):
21506
+ except GAPI.forbidden:
21507
+ userPeopleServiceNotEnabledWarning(user, i, count)
21508
+ except GAPI.serviceNotAvailable:
21433
21509
  entityUnknownWarning(entityType, user, i, count)
21434
21510
  return None
21435
21511
 
@@ -21549,10 +21625,8 @@ def createUserPeopleContact(users):
21549
21625
  csvPF.WriteRow(row)
21550
21626
  except GAPI.invalidArgument as e:
21551
21627
  entityActionFailedWarning([entityType, user, peopleEntityType, None], str(e), i, count)
21552
- except (GAPI.permissionDenied, GAPI.failedPrecondition) as e:
21628
+ except (GAPI.serviceNotAvailable, GAPI.forbidden, GAPI.permissionDenied, GAPI.failedPrecondition) as e:
21553
21629
  ClientAPIAccessDeniedExit(str(e))
21554
- except (GAPI.serviceNotAvailable, GAPI.forbidden):
21555
- ClientAPIAccessDeniedExit()
21556
21630
  if csvPF:
21557
21631
  csvPF.writeCSVfile('People Contacts')
21558
21632
 
@@ -21714,10 +21788,8 @@ def _clearUpdatePeopleContacts(users, updateContacts):
21714
21788
  entityActionFailedWarning([entityType, user, peopleEntityType, resourceName], str(e), j, jcount)
21715
21789
  except (GAPI.notFound, GAPI.internalError):
21716
21790
  entityActionFailedWarning([entityType, user, peopleEntityType, resourceName], Msg.DOES_NOT_EXIST, j, jcount)
21717
- except (GAPI.permissionDenied, GAPI.failedPrecondition) as e:
21791
+ except (GAPI.serviceNotAvailable, GAPI.forbidden, GAPI.permissionDenied, GAPI.failedPrecondition) as e:
21718
21792
  ClientAPIAccessDeniedExit(str(e))
21719
- except (GAPI.serviceNotAvailable, GAPI.forbidden):
21720
- ClientAPIAccessDeniedExit()
21721
21793
  Ind.Decrement()
21722
21794
 
21723
21795
  # gam <UserTypeEntity> clear contacts <PeopleResourceNameEntity>|<PeopleUserContactSelection>
@@ -21864,10 +21936,8 @@ def dedupReplaceDomainUserPeopleContacts(users):
21864
21936
  entityActionFailedWarning([entityType, user, peopleEntityType, resourceName], str(e), j, jcount)
21865
21937
  except (GAPI.notFound, GAPI.internalError):
21866
21938
  entityActionFailedWarning([entityType, user, peopleEntityType, resourceName], Msg.DOES_NOT_EXIST, j, jcount)
21867
- except (GAPI.permissionDenied, GAPI.failedPrecondition) as e:
21939
+ except (GAPI.serviceNotAvailable, GAPI.forbidden, GAPI.permissionDenied, GAPI.failedPrecondition) as e:
21868
21940
  ClientAPIAccessDeniedExit(str(e))
21869
- except (GAPI.serviceNotAvailable, GAPI.forbidden):
21870
- ClientAPIAccessDeniedExit()
21871
21941
  Ind.Decrement()
21872
21942
 
21873
21943
  # gam <UserTypeEntity> delete contacts <PeopleResourceNameEntity>|<PeopleUserContactSelection>
@@ -21919,10 +21989,8 @@ def deleteUserPeopleContacts(users):
21919
21989
  entityActionPerformed([entityType, user, peopleEntityType, resourceName], j, jcount)
21920
21990
  except (GAPI.notFound, GAPI.internalError):
21921
21991
  entityActionFailedWarning([entityType, user, peopleEntityType, resourceName], Msg.DOES_NOT_EXIST, j, jcount)
21922
- except (GAPI.permissionDenied, GAPI.failedPrecondition) as e:
21992
+ except (GAPI.serviceNotAvailable, GAPI.forbidden, GAPI.permissionDenied, GAPI.failedPrecondition) as e:
21923
21993
  ClientAPIAccessDeniedExit(str(e))
21924
- except (GAPI.serviceNotAvailable, GAPI.forbidden):
21925
- ClientAPIAccessDeniedExit()
21926
21994
  Ind.Decrement()
21927
21995
 
21928
21996
  def _initPersonMetadataParameters():
@@ -22216,10 +22284,8 @@ def _infoPeople(users, entityType, source):
22216
22284
  except GAPI.invalidArgument as e:
22217
22285
  entityActionFailedWarning([entityType, user, peopleEntityType, resourceName], str(e), j, jcount)
22218
22286
  continue
22219
- except (GAPI.permissionDenied, GAPI.failedPrecondition) as e:
22287
+ except (GAPI.serviceNotAvailable, GAPI.forbidden, GAPI.permissionDenied, GAPI.failedPrecondition) as e:
22220
22288
  ClientAPIAccessDeniedExit(str(e))
22221
- except (GAPI.serviceNotAvailable, GAPI.forbidden):
22222
- ClientAPIAccessDeniedExit()
22223
22289
  if showContactGroups and contactGroupIDs:
22224
22290
  addContactGroupNamesToContacts([result], contactGroupIDs, False)
22225
22291
  _showPerson(entityType, user, peopleEntityType, result, j, jcount, FJQC, parameters)
@@ -22396,10 +22462,8 @@ def copyUserPeopleOtherContacts(users):
22396
22462
  except (GAPI.notFound, GAPI.internalError):
22397
22463
  entityActionFailedWarning([entityType, user, peopleEntityType, resourceName], Msg.DOES_NOT_EXIST, j, jcount)
22398
22464
  continue
22399
- except GAPI.permissionDenied as e:
22465
+ except (GAPI.serviceNotAvailable, GAPI.forbidden, GAPI.permissionDenied, GAPI.failedPrecondition) as e:
22400
22466
  ClientAPIAccessDeniedExit(str(e))
22401
- except (GAPI.serviceNotAvailable, GAPI.forbidden):
22402
- ClientAPIAccessDeniedExit()
22403
22467
  Ind.Decrement()
22404
22468
 
22405
22469
  # gam <UserTypeEntity> delete othercontacts
@@ -22512,10 +22576,8 @@ def processUserPeopleOtherContacts(users):
22512
22576
  except (GAPI.notFound, GAPI.internalError):
22513
22577
  entityActionFailedWarning([entityType, user, peopleEntityType, resourceName], Msg.DOES_NOT_EXIST, j, jcount)
22514
22578
  continue
22515
- except GAPI.permissionDenied as e:
22579
+ except (GAPI.serviceNotAvailable, GAPI.forbidden, GAPI.permissionDenied, GAPI.failedPrecondition) as e:
22516
22580
  ClientAPIAccessDeniedExit(str(e))
22517
- except (GAPI.serviceNotAvailable, GAPI.forbidden):
22518
- ClientAPIAccessDeniedExit()
22519
22581
  Ind.Decrement()
22520
22582
 
22521
22583
  # gam <UserTypeEntity> print othercontacts [todrive <ToDriveAttribute>*] <OtherContactSelection>
@@ -22631,10 +22693,8 @@ def _printShowPeople(source):
22631
22693
  pageSize=GC.Values[GC.PEOPLE_MAX_RESULTS],
22632
22694
  sources=sources, mergeSources=mergeSources,
22633
22695
  readMask=fields, fields='nextPageToken,people', **kwargs)
22634
- except (GAPI.permissionDenied, GAPI.failedPrecondition) as e:
22696
+ except (GAPI.serviceNotAvailable, GAPI.forbidden, GAPI.permissionDenied, GAPI.failedPrecondition) as e:
22635
22697
  ClientAPIAccessDeniedExit(str(e))
22636
- except (GAPI.serviceNotAvailable, GAPI.forbidden):
22637
- ClientAPIAccessDeniedExit()
22638
22698
  if not countsOnly:
22639
22699
  _printPersonEntityList(peopleEntityType, entityList, Ent.DOMAIN, GC.Values[GC.DOMAIN], 0, 0, csvPF, FJQC, parameters, None)
22640
22700
  else:
@@ -22753,10 +22813,8 @@ def printShowUserPeopleProfiles(users):
22753
22813
  except GAPI.notFound:
22754
22814
  entityUnknownWarning(Ent.PEOPLE_PROFILE, user, i, count)
22755
22815
  continue
22756
- except (GAPI.permissionDenied, GAPI.failedPrecondition) as e:
22816
+ except (GAPI.serviceNotAvailable, GAPI.forbidden, GAPI.permissionDenied, GAPI.failedPrecondition) as e:
22757
22817
  ClientAPIAccessDeniedExit(str(e))
22758
- except (GAPI.serviceNotAvailable, GAPI.forbidden):
22759
- ClientAPIAccessDeniedExit()
22760
22818
  if not csvPF:
22761
22819
  _showPerson(entityType, user, Ent.PEOPLE_PROFILE, result, i, count, FJQC, parameters)
22762
22820
  else:
@@ -22909,10 +22967,8 @@ def _processPeopleContactPhotos(users, function):
22909
22967
  entityDoesNotHaveItemWarning([entityType, user, peopleEntityType, resourceName, Ent.PHOTO, filename], j, jcount)
22910
22968
  except (GAPI.invalidArgument, OSError, IOError) as e:
22911
22969
  entityActionFailedWarning([entityType, user, peopleEntityType, resourceName, Ent.PHOTO, filename], str(e), j, jcount)
22912
- except (GAPI.permissionDenied, GAPI.failedPrecondition) as e:
22970
+ except (GAPI.serviceNotAvailable, GAPI.forbidden, GAPI.permissionDenied, GAPI.failedPrecondition) as e:
22913
22971
  ClientAPIAccessDeniedExit(str(e))
22914
- except (GAPI.serviceNotAvailable, GAPI.forbidden):
22915
- ClientAPIAccessDeniedExit()
22916
22972
  break
22917
22973
  Ind.Decrement()
22918
22974
 
@@ -23234,10 +23290,8 @@ def printShowUserPeopleContactGroups(users):
23234
23290
  throwReasons=GAPI.PEOPLE_ACCESS_THROW_REASONS,
23235
23291
  pageSize=GC.Values[GC.PEOPLE_MAX_RESULTS],
23236
23292
  groupFields=fields, fields='nextPageToken,contactGroups')
23237
- except GAPI.permissionDenied as e:
23293
+ except (GAPI.serviceNotAvailable, GAPI.forbidden, GAPI.permissionDenied) as e:
23238
23294
  ClientAPIAccessDeniedExit(str(e))
23239
- except (GAPI.serviceNotAvailable, GAPI.forbidden):
23240
- ClientAPIAccessDeniedExit()
23241
23295
  _printPersonEntityList(Ent.PEOPLE_CONTACT_GROUP, entityList, entityType, user, i, count, csvPF, FJQC, parameters, None)
23242
23296
  if csvPF:
23243
23297
  csvPF.writeCSVfile('People Contact Groups')
@@ -31782,15 +31836,18 @@ def getMobileDeviceEntity():
31782
31836
  printGettingAllAccountEntities(Ent.MOBILE_DEVICE, query)
31783
31837
  devices = callGAPIpages(cd.mobiledevices(), 'list', 'mobiledevices',
31784
31838
  pageMessage=getPageMessage(),
31785
- throwReasons=[GAPI.INVALID_INPUT, GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
31839
+ throwReasons=[GAPI.INVALID_INPUT, GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND,
31840
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
31786
31841
  customerId=GC.Values[GC.CUSTOMER_ID], query=query,
31787
31842
  fields='nextPageToken,mobiledevices(resourceId,email)')
31843
+ return ([{'resourceId': device['resourceId'], 'email': device.get('email', [])} for device in devices], cd, False)
31788
31844
  except GAPI.invalidInput:
31789
31845
  Cmd.Backup()
31790
31846
  usageErrorExit(Msg.INVALID_QUERY)
31791
- except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
31847
+ except (GAPI.badRequest, GAPI.resourceNotFound):
31792
31848
  accessErrorExit(cd)
31793
- return ([{'resourceId': device['resourceId'], 'email': device.get('email', [])} for device in devices], cd, False)
31849
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
31850
+ ClientAPIAccessDeniedExit(str(e))
31794
31851
 
31795
31852
  def _getUpdateDeleteMobileOptions(myarg, options):
31796
31853
  if myarg in {'matchusers', 'ifusers'}:
@@ -31843,14 +31900,17 @@ def doUpdateMobileDevices():
31843
31900
  callGAPI(cd.mobiledevices(), 'action',
31844
31901
  bailOnInternalError=True,
31845
31902
  throwReasons=[GAPI.INTERNAL_ERROR, GAPI.RESOURCE_ID_NOT_FOUND,
31846
- GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
31903
+ GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND,
31904
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
31847
31905
  customerId=GC.Values[GC.CUSTOMER_ID], resourceId=resourceId, body=body)
31848
31906
  printEntityKVList([Ent.MOBILE_DEVICE, resourceId, Ent.USER, deviceUser],
31849
31907
  [Msg.ACTION_APPLIED, body['action']], i, count)
31850
31908
  except GAPI.internalError:
31851
31909
  entityActionFailedWarning([Ent.MOBILE_DEVICE, resourceId], Msg.DOES_NOT_EXIST, i, count)
31852
- except (GAPI.resourceIdNotFound, GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden) as e:
31910
+ except (GAPI.resourceIdNotFound, GAPI.badRequest, GAPI.resourceNotFound) as e:
31853
31911
  entityActionFailedWarning([Ent.MOBILE_DEVICE, resourceId], str(e), i, count)
31912
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
31913
+ ClientAPIAccessDeniedExit(str(e))
31854
31914
 
31855
31915
  # gam delete mobile|mobiles <MobileDeviceEntity>
31856
31916
  # [doit] [matchusers <UserTypeEntity>]
@@ -31874,14 +31934,16 @@ def doDeleteMobileDevices():
31874
31934
  try:
31875
31935
  callGAPI(cd.mobiledevices(), 'delete',
31876
31936
  bailOnInternalError=True,
31877
- throwReasons=[GAPI.INTERNAL_ERROR, GAPI.RESOURCE_ID_NOT_FOUND, GAPI.BAD_REQUEST,
31878
- GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
31937
+ throwReasons=[GAPI.INTERNAL_ERROR, GAPI.RESOURCE_ID_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND,
31938
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
31879
31939
  customerId=GC.Values[GC.CUSTOMER_ID], resourceId=resourceId)
31880
31940
  entityActionPerformed([Ent.MOBILE_DEVICE, resourceId, Ent.USER, deviceUser], i, count)
31881
31941
  except GAPI.internalError:
31882
31942
  entityActionFailedWarning([Ent.MOBILE_DEVICE, resourceId], Msg.DOES_NOT_EXIST, i, count)
31883
- except (GAPI.resourceIdNotFound, GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden) as e:
31943
+ except (GAPI.resourceIdNotFound, GAPI.badRequest, GAPI.resourceNotFound) as e:
31884
31944
  entityActionFailedWarning([Ent.MOBILE_DEVICE, resourceId], str(e), i, count)
31945
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
31946
+ ClientAPIAccessDeniedExit(str(e))
31885
31947
 
31886
31948
  MOBILE_FIELDS_CHOICE_MAP = {
31887
31949
  'adbstatus': 'adbStatus',
@@ -31963,8 +32025,8 @@ def doInfoMobileDevices():
31963
32025
  try:
31964
32026
  mobile = callGAPI(cd.mobiledevices(), 'get',
31965
32027
  bailOnInternalError=True,
31966
- throwReasons=[GAPI.INTERNAL_ERROR, GAPI.RESOURCE_ID_NOT_FOUND,
31967
- GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
32028
+ throwReasons=[GAPI.INTERNAL_ERROR, GAPI.RESOURCE_ID_NOT_FOUND, GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND,
32029
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
31968
32030
  customerId=GC.Values[GC.CUSTOMER_ID], resourceId=resourceId, projection=parameters['projection'], fields=fields)
31969
32031
  if FJQC.formatJSON:
31970
32032
  printLine(json.dumps(cleanJSON(mobile, timeObjects=MOBILE_TIME_OBJECTS), ensure_ascii=False, sort_keys=True))
@@ -31981,8 +32043,10 @@ def doInfoMobileDevices():
31981
32043
  Ind.Decrement()
31982
32044
  except GAPI.internalError:
31983
32045
  entityActionFailedWarning([Ent.MOBILE_DEVICE, resourceId], Msg.DOES_NOT_EXIST, i, count)
31984
- except (GAPI.resourceIdNotFound, GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden) as e:
32046
+ except (GAPI.resourceIdNotFound, GAPI.badRequest, GAPI.resourceNotFound) as e:
31985
32047
  entityActionFailedWarning([Ent.MOBILE_DEVICE, resourceId], str(e), i, count)
32048
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
32049
+ ClientAPIAccessDeniedExit(str(e))
31986
32050
 
31987
32051
  MOBILE_ORDERBY_CHOICE_MAP = {
31988
32052
  'deviceid': 'deviceId',
@@ -32111,7 +32175,8 @@ def doPrintMobileDevices():
32111
32175
  try:
32112
32176
  feed = yieldGAPIpages(cd.mobiledevices(), 'list', 'mobiledevices',
32113
32177
  pageMessage=pageMessage,
32114
- throwReasons=[GAPI.INVALID_INPUT, GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
32178
+ throwReasons=[GAPI.INVALID_INPUT, GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND,
32179
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
32115
32180
  customerId=GC.Values[GC.CUSTOMER_ID], query=query, projection=parameters['projection'],
32116
32181
  orderBy=orderBy, sortOrder=sortOrder, fields=fields, maxResults=GC.Values[GC.MOBILE_MAX_RESULTS])
32117
32182
  for mobiles in feed:
@@ -32125,8 +32190,10 @@ def doPrintMobileDevices():
32125
32190
  except GAPI.invalidInput:
32126
32191
  entityActionFailedWarning([Ent.MOBILE_DEVICE, None], invalidQuery(query))
32127
32192
  return
32128
- except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
32193
+ except (GAPI.badRequest, GAPI.resourceNotFound):
32129
32194
  accessErrorExit(cd)
32195
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
32196
+ ClientAPIAccessDeniedExit(str(e))
32130
32197
  if showItemCountOnly:
32131
32198
  writeStdout(f'{itemCount}\n')
32132
32199
  return
@@ -36452,8 +36519,8 @@ def doPrintShowCIPolicies():
36452
36519
  sort_keys=True)})
36453
36520
 
36454
36521
  _checkPoliciesWithDASA()
36455
- groups_ci = buildGAPIObject(API.CLOUDIDENTITY_GROUPS)
36456
36522
  ci = buildGAPIObject(API.CLOUDIDENTITY_POLICY)
36523
+ groups_ci = buildGAPIObject(API.CLOUDIDENTITY_GROUPS)
36457
36524
  cd = buildGAPIObject(API.DIRECTORY)
36458
36525
  csvPF = CSVPrintFile(['name']) if Act.csvFormat() else None
36459
36526
  FJQC = FormatJSONQuoteChar(csvPF)
@@ -38464,10 +38531,13 @@ def doPrintShowResourceCalendars():
38464
38531
  try:
38465
38532
  resources = callGAPIpages(cd.resources().calendars(), 'list', 'items',
38466
38533
  pageMessage=getPageMessage(showFirstLastItems=True), messageAttribute='resourceName',
38467
- throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID_INPUT],
38534
+ throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN,
38535
+ GAPI.PERMISSION_DENIED, GAPI.INVALID_INPUT],
38468
38536
  query=query, customer=GC.Values[GC.CUSTOMER_ID], fields=fields)
38469
- except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
38537
+ except (GAPI.badRequest, GAPI.resourceNotFound):
38470
38538
  accessErrorExit(cd)
38539
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
38540
+ ClientAPIAccessDeniedExit(str(e))
38471
38541
  except GAPI.invalidInput as e:
38472
38542
  entityActionFailedWarning([Ent.RESOURCE_CALENDAR, ''], str(e))
38473
38543
  return
@@ -40706,7 +40776,8 @@ def doCreateUpdateUserSchemas():
40706
40776
  try:
40707
40777
  if updateCmd:
40708
40778
  oldBody = callGAPI(cd.schemas(), 'get',
40709
- throwReasons=[GAPI.INVALID, GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
40779
+ throwReasons=[GAPI.INVALID, GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND,
40780
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
40710
40781
  customerId=GC.Values[GC.CUSTOMER_ID], schemaKey=schemaName, fields='schemaName,displayName,fields')
40711
40782
  for field in oldBody['fields']:
40712
40783
  field.pop('etag', None)
@@ -40745,15 +40816,18 @@ def doCreateUpdateUserSchemas():
40745
40816
  addBody['schemaName'] = schemaName.replace(' ', '_')
40746
40817
  addBody['displayName'] = schemaDisplayName if schemaDisplayName else schemaName
40747
40818
  result = callGAPI(cd.schemas(), 'insert',
40748
- throwReasons=[GAPI.DUPLICATE, GAPI.CONDITION_NOT_MET, GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
40819
+ throwReasons=[GAPI.DUPLICATE, GAPI.CONDITION_NOT_MET, GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND,
40820
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
40749
40821
  customerId=GC.Values[GC.CUSTOMER_ID], body=addBody, fields='schemaName')
40750
40822
  entityActionPerformed([Ent.USER_SCHEMA, result['schemaName']], i, count)
40751
40823
  except GAPI.duplicate:
40752
40824
  entityDuplicateWarning([Ent.USER_SCHEMA, schemaName], i, count)
40753
- except (GAPI.conditionNotMet, GAPI.fieldInUse, GAPI.forbidden) as e:
40825
+ except (GAPI.conditionNotMet, GAPI.fieldInUse) as e:
40754
40826
  entityActionFailedWarning([Ent.USER_SCHEMA, schemaName], str(e), i, count)
40755
40827
  except (GAPI.badRequest, GAPI.resourceNotFound):
40756
40828
  checkEntityAFDNEorAccessErrorExit(cd, Ent.USER_SCHEMA, schemaName, i, count)
40829
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
40830
+ ClientAPIAccessDeniedExit(str(e))
40757
40831
 
40758
40832
  # gam delete schema|schemas <SchemaEntity>
40759
40833
  def doDeleteUserSchemas():
@@ -40766,13 +40840,16 @@ def doDeleteUserSchemas():
40766
40840
  i += 1
40767
40841
  try:
40768
40842
  callGAPI(cd.schemas(), 'delete',
40769
- throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN, GAPI.FIELD_IN_USE],
40843
+ throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FIELD_IN_USE,
40844
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
40770
40845
  customerId=GC.Values[GC.CUSTOMER_ID], schemaKey=schemaKey)
40771
40846
  entityActionPerformed([Ent.USER_SCHEMA, schemaKey], i, count)
40772
40847
  except GAPI.fieldInUse as e:
40773
40848
  entityActionFailedWarning([Ent.USER_SCHEMA, schemaKey], str(e), i, count)
40774
- except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
40849
+ except (GAPI.badRequest, GAPI.resourceNotFound):
40775
40850
  checkEntityAFDNEorAccessErrorExit(cd, Ent.USER_SCHEMA, schemaKey, i, count)
40851
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
40852
+ ClientAPIAccessDeniedExit(str(e))
40776
40853
 
40777
40854
  # gam info schema|schemas <SchemaEntity>
40778
40855
  def doInfoUserSchemas():
@@ -40785,11 +40862,14 @@ def doInfoUserSchemas():
40785
40862
  i += 1
40786
40863
  try:
40787
40864
  schema = callGAPI(cd.schemas(), 'get',
40788
- throwReasons=[GAPI.INVALID, GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
40865
+ throwReasons=[GAPI.INVALID, GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND,
40866
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
40789
40867
  customerId=GC.Values[GC.CUSTOMER_ID], schemaKey=schemaKey)
40790
40868
  _showSchema(schema, i, count)
40791
- except (GAPI.invalid, GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
40869
+ except (GAPI.invalid, GAPI.badRequest, GAPI.resourceNotFound):
40792
40870
  checkEntityAFDNEorAccessErrorExit(cd, Ent.USER_SCHEMA, schemaKey, i, count)
40871
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
40872
+ ClientAPIAccessDeniedExit(str(e))
40793
40873
 
40794
40874
  SCHEMAS_SORT_TITLES = ['schemaId', 'schemaName', 'displayName']
40795
40875
  SCHEMAS_INDEXED_TITLES = ['fields']
@@ -40802,7 +40882,8 @@ def doPrintShowUserSchemas():
40802
40882
  getTodriveOnly(csvPF)
40803
40883
  try:
40804
40884
  result = callGAPI(cd.schemas(), 'list',
40805
- throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
40885
+ throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND,
40886
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
40806
40887
  customerId=GC.Values[GC.CUSTOMER_ID])
40807
40888
  jcount = len(result.get('schemas', [])) if (result) else 0
40808
40889
  if not csvPF:
@@ -40820,8 +40901,10 @@ def doPrintShowUserSchemas():
40820
40901
  else:
40821
40902
  for schema in result['schemas']:
40822
40903
  csvPF.WriteRowTitles(flattenJSON(schema))
40823
- except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
40904
+ except (GAPI.badRequest, GAPI.resourceNotFound):
40824
40905
  accessErrorExit(cd)
40906
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
40907
+ ClientAPIAccessDeniedExit(str(e))
40825
40908
  if csvPF:
40826
40909
  csvPF.writeCSVfile('User Schemas')
40827
40910
 
@@ -41082,11 +41165,14 @@ def convertExportNameToID(v, nameOrId, matterId, matterNameId):
41082
41165
  if cg:
41083
41166
  try:
41084
41167
  export = callGAPI(v.matters().exports(), 'get',
41085
- throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
41168
+ throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN,
41169
+ GAPI.INVALID_ARGUMENT, GAPI.FAILED_PRECONDITION],
41086
41170
  matterId=matterId, exportId=cg.group(1))
41087
41171
  return (export['id'], export['name'], formatVaultNameId(export['id'], export['name']))
41088
41172
  except (GAPI.notFound, GAPI.badRequest):
41089
41173
  entityDoesNotHaveItemExit([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_EXPORT, nameOrId])
41174
+ except (GAPI.failedPrecondition) as e:
41175
+ entityActionFailedExit([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_EXPORT, nameOrId], str(e))
41090
41176
  except (GAPI.forbidden, GAPI.invalidArgument) as e:
41091
41177
  ClientAPIAccessDeniedExit(str(e))
41092
41178
  nameOrIdlower = nameOrId.lower()
@@ -41582,10 +41668,11 @@ def doInfoVaultExport():
41582
41668
  fields = getFieldsFromFieldsList(fieldsList)
41583
41669
  try:
41584
41670
  export = callGAPI(v.matters().exports(), 'get',
41585
- throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
41671
+ throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN,
41672
+ GAPI.INVALID_ARGUMENT, GAPI.FAILED_PRECONDITION],
41586
41673
  matterId=matterId, exportId=exportId, fields=fields)
41587
41674
  _showVaultExport(matterNameId, export, cd, FJQC)
41588
- except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument) as e:
41675
+ except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument, GAPI.failedPrecondition) as e:
41589
41676
  entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_EXPORT, exportNameId], str(e))
41590
41677
 
41591
41678
  VAULT_EXPORT_STATUS_MAP = {'completed': 'COMPLETED', 'failed': 'FAILED', 'inprogress': 'IN_PROGRESS'}
@@ -41778,9 +41865,10 @@ def doCopyVaultExport():
41778
41865
  while True:
41779
41866
  try:
41780
41867
  export = callGAPI(v.matters().exports(), 'get',
41781
- throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
41868
+ throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN,
41869
+ GAPI.INVALID_ARGUMENT, GAPI.FAILED_PRECONDITION],
41782
41870
  matterId=matterId, exportId=exportId)
41783
- except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument) as e:
41871
+ except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument, GAPI.failedPrecondition) as e:
41784
41872
  entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_EXPORT, exportNameId], str(e))
41785
41873
  return
41786
41874
  if export['status'] == 'COMPLETED':
@@ -41878,9 +41966,10 @@ def doDownloadVaultExport():
41878
41966
  while True:
41879
41967
  try:
41880
41968
  export = callGAPI(v.matters().exports(), 'get',
41881
- throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
41969
+ throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN,
41970
+ GAPI.INVALID_ARGUMENT, GAPI.FAILED_PRECONDITION],
41882
41971
  matterId=matterId, exportId=exportId)
41883
- except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument) as e:
41972
+ except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument, GAPI.failedPrecondition) as e:
41884
41973
  entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_EXPORT, exportNameId], str(e))
41885
41974
  return
41886
41975
  if export['status'] == 'COMPLETED':
@@ -44306,6 +44395,28 @@ def doUndeleteUsers():
44306
44395
  def doUndeleteUser():
44307
44396
  undeleteUsers(getStringReturnInList(Cmd.OB_USER_ITEM))
44308
44397
 
44398
+ # gam check suspended <UserItem>
44399
+ def doCheckUserSuspended():
44400
+ cd = buildGAPIObject(API.DIRECTORY)
44401
+ user = getEmailAddress()
44402
+ checkForExtraneousArguments()
44403
+ try:
44404
+ result = callGAPI(cd.users(), 'get',
44405
+ throwReasons=GAPI.USER_GET_THROW_REASONS,
44406
+ userKey=user, fields='suspended,suspensionReason', projection='basic')
44407
+ except (GAPI.userNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden):
44408
+ entityDoesNotExistExit(Ent.USER, user)
44409
+ except (GAPI.badRequest, GAPI.invalidCustomerId, GAPI.loginRequired):
44410
+ accessErrorExit(cd)
44411
+ kvList = [Ent.Singular(Ent.USER), user]
44412
+ up = 'suspended'
44413
+ kvList.extend([UProp.PROPERTIES[up][UProp.TITLE], result[up]])
44414
+ if result[up]:
44415
+ up = 'suspensionReason'
44416
+ kvList.extend([UProp.PROPERTIES[up][UProp.TITLE], result[up]])
44417
+ setSysExitRC(USER_SUSPENDED_RC)
44418
+ printKeyValueList(kvList)
44419
+
44309
44420
  # gam <UserTypeEntity> suspend users [noactionifalias]
44310
44421
  # gam <UserTypeEntity> unsuspend users [noactionifalias]
44311
44422
  def suspendUnsuspendUsers(entityList):
@@ -44359,13 +44470,13 @@ def signoutTurnoff2SVUsers(entityList):
44359
44470
  callGAPI(service, function,
44360
44471
  throwReasons=[GAPI.NOT_FOUND, GAPI.USER_NOT_FOUND, GAPI.INVALID, GAPI.INVALID_INPUT,
44361
44472
  GAPI.DOMAIN_NOT_FOUND, GAPI.DOMAIN_CANNOT_USE_APIS,
44362
- GAPI.FORBIDDEN, GAPI.AUTH_ERROR],
44473
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.AUTH_ERROR],
44363
44474
  userKey=user)
44364
44475
  entityActionPerformed([Ent.USER, user], i, count)
44365
44476
  except (GAPI.notFound, GAPI.userNotFound):
44366
44477
  entityUnknownWarning(Ent.USER, user, i, count)
44367
44478
  except (GAPI.invalid, GAPI.invalidInput, GAPI.domainNotFound, GAPI.domainCannotUseApis,
44368
- GAPI.forbidden, GAPI.authError) as e:
44479
+ GAPI.forbidden, GAPI.permissionDenied, GAPI.authError) as e:
44369
44480
  entityActionFailedWarning([Ent.USER, user], str(e), i, count)
44370
44481
 
44371
44482
  # gam <UserTypeEntity> waitformailbox [retries <Number>]
@@ -47229,10 +47340,7 @@ class CourseAttributes():
47229
47340
  newTopicsByName[topicName] = result['topicId']
47230
47341
  entityModifierItemValueListActionPerformed([Ent.COURSE, newCourseId, Ent.COURSE_TOPIC, topicName], Act.MODIFIER_FROM,
47231
47342
  [Ent.COURSE, self.courseId], j, jcount)
47232
- except GAPI.notFound as e:
47233
- entityActionFailedWarning([Ent.COURSE, newCourseId], str(e), i, count)
47234
- return
47235
- except (GAPI.failedPrecondition, GAPI.invalidArgument, GAPI.forbidden, GAPI.serviceNotAvailable) as e:
47343
+ except (GAPI.notFound, GAPI.failedPrecondition, GAPI.invalidArgument, GAPI.forbidden, GAPI.serviceNotAvailable) as e:
47236
47344
  entityModifierItemValueListActionFailedWarning([Ent.COURSE, newCourseId], Act.MODIFIER_FROM,
47237
47345
  [Ent.COURSE, self.courseId, Ent.COURSE_TOPIC, topicName], str(e), j, jcount)
47238
47346
  if self.courseAnnouncements:
@@ -47255,10 +47363,7 @@ class CourseAttributes():
47255
47363
  courseId=newCourseId, body=body, fields='id')
47256
47364
  entityModifierItemValueListActionPerformed([Ent.COURSE, newCourseId, Ent.COURSE_ANNOUNCEMENT_ID, result['id']], Act.MODIFIER_FROM,
47257
47365
  [Ent.COURSE, self.courseId, Ent.COURSE_ANNOUNCEMENT, courseAnnouncementId], j, jcount)
47258
- except GAPI.notFound as e:
47259
- entityActionFailedWarning([Ent.COURSE, newCourseId], str(e), i, count)
47260
- return
47261
- except (GAPI.badRequest, GAPI.failedPrecondition, GAPI.backendError, GAPI.internalError,
47366
+ except (GAPI.notFound, GAPI.badRequest, GAPI.failedPrecondition, GAPI.backendError, GAPI.internalError,
47262
47367
  GAPI.permissionDenied, GAPI.forbidden, GAPI.serviceNotAvailable) as e:
47263
47368
  entityModifierItemValueListActionFailedWarning([Ent.COURSE, newCourseId], Act.MODIFIER_FROM,
47264
47369
  [Ent.COURSE, self.courseId, Ent.COURSE_ANNOUNCEMENT, courseAnnouncementId], str(e), j, jcount)
@@ -47290,10 +47395,7 @@ class CourseAttributes():
47290
47395
  courseId=newCourseId, body=body, fields='id')
47291
47396
  entityModifierItemValueListActionPerformed([Ent.COURSE, newCourseId, Ent.COURSE_MATERIAL_ID, result['id']], Act.MODIFIER_FROM,
47292
47397
  [Ent.COURSE, self.courseId, Ent.COURSE_MATERIAL, courseMaterialId], j, jcount)
47293
- except GAPI.notFound as e:
47294
- entityActionFailedWarning([Ent.COURSE, newCourseId], str(e), i, count)
47295
- return
47296
- except (GAPI.badRequest, GAPI.failedPrecondition, GAPI.backendError, GAPI.internalError,
47398
+ except (GAPI.notFound, GAPI.badRequest, GAPI.failedPrecondition, GAPI.backendError, GAPI.internalError,
47297
47399
  GAPI.permissionDenied, GAPI.forbidden, GAPI.serviceNotAvailable) as e:
47298
47400
  entityModifierItemValueListActionFailedWarning([Ent.COURSE, newCourseId], Act.MODIFIER_FROM,
47299
47401
  [Ent.COURSE, self.courseId, Ent.COURSE_MATERIAL, courseMaterialId], str(e), j, jcount)
@@ -47330,10 +47432,7 @@ class CourseAttributes():
47330
47432
  courseId=newCourseId, body=body, fields='id')
47331
47433
  entityModifierItemValueListActionPerformed([Ent.COURSE, newCourseId, Ent.COURSE_WORK_ID, result['id']], Act.MODIFIER_FROM,
47332
47434
  [Ent.COURSE, self.courseId, Ent.COURSE_WORK, courseWorkId], j, jcount)
47333
- except GAPI.notFound as e:
47334
- entityActionFailedWarning([Ent.COURSE, newCourseId], str(e), i, count)
47335
- return
47336
- except (GAPI.badRequest, GAPI.failedPrecondition, GAPI.backendError, GAPI.internalError, GAPI.invalidArgument,
47435
+ except (GAPI.notFound, GAPI.badRequest, GAPI.failedPrecondition, GAPI.backendError, GAPI.internalError, GAPI.invalidArgument,
47337
47436
  GAPI.permissionDenied, GAPI.forbidden, GAPI.serviceNotAvailable) as e:
47338
47437
  entityModifierItemValueListActionFailedWarning([Ent.COURSE, newCourseId], Act.MODIFIER_FROM,
47339
47438
  [Ent.COURSE, self.courseId, Ent.COURSE_WORK, courseWorkId], str(e), j, jcount)
@@ -47688,7 +47787,8 @@ def _getCoursesOwnerInfo(croom, courseIds, useOwnerAccess, addCIIdScope=True):
47688
47787
  if courseId not in coursesInfo:
47689
47788
  try:
47690
47789
  course = callGAPI(croom.courses(), 'get',
47691
- throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.SERVICE_NOT_AVAILABLE],
47790
+ throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE,
47791
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
47692
47792
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
47693
47793
  id=courseId, fields='name,ownerId')
47694
47794
  if useOwnerAccess:
@@ -47699,10 +47799,10 @@ def _getCoursesOwnerInfo(croom, courseIds, useOwnerAccess, addCIIdScope=True):
47699
47799
  coursesInfo[ciCourseId] = {'name': course['name'], 'croom': ocroom}
47700
47800
  except GAPI.notFound:
47701
47801
  entityDoesNotExistWarning(Ent.COURSE, courseId)
47702
- except (GAPI.permissionDenied, GAPI.serviceNotAvailable) as e:
47802
+ except GAPI.serviceNotAvailable as e:
47703
47803
  entityActionFailedWarning([Ent.COURSE, courseId], str(e))
47704
- except GAPI.forbidden:
47705
- ClientAPIAccessDeniedExit()
47804
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
47805
+ ClientAPIAccessDeniedExit(str(e))
47706
47806
  return 0, len(coursesInfo), coursesInfo
47707
47807
 
47708
47808
  def _getCourseAliasesMembers(croom, ocroom, courseId, courseShowProperties, teachersFields, studentsFields, showGettings=False, i=0, count=0):
@@ -47718,13 +47818,14 @@ def _getCourseAliasesMembers(croom, ocroom, courseId, courseShowProperties, teac
47718
47818
  try:
47719
47819
  aliases = callGAPIpages(croom.courses().aliases(), 'list', 'aliases',
47720
47820
  pageMessage=pageMessage,
47721
- throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.SERVICE_NOT_AVAILABLE, GAPI.NOT_IMPLEMENTED],
47821
+ throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE, GAPI.NOT_IMPLEMENTED,
47822
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
47722
47823
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
47723
47824
  courseId=courseId, pageSize=GC.Values[GC.CLASSROOM_MAX_RESULTS])
47724
47825
  except (GAPI.notFound, GAPI.serviceNotAvailable, GAPI.notImplemented):
47725
47826
  pass
47726
- except GAPI.forbidden:
47727
- ClientAPIAccessDeniedExit()
47827
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
47828
+ ClientAPIAccessDeniedExit(str(e))
47728
47829
  if courseShowProperties['members'] != 'none':
47729
47830
  if courseShowProperties['members'] != 'students':
47730
47831
  if showGettings:
@@ -47733,13 +47834,14 @@ def _getCourseAliasesMembers(croom, ocroom, courseId, courseShowProperties, teac
47733
47834
  try:
47734
47835
  teachers = callGAPIpages(ocroom.courses().teachers(), 'list', 'teachers',
47735
47836
  pageMessage=pageMessage,
47736
- throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.SERVICE_NOT_AVAILABLE],
47837
+ throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE,
47838
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
47737
47839
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
47738
47840
  courseId=courseId, fields=teachersFields, pageSize=GC.Values[GC.CLASSROOM_MAX_RESULTS])
47739
47841
  except (GAPI.notFound, GAPI.serviceNotAvailable):
47740
47842
  pass
47741
- except GAPI.forbidden:
47742
- ClientAPIAccessDeniedExit()
47843
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
47844
+ ClientAPIAccessDeniedExit(str(e))
47743
47845
  if courseShowProperties['members'] != 'teachers':
47744
47846
  if showGettings:
47745
47847
  printGettingEntityItemForWhom(Ent.STUDENT, formatKeyValueList('', [Ent.Singular(Ent.COURSE), courseId], currentCount(i, count)))
@@ -47747,13 +47849,14 @@ def _getCourseAliasesMembers(croom, ocroom, courseId, courseShowProperties, teac
47747
47849
  try:
47748
47850
  students = callGAPIpages(ocroom.courses().students(), 'list', 'students',
47749
47851
  pageMessage=pageMessage,
47750
- throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.SERVICE_NOT_AVAILABLE],
47852
+ throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE,
47853
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
47751
47854
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
47752
47855
  courseId=courseId, fields=studentsFields, pageSize=GC.Values[GC.CLASSROOM_MAX_RESULTS])
47753
47856
  except (GAPI.notFound, GAPI.serviceNotAvailable):
47754
47857
  pass
47755
- except GAPI.forbidden:
47756
- ClientAPIAccessDeniedExit()
47858
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
47859
+ ClientAPIAccessDeniedExit(str(e))
47757
47860
  return (aliases, teachers, students)
47758
47861
 
47759
47862
  def _doInfoCourses(courseIdList):
@@ -47849,10 +47952,10 @@ def _doInfoCourses(courseIdList):
47849
47952
  Ind.Decrement()
47850
47953
  except GAPI.notFound:
47851
47954
  entityActionFailedWarning([Ent.COURSE, removeCourseIdScope(courseId)], Msg.DOES_NOT_EXIST, i, count)
47852
- except (GAPI.permissionDenied, GAPI.serviceNotAvailable) as e:
47955
+ except GAPI.serviceNotAvailable as e:
47853
47956
  entityActionFailedWarning([Ent.COURSE, removeCourseIdScope(courseId)], str(e), i, count)
47854
- except GAPI.forbidden:
47855
- ClientAPIAccessDeniedExit()
47957
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
47958
+ ClientAPIAccessDeniedExit(str(e))
47856
47959
 
47857
47960
  # gam info courses <CourseEntity> [owneraccess]
47858
47961
  # [owneremail] [alias|aliases] [show none|all|students|teachers] [countsonly]
@@ -47959,7 +48062,8 @@ def _getCoursesInfo(croom, courseSelectionParameters, courseShowProperties, getO
47959
48062
  courseId = addCourseIdScope(courseId)
47960
48063
  try:
47961
48064
  info = callGAPI(croom.courses(), 'get',
47962
- throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.SERVICE_NOT_AVAILABLE],
48065
+ throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE,
48066
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
47963
48067
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
47964
48068
  id=courseId, fields=fields)
47965
48069
  coursesInfo.append(info)
@@ -47967,8 +48071,8 @@ def _getCoursesInfo(croom, courseSelectionParameters, courseShowProperties, getO
47967
48071
  entityDoesNotExistWarning(Ent.COURSE, courseId)
47968
48072
  except GAPI.serviceNotAvailable as e:
47969
48073
  entityActionFailedWarning([Ent.COURSE, courseId], str(e))
47970
- except GAPI.forbidden:
47971
- ClientAPIAccessDeniedExit()
48074
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
48075
+ ClientAPIAccessDeniedExit(str(e))
47972
48076
  return coursesInfo
47973
48077
 
47974
48078
  # gam print courses [todrive <ToDriveAttribute>*] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
@@ -48931,43 +49035,73 @@ def doPrintCourseParticipants():
48931
49035
  csvPF.writeCSVfile('Course Participants')
48932
49036
 
48933
49037
  def _batchAddItemsToCourse(croom, courseId, i, count, addItems, addType):
49038
+ def _addIdToResponse(response, riItem):
49039
+ if addType == Ent.COURSE_ANNOUNCEMENT:
49040
+ respId = response.get('id', '')
49041
+ elif addType == Ent.COURSE_TOPIC:
49042
+ respId = response.get('topicId', '')
49043
+ else:
49044
+ respId = ''
49045
+ if respId:
49046
+ return riItem + f'({respId})'
49047
+ return riItem
49048
+
48934
49049
  _ADD_PART_REASON_TO_MESSAGE_MAP = {GAPI.NOT_FOUND: Msg.DOES_NOT_EXIST,
48935
49050
  GAPI.ALREADY_EXISTS: Msg.DUPLICATE,
48936
49051
  GAPI.FAILED_PRECONDITION: Msg.NOT_ALLOWED}
48937
- def _callbackAddItemsToCourse(request_id, _, exception):
49052
+ def _callbackAddItemsToCourse(request_id, response, exception):
48938
49053
  ri = request_id.splitlines()
49054
+ if addType == Ent.COURSE_ANNOUNCEMENT:
49055
+ mg = re.match(r"^{'text': '(.+)'}$", ri[RI_ITEM])
49056
+ if mg:
49057
+ riText = mg.group(1)
49058
+ else:
49059
+ riText = ''
49060
+ if len(riText) > 100:
49061
+ riItem = riText[0:100]+'...'
49062
+ else:
49063
+ riItem = riText
49064
+ else:
49065
+ riItem = ri[RI_ITEM]
48939
49066
  if exception is None:
48940
- entityActionPerformed([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], int(ri[RI_J]), int(ri[RI_JCOUNT]))
49067
+ riItem = _addIdToResponse(response, riItem)
49068
+ entityActionPerformed([Ent.COURSE, ri[RI_ENTITY], addType, riItem], int(ri[RI_J]), int(ri[RI_JCOUNT]))
48941
49069
  else:
48942
49070
  http_status, reason, message = checkGAPIError(exception)
48943
- if (reason not in {GAPI.QUOTA_EXCEEDED, GAPI.SERVICE_NOT_AVAILABLE}) and ((reason != GAPI.NOT_FOUND) or (ri[RI_ROLE] == Ent.COURSE_ALIAS)):
49071
+ if (reason not in {GAPI.QUOTA_EXCEEDED, GAPI.SERVICE_NOT_AVAILABLE}) and ((reason != GAPI.NOT_FOUND) or (addType == Ent.COURSE_ALIAS)):
48944
49072
  if reason in [GAPI.FORBIDDEN, GAPI.BACKEND_ERROR]:
48945
- errMsg = getPhraseDNEorSNA(ri[RI_ITEM])
49073
+ errMsg = getPhraseDNEorSNA(riItem)
48946
49074
  else:
48947
49075
  errMsg = getHTTPError(_ADD_PART_REASON_TO_MESSAGE_MAP, http_status, reason, message)
48948
- if (reason == GAPI.PERMISSION_DENIED) and (ri[RI_ROLE] in {Ent.STUDENT, Ent.TEACHER}) and ('CannotDirectAddUser' in errMsg):
48949
- errMsg += f' Add external user with: gam user {ri[RI_ITEM]} create classroominvitation courses {ri[RI_ENTITY]} addType {Ent.Singular(ri[RI_ROLE])}'
48950
- entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], errMsg, int(ri[RI_J]), int(ri[RI_JCOUNT]))
49076
+ if (reason == GAPI.PERMISSION_DENIED) and (addType in {Ent.STUDENT, Ent.TEACHER}) and ('CannotDirectAddUser' in errMsg):
49077
+ errMsg += f' Add external user with: gam user {riItem} create classroominvitation courses {ri[RI_ENTITY]} addType {Ent.Singular(addType)}'
49078
+ entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], addType, riItem], errMsg, int(ri[RI_J]), int(ri[RI_JCOUNT]))
48951
49079
  return
48952
49080
  waitOnFailure(1, 10, reason, message)
49081
+ if addType in {Ent.STUDENT, Ent.TEACHER, Ent.COURSE_TOPIC}:
49082
+ rbody = {attribute: riItem}
49083
+ elif addType == Ent.COURSE_ALIAS:
49084
+ rbody = {attribute: addCourseAliasScope(riItem)}
49085
+ else: # addType == Ent.COURSE_ANNOUNCEMENT:
49086
+ rbody = ri[RI_ITEM]
48953
49087
  try:
48954
- callGAPI(service, 'create',
48955
- throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.BACKEND_ERROR,
48956
- GAPI.ALREADY_EXISTS, GAPI.FAILED_PRECONDITION,
48957
- GAPI.QUOTA_EXCEEDED, GAPI.SERVICE_NOT_AVAILABLE],
48958
- retryReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE], triesLimit=0 if reason != GAPI.NOT_FOUND else 3,
48959
- courseId=addCourseIdScope(ri[RI_ENTITY]),
48960
- body={attribute: ri[RI_ITEM] if ri[RI_ROLE] != Ent.COURSE_ALIAS else addCourseAliasScope(ri[RI_ITEM])},
48961
- fields='')
49088
+ result = callGAPI(service, 'create',
49089
+ throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.BACKEND_ERROR,
49090
+ GAPI.ALREADY_EXISTS, GAPI.FAILED_PRECONDITION,
49091
+ GAPI.QUOTA_EXCEEDED, GAPI.SERVICE_NOT_AVAILABLE],
49092
+ retryReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE], triesLimit=0 if reason != GAPI.NOT_FOUND else 3,
49093
+ courseId=addCourseIdScope(ri[RI_ENTITY]), body=rbody, fields=returnFields)
49094
+ riItem = _addIdToResponse(result, riItem)
48962
49095
  except (GAPI.notFound, GAPI.backendError, GAPI.forbidden):
48963
- entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], getPhraseDNEorSNA(ri[RI_ITEM]), int(ri[RI_J]), int(ri[RI_JCOUNT]))
49096
+ entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], addType, riItem], getPhraseDNEorSNA(riItem), int(ri[RI_J]), int(ri[RI_JCOUNT]))
48964
49097
  except GAPI.alreadyExists:
48965
- entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], Msg.DUPLICATE, int(ri[RI_J]), int(ri[RI_JCOUNT]))
49098
+ entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], addType, riItem], Msg.DUPLICATE, int(ri[RI_J]), int(ri[RI_JCOUNT]))
48966
49099
  except GAPI.failedPrecondition:
48967
- entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], Msg.NOT_ALLOWED, int(ri[RI_J]), int(ri[RI_JCOUNT]))
49100
+ entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], addType, riItem], Msg.NOT_ALLOWED, int(ri[RI_J]), int(ri[RI_JCOUNT]))
48968
49101
  except (GAPI.quotaExceeded, GAPI.serviceNotAvailable) as e:
48969
- entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], str(e), int(ri[RI_J]), int(ri[RI_JCOUNT]))
49102
+ entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], addType, riItem], str(e), int(ri[RI_J]), int(ri[RI_JCOUNT]))
48970
49103
 
49104
+ returnFields = ''
48971
49105
  if addType == Ent.STUDENT:
48972
49106
  service = croom.courses().students()
48973
49107
  attribute = 'userId'
@@ -48980,16 +49114,18 @@ def _batchAddItemsToCourse(croom, courseId, i, count, addItems, addType):
48980
49114
  elif addType == Ent.COURSE_TOPIC:
48981
49115
  service = croom.courses().topics()
48982
49116
  attribute = 'name'
49117
+ returnFields = 'topicId'
48983
49118
  else: # addType == Ent.COURSE_ANNOUNCEMENT:
48984
49119
  service = croom.courses().announcements()
48985
49120
  attribute = 'text'
49121
+ returnFields = 'id'
48986
49122
  method = getattr(service, 'create')
48987
49123
  Act.Set(Act.ADD)
48988
49124
  jcount = len(addItems)
48989
49125
  noScopeCourseId = removeCourseIdScope(courseId)
48990
49126
  entityPerformActionNumItems([Ent.COURSE, noScopeCourseId], jcount, addType, i, count)
48991
49127
  Ind.Increment()
48992
- svcargs = dict([('courseId', courseId), ('body', {attribute: None}), ('fields', '')]+GM.Globals[GM.EXTRA_ARGS_LIST])
49128
+ svcargs = dict([('courseId', courseId), ('body', {attribute: None}), ('fields', returnFields)]+GM.Globals[GM.EXTRA_ARGS_LIST])
48993
49129
  dbatch = croom.new_batch_http_request(callback=_callbackAddItemsToCourse)
48994
49130
  bcount = 0
48995
49131
  j = 0
@@ -49021,34 +49157,37 @@ def _batchRemoveItemsFromCourse(croom, courseId, i, count, removeItems, removeTy
49021
49157
  GAPI.PERMISSION_DENIED: Msg.PERMISSION_DENIED}
49022
49158
  def _callbackRemoveItemsFromCourse(request_id, _, exception):
49023
49159
  ri = request_id.splitlines()
49160
+ riItem = ri[RI_ITEM]
49024
49161
  if exception is None:
49025
- entityActionPerformed([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], int(ri[RI_J]), int(ri[RI_JCOUNT]))
49162
+ entityActionPerformed([Ent.COURSE, ri[RI_ENTITY], removeType, riItem], int(ri[RI_J]), int(ri[RI_JCOUNT]))
49026
49163
  else:
49027
49164
  http_status, reason, message = checkGAPIError(exception)
49028
49165
  if reason not in {GAPI.QUOTA_EXCEEDED, GAPI.SERVICE_NOT_AVAILABLE}:
49029
- if reason == GAPI.NOT_FOUND and ri[RI_ROLE] != Ent.COURSE_ALIAS:
49030
- errMsg = f'{Msg.NOT_A} {Ent.Singular(ri[RI_ROLE])}'
49166
+ if reason == GAPI.NOT_FOUND and removeType != Ent.COURSE_ALIAS:
49167
+ errMsg = f'{Msg.NOT_A} {Ent.Singular(removeType)}'
49031
49168
  else:
49032
49169
  errMsg = getHTTPError(_REMOVE_PART_REASON_TO_MESSAGE_MAP, http_status, reason, message)
49033
- entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], errMsg, int(ri[RI_J]), int(ri[RI_JCOUNT]))
49170
+ entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], removeType, riItem], errMsg, int(ri[RI_J]), int(ri[RI_JCOUNT]))
49034
49171
  return
49035
49172
  waitOnFailure(1, 10, reason, message)
49173
+ if removeType in {Ent.STUDENT, Ent.TEACHER, Ent.COURSE_TOPIC, Ent.COURSE_ANNOUNCEMENT}:
49174
+ rbody = {attribute: riItem}
49175
+ else: # removeType == Ent.COURSE_ALIAS:
49176
+ rbody = {attribute: addCourseAliasScope(riItem)}
49036
49177
  try:
49037
49178
  callGAPI(service, 'delete',
49038
49179
  throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED,
49039
49180
  GAPI.QUOTA_EXCEEDED, GAPI.SERVICE_NOT_AVAILABLE, GAPI.FAILED_PRECONDITION],
49040
49181
  retryReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE], triesLimit=0 if reason != GAPI.NOT_FOUND else 3,
49041
- courseId=addCourseIdScope(ri[RI_ENTITY]),
49042
- body={attribute: ri[RI_ITEM] if ri[RI_ROLE] != Ent.COURSE_ALIAS else addCourseAliasScope(ri[RI_ITEM])},
49043
- fields='')
49182
+ courseId=addCourseIdScope(ri[RI_ENTITY]), body=rbody, fields='')
49044
49183
  except GAPI.notFound:
49045
- entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], Msg.DOES_NOT_EXIST, int(ri[RI_J]), int(ri[RI_JCOUNT]))
49184
+ entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], removeType, riItem], Msg.DOES_NOT_EXIST, int(ri[RI_J]), int(ri[RI_JCOUNT]))
49046
49185
  except GAPI.forbidden:
49047
- entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], Msg.FORBIDDEN, int(ri[RI_J]), int(ri[RI_JCOUNT]))
49186
+ entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], removeType, riItem], Msg.FORBIDDEN, int(ri[RI_J]), int(ri[RI_JCOUNT]))
49048
49187
  except GAPI.permissionDenied:
49049
- entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], Msg.PERMISSION_DENIED, int(ri[RI_J]), int(ri[RI_JCOUNT]))
49188
+ entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], removeType, riItem], Msg.PERMISSION_DENIED, int(ri[RI_J]), int(ri[RI_JCOUNT]))
49050
49189
  except (GAPI.quotaExceeded, GAPI.serviceNotAvailable, GAPI.failedPrecondition) as e:
49051
- entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], ri[RI_ROLE], ri[RI_ITEM]], str(e), int(ri[RI_J]), int(ri[RI_JCOUNT]))
49190
+ entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], removeType, riItem], str(e), int(ri[RI_J]), int(ri[RI_JCOUNT]))
49052
49191
 
49053
49192
  if removeType == Ent.STUDENT:
49054
49193
  service = croom.courses().students()
@@ -49121,8 +49260,8 @@ def getCourseAnnouncement(createCmd):
49121
49260
  body = {}
49122
49261
  while Cmd.ArgumentsRemaining():
49123
49262
  myarg = getArgument()
49124
- if myarg == 'text':
49125
- body['text'] = getString(Cmd.OB_STRING, minLen=1, maxLen=30000)
49263
+ if myarg in SORF_TEXT_ARGUMENTS:
49264
+ body['text'] = getStringOrFile(myarg, minLen=1, unescapeCRLF=True)[0]
49126
49265
  elif myarg == 'scheduledtime':
49127
49266
  body['scheduledTime'] = getTimeOrDeltaFromNow()
49128
49267
  elif myarg == 'state':
@@ -49160,9 +49299,9 @@ PARTICIPANT_EN_MAP = {
49160
49299
  # gam courses <CourseEntity> create alias <CourseAliasEntity>
49161
49300
  # gam course <CourseID> create alias <CourseAlias>
49162
49301
  # gam courses <CourseEntity> create announcement
49163
- # text <String> [scheduledtime <Time>] [state draft|published]
49302
+ # <CourseAnnouncementContent> [scheduledtime <Time>] [state draft|published]
49164
49303
  # gam course <CourseID> create announcement
49165
- # text <String> [scheduledtime <Time>] [state draft|published]
49304
+ # <CourseAnnouncementContent> [scheduledtime <Time>] [state draft|published]
49166
49305
  # gam courses <CourseEntity> create topic <CourseTopicEntity>
49167
49306
  # gam course <CourseID> create topic <CourseTopic>
49168
49307
  # gam courses <CourseEntity> create students <UserTypeEntity>
@@ -49270,9 +49409,9 @@ def doCourseRemoveItems(courseIdList, getEntityListArg):
49270
49409
  _batchRemoveItemsFromCourse(courseInfo['croom'], courseId, i, count, removeItems, removeType)
49271
49410
 
49272
49411
  # gam courses <CourseEntity> update announcement <CourseAnnouncemntIDEntity>
49273
- # [text <String>] [scheduledtime <Time>] [state published]
49412
+ # [<CourseAnnouncementContent>] [scheduledtime <Time>] [state published]
49274
49413
  # gam course <CourseID> update announcement <CourseAnnouncementID>
49275
- # [text <String>] [scheduledtime <Time>] [state published]
49414
+ # [<CourseAnnouncementContent>] [scheduledtime <Time>] [state published]
49276
49415
  # gam courses <CourseEntity> update topic <CourseTopicIDEntity> <CourseTopic>
49277
49416
  # gam course <CourseID> update topic <CourseTopicID> <CourseTopic>
49278
49417
  def doCourseUpdateItems(courseIdList, getEntityListArg):
@@ -49520,7 +49659,8 @@ def _cancelGuardianInvitation(croom, studentId, invitationId, i=0, count=0, j=0,
49520
49659
  entityActionFailedWarning([Ent.STUDENT, studentId, Ent.GUARDIAN_INVITATION, invitationId], str(e), j, jcount)
49521
49660
  return -1
49522
49661
  except (GAPI.forbidden, GAPI.permissionDenied) as e:
49523
- studentUnknownWarning(studentId, str(e), i, count)
49662
+ ClientAPIAccessDeniedExit(str(e))
49663
+ # studentUnknownWarning(studentId, str(e), i, count)
49524
49664
  return -1
49525
49665
 
49526
49666
  # gam cancel guardianinvitation|guardianinvitations <GuardianInvitationID> <StudentItem>
@@ -49565,7 +49705,8 @@ def _deleteGuardian(croom, studentId, guardianId, guardianEmail, i, count, j, jc
49565
49705
  entityActionFailedWarning([Ent.STUDENT, studentId, Ent.GUARDIAN, guardianEmail], str(e), j, jcount)
49566
49706
  return -1
49567
49707
  except (GAPI.forbidden, GAPI.permissionDenied) as e:
49568
- studentUnknownWarning(studentId, str(e), i, count)
49708
+ ClientAPIAccessDeniedExit(str(e))
49709
+ # studentUnknownWarning(studentId, str(e), i, count)
49569
49710
  return -1
49570
49711
 
49571
49712
  def _doDeleteGuardian(croom, studentId, guardianId, guardianClass, i=0, count=0, j=0, jcount=0):
@@ -52675,7 +52816,8 @@ def doSharedDriveSearch(drive, user, i, count, query, useDomainAdminAccess):
52675
52816
  pageMessage=getPageMessageForWhom(),
52676
52817
  throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.INVALID_QUERY, GAPI.INVALID,
52677
52818
  GAPI.QUERY_REQUIRES_ADMIN_CREDENTIALS,
52678
- GAPI.NO_LIST_TEAMDRIVES_ADMINISTRATOR_PRIVILEGE],
52819
+ GAPI.NO_LIST_TEAMDRIVES_ADMINISTRATOR_PRIVILEGE,
52820
+ GAPI.INSUFFICIENT_ADMINISTRATOR_PRIVILEGES],
52679
52821
  q=query, useDomainAdminAccess=useDomainAdminAccess,
52680
52822
  fields='nextPageToken,drives(id)', pageSize=100)
52681
52823
  if files:
@@ -52683,7 +52825,7 @@ def doSharedDriveSearch(drive, user, i, count, query, useDomainAdminAccess):
52683
52825
  entityActionNotPerformedWarning([Ent.USER, user, Ent.DRIVE_FILE, None], emptyQuery(query, Ent.SHAREDDRIVE), i, count)
52684
52826
  except (GAPI.invalidQuery, GAPI.invalid):
52685
52827
  entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE, None], invalidQuery(query), i, count)
52686
- except (GAPI.queryRequiresAdminCredentials, GAPI.noListTeamDrivesAdministratorPrivilege) as e:
52828
+ except (GAPI.queryRequiresAdminCredentials, GAPI.noListTeamDrivesAdministratorPrivilege, GAPI.insufficientAdministratorPrivileges) as e:
52687
52829
  entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE, None], str(e), i, count)
52688
52830
  except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
52689
52831
  userDriveServiceNotEnabledWarning(user, str(e), i, count)
@@ -52986,7 +53128,11 @@ def _convertSharedDriveNameToId(drive, user, i, count, fileIdEntity, useDomainAd
52986
53128
  else:
52987
53129
  name = fileIdEntity['shareddrivename'].replace("'", "\\'")
52988
53130
  tdlist = callGAPIpages(drive.drives(), 'list', 'drives',
52989
- throwReasons=GAPI.DRIVE_USER_THROW_REASONS,
53131
+ throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.INVALID_QUERY, GAPI.INVALID,
53132
+ GAPI.QUERY_REQUIRES_ADMIN_CREDENTIALS,
53133
+ GAPI.NO_LIST_TEAMDRIVES_ADMINISTRATOR_PRIVILEGE,
53134
+ GAPI.INSUFFICIENT_ADMINISTRATOR_PRIVILEGES,
53135
+ GAPI.FILE_NOT_FOUND],
52990
53136
  useDomainAdminAccess=useDomainAdminAccess,
52991
53137
  q=f"name='{name}'",
52992
53138
  fields='nextPageToken,drives(id,name)', pageSize=100)
@@ -52995,13 +53141,19 @@ def _convertSharedDriveNameToId(drive, user, i, count, fileIdEntity, useDomainAd
52995
53141
  if not tdlist:
52996
53142
  name = fileIdEntity['shareddrivename'].lower()
52997
53143
  feed = callGAPIpages(drive.drives(), 'list', 'drives',
52998
- throwReasons=GAPI.DRIVE_USER_THROW_REASONS,
53144
+ throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.NO_LIST_TEAMDRIVES_ADMINISTRATOR_PRIVILEGE,
53145
+ GAPI.INSUFFICIENT_ADMINISTRATOR_PRIVILEGES],
52999
53146
  useDomainAdminAccess=useDomainAdminAccess,
53000
53147
  fields='nextPageToken,drives(id,name)', pageSize=100)
53001
53148
  tdlist = [td for td in feed if td['name'].lower() == name]
53002
53149
  except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy):
53003
53150
  entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE_NAME, fileIdEntity['shareddrivename']], Msg.DOES_NOT_EXIST, i, count)
53004
53151
  return False
53152
+ except (GAPI.invalidQuery, GAPI.invalid, GAPI.queryRequiresAdminCredentials,
53153
+ GAPI.noListTeamDrivesAdministratorPrivilege, GAPI.insufficientAdministratorPrivileges,
53154
+ GAPI.fileNotFound) as e:
53155
+ entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE_NAME, fileIdEntity['shareddrivename']], str(e), i, count)
53156
+ return False
53005
53157
  jcount = len(tdlist)
53006
53158
  if jcount == 1:
53007
53159
  fileIdEntity['shareddrive']['driveId'] = tdlist[0]['id']
@@ -53019,10 +53171,10 @@ def _getSharedDriveNameFromId(drive, sharedDriveId, useDomainAdminAccess=False):
53019
53171
  if not sharedDriveName:
53020
53172
  try:
53021
53173
  sharedDriveName = callGAPI(drive.drives(), 'get',
53022
- throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.NOT_FOUND],
53174
+ throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.FILE_NOT_FOUND, GAPI.NOT_FOUND],
53023
53175
  useDomainAdminAccess=useDomainAdminAccess,
53024
53176
  driveId=sharedDriveId, fields='name')['name']
53025
- except (GAPI.notFound, GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy):
53177
+ except (GAPI.fileNotFound, GAPI.notFound, GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy):
53026
53178
  sharedDriveName = TEAM_DRIVE
53027
53179
  GM.Globals[GM.MAP_SHAREDDRIVE_ID_TO_NAME][sharedDriveId] = sharedDriveName
53028
53180
  return sharedDriveName
@@ -53043,7 +53195,7 @@ def _getDriveFileNameFromId(drive, fileId, combineTitleId=True, useDomainAdminAc
53043
53195
  if useDomainAdminAccess:
53044
53196
  try:
53045
53197
  result = callGAPI(drive.drives(), 'get',
53046
- throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.NOT_FOUND],
53198
+ throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.FILE_NOT_FOUND, GAPI.NOT_FOUND],
53047
53199
  useDomainAdminAccess=useDomainAdminAccess,
53048
53200
  driveId=fileId, fields='name')
53049
53201
  if result:
@@ -53051,7 +53203,7 @@ def _getDriveFileNameFromId(drive, fileId, combineTitleId=True, useDomainAdminAc
53051
53203
  if combineTitleId:
53052
53204
  fileName += '('+fileId+')'
53053
53205
  return (fileName, Ent.DRIVE_FOLDER, MIMETYPE_GA_FOLDER)
53054
- except GAPI.notFound:
53206
+ except (GAPI.fileNotFound, GAPI.notFound):
53055
53207
  pass
53056
53208
  except (GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.internalError,
53057
53209
  GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy):
@@ -53217,7 +53369,7 @@ def _getDriveFileParentInfo(drive, user, i, count, body, parameters, emptyQueryO
53217
53369
  _setSearchArgs(result['driveId'])
53218
53370
  else:
53219
53371
  result = callGAPI(drive.drives(), 'get',
53220
- throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.NOT_FOUND],
53372
+ throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.FILE_NOT_FOUND, GAPI.NOT_FOUND],
53221
53373
  driveId=parameters[DFA_SHAREDDRIVE_PARENTID], fields='id')
53222
53374
  parameters[DFA_KWARGS]['corpora'] = 'drive'
53223
53375
  parameters[DFA_KWARGS]['driveId'] = result['id']
@@ -54427,6 +54579,7 @@ DRIVE_CAPABILITIES_SUBFIELDS_CHOICE_MAP = {
54427
54579
  'canaddmydriveparent': 'canAddMyDriveParent',
54428
54580
  'canchangecopyrequireswriterpermission': 'canChangeCopyRequiresWriterPermission',
54429
54581
  'canchangecopyrequireswriterpermissionrestriction': 'canChangeCopyRequiresWriterPermissionRestriction',
54582
+ 'canchangedownloadrestriction': 'canChangeDownloadRestriction',
54430
54583
  'canchangedomainusersonlyrestriction': 'canChangeDomainUsersOnlyRestriction',
54431
54584
  'canchangedrivebackground': 'canChangeDriveBackground',
54432
54585
  'canchangedrivemembersonlyrestriction': 'canChangeDriveMembersOnlyRestriction',
@@ -55443,7 +55596,7 @@ def initFileTree(drive, shareddrive, DLP, shareddriveFields, showParent, user, i
55443
55596
  f_file['parents'] = []
55444
55597
  fileTree[f_file['id']] = {'info': f_file, 'noParents': True, 'children': []}
55445
55598
  name = callGAPI(drive.drives(), 'get',
55446
- throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.NOT_FOUND],
55599
+ throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.FILE_NOT_FOUND, GAPI.NOT_FOUND],
55447
55600
  driveId=fileId, fields='name')['name']
55448
55601
  fileTree[f_file['id']]['info']['name'] = f'{SHARED_DRIVES}/{name}'
55449
55602
  else:
@@ -56629,12 +56782,12 @@ def printFileList(users):
56629
56782
  rootFolderId = fileIdEntity['shareddrive']['driveId']
56630
56783
  if not fileIdEntity['shareddrivename']:
56631
56784
  fileIdEntity['shareddrivename'] = callGAPI(drive.drives(), 'get',
56632
- throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.FILE_NOT_FOUND],
56785
+ throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.FILE_NOT_FOUND, GAPI.NOT_FOUND],
56633
56786
  driveId=rootFolderId, fields='name')['name']
56634
56787
  rootFolderName = fileIdEntity['shareddrivename']
56635
56788
  if not showParentsIdsAsList and DFF.parentsSubFields['isRoot']:
56636
56789
  DFF.parentsSubFields['rootFolderId'] = rootFolderId
56637
- except (GAPI.notFound, GAPI.fileNotFound) as e:
56790
+ except (GAPI.fileNotFound, GAPI.notFound) as e:
56638
56791
  entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE_ID, fileIdEntity['shareddrive']['driveId']], str(e), i, count)
56639
56792
  continue
56640
56793
  except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
@@ -65496,6 +65649,8 @@ SHAREDDRIVE_RESTRICTIONS_MAP = {
65496
65649
  'allowcontentmanagerstosharefolders': 'sharingFoldersRequiresOrganizerPermission',
65497
65650
  'copyrequireswriterpermission': 'copyRequiresWriterPermission',
65498
65651
  'domainusersonly': 'domainUsersOnly',
65652
+ 'downloadrestrictedforreaders': 'restrictedForReaders',
65653
+ 'downloadrestrictedforwriters': 'restrictedForWriters',
65499
65654
  'drivemembersonly': 'driveMembersOnly',
65500
65655
  'sharingfoldersrequiresorganizerpermission': 'sharingFoldersRequiresOrganizerPermission',
65501
65656
  'teammembersonly': 'driveMembersOnly',
@@ -65504,7 +65659,10 @@ SHAREDDRIVE_RESTRICTIONS_MAP = {
65504
65659
  def _getSharedDriveRestrictions(myarg, body):
65505
65660
  def _setRestriction(restriction):
65506
65661
  body.setdefault('restrictions', {})
65507
- if restriction != 'allowcontentmanagerstosharefolders':
65662
+ if restriction in {'downloadrestrictedforreaders', 'downloadrestrictedforwriters'}:
65663
+ body['restrictions'].setdefault('downloadRestriction', {})
65664
+ body['restrictions']['downloadRestriction'][SHAREDDRIVE_RESTRICTIONS_MAP[restriction]] = getBoolean()
65665
+ elif restriction != 'allowcontentmanagerstosharefolders':
65508
65666
  body['restrictions'][SHAREDDRIVE_RESTRICTIONS_MAP[restriction]] = getBoolean()
65509
65667
  else:
65510
65668
  body['restrictions'][SHAREDDRIVE_RESTRICTIONS_MAP[restriction]] = not getBoolean()
@@ -65657,12 +65815,12 @@ def createSharedDrive(users, useDomainAdminAccess=False):
65657
65815
  while not created:
65658
65816
  try:
65659
65817
  callGAPI(drive.drives(), 'get',
65660
- throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.NOT_FOUND],
65818
+ throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.FILE_NOT_FOUND, GAPI.NOT_FOUND],
65661
65819
  useDomainAdminAccess=useDomainAdminAccess,
65662
65820
  driveId=driveId, fields='id')
65663
65821
  created = True
65664
65822
  break
65665
- except GAPI.notFound as e:
65823
+ except (GAPI.fileNotFound, GAPI.notFound) as e:
65666
65824
  retry += 1
65667
65825
  if retry > errorRetries:
65668
65826
  entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE_ID, driveId], str(e), i, count)
@@ -65678,6 +65836,7 @@ def createSharedDrive(users, useDomainAdminAccess=False):
65678
65836
  bailOnInternalError=True,
65679
65837
  throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.FORBIDDEN,
65680
65838
  GAPI.NO_MANAGE_TEAMDRIVE_ADMINISTRATOR_PRIVILEGE,
65839
+ GAPI.OUTSIDE_DOMAIN_MEMBER_CANNOT_CHANGE_TEAMDRIVE_RESTRICTIONS,
65681
65840
  GAPI.BAD_REQUEST, GAPI.INTERNAL_ERROR, GAPI.PERMISSION_DENIED,
65682
65841
  GAPI.FILE_NOT_FOUND],
65683
65842
  useDomainAdminAccess=useDomainAdminAccess, driveId=driveId, body=updateBody)
@@ -65697,7 +65856,8 @@ def createSharedDrive(users, useDomainAdminAccess=False):
65697
65856
  if orgUnit:
65698
65857
  waitingForCreationToComplete(moveToOrgUnitDelay)
65699
65858
  ci = _moveSharedDriveToOU(orgUnit, orgUnitId, driveId, user, i, count, ci, returnIdOnly or csvPF)
65700
- except (GAPI.notFound, GAPI.forbidden, GAPI.badRequest, GAPI.noManageTeamDriveAdministratorPrivilege) as e:
65859
+ except (GAPI.notFound, GAPI.forbidden, GAPI.badRequest,
65860
+ GAPI.noManageTeamDriveAdministratorPrivilege, GAPI.outsideDomainMemberCannotChangeTeamDriveRestrictions) as e:
65701
65861
  entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE_ID, driveId], str(e), i, count)
65702
65862
  except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
65703
65863
  userDriveServiceNotEnabledWarning(user, str(e), i, count)
@@ -65752,6 +65912,7 @@ def updateSharedDrive(users, useDomainAdminAccess=False):
65752
65912
  bailOnInternalError=True,
65753
65913
  throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.BAD_REQUEST,
65754
65914
  GAPI.NO_MANAGE_TEAMDRIVE_ADMINISTRATOR_PRIVILEGE,
65915
+ GAPI.OUTSIDE_DOMAIN_MEMBER_CANNOT_CHANGE_TEAMDRIVE_RESTRICTIONS,
65755
65916
  GAPI.INTERNAL_ERROR, GAPI.FILE_NOT_FOUND],
65756
65917
  useDomainAdminAccess=useDomainAdminAccess, driveId=driveId, body=body, fields='name')
65757
65918
  entityActionPerformed([Ent.USER, user, Ent.SHAREDDRIVE_NAME, result['name'], Ent.SHAREDDRIVE_ID, driveId], i, count)
@@ -65769,7 +65930,7 @@ def updateSharedDrive(users, useDomainAdminAccess=False):
65769
65930
  if orgUnit:
65770
65931
  ci = _moveSharedDriveToOU(orgUnit, orgUnitId, driveId, user, i, count, ci, False)
65771
65932
  except (GAPI.notFound, GAPI.forbidden, GAPI.badRequest, GAPI.internalError,
65772
- GAPI.noManageTeamDriveAdministratorPrivilege) as e:
65933
+ GAPI.noManageTeamDriveAdministratorPrivilege, GAPI.outsideDomainMemberCannotChangeTeamDriveRestrictions) as e:
65773
65934
  entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE_ID, driveId], str(e), i, count)
65774
65935
  except GAPI.fileNotFound as e:
65775
65936
  entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE_ID, driveId,
@@ -65898,14 +66059,6 @@ def _getSharedDriveRole(shareddrive):
65898
66059
  return role
65899
66060
 
65900
66061
  def _showSharedDrive(user, shareddrive, j, jcount, FJQC):
65901
- def _showCapabilitiesRestrictions(field):
65902
- if field in shareddrive:
65903
- printKeyValueList([field, ''])
65904
- Ind.Increment()
65905
- for capability in sorted(shareddrive[field]):
65906
- printKeyValueList([capability, shareddrive[field][capability]])
65907
- Ind.Decrement()
65908
-
65909
66062
  if FJQC.formatJSON:
65910
66063
  printLine(json.dumps(cleanJSON(shareddrive, timeObjects=SHAREDDRIVE_TIME_OBJECTS), ensure_ascii=False, sort_keys=True))
65911
66064
  return
@@ -65922,8 +66075,9 @@ def _showSharedDrive(user, shareddrive, j, jcount, FJQC):
65922
66075
  printKeyValueList([setting, shareddrive[setting]])
65923
66076
  if 'role' in shareddrive:
65924
66077
  printKeyValueList(['role', shareddrive['role']])
65925
- _showCapabilitiesRestrictions('capabilities')
65926
- _showCapabilitiesRestrictions('restrictions')
66078
+ for setting in ['capabilities', 'restrictions']:
66079
+ if setting in shareddrive:
66080
+ showJSON(setting, shareddrive[setting])
65927
66081
  Ind.Decrement()
65928
66082
 
65929
66083
  # gam <UserTypeEntity> info shareddrive <SharedDriveEntity>
@@ -65955,14 +66109,14 @@ def infoSharedDrive(users, useDomainAdminAccess=False):
65955
66109
  try:
65956
66110
  driveId = fileIdEntity['shareddrive']['driveId']
65957
66111
  shareddrive = callGAPI(drive.drives(), 'get',
65958
- throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.NOT_FOUND],
66112
+ throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.FILE_NOT_FOUND, GAPI.NOT_FOUND],
65959
66113
  useDomainAdminAccess=useDomainAdminAccess,
65960
66114
  driveId=driveId, fields=fields)
65961
66115
  role = _getSharedDriveRole(shareddrive)
65962
66116
  if role:
65963
66117
  shareddrive['role'] = role if not guiRoles else SHAREDDRIVE_API_GUI_ROLES_MAP[role]
65964
66118
  _showSharedDrive(user, shareddrive, i, count, FJQC)
65965
- except GAPI.notFound as e:
66119
+ except (GAPI.fileNotFound, GAPI.notFound) as e:
65966
66120
  entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE_ID, driveId], str(e), i, count)
65967
66121
  except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
65968
66122
  userDriveServiceNotEnabledWarning(user, str(e), i, count)
@@ -66116,11 +66270,13 @@ def printShowSharedDrives(users, useDomainAdminAccess=False):
66116
66270
  throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.INVALID_QUERY, GAPI.INVALID,
66117
66271
  GAPI.QUERY_REQUIRES_ADMIN_CREDENTIALS,
66118
66272
  GAPI.NO_LIST_TEAMDRIVES_ADMINISTRATOR_PRIVILEGE,
66273
+ GAPI.INSUFFICIENT_ADMINISTRATOR_PRIVILEGES,
66119
66274
  GAPI.FILE_NOT_FOUND],
66120
66275
  q=query, useDomainAdminAccess=useDomainAdminAccess,
66121
66276
  fields='*', pageSize=100)
66122
66277
  except (GAPI.invalidQuery, GAPI.invalid, GAPI.queryRequiresAdminCredentials,
66123
- GAPI.noListTeamDrivesAdministratorPrivilege, GAPI.fileNotFound) as e:
66278
+ GAPI.noListTeamDrivesAdministratorPrivilege, GAPI.insufficientAdministratorPrivileges,
66279
+ GAPI.fileNotFound) as e:
66124
66280
  entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE, None], str(e), i, count)
66125
66281
  continue
66126
66282
  except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
@@ -66455,8 +66611,10 @@ def printShowSharedDriveACLs(users, useDomainAdminAccess=False):
66455
66611
  if userdrive is not None:
66456
66612
  try:
66457
66613
  feed = callGAPIpages(userdrive.drives(), 'list', 'drives',
66458
- throwReasons=GAPI.DRIVE_USER_THROW_REASONS,
66614
+ throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.INVALID, GAPI.NO_LIST_TEAMDRIVES_ADMINISTRATOR_PRIVILEGE],
66459
66615
  fields='nextPageToken,drives(id,name,createdTime,orgUnitId)', pageSize=100)
66616
+ except (GAPI.invalid, GAPI.noListTeamDrivesAdministratorPrivilege):
66617
+ pass
66460
66618
  except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy):
66461
66619
  pass
66462
66620
  if feed is None:
@@ -66471,10 +66629,12 @@ def printShowSharedDriveACLs(users, useDomainAdminAccess=False):
66471
66629
  pageMessage=pageMessage,
66472
66630
  throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.INVALID_QUERY, GAPI.INVALID,
66473
66631
  GAPI.QUERY_REQUIRES_ADMIN_CREDENTIALS,
66474
- GAPI.NO_LIST_TEAMDRIVES_ADMINISTRATOR_PRIVILEGE],
66632
+ GAPI.NO_LIST_TEAMDRIVES_ADMINISTRATOR_PRIVILEGE,
66633
+ GAPI.INSUFFICIENT_ADMINISTRATOR_PRIVILEGES],
66475
66634
  q=query, useDomainAdminAccess=useDomainAdminAccess,
66476
66635
  fields='nextPageToken,drives(id,name,createdTime,orgUnitId)', pageSize=100)
66477
- except (GAPI.invalidQuery, GAPI.invalid, GAPI.queryRequiresAdminCredentials, GAPI.noListTeamDrivesAdministratorPrivilege) as e:
66636
+ except (GAPI.invalidQuery, GAPI.invalid, GAPI.queryRequiresAdminCredentials,
66637
+ GAPI.noListTeamDrivesAdministratorPrivilege, GAPI.insufficientAdministratorPrivileges) as e:
66478
66638
  entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE, None], str(e), i, count)
66479
66639
  continue
66480
66640
  except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
@@ -66705,11 +66865,11 @@ def printSharedDriveOrganizers(users, useDomainAdminAccess=False):
66705
66865
  throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.INVALID_QUERY, GAPI.INVALID,
66706
66866
  GAPI.QUERY_REQUIRES_ADMIN_CREDENTIALS,
66707
66867
  GAPI.NO_LIST_TEAMDRIVES_ADMINISTRATOR_PRIVILEGE,
66708
- GAPI.FILE_NOT_FOUND],
66868
+ GAPI.INSUFFICIENT_ADMINISTRATOR_PRIVILEGES],
66709
66869
  q=query, useDomainAdminAccess=useDomainAdminAccess,
66710
66870
  fields='nextPageToken,drives(id,name,createdTime,orgUnitId)', pageSize=100)
66711
66871
  except (GAPI.invalidQuery, GAPI.invalid, GAPI.queryRequiresAdminCredentials,
66712
- GAPI.noListTeamDrivesAdministratorPrivilege, GAPI.fileNotFound) as e:
66872
+ GAPI.noListTeamDrivesAdministratorPrivilege, GAPI.insufficientAdministratorPrivileges) as e:
66713
66873
  entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE, None], str(e), i, count)
66714
66874
  continue
66715
66875
  except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
@@ -66723,7 +66883,7 @@ def printSharedDriveOrganizers(users, useDomainAdminAccess=False):
66723
66883
  j +=1
66724
66884
  try:
66725
66885
  feed.append(callGAPI(drive.drives(), 'get',
66726
- throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.NOT_FOUND],
66886
+ throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.FILE_NOT_FOUND, GAPI.NOT_FOUND],
66727
66887
  useDomainAdminAccess=useDomainAdminAccess,
66728
66888
  driveId=driveId, fields='id,name,createdTime,orgUnitId'))
66729
66889
  except (GAPI.fileNotFound, GAPI.notFound) as e:
@@ -67179,7 +67339,7 @@ def _addUserToGroups(cd, user, addGroupsSet, addGroups, i, count):
67179
67339
  retryReasons=GAPI.MEMBERS_RETRY_REASONS,
67180
67340
  groupKey=group, body=body, fields='')
67181
67341
  entityActionPerformed([Ent.GROUP, group, role, user], j, jcount)
67182
- except (GAPI.groupNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.invalid, GAPI.forbidden):
67342
+ except (GAPI.groupNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.invalid):
67183
67343
  entityUnknownWarning(Ent.GROUP, group, j, jcount)
67184
67344
  except (GAPI.duplicate, GAPI.cyclicMembershipsNotAllowed, GAPI.conditionNotMet, GAPI.serviceNotAvailable) as e:
67185
67345
  entityActionFailedWarning([Ent.GROUP, group, role, user], str(e), j, jcount)
@@ -67187,6 +67347,8 @@ def _addUserToGroups(cd, user, addGroupsSet, addGroups, i, count):
67187
67347
  entityActionPerformedMessage([Ent.GROUP, group, role, user], Msg.ACTION_MAY_BE_DELAYED, j, jcount)
67188
67348
  except (GAPI.memberNotFound, GAPI.resourceNotFound, GAPI.invalidMember) as e:
67189
67349
  entityActionFailedWarning([Ent.USER, user], str(e), i, count)
67350
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
67351
+ ClientAPIAccessDeniedExit(str(e))
67190
67352
  Ind.Decrement()
67191
67353
 
67192
67354
  # gam <UserTypeEntity> add group|groups
@@ -67246,12 +67408,14 @@ def _deleteUserFromGroups(cd, user, deleteGroupsSet, deleteGroups, i, count):
67246
67408
  retryReasons=GAPI.MEMBERS_RETRY_REASONS,
67247
67409
  groupKey=group, memberKey=user)
67248
67410
  entityActionPerformed([Ent.GROUP, group, role, user], j, jcount)
67249
- except (GAPI.groupNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.invalid, GAPI.forbidden):
67411
+ except (GAPI.groupNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.invalid):
67250
67412
  entityUnknownWarning(Ent.GROUP, group, j, jcount)
67251
67413
  except (GAPI.memberNotFound, GAPI.invalidMember, GAPI.conditionNotMet, GAPI.serviceNotAvailable) as e:
67252
67414
  entityActionFailedWarning([Ent.USER, user, Ent.GROUP, group], str(e), j, jcount)
67253
67415
  except GAPI.conflict:
67254
67416
  entityActionPerformedMessage([Ent.GROUP, group, role, user], Msg.ACTION_MAY_BE_DELAYED, j, jcount)
67417
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
67418
+ ClientAPIAccessDeniedExit(str(e))
67255
67419
  Ind.Decrement()
67256
67420
 
67257
67421
  def _getUserGroupOptionalDomainCustomerId():
@@ -67318,8 +67482,10 @@ def deleteUserFromGroups(users):
67318
67482
  except (GAPI.invalidMember, GAPI.invalidInput):
67319
67483
  badRequestWarning(Ent.GROUP, Ent.MEMBER, user)
67320
67484
  continue
67321
- except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.forbidden, GAPI.badRequest):
67485
+ except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.badRequest):
67322
67486
  accessErrorExit(cd)
67487
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
67488
+ ClientAPIAccessDeniedExit(str(e))
67323
67489
  deleteGroups = {}
67324
67490
  for group in result:
67325
67491
  if not matchPattern or checkUserGroupMatchPattern(group['email'], matchPattern):
@@ -67348,10 +67514,12 @@ def _updateUserGroups(cd, user, updateGroupsSet, updateGroups, i, count):
67348
67514
  retryReasons=GAPI.MEMBERS_RETRY_REASONS,
67349
67515
  groupKey=group, memberKey=user, body=body, fields='')
67350
67516
  entityActionPerformed([Ent.GROUP, group, role, user], j, jcount)
67351
- except (GAPI.groupNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.invalid, GAPI.forbidden):
67517
+ except (GAPI.groupNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.invalid):
67352
67518
  entityUnknownWarning(Ent.GROUP, group, j, jcount)
67353
67519
  except (GAPI.memberNotFound, GAPI.invalidMember, GAPI.conditionNotMet, GAPI.serviceNotAvailable) as e:
67354
67520
  entityActionFailedWarning([Ent.USER, user, Ent.GROUP, group], str(e), j, jcount)
67521
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
67522
+ ClientAPIAccessDeniedExit(str(e))
67355
67523
  Ind.Decrement()
67356
67524
 
67357
67525
  # gam <UserTypeEntity> update group|groups
@@ -67398,8 +67566,10 @@ def updateUserGroups(users):
67398
67566
  except (GAPI.invalidMember, GAPI.invalidInput):
67399
67567
  badRequestWarning(Ent.GROUP, Ent.MEMBER, user)
67400
67568
  continue
67401
- except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.forbidden, GAPI.badRequest):
67569
+ except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.badRequest):
67402
67570
  accessErrorExit(cd)
67571
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
67572
+ ClientAPIAccessDeniedExit(str(e))
67403
67573
  updateGroups = {}
67404
67574
  for group in result:
67405
67575
  updateGroups[group['email']] = {'role': baseRole, 'delivery_settings': baseDeliverySettings}
@@ -67473,8 +67643,10 @@ def syncUserWithGroups(users):
67473
67643
  except (GAPI.invalidMember, GAPI.invalidInput):
67474
67644
  badRequestWarning(Ent.GROUP, Ent.MEMBER, user)
67475
67645
  continue
67476
- except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.forbidden, GAPI.badRequest):
67646
+ except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.badRequest):
67477
67647
  accessErrorExit(cd)
67648
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
67649
+ ClientAPIAccessDeniedExit(str(e))
67478
67650
  for groupEntity in entityList:
67479
67651
  groupEmail = groupEntity['email']
67480
67652
  try:
@@ -67593,7 +67765,7 @@ def checkUserInGroups(users):
67593
67765
  retryReasons=GAPI.MEMBERS_RETRY_REASONS,
67594
67766
  groupKey=groupEmail, memberKey=user, fields='role')
67595
67767
  _checkMember(result)
67596
- except (GAPI.groupNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.invalid, GAPI.forbidden):
67768
+ except (GAPI.groupNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.invalid):
67597
67769
  entityUnknownWarning(Ent.GROUP, groupEmail, j, jcount)
67598
67770
  _setCheckError()
67599
67771
  except GAPI.memberNotFound:
@@ -67605,6 +67777,8 @@ def checkUserInGroups(users):
67605
67777
  except (GAPI.invalidMember, GAPI.conditionNotMet, GAPI.serviceNotAvailable) as e:
67606
67778
  entityActionFailedWarning([Ent.USER, user, Ent.GROUP, groupEmail], str(e), j, jcount)
67607
67779
  _setCheckError()
67780
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
67781
+ ClientAPIAccessDeniedExit(str(e))
67608
67782
  else:
67609
67783
  try:
67610
67784
  result = callGAPIpages(cd.members(), 'list', 'members',
@@ -67622,12 +67796,14 @@ def checkUserInGroups(users):
67622
67796
  else:
67623
67797
  csvPF.WriteRow({'user': user, 'group': groupEmail, 'role': notMemberOrRole})
67624
67798
  _setCheckError()
67625
- except (GAPI.groupNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.invalid, GAPI.forbidden):
67799
+ except (GAPI.groupNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.invalid):
67626
67800
  entityUnknownWarning(Ent.GROUP, groupEmail, j, jcount)
67627
67801
  _setCheckError()
67628
67802
  except (GAPI.invalidMember, GAPI.conditionNotMet, GAPI.serviceNotAvailable) as e:
67629
67803
  entityActionFailedWarning([Ent.USER, user, Ent.GROUP, groupEmail], str(e), j, jcount)
67630
67804
  _setCheckError()
67805
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
67806
+ ClientAPIAccessDeniedExit(str(e))
67631
67807
  Ind.Decrement()
67632
67808
  if csvPF:
67633
67809
  csvPF.writeCSVfile('User Check Groups')
@@ -67706,11 +67882,13 @@ def printShowUserGroups(users):
67706
67882
  except (GAPI.invalidMember, GAPI.invalidInput):
67707
67883
  badRequestWarning(Ent.GROUP, Ent.MEMBER, user)
67708
67884
  continue
67709
- except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.forbidden, GAPI.badRequest):
67885
+ except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.badRequest):
67710
67886
  if kwargs.get('domain'):
67711
67887
  badRequestWarning(Ent.GROUP, Ent.DOMAIN, kwargs['domain'])
67712
67888
  return
67713
67889
  accessErrorExit(cd)
67890
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
67891
+ ClientAPIAccessDeniedExit(str(e))
67714
67892
  jcount = len(entityList)
67715
67893
  if totalOnly:
67716
67894
  if not csvPF:
@@ -67840,6 +68018,8 @@ def printShowGroupTree(users):
67840
68018
  except (GAPI.invalidMember, GAPI.invalidInput):
67841
68019
  entityUnknownWarning(Ent.USER, user, i, count)
67842
68020
  continue
68021
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
68022
+ ClientAPIAccessDeniedExit(str(e))
67843
68023
  j = 0
67844
68024
  jcount = len(groups)
67845
68025
  if not csvPF and not FJQC.formatJSON:
@@ -67932,11 +68112,13 @@ def printUserGroupsList(users):
67932
68112
  except (GAPI.invalidMember, GAPI.invalidInput):
67933
68113
  badRequestWarning(Ent.GROUP, Ent.MEMBER, user)
67934
68114
  continue
67935
- except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.forbidden, GAPI.badRequest):
68115
+ except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.badRequest):
67936
68116
  if kwargs.get('domain'):
67937
68117
  badRequestWarning(Ent.GROUP, Ent.DOMAIN, kwargs['domain'])
67938
68118
  return
67939
68119
  accessErrorExit(cd)
68120
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
68121
+ ClientAPIAccessDeniedExit(str(e))
67940
68122
  csvPF.WriteRow({'User': user, 'Groups': len(entityList), 'GroupsList': delimiter.join([group['email'] for group in entityList])})
67941
68123
  csvPF.writeCSVfile('User GroupsList')
67942
68124
 
@@ -69119,19 +69301,23 @@ def deleteTokens(users):
69119
69301
  try:
69120
69302
  callGAPI(cd.tokens(), 'get',
69121
69303
  throwReasons=[GAPI.USER_NOT_FOUND, GAPI.DOMAIN_NOT_FOUND,
69122
- GAPI.DOMAIN_CANNOT_USE_APIS, GAPI.FORBIDDEN,
69123
- GAPI.NOT_FOUND, GAPI.RESOURCE_NOT_FOUND],
69304
+ GAPI.DOMAIN_CANNOT_USE_APIS,
69305
+ GAPI.NOT_FOUND, GAPI.RESOURCE_NOT_FOUND,
69306
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
69124
69307
  userKey=user, clientId=clientId, fields='')
69125
69308
  callGAPI(cd.tokens(), 'delete',
69126
69309
  throwReasons=[GAPI.USER_NOT_FOUND, GAPI.DOMAIN_NOT_FOUND,
69127
- GAPI.DOMAIN_CANNOT_USE_APIS, GAPI.FORBIDDEN,
69128
- GAPI.NOT_FOUND, GAPI.RESOURCE_NOT_FOUND],
69310
+ GAPI.DOMAIN_CANNOT_USE_APIS,
69311
+ GAPI.NOT_FOUND, GAPI.RESOURCE_NOT_FOUND,
69312
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
69129
69313
  userKey=user, clientId=clientId)
69130
69314
  entityActionPerformed([Ent.USER, user, Ent.ACCESS_TOKEN, clientId], i, count)
69131
69315
  except (GAPI.notFound, GAPI.resourceNotFound) as e:
69132
69316
  entityActionFailedWarning([Ent.USER, user, Ent.ACCESS_TOKEN, clientId], str(e), i, count)
69133
- except (GAPI.userNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden):
69317
+ except (GAPI.userNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis):
69134
69318
  entityUnknownWarning(Ent.USER, user, i, count)
69319
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
69320
+ ClientAPIAccessDeniedExit(str(e))
69135
69321
 
69136
69322
  TOKENS_FIELDS_TITLES = ['clientId', 'displayText', 'anonymous', 'nativeApp', 'userKey', 'scopes']
69137
69323
  TOKENS_AGGREGATE_FIELDS_TITLES = ['clientId', 'displayText', 'anonymous', 'nativeApp', 'users', 'scopes']
@@ -69225,13 +69411,15 @@ def _printShowTokens(entityType, users):
69225
69411
  if clientId:
69226
69412
  results = [callGAPI(cd.tokens(), 'get',
69227
69413
  throwReasons=[GAPI.USER_NOT_FOUND, GAPI.DOMAIN_NOT_FOUND,
69228
- GAPI.DOMAIN_CANNOT_USE_APIS, GAPI.FORBIDDEN, GAPI.BAD_REQUEST,
69229
- GAPI.NOT_FOUND, GAPI.RESOURCE_NOT_FOUND],
69414
+ GAPI.DOMAIN_CANNOT_USE_APIS, GAPI.BAD_REQUEST,
69415
+ GAPI.NOT_FOUND, GAPI.RESOURCE_NOT_FOUND,
69416
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
69230
69417
  userKey=user, clientId=clientId, fields=fields)]
69231
69418
  else:
69232
69419
  results = callGAPIitems(cd.tokens(), 'list', 'items',
69233
69420
  throwReasons=[GAPI.USER_NOT_FOUND, GAPI.DOMAIN_NOT_FOUND,
69234
- GAPI.DOMAIN_CANNOT_USE_APIS, GAPI.FORBIDDEN, GAPI.BAD_REQUEST],
69421
+ GAPI.DOMAIN_CANNOT_USE_APIS, GAPI.BAD_REQUEST,
69422
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
69235
69423
  userKey=user, fields=f'items({fields})')
69236
69424
  jcount = len(results)
69237
69425
  if not aggregateUsersBy:
@@ -69271,8 +69459,10 @@ def _printShowTokens(entityType, users):
69271
69459
  aggregateTokensById[user] = jcount
69272
69460
  except (GAPI.notFound, GAPI.resourceNotFound) as e:
69273
69461
  entityActionFailedWarning([Ent.USER, user, Ent.ACCESS_TOKEN, clientId], str(e), i, count)
69274
- except (GAPI.userNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden, GAPI.badRequest):
69462
+ except (GAPI.userNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.badRequest):
69275
69463
  entityUnknownWarning(Ent.USER, user, i, count)
69464
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
69465
+ ClientAPIAccessDeniedExit(str(e))
69276
69466
  if aggregateUsersBy == 'clientId':
69277
69467
  if not csvPF:
69278
69468
  jcount = len(aggregateTokensById)
@@ -76487,6 +76677,7 @@ MAIN_COMMANDS_WITH_OBJECTS = {
76487
76677
  Cmd.ARG_USERINVITATION: doCheckCIUserInvitations,
76488
76678
  Cmd.ARG_ISINVITABLE: doCheckCIUserInvitations,
76489
76679
  Cmd.ARG_ORG: doCheckOrgUnit,
76680
+ Cmd.ARG_SUSPENDED: doCheckUserSuspended,
76490
76681
  }
76491
76682
  ),
76492
76683
  'clear':