gam7 7.18.3__py3-none-any.whl → 7.18.5__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.
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.18.03'
28
+ __version__ = '7.18.05'
29
29
  __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
30
30
 
31
31
  #pylint: disable=wrong-import-position
@@ -3952,14 +3952,20 @@ def SetGlobalVariables():
3952
3952
  if checkArgumentPresent(Cmd.SELECT_CMD):
3953
3953
  sectionName = _selectSection()
3954
3954
  GM.Globals[GM.SECTION] = sectionName # Save section for inner gams
3955
- while Cmd.ArgumentsRemaining():
3956
- if checkArgumentPresent('save'):
3957
- GM.Globals[GM.PARSER].set(configparser.DEFAULTSECT, GC.SECTION, sectionName)
3958
- _writeGamCfgFile(GM.Globals[GM.PARSER], GM.Globals[GM.GAM_CFG_FILE], Act.SAVE)
3959
- elif checkArgumentPresent('verify'):
3960
- _verifyValues(sectionName, inputFilterSectionName, outputFilterSectionName)
3961
- else:
3962
- break
3955
+ # If command line is simply: gam select <SectionName>
3956
+ # assume save
3957
+ if not Cmd.ArgumentsRemaining():
3958
+ GM.Globals[GM.PARSER].set(configparser.DEFAULTSECT, GC.SECTION, sectionName)
3959
+ _writeGamCfgFile(GM.Globals[GM.PARSER], GM.Globals[GM.GAM_CFG_FILE], Act.SAVE)
3960
+ else:
3961
+ while Cmd.ArgumentsRemaining():
3962
+ if checkArgumentPresent('save'):
3963
+ GM.Globals[GM.PARSER].set(configparser.DEFAULTSECT, GC.SECTION, sectionName)
3964
+ _writeGamCfgFile(GM.Globals[GM.PARSER], GM.Globals[GM.GAM_CFG_FILE], Act.SAVE)
3965
+ elif checkArgumentPresent('verify'):
3966
+ _verifyValues(sectionName, inputFilterSectionName, outputFilterSectionName)
3967
+ else:
3968
+ break
3963
3969
  GM.Globals[GM.GAM_CFG_SECTION_NAME] = sectionName
3964
3970
  # showsections
3965
3971
  if checkArgumentPresent(Cmd.SHOWSECTIONS_CMD):
@@ -11482,13 +11488,14 @@ def _createOauth2serviceJSON(httpObj, projectInfo, svcAcctInfo, create_key=True)
11482
11488
  iam = getAPIService(API.IAM, httpObj)
11483
11489
  try:
11484
11490
  service_account = callGAPI(iam.projects().serviceAccounts(), 'create',
11485
- throwReasons=[GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED, GAPI.ALREADY_EXISTS],
11491
+ throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.NOT_FOUND,
11492
+ GAPI.PERMISSION_DENIED, GAPI.ALREADY_EXISTS],
11486
11493
  name=f'projects/{projectInfo["projectId"]}',
11487
11494
  body={'accountId': svcAcctInfo['name'],
11488
11495
  'serviceAccount': {'displayName': svcAcctInfo['displayName'],
11489
11496
  'description': svcAcctInfo['description']}})
11490
11497
  entityActionPerformed([Ent.PROJECT, projectInfo['projectId'], Ent.SVCACCT, service_account['name'].rsplit('/', 1)[-1]])
11491
- except (GAPI.notFound, GAPI.permissionDenied) as e:
11498
+ except (GAPI.failedPrecondition, GAPI.notFound, GAPI.permissionDenied) as e:
11492
11499
  entityActionFailedWarning([Ent.PROJECT, projectInfo['projectId']], str(e))
11493
11500
  return False
11494
11501
  except GAPI.alreadyExists as e:
@@ -27081,6 +27088,8 @@ def _getChatMemberEmail(cd, member):
27081
27088
  if member['member']['type'] == 'HUMAN':
27082
27089
  _, memberUid = member['member']['name'].split('/')
27083
27090
  member['member']['email'], _ = convertUIDtoEmailAddressWithType(f'uid:{memberUid}', cd, None, emailTypes=['user'])
27091
+ if member['member']['email'].find('@') == -1:
27092
+ member['member']['email'] = 'id:'+member['member']['email']
27084
27093
  elif 'groupMember' in member:
27085
27094
  _, memberUid = member['groupMember']['name'].split('/')
27086
27095
  member['groupMember']['email'], _ = convertUIDtoEmailAddressWithType(f'uid:{memberUid}', cd, None, emailTypes=['group'])
@@ -37798,6 +37807,54 @@ def doDeleteOrUndeleteAlert():
37798
37807
  except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.permissionDenied):
37799
37808
  userAlertsServiceNotEnabledWarning(user)
37800
37809
 
37810
+ def _showAlertSettings(settings):
37811
+ notifications = settings.get('notifications', [])
37812
+ count = len(notifications)
37813
+ entityPerformAction([Ent.ALERT_SETTINGS, None])
37814
+ i = 0
37815
+ for notification in notifications:
37816
+ i += 1
37817
+ printEntity([Ent.NOTIFICATION, None], i, count)
37818
+ Ind.Increment()
37819
+ showJSON(None, notification)
37820
+ Ind.Decrement()
37821
+
37822
+ # gam show alertsettings
37823
+ def doShowAlertSettings():
37824
+ checkForExtraneousArguments()
37825
+ user, ac = buildGAPIServiceObject(API.ALERTCENTER, _getAdminEmail())
37826
+ if not ac:
37827
+ return
37828
+ try:
37829
+ settings = callGAPI(ac.v1beta1(), 'getSettings',
37830
+ throwReasons=GAPI.ALERT_THROW_REASONS)
37831
+ _showAlertSettings(settings)
37832
+ except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.permissionDenied):
37833
+ userAlertsServiceNotEnabledWarning(user)
37834
+
37835
+ # gam update alertsettings <PubsubTopicName>
37836
+ def doUpdateAlertSettings(clear=False):
37837
+ if not clear:
37838
+ body = {'notifications':
37839
+ [{'cloudPubsubTopic': {'topicName': getString(Cmd.OB_PUBSUB_TOPIC_NAME)}}]}
37840
+ else:
37841
+ body = {'notifications': []}
37842
+ checkForExtraneousArguments()
37843
+ user, ac = buildGAPIServiceObject(API.ALERTCENTER, _getAdminEmail())
37844
+ if not ac:
37845
+ return
37846
+ try:
37847
+ settings = callGAPI(ac.v1beta1(), 'updateSettings',
37848
+ throwReasons=GAPI.ALERT_THROW_REASONS,
37849
+ body=body)
37850
+ _showAlertSettings(settings)
37851
+ except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.permissionDenied):
37852
+ userAlertsServiceNotEnabledWarning(user)
37853
+
37854
+ # gam clear alertsettings
37855
+ def doClearAlertSettings():
37856
+ doUpdateAlertSettings(clear=True)
37857
+
37801
37858
  ALERT_TIME_OBJECTS = {'createTime', 'startTime', 'endTime'}
37802
37859
 
37803
37860
  def _showAlert(alert, FJQC, i=0, count=0):
@@ -44844,21 +44901,39 @@ def waitForMailbox(entityList):
44844
44901
  Ind.Decrement()
44845
44902
 
44846
44903
  def getUserLicenses(lic, user, skus):
44847
- def _callbackGetLicense(_, response, exception):
44904
+ def _callbackGetLicense(request_id, response, exception):
44848
44905
  if exception is None:
44849
44906
  if response and 'skuId' in response:
44850
44907
  licenses.append(response['skuId'])
44908
+ del(sku_calls[request_id])
44909
+ else:
44910
+ if exception.reason == not_found:
44911
+ del(sku_calls[request_id])
44851
44912
 
44913
+ not_found = 'User does not have a license for specified sku and product'
44852
44914
  licenses = []
44853
44915
  svcargs = dict([('userId', user['primaryEmail']), ('productId', None), ('skuId', None), ('fields', 'skuId')]+GM.Globals[GM.EXTRA_ARGS_LIST])
44854
44916
  method = getattr(lic.licenseAssignments(), 'get')
44855
44917
  dbatch = lic.new_batch_http_request(callback=_callbackGetLicense)
44918
+ sku_calls = {}
44856
44919
  for sku in skus:
44857
44920
  svcparms = svcargs.copy()
44858
44921
  svcparms['productId'] = sku[0]
44859
- svcparms['skuId'] = sku[1]
44860
- dbatch.add(method(**svcparms))
44861
- dbatch.execute()
44922
+ sku_id = sku[1]
44923
+ svcparms['skuId'] = sku_id
44924
+ sku_calls[sku_id] = method(**svcparms)
44925
+ try_count = 0
44926
+ while sku_calls:
44927
+ try_count += 1
44928
+ dbatch = lic.new_batch_http_request(callback=_callbackGetLicense)
44929
+ for sku_id, sku_call in sku_calls.items():
44930
+ dbatch.add(sku_call, request_id=sku_id)
44931
+ dbatch.execute()
44932
+ if sku_calls:
44933
+ if try_count >= 5:
44934
+ # give up and return what we have
44935
+ return licenses
44936
+ time.sleep(5)
44862
44937
  return licenses
44863
44938
 
44864
44939
  USER_NAME_PROPERTY_PRINT_ORDER = [
@@ -46343,9 +46418,30 @@ def checkCIUserIsInvitable(users):
46343
46418
  return
46344
46419
  csvPF.writeCSVfile('Invitable Users')
46345
46420
 
46421
+ INBOUNDSSO_INPUT_MODE_CHOICE_MAP = {
46422
+ 'saml': 'saml',
46423
+ 'samlsso': 'saml',
46424
+ 'oidc': 'oidc',
46425
+ 'oidcsso': 'oidc',
46426
+ }
46427
+
46428
+ INBOUNDSSO_OUTPUT_MODE_CHOICE_MAP = {
46429
+ 'all': 'all',
46430
+ 'saml': 'saml',
46431
+ 'samlsso': 'saml',
46432
+ 'oidc': 'oidc',
46433
+ 'oidcsso': 'oidc',
46434
+ }
46435
+
46436
+ INBOUNDSSO_ALL_SAML = {'all', 'saml'}
46437
+ INBOUNDSSO_ALL_OIDC = {'all', 'oidc'}
46438
+
46346
46439
  INBOUNDSSO_MODE_CHOICE_MAP = {
46347
46440
  'ssooff': 'SSO_OFF',
46441
+ 'saml': 'SAML_SSO',
46348
46442
  'samlsso': 'SAML_SSO',
46443
+ 'oidc': 'OIDC_SSO',
46444
+ 'oidcsso': 'OIDC_SSO',
46349
46445
  'domainwidesamlifenabled': 'DOMAIN_WIDE_SAML_IF_ENABLED'
46350
46446
  }
46351
46447
 
@@ -46355,29 +46451,49 @@ def getCIOrgunitID(cd, orgunit):
46355
46451
  ou_id = ou_id[3:]
46356
46452
  return f'orgUnits/{ou_id}'
46357
46453
 
46358
- def _getInboundSSOProfiles(ci):
46454
+ def _getInboundSSOProfiles(ci, mode):
46359
46455
  customer = normalizeChannelCustomerID(GC.Values[GC.CUSTOMER_ID])
46360
- try:
46361
- return callGAPIpages(ci.inboundSamlSsoProfiles(), 'list', 'inboundSamlSsoProfiles',
46362
- throwReasons=GAPI.CISSO_LIST_THROW_REASONS,
46363
- retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46364
- bailOnInternalError=True,
46365
- filter=f'customer=="{customer}"')
46366
- except (GAPI.notFound, GAPI.domainNotFound, GAPI.domainCannotUseApis,
46367
- GAPI.forbidden, GAPI.badRequest, GAPI.invalid,
46368
- GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46369
- entityActionFailedWarning([Ent.INBOUND_SSO_PROFILE, customer], str(e))
46370
- return []
46456
+ profiles = []
46457
+ if mode in INBOUNDSSO_ALL_SAML:
46458
+ try:
46459
+ profiles.extend(callGAPIpages(ci.inboundSamlSsoProfiles(), 'list', 'inboundSamlSsoProfiles',
46460
+ throwReasons=GAPI.CISSO_LIST_THROW_REASONS,
46461
+ retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46462
+ bailOnInternalError=True,
46463
+ filter=f'customer=="{customer}"'))
46464
+ except (GAPI.notFound, GAPI.domainNotFound, GAPI.domainCannotUseApis,
46465
+ GAPI.forbidden, GAPI.badRequest, GAPI.invalid,
46466
+ GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46467
+ entityActionFailedWarning([Ent.INBOUND_SSO_PROFILE, customer], str(e))
46468
+ if mode in INBOUNDSSO_ALL_OIDC:
46469
+ try:
46470
+ profiles.extend(callGAPIpages(ci.inboundOidcSsoProfiles(), 'list', 'inboundOidcSsoProfiles',
46471
+ throwReasons=GAPI.CISSO_LIST_THROW_REASONS,
46472
+ retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46473
+ bailOnInternalError=True,
46474
+ filter=f'customer=="{customer}"'))
46475
+ except (GAPI.notFound, GAPI.domainNotFound, GAPI.domainCannotUseApis,
46476
+ GAPI.forbidden, GAPI.badRequest, GAPI.invalid,
46477
+ GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46478
+ entityActionFailedWarning([Ent.INBOUND_SSO_PROFILE, customer], str(e))
46479
+ return profiles
46371
46480
 
46372
- def _convertInboundSSOProfileDisplaynameToName(ci=None, displayName=''):
46481
+ def _convertInboundSSOProfileDisplaynameToName(ci, mode, displayName='',
46482
+ entityType=Ent.INBOUND_SSO_PROFILE):
46373
46483
  if displayName.lower().startswith('id:') or displayName.lower().startswith('uid:'):
46374
46484
  displayName = displayName.split(':', 1)[1]
46375
- if not displayName.startswith('inboundSamlSsoProfiles/'):
46376
- displayName = f'inboundSamlSsoProfiles/{displayName}'
46485
+ if mode == 'all':
46486
+ if not (displayName.startswith('inboundSamlSsoProfiles/') and
46487
+ displayName.startswith('inboundOidcSsoProfiles/')):
46488
+ displayName = f'inboundSamlSsoProfiles/{displayName}'
46489
+ elif mode == 'saml':
46490
+ if not displayName.startswith('inboundSamlSsoProfiles/'):
46491
+ displayName = f'inboundSamlSsoProfiles/{displayName}'
46492
+ else:
46493
+ if not displayName.startswith('inboundOidcSsoProfiles/'):
46494
+ displayName = f'inboundOidcSsoProfiles/{displayName}'
46377
46495
  return displayName
46378
- if not ci:
46379
- ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
46380
- profiles = _getInboundSSOProfiles(ci)
46496
+ profiles = _getInboundSSOProfiles(ci, mode)
46381
46497
  matches = []
46382
46498
  for profile in profiles:
46383
46499
  if displayName.lower() == profile.get('displayName', '').lower():
@@ -46385,30 +46501,50 @@ def _convertInboundSSOProfileDisplaynameToName(ci=None, displayName=''):
46385
46501
  if len(matches) == 1:
46386
46502
  return matches[0]['name']
46387
46503
  if len(matches) == 0:
46388
- usageErrorExit(Msg.NO_SSO_PROFILE_MATCHES.format(displayName))
46389
- errMsg = Msg.MULTIPLE_SSO_PROFILES_MATCH.format(displayName)
46390
- for m in matches:
46391
- errMsg += f' {m["name"]} {m["displayName"]}\n'
46392
- usageErrorExit(errMsg)
46504
+ errMsg = Msg.NO_SSO_PROFILE_MATCHES.format(displayName)
46505
+ else:
46506
+ errMsg = Msg.MULTIPLE_SSO_PROFILES_MATCH.format(displayName)
46507
+ for m in matches:
46508
+ errMsg += f' {m["name"]} {m["displayName"]}\n'
46509
+ entityActionFailedWarning([entityType, None], errMsg)
46510
+ return None
46393
46511
 
46394
- def _getInboundSSOProfileArguments(body):
46512
+ def _getInboundSSOProfileArguments(body, mode):
46395
46513
  returnNameOnly = False
46396
- while Cmd.ArgumentsRemaining():
46397
- myarg = getArgument()
46398
- if myarg == 'name':
46399
- body['displayName'] = getString(Cmd.OB_STRING)
46400
- elif myarg == 'entityid':
46401
- body.setdefault('idpConfig', {})['entityId'] = getString(Cmd.OB_STRING)
46402
- elif myarg == 'loginurl':
46403
- body.setdefault('idpConfig', {})['singleSignOnServiceUri'] = getString(Cmd.OB_STRING)
46404
- elif myarg == 'logouturl':
46405
- body.setdefault('idpConfig', {})['logoutRedirectUri'] = getString(Cmd.OB_STRING)
46406
- elif myarg == 'changepasswordurl':
46407
- body.setdefault('idpConfig', {})['changePasswordUri'] = getString(Cmd.OB_STRING)
46408
- elif myarg == 'returnnameonly':
46409
- returnNameOnly = True
46410
- else:
46411
- unknownArgumentExit()
46514
+ if mode == 'saml':
46515
+ while Cmd.ArgumentsRemaining():
46516
+ myarg = getArgument()
46517
+ if myarg == 'name':
46518
+ body['displayName'] = getString(Cmd.OB_STRING)
46519
+ elif myarg == 'entityid':
46520
+ body.setdefault('idpConfig', {})['entityId'] = getString(Cmd.OB_STRING)
46521
+ elif myarg == 'loginurl':
46522
+ body.setdefault('idpConfig', {})['singleSignOnServiceUri'] = getString(Cmd.OB_STRING)
46523
+ elif myarg == 'logouturl':
46524
+ body.setdefault('idpConfig', {})['logoutRedirectUri'] = getString(Cmd.OB_STRING)
46525
+ elif myarg == 'changepasswordurl':
46526
+ body.setdefault('idpConfig', {})['changePasswordUri'] = getString(Cmd.OB_STRING)
46527
+ elif myarg == 'returnnameonly':
46528
+ returnNameOnly = True
46529
+ else:
46530
+ unknownArgumentExit()
46531
+ else:
46532
+ while Cmd.ArgumentsRemaining():
46533
+ myarg = getArgument()
46534
+ if myarg == 'name':
46535
+ body['displayName'] = getString(Cmd.OB_STRING)
46536
+ elif myarg == 'issueruri':
46537
+ body.setdefault('idpConfig', {})['issuerUri'] = getString(Cmd.OB_STRING)
46538
+ elif myarg == 'changepasswordurl':
46539
+ body.setdefault('idpConfig', {})['changePasswordUri'] = getString(Cmd.OB_STRING)
46540
+ elif myarg == 'clientid':
46541
+ body.setdefault('rpConfig', {})['clientId'] = getString(Cmd.OB_STRING)
46542
+ elif myarg == 'clientsecret':
46543
+ body.setdefault('rpConfig', {})['clientSecret'] = getString(Cmd.OB_STRING)
46544
+ elif myarg == 'returnnameonly':
46545
+ returnNameOnly = True
46546
+ else:
46547
+ unknownArgumentExit()
46412
46548
  return (returnNameOnly, body)
46413
46549
 
46414
46550
  def _showInboundSSOProfile(profile, FJQC, i=0, count=0):
@@ -46439,18 +46575,24 @@ def _processInboundSSOProfileResult(result, returnNameOnly, kvlist, function):
46439
46575
  else:
46440
46576
  writeStdout('inProgress\n')
46441
46577
 
46442
- # gam create inboundssoprofile [name <SSOProfileName>]
46578
+ def _getInboundSSOModeService(ci):
46579
+ mode = getChoice(INBOUNDSSO_INPUT_MODE_CHOICE_MAP, defaultChoice='saml', mapChoice=True)
46580
+ service = ci.inboundSamlSsoProfiles() if mode == 'saml' else ci.inboundOidcSsoProfiles()
46581
+ return (mode, service)
46582
+
46583
+ # gam create inboundssoprofile [saml|oidc] [name <SSOProfileName>]
46443
46584
  # [entityid <String>] [loginurl <URL>] [logouturl <URL>] [changepasswordurl <URL>]
46444
46585
  # [returnnameonly]
46445
46586
  def doCreateInboundSSOProfile():
46446
46587
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
46588
+ mode, service = _getInboundSSOModeService(ci)
46447
46589
  body = {'customer': normalizeChannelCustomerID(GC.Values[GC.CUSTOMER_ID]),
46448
46590
  'displayName': 'SSO Profile'
46449
46591
  }
46450
- returnNameOnly, body = _getInboundSSOProfileArguments(body)
46592
+ returnNameOnly, body = _getInboundSSOProfileArguments(body, mode)
46451
46593
  kvlist = [Ent.INBOUND_SSO_PROFILE, body['displayName']]
46452
46594
  try:
46453
- result = callGAPI(ci.inboundSamlSsoProfiles(), 'create',
46595
+ result = callGAPI(service, 'create',
46454
46596
  throwReasons=GAPI.CISSO_CREATE_THROW_REASONS,
46455
46597
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46456
46598
  bailOnInternalError=True,
@@ -46461,16 +46603,19 @@ def doCreateInboundSSOProfile():
46461
46603
  GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46462
46604
  entityActionFailedWarning(kvlist, str(e))
46463
46605
 
46464
- # gam update inboundssoprofile <SSOProfileItem>
46606
+ # gam update inboundssoprofile [saml|oidc] <SSOProfileItem>
46465
46607
  # [entityid <String>] [loginurl <URL>] [logouturl <URL>] [changepasswordurl <URL>]
46466
46608
  # [returnnameonly]
46467
46609
  def doUpdateInboundSSOProfile():
46468
46610
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
46469
- name = _convertInboundSSOProfileDisplaynameToName(ci, getString(Cmd.OB_STRING))
46470
- returnNameOnly, body = _getInboundSSOProfileArguments({})
46611
+ mode, service = _getInboundSSOModeService(ci)
46612
+ name = _convertInboundSSOProfileDisplaynameToName(ci, mode, getString(Cmd.OB_STRING))
46613
+ if not name:
46614
+ return
46615
+ returnNameOnly, body = _getInboundSSOProfileArguments({}, mode)
46471
46616
  kvlist = [Ent.INBOUND_SSO_PROFILE, name]
46472
46617
  try:
46473
- result = callGAPI(ci.inboundSamlSsoProfiles(), 'patch',
46618
+ result = callGAPI(service, 'patch',
46474
46619
  throwReasons=GAPI.CISSO_UPDATE_THROW_REASONS,
46475
46620
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46476
46621
  bailOnInternalError=True,
@@ -46483,14 +46628,17 @@ def doUpdateInboundSSOProfile():
46483
46628
  GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46484
46629
  entityActionFailedWarning(kvlist, str(e))
46485
46630
 
46486
- # gam delete inboundssoprofile <SSOProfileItem>
46631
+ # gam delete inboundssoprofile [saml|oidc] <SSOProfileItem>
46487
46632
  def doDeleteInboundSSOProfile():
46488
46633
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
46489
- name = _convertInboundSSOProfileDisplaynameToName(ci, getString(Cmd.OB_STRING))
46634
+ mode, service = _getInboundSSOModeService(ci)
46635
+ name = _convertInboundSSOProfileDisplaynameToName(ci, mode, getString(Cmd.OB_STRING))
46636
+ if not name:
46637
+ return
46490
46638
  checkForExtraneousArguments()
46491
46639
  kvlist = [Ent.INBOUND_SSO_PROFILE, name]
46492
46640
  try:
46493
- result = callGAPI(ci.inboundSamlSsoProfiles(), 'delete',
46641
+ result = callGAPI(service, 'delete',
46494
46642
  throwReasons=GAPI.CISSO_UPDATE_THROW_REASONS,
46495
46643
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46496
46644
  bailOnInternalError=True,
@@ -46503,33 +46651,54 @@ def doDeleteInboundSSOProfile():
46503
46651
  GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46504
46652
  entityActionFailedWarning(kvlist, str(e))
46505
46653
 
46506
- def _getInboundSSOProfile(ci, name):
46654
+ def _getInboundSSOProfileByName(ci, mode, name):
46655
+ notFound = False
46507
46656
  kvlist = [Ent.INBOUND_SSO_PROFILE, name]
46508
- try:
46509
- return callGAPI(ci.inboundSamlSsoProfiles(), 'get',
46510
- throwReasons=GAPI.CISSO_GET_THROW_REASONS,
46511
- retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46512
- bailOnInternalError=True,
46513
- name=name)
46514
- except GAPI.notFound:
46657
+ if mode in INBOUNDSSO_ALL_SAML:
46658
+ try:
46659
+ return callGAPI(ci.inboundSamlSsoProfiles(), 'get',
46660
+ throwReasons=GAPI.CISSO_GET_THROW_REASONS,
46661
+ retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46662
+ bailOnInternalError=True,
46663
+ name=name)
46664
+ except GAPI.notFound:
46665
+ notFound = True
46666
+ except (GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden,
46667
+ GAPI.badRequest, GAPI.invalid, GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46668
+ entityActionFailedWarning(kvlist, str(e))
46669
+ if mode in INBOUNDSSO_ALL_OIDC:
46670
+ try:
46671
+ return callGAPI(ci.inboundOidcSsoProfiles(), 'get',
46672
+ throwReasons=GAPI.CISSO_GET_THROW_REASONS,
46673
+ retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46674
+ bailOnInternalError=True,
46675
+ name=name)
46676
+ except GAPI.notFound:
46677
+ notFound = True
46678
+ except (GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden,
46679
+ GAPI.badRequest, GAPI.invalid, GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46680
+ entityActionFailedWarning(kvlist, str(e))
46681
+ if notFound:
46515
46682
  entityActionFailedWarning(kvlist, Msg.DOES_NOT_EXIST)
46516
- except (GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden,
46517
- GAPI.badRequest, GAPI.invalid, GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46518
- entityActionFailedWarning(kvlist, str(e))
46519
46683
  return None
46520
46684
 
46521
- # gam info inboundssoprofile <SSOProfileItem> [formatjson]
46685
+ # gam info inboundssoprofile [all|saml|oidc] <SSOProfileItem> [formatjson]
46522
46686
  def doInfoInboundSSOProfile():
46523
46687
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
46524
- name = _convertInboundSSOProfileDisplaynameToName(ci, getString(Cmd.OB_STRING))
46688
+ mode = getChoice(INBOUNDSSO_OUTPUT_MODE_CHOICE_MAP, defaultChoice='all', mapChoice=True)
46689
+ name = getString(Cmd.OB_STRING)
46525
46690
  FJQC = FormatJSONQuoteChar(formatJSONOnly=True)
46526
- profile = _getInboundSSOProfile(ci, name)
46691
+ name = _convertInboundSSOProfileDisplaynameToName(ci, mode, name)
46692
+ if not name:
46693
+ return
46694
+ mode = 'saml' if name.startswith('inboundSamlSsoProfiles/') else 'oidc'
46695
+ profile = _getInboundSSOProfileByName(ci, mode, name)
46527
46696
  if profile:
46528
46697
  _showInboundSSOProfile(profile, FJQC)
46529
46698
 
46530
- # gam show inboundssoprofile
46699
+ # gam show inboundssoprofile [all|saml|oidc]
46531
46700
  # [formatjson]
46532
- # gam print inboundssoprofile [todrive <ToDriveAttribute>*]
46701
+ # gam print inboundssoprofile [all|saml|oidc] [todrive <ToDriveAttribute>*]
46533
46702
  # [[formatjson [quotechar <Character>]]
46534
46703
  def doPrintShowInboundSSOProfiles():
46535
46704
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
@@ -46537,6 +46706,7 @@ def doPrintShowInboundSSOProfiles():
46537
46706
  csvPF = CSVPrintFile(['name']) if Act.csvFormat() else None
46538
46707
  FJQC = FormatJSONQuoteChar(csvPF)
46539
46708
  cfilter = f'customer=="{customer}"'
46709
+ mode = getChoice(INBOUNDSSO_OUTPUT_MODE_CHOICE_MAP, defaultChoice='all', mapChoice=True)
46540
46710
  while Cmd.ArgumentsRemaining():
46541
46711
  myarg = getArgument()
46542
46712
  if csvPF and myarg == 'todrive':
@@ -46545,7 +46715,7 @@ def doPrintShowInboundSSOProfiles():
46545
46715
  FJQC.GetFormatJSONQuoteChar(myarg, True)
46546
46716
  if csvPF:
46547
46717
  printGettingAllAccountEntities(Ent.INBOUND_SSO_PROFILE, cfilter)
46548
- profiles = _getInboundSSOProfiles(ci)
46718
+ profiles = _getInboundSSOProfiles(ci, mode)
46549
46719
  if not csvPF:
46550
46720
  count = len(profiles)
46551
46721
  if not FJQC.formatJSON:
@@ -46615,6 +46785,7 @@ def _processInboundSSOCredentialsResult(result, kvlist, function):
46615
46785
  # (pemfile <FileName>)|(generatekey [keysize 1024|2048|4096]) [replaceolddest]
46616
46786
  def doCreateInboundSSOCredential():
46617
46787
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
46788
+ mode = 'saml'
46618
46789
  profile = None
46619
46790
  generateKey = replaceOldest = False
46620
46791
  keySize = 2048
@@ -46622,7 +46793,11 @@ def doCreateInboundSSOCredential():
46622
46793
  while Cmd.ArgumentsRemaining():
46623
46794
  myarg = getArgument()
46624
46795
  if myarg == 'profile':
46625
- profile = _convertInboundSSOProfileDisplaynameToName(ci, getString(Cmd.OB_STRING))
46796
+ profile = _convertInboundSSOProfileDisplaynameToName(ci, mode,
46797
+ getString(Cmd.OB_STRING),
46798
+ Ent.INBOUND_SSO_CREDENTIALS)
46799
+ if not profile:
46800
+ return
46626
46801
  elif myarg == 'pemfile':
46627
46802
  pemData = readFile(getString(Cmd.OB_FILE_NAME))
46628
46803
  elif myarg == 'generatekey':
@@ -46726,15 +46901,24 @@ def doPrintShowInboundSSOCredentials():
46726
46901
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
46727
46902
  csvPF = CSVPrintFile(['name']) if Act.csvFormat() else None
46728
46903
  FJQC = FormatJSONQuoteChar(csvPF)
46904
+ mode = 'saml'
46729
46905
  profiles = []
46730
46906
  while Cmd.ArgumentsRemaining():
46731
46907
  myarg = getArgument()
46732
46908
  if myarg in {'profile', 'profiles'}:
46733
- profiles = [_convertInboundSSOProfileDisplaynameToName(ci, profile) for profile in getString(Cmd.OB_STRING_LIST).split(',')]
46909
+ errors = 0
46910
+ for profile in getEntityList(Cmd.OB_STRING_LIST, shlexSplit=True):
46911
+ name = _convertInboundSSOProfileDisplaynameToName(ci, mode, profile, Ent.INBOUND_SSO_CREDENTIALS)
46912
+ if name:
46913
+ profiles.append(name)
46914
+ else:
46915
+ errors += 1
46916
+ if errors:
46917
+ return
46734
46918
  else:
46735
46919
  FJQC.GetFormatJSONQuoteChar(myarg, True)
46736
46920
  if not profiles:
46737
- profiles = [p['name'] for p in _getInboundSSOProfiles(ci)]
46921
+ profiles = [p['name'] for p in _getInboundSSOProfiles(ci, mode)]
46738
46922
  count = len(profiles)
46739
46923
  i = 0
46740
46924
  for profile in profiles:
@@ -46827,6 +47011,7 @@ def _getInboundSSOAssignmentByTarget(ci, cd, target):
46827
47011
  usageErrorExit(Msg.NO_SSO_PROFILE_ASSIGNED.format(targetType, target))
46828
47012
 
46829
47013
  def _getInboundSSOAssignmentArguments(ci, cd, body):
47014
+ mode = None
46830
47015
  rank = 0
46831
47016
  while Cmd.ArgumentsRemaining():
46832
47017
  myarg = getArgument()
@@ -46834,9 +47019,19 @@ def _getInboundSSOAssignmentArguments(ci, cd, body):
46834
47019
  rank = getInteger(minVal=1)
46835
47020
  elif myarg == 'mode':
46836
47021
  body['ssoMode'] = getChoice(INBOUNDSSO_MODE_CHOICE_MAP, mapChoice=True)
46837
- elif myarg == 'profile':
46838
- body['samlSsoInfo'] = {'inboundSamlSsoProfile':
46839
- _convertInboundSSOProfileDisplaynameToName(ci, getString(Cmd.OB_STRING))}
47022
+ if body['ssoMode'] == 'SAML_SSO':
47023
+ mode = 'saml'
47024
+ profile = 'inboundSamlSsoProfile'
47025
+ elif body['ssoMode'] == 'OIDC_SSO':
47026
+ mode = 'oidc'
47027
+ profile = 'inboundOidcSsoProfile'
47028
+ elif mode and myarg == 'profile':
47029
+ name = _convertInboundSSOProfileDisplaynameToName(ci, mode,
47030
+ getString(Cmd.OB_STRING),
47031
+ Ent.INBOUND_SSO_ASSIGNMENT)
47032
+ if not name:
47033
+ return None
47034
+ body['samlSsoInfo'] = {profile: name}
46840
47035
  elif myarg == 'neverredirect':
46841
47036
  body['signInBehavior'] = {'redirectCondition': 'NEVER'}
46842
47037
  elif myarg == 'group':
@@ -46847,7 +47042,7 @@ def _getInboundSSOAssignmentArguments(ci, cd, body):
46847
47042
  unknownArgumentExit()
46848
47043
  if 'ssoMode' not in body:
46849
47044
  missingArgumentExit('mode')
46850
- if body['ssoMode'] == 'SAML_SSO' and 'samlSsoInfo' not in body:
47045
+ if mode and 'samlSsoInfo' not in body:
46851
47046
  missingArgumentExit('profile')
46852
47047
  if 'targetGroup' in body:
46853
47048
  if 'targetOrgUnit' in body:
@@ -46885,13 +47080,17 @@ def _processInboundSSOAssignmentResult(result, kvlist, ci, cd, function):
46885
47080
  else:
46886
47081
  entityActionPerformedMessage(kvlist, Msg.ACTION_IN_PROGRESS.format(f'{function} inboundssoassignment'))
46887
47082
 
46888
- # gam create inboundssoassignment (group <GroupItem> rank <Number>)|(ou|org|orgunit <OrgUnitItem>)
46889
- # (mode sso_off)|(mode saml_sso profile <SSOProfileItem>)(mode domain_wide_saml_if_enabled) [neverredirect]
47083
+ # gam create inboundssoassignment
47084
+ # (group <GroupItem> rank <Number>)|(ou|org|orgunit <OrgUnitItem>)
47085
+ # (mode sso_off)|(mode saml_sso profile <SSOProfileItem>)|(mode oidc_sso profile <SSOProfileName>}|(mode domain_wide_saml_if_enabled)
47086
+ # [neverredirect]
46890
47087
  def doCreateInboundSSOAssignment():
46891
47088
  cd = buildGAPIObject(API.DIRECTORY)
46892
47089
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
46893
47090
  body = {'customer': normalizeChannelCustomerID(GC.Values[GC.CUSTOMER_ID])}
46894
47091
  body = _getInboundSSOAssignmentArguments(ci, cd, body)
47092
+ if not body:
47093
+ return
46895
47094
  kvlist = [Ent.INBOUND_SSO_ASSIGNMENT, body['customer']]
46896
47095
  try:
46897
47096
  result = callGAPI(ci.inboundSsoAssignments(), 'create',
@@ -46905,8 +47104,10 @@ def doCreateInboundSSOAssignment():
46905
47104
  GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46906
47105
  entityActionFailedWarning(kvlist, str(e))
46907
47106
 
46908
- # gam update inboundssoassignment [(group <GroupItem> rank <Number>)|(ou|org|orgunit <OrgUnitItem>)]
46909
- # [(mode sso_off)|(mode saml_sso profile <SSOProfileItem>)(mode domain_wide_saml_if_enabled)] [neverredirect]
47107
+ # gam update inboundssoassignment <SSOAssignmentName>
47108
+ # [(group <GroupItem> rank <Number>)|(ou|org|orgunit <OrgUnitItem>)]
47109
+ # (mode sso_off)|(mode saml_sso profile <SSOProfileItem>)|(mode oidc_sso profile <SSOProfileName>}|(mode domain_wide_saml_if_enabled)
47110
+ # [neverredirect]
46910
47111
  def doUpdateInboundSSOAssignment():
46911
47112
  cd = buildGAPIObject(API.DIRECTORY)
46912
47113
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
@@ -46963,14 +47164,20 @@ def doInfoInboundSSOAssignment():
46963
47164
  return
46964
47165
  name = assignment.get('samlSsoInfo', {}).get('inboundSamlSsoProfile')
46965
47166
  if name:
46966
- profile = _getInboundSSOProfile(ci, name)
47167
+ profile = _getInboundSSOProfileByName(ci, 'saml', name)
46967
47168
  if profile:
46968
47169
  assignment['samlSsoInfo']['inboundSamlSsoProfile'] = profile
47170
+ else:
47171
+ name = assignment.get('oidcSsoInfo', {}).get('inboundOidcSsoProfile')
47172
+ if name:
47173
+ profile = _getInboundSSOProfileByName(ci, 'oidc', name)
47174
+ if profile:
47175
+ assignment['oidcSsoInfo']['inboundOidcSsoProfile'] = profile
46969
47176
  _showInboundSSOAssignment(assignment, FJQC, ci, cd)
46970
47177
 
46971
- # gam show inboundssoassignment
47178
+ # gam show inboundssoassignments
46972
47179
  # [formatjson]
46973
- # gam print inboundssoassignment [todrive <ToDriveAttribute>*]
47180
+ # gam print inboundssoassignments [todrive <ToDriveAttribute>*]
46974
47181
  # [[formatjson [quotechar <Character>]]
46975
47182
  def doPrintShowInboundSSOAssignments():
46976
47183
  cd = buildGAPIObject(API.DIRECTORY)
@@ -77185,7 +77392,8 @@ MAIN_COMMANDS_WITH_OBJECTS = {
77185
77392
  ),
77186
77393
  'clear':
77187
77394
  (Act.CLEAR,
77188
- {Cmd.ARG_CONTACT: doClearDomainContacts,
77395
+ {Cmd.ARG_ALERTSETTINGS: doClearAlertSettings,
77396
+ Cmd.ARG_CONTACT: doClearDomainContacts,
77189
77397
  }
77190
77398
  ),
77191
77399
  'close':
@@ -77506,6 +77714,7 @@ MAIN_COMMANDS_WITH_OBJECTS = {
77506
77714
  Cmd.ARG_ADMIN: doPrintShowAdmins,
77507
77715
  Cmd.ARG_ALERT: doPrintShowAlerts,
77508
77716
  Cmd.ARG_ALERTFEEDBACK: doPrintShowAlertFeedback,
77717
+ Cmd.ARG_ALERTSETTINGS: doShowAlertSettings,
77509
77718
  Cmd.ARG_BROWSER: doPrintShowBrowsers,
77510
77719
  Cmd.ARG_BROWSERTOKEN: doPrintShowBrowserTokens,
77511
77720
  Cmd.ARG_BUILDING: doPrintShowBuildings,
@@ -77598,6 +77807,7 @@ MAIN_COMMANDS_WITH_OBJECTS = {
77598
77807
  'update':
77599
77808
  (Act.UPDATE,
77600
77809
  {Cmd.ARG_ADMINROLE: doCreateUpdateAdminRoles,
77810
+ Cmd.ARG_ALERTSETTINGS: doUpdateAlertSettings,
77601
77811
  Cmd.ARG_ALIAS: doCreateUpdateAliases,
77602
77812
  Cmd.ARG_BROWSER: doUpdateBrowsers,
77603
77813
  Cmd.ARG_BUILDING: doUpdateBuilding,
gam/gamlib/glclargs.py CHANGED
@@ -411,6 +411,7 @@ class GamCLArgs():
411
411
  ARG_ALERTFEEDBACK = 'alertfeedback'
412
412
  ARG_ALERTFEEDBACKS = 'alertfeedbacks'
413
413
  ARG_ALERTSFEEDBACK = 'alertsfeedback'
414
+ ARG_ALERTSETTINGS = 'alertsettings'
414
415
  ARG_ALIAS = 'alias'
415
416
  ARG_ALIASES = 'aliases'
416
417
  ARG_ALIASDOMAIN = 'aliasdomain'
@@ -1013,6 +1014,7 @@ class GamCLArgs():
1013
1014
  OB_PROJECT_ID_ENTITY = 'ProjectIDEntity'
1014
1015
  OB_PROPERTY_KEY = 'PropertyKey'
1015
1016
  OB_PROPERTY_VALUE = 'PropertyValue'
1017
+ OB_PUBSUB_TOPIC_NAME = 'PubSubTopicName'
1016
1018
  OB_QUERY = 'Query'
1017
1019
  OB_QUERY_ITEM = 'QueryItem'
1018
1020
  OB_QUERY_LIST = 'QueryList'
gam/gamlib/glentity.py CHANGED
@@ -54,6 +54,7 @@ class GamEntity():
54
54
  ALERT_ID = 'alri'
55
55
  ALERT_FEEDBACK = 'alfb'
56
56
  ALERT_FEEDBACK_ID = 'alfi'
57
+ ALERT_SETTINGS = 'alrs'
57
58
  ALIAS = 'alia'
58
59
  ALIAS_EMAIL = 'alie'
59
60
  ALIAS_TARGET = 'alit'
@@ -285,10 +286,11 @@ class GamEntity():
285
286
  MIMETYPE = 'mime'
286
287
  MOBILE_DEVICE = 'mobi'
287
288
  NAME = 'name'
289
+ NONEDITABLE_ALIAS = 'neal'
288
290
  NOTE = 'note'
289
291
  NOTE_ACL = 'nota'
290
292
  NOTES_ACLS = 'naac'
291
- NONEDITABLE_ALIAS = 'neal'
293
+ NOTIFICATION = 'noti'
292
294
  OAUTH2_TXT_FILE = 'oaut'
293
295
  OAUTH2SERVICE_JSON_FILE = 'oau2'
294
296
  ORGANIZATIONAL_UNIT = 'orgu'
@@ -414,6 +416,7 @@ class GamEntity():
414
416
  ALERT_ID: ['Alert IDs', 'Alert ID'],
415
417
  ALERT_FEEDBACK: ['Alert Feedbacks', 'Alert Feedback'],
416
418
  ALERT_FEEDBACK_ID: ['Alert Feedback IDs', 'Alert Feedback ID'],
419
+ ALERT_SETTINGS: ['Alert Settings', 'Alert Settings'],
417
420
  ALIAS: ['Aliases', 'Alias'],
418
421
  ALIAS_EMAIL: ['Alias Emails', 'Alias Email'],
419
422
  ALIAS_TARGET: ['Alias Targets', 'Alias Target'],
@@ -645,10 +648,11 @@ class GamEntity():
645
648
  MIMETYPE: ['MIME Types', 'MIME Type'],
646
649
  MOBILE_DEVICE: ['Mobile Devices', 'Mobile Device'],
647
650
  NAME: ['Names', 'Name'],
651
+ NONEDITABLE_ALIAS: ['Non-Editable Aliases', 'Non-Editable Alias'],
648
652
  NOTE: ['Notes', 'Note'],
649
653
  NOTE_ACL: ['Note ACLs', 'Note ACL'],
650
654
  NOTES_ACLS: ["'Note's ACLs", "Note's ACLs"],
651
- NONEDITABLE_ALIAS: ['Non-Editable Aliases', 'Non-Editable Alias'],
655
+ NOTIFICATION: ['Notifications', 'Notification'],
652
656
  OAUTH2_TXT_FILE: ['Client OAuth2 File', 'Client OAuth2 File'],
653
657
  OAUTH2SERVICE_JSON_FILE: ['Service Account OAuth2 File', 'Service Account OAuth2 File'],
654
658
  ORGANIZATIONAL_UNIT: ['Organizational Units', 'Organizational Unit'],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gam7
3
- Version: 7.18.3
3
+ Version: 7.18.5
4
4
  Summary: CLI tool to manage Google Workspace
5
5
  Project-URL: Homepage, https://github.com/GAM-team/GAM
6
6
  Project-URL: Issues, https://github.com/GAM-team/GAM/issues
@@ -1,4 +1,4 @@
1
- gam/__init__.py,sha256=IuejoFwuNltKresUI9ioszMMmb8xBs9LjSpjHZJwIkE,3575349
1
+ gam/__init__.py,sha256=QJekeV8HEGrQCPUNeJc6AL-0fkgPuC0tSNR6M-ETh-E,3583485
2
2
  gam/__main__.py,sha256=amz0-959ph6zkZKqjaar4n60yho-T37w6qWI36qx0CA,1049
3
3
  gam/cacerts.pem,sha256=82Ak7btW_2XvocLUvAwPmpx8Chi0oqtZUG1gseLK_t4,50235
4
4
  gam/cbcm-v1.1beta1.json,sha256=xO5XloCQQULmPbFBx5bckdqmbLFQ7sJ2TImhE1ysDIY,19439
@@ -25,8 +25,8 @@ gam/gamlib/__init__.py,sha256=z5mF-y0j8pm-YNFBaiuxB4M_GAUPG-cXWwrhYwrVReM,679
25
25
  gam/gamlib/glaction.py,sha256=1Il_HrChVnPkzZwiZs5au4mFQVtq4K1Z42uIuR6qdnI,9419
26
26
  gam/gamlib/glapi.py,sha256=YPa_XvdoltFLSSrZOZ9thAwrAB_PU9BzJAIO6cUOSWI,35760
27
27
  gam/gamlib/glcfg.py,sha256=J4w16Nfk282S7iuSmk3601GHgt_MJ4qWeSzF5y7ZzX0,28139
28
- gam/gamlib/glclargs.py,sha256=u4OFdkNogXVBV7K7oH4pXTc8TmAEJPvnqy3r0NblD60,43800
29
- gam/gamlib/glentity.py,sha256=WsSwlzwgp3uwYLDu8t5seFNKoZ9Bj0bTGRjTXcC56Ro,34694
28
+ gam/gamlib/glclargs.py,sha256=pgomQOKbiKOI5TfdC0hTT5BqGbQcikDMRfkUk6DEXrM,43881
29
+ gam/gamlib/glentity.py,sha256=ZQTdjVtGe8soMlgcSHJIpLHjQ_UtUL9qfw8ux-C4kik,34855
30
30
  gam/gamlib/glgapi.py,sha256=pdBbwNtnCwFWxJGaP-_3hdTjSNoOCJF2yo76WdQOi1k,40426
31
31
  gam/gamlib/glgdata.py,sha256=weRppttWm6uRyqtBoGPKoHiNZ2h28nhfUV4J_mbCszY,2707
32
32
  gam/gamlib/glglobals.py,sha256=J0xcHggVrUBzHJ5GruenKV-qV1zPKcK2qWgAgN3i5Jw,9608
@@ -65,8 +65,8 @@ gam/googleapiclient/discovery_cache/base.py,sha256=yCDPtxnbNN-p5_9fzBacC6P3wcUPl
65
65
  gam/googleapiclient/discovery_cache/file_cache.py,sha256=sim3Mg4HgRYo3vX75jvcKy_aV568EvIrtBfvfbw-044,4774
66
66
  gam/iso8601/__init__.py,sha256=Z2PsYbXgAH5a5xzUvgczCboPzqWpm65kRcIngCnhViU,1218
67
67
  gam/iso8601/iso8601.py,sha256=Li2FHZ4sBTWuthuQhyCvmvj0j6At8JbGzkSv2fc2RHU,4384
68
- gam7-7.18.3.dist-info/METADATA,sha256=ai7pzoGdGh0EOpT7wsAyrIymufCu77HLCsu8qs51jMQ,2940
69
- gam7-7.18.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
70
- gam7-7.18.3.dist-info/entry_points.txt,sha256=HVUM5J7dA8YwvJfG30jiLefR19ExMs387TWugWd9sf4,42
71
- gam7-7.18.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
72
- gam7-7.18.3.dist-info/RECORD,,
68
+ gam7-7.18.5.dist-info/METADATA,sha256=628E9mgFMjRM6W-64H88Hp6dW9X1APB82o-I6MbUSjw,2940
69
+ gam7-7.18.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
70
+ gam7-7.18.5.dist-info/entry_points.txt,sha256=HVUM5J7dA8YwvJfG30jiLefR19ExMs387TWugWd9sf4,42
71
+ gam7-7.18.5.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
72
+ gam7-7.18.5.dist-info/RECORD,,
File without changes