zscaler-sdk-python 0.9.5__tar.gz → 0.9.6__tar.gz

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.
Files changed (99) hide show
  1. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/PKG-INFO +3 -3
  2. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/pyproject.toml +4 -5
  3. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/__init__.py +1 -1
  4. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/__init__.py +82 -50
  5. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/admin_and_role_management.py +2 -1
  6. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/labels.py +2 -1
  7. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/locations.py +2 -1
  8. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/traffic.py +2 -1
  9. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/users.py +6 -3
  10. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/policies.py +18 -4
  11. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/LICENSE.md +0 -0
  12. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/README.md +0 -0
  13. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/cache/__init__.py +0 -0
  14. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/cache/cache.py +0 -0
  15. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/cache/no_op_cache.py +0 -0
  16. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/cache/zscaler_cache.py +0 -0
  17. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/constants.py +0 -0
  18. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/errors/__init__.py +0 -0
  19. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/errors/error.py +0 -0
  20. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/errors/http_error.py +0 -0
  21. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/errors/zscaler_api_error.py +0 -0
  22. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/exceptions/__init__.py +0 -0
  23. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/exceptions/exceptions.py +0 -0
  24. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/logger.py +0 -0
  25. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/ratelimiter/__init__.py +0 -0
  26. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/ratelimiter/ratelimiter.py +0 -0
  27. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/user_agent.py +0 -0
  28. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/utils.py +0 -0
  29. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zcc/__init__.py +0 -0
  30. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zcc/client.py +0 -0
  31. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zcc/devices.py +0 -0
  32. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zcc/secrets.py +0 -0
  33. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zcon/__init__.py +0 -0
  34. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zcon/activation.py +0 -0
  35. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zcon/admin_and_role_management.py +0 -0
  36. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zcon/client.py +0 -0
  37. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zcon/ecgroups.py +0 -0
  38. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zcon/locations.py +0 -0
  39. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zcon/provisioning.py +0 -0
  40. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zdx/__init__.py +0 -0
  41. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zdx/admin.py +0 -0
  42. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zdx/alerts.py +0 -0
  43. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zdx/apps.py +0 -0
  44. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zdx/devices.py +0 -0
  45. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zdx/filters.py +0 -0
  46. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zdx/inventory.py +0 -0
  47. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zdx/troubleshooting.py +0 -0
  48. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zdx/users.py +0 -0
  49. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zdx/zdx_client.py +0 -0
  50. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/activate.py +0 -0
  51. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/apptotal.py +0 -0
  52. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/audit_logs.py +0 -0
  53. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/authentication_settings.py +0 -0
  54. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/client.py +0 -0
  55. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/cloud_apps.py +0 -0
  56. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/cloudappcontrol.py +0 -0
  57. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/device_management.py +0 -0
  58. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/dlp.py +0 -0
  59. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/errors.py +0 -0
  60. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/firewall.py +0 -0
  61. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/forwarding_control.py +0 -0
  62. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/isolation_profile.py +0 -0
  63. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/sandbox.py +0 -0
  64. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/security.py +0 -0
  65. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/ssl_inspection.py +0 -0
  66. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/url_categories.py +0 -0
  67. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/url_filtering.py +0 -0
  68. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/web_dlp.py +0 -0
  69. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/workload_groups.py +0 -0
  70. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zia/zpa_gateway.py +0 -0
  71. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/README.md +0 -0
  72. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/__init__.py +0 -0
  73. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/app_segments.py +0 -0
  74. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/app_segments_inspection.py +0 -0
  75. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/app_segments_pra.py +0 -0
  76. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/authdomains.py +0 -0
  77. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/certificates.py +0 -0
  78. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/client.py +0 -0
  79. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/cloud_connector_groups.py +0 -0
  80. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/connectors.py +0 -0
  81. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/emergency_access.py +0 -0
  82. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/errors.py +0 -0
  83. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/idp.py +0 -0
  84. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/inspection.py +0 -0
  85. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/isolation.py +0 -0
  86. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/lss.py +0 -0
  87. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/machine_groups.py +0 -0
  88. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/microtenants.py +0 -0
  89. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/posture_profiles.py +0 -0
  90. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/privileged_remote_access.py +0 -0
  91. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/provisioning.py +0 -0
  92. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/saml_attributes.py +0 -0
  93. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/scim_attributes.py +0 -0
  94. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/scim_groups.py +0 -0
  95. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/segment_groups.py +0 -0
  96. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/server_groups.py +0 -0
  97. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/servers.py +0 -0
  98. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/service_edges.py +0 -0
  99. {zscaler_sdk_python-0.9.5 → zscaler_sdk_python-0.9.6}/zscaler/zpa/trusted_networks.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zscaler-sdk-python
3
- Version: 0.9.5
3
+ Version: 0.9.6
4
4
  Summary: Official Python SDK for the Zscaler Products (Beta)
5
5
  Home-page: https://github.com/zscaler/zscaler-sdk-python
6
6
  License: MIT
@@ -42,8 +42,8 @@ Requires-Dist: requests (>=2.32.3)
42
42
  Requires-Dist: responses (>=0.25.3)
43
43
  Requires-Dist: restfly (>=1.5.0)
44
44
  Requires-Dist: six
45
- Requires-Dist: xmltodict
46
- Requires-Dist: yarl
45
+ Requires-Dist: xmltodict (>=0.14.2)
46
+ Requires-Dist: yarl (>=1.14.0)
47
47
  Project-URL: Bug Tracker, https://github.com/zscaler/zscaler-sdk-python/issues
48
48
  Project-URL: Documentation, https://zscaler-sdk-python.readthedocs.io
49
49
  Project-URL: Repository, https://github.com/zscaler/zscaler-sdk-python
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "zscaler-sdk-python"
3
- version = "0.9.5"
3
+ version = "0.9.6"
4
4
  description = "Official Python SDK for the Zscaler Products (Beta)"
5
5
  authors = ["Zscaler, Inc. <devrel@zscaler.com>"]
6
6
  license = "MIT"
@@ -41,15 +41,14 @@ restfly = ">=1.5.0"
41
41
  six = "*"
42
42
  flatdict = "*"
43
43
  pyyaml = "*"
44
- xmltodict = "*"
45
- yarl = "*"
44
+ xmltodict = ">=0.14.2"
45
+ yarl = ">=1.14.0"
46
46
  pycryptodomex = ">=3.20.0"
47
47
  aenum = "*"
48
48
  pydash = ">=8.0.3"
49
49
  flake8 = "*"
50
50
  pytz = ">=2024.2"
51
51
  black = ">=24.3.0"
52
- # cryptography = ">=3.4,<43.0"
53
52
  cryptography = ">=43.0.0"
54
53
  okta = ">=2.9.7"
55
54
  aiohttp = ">=3.10.2"
@@ -61,7 +60,7 @@ pytest-asyncio = "^0.23.8"
61
60
  pytest-mock = "*"
62
61
  pytest-recording = "^0.13.2"
63
62
  pytest-cov = "*"
64
- pyfakefs = "^5.6.0"
63
+ pyfakefs = ">=5.6.0"
65
64
  isort = "*"
66
65
  wheel = "*"
67
66
  sphinx = "^7.4.7"
@@ -29,7 +29,7 @@ __license__ = "MIT"
29
29
  __contributors__ = [
30
30
  "William Guilherme",
31
31
  ]
32
- __version__ = "0.9.5"
32
+ __version__ = "0.9.6"
33
33
 
34
34
  from zscaler.zdx import ZDXClientHelper # noqa
35
35
  from zscaler.zia import ZIAClientHelper # noqa
@@ -399,67 +399,99 @@ class ZIAClientHelper(ZIAClient):
399
399
  time.sleep(delay)
400
400
  return self.send("DELETE", path, json, params)
401
401
 
402
- ERROR_MESSAGES = {
403
- "UNEXPECTED_STATUS": "Unexpected status code {status_code} received for page {page}.",
404
- "MISSING_DATA_KEY": "The key '{data_key_name}' was not found in the response for page {page}.",
405
- "EMPTY_RESULTS": "No results found for page {page}.",
406
- }
407
-
408
- def get_paginated_data(self, path=None, data_key_name=None, data_per_page=5, expected_status_code=200):
409
- """
410
- Fetch paginated data from the ZIA API.
411
- ...
402
+ def get_paginated_data(
403
+ self,
404
+ path=None,
405
+ expected_status_code=200,
406
+ page=None,
407
+ pagesize=None,
408
+ search=None,
409
+ ):
410
+ """
411
+ Fetches paginated data from the API based on specified parameters and handles pagination.
412
+
413
+ Args:
414
+ path (str): The API endpoint path to send requests to.
415
+ expected_status_code (int): The expected HTTP status code for a successful request. Defaults to 200.
416
+ page (int): Specific page number to fetch. Defaults to 1 if not provided.
417
+ pagesize (int): Number of items per page, default is 100, with a maximum of 1000.
418
+ search (str): Search query to filter the results.
412
419
 
413
420
  Returns:
414
- - list: List of fetched items.
415
- - str: Error message, if any occurred.
421
+ tuple: A tuple containing:
422
+ - BoxList: A list of fetched items wrapped in a BoxList for easy access.
423
+ - str: An error message if any occurred during the data fetching process.
416
424
  """
425
+ logger = logging.getLogger(__name__)
417
426
 
418
- page = 1
419
- ret_data = []
420
- error_message = None
421
-
422
- while True:
423
- required_url = f"{path}"
424
- should_wait, delay = self.rate_limiter.wait("GET")
425
- if should_wait:
426
- time.sleep(delay)
427
-
428
- # Now proceed with sending the request
429
- response = self.send(
430
- method="GET",
431
- path=required_url,
432
- params={"page": page, "pageSize": data_per_page},
433
- )
427
+ ERROR_MESSAGES = {
428
+ "UNEXPECTED_STATUS": "Unexpected status code {status_code} received for page {page}.",
429
+ "EMPTY_RESULTS": "No results found for page {page}.",
430
+ }
431
+
432
+ params = {}
433
+ params["page"] = page if page is not None else 1 # Default to page 1
434
+ params["pagesize"] = min(pagesize if pagesize is not None else 100, 1000) # Default pagesize is 100, max 1000
434
435
 
435
- if response.status_code != expected_status_code:
436
- error_message = self.ERROR_MESSAGES["UNEXPECTED_STATUS"].format(status_code=response.status_code, page=page)
437
- logger.error(error_message)
438
- break
439
- data_json = response.json()
440
- if isinstance(data_json, list):
441
- data = data_json
442
- else:
443
- data = data_json.get(data_key_name)
436
+ if search:
437
+ params["search"] = search
438
+
439
+ ret_data = []
444
440
 
445
- if data is None:
446
- error_message = self.ERROR_MESSAGES["MISSING_DATA_KEY"].format(data_key_name=data_key_name, page=page)
447
- logger.error(error_message)
448
- break
441
+ try:
442
+ while True:
443
+ # Apply rate-limiting if necessary
444
+ should_wait, delay = self.rate_limiter.wait("GET")
445
+ if should_wait:
446
+ time.sleep(delay)
447
+
448
+ # Send the request to the API
449
+ response = self.send("GET", path=path, params=params)
450
+
451
+ # Check for unexpected status code
452
+ if response.status_code != expected_status_code:
453
+ error_msg = ERROR_MESSAGES["UNEXPECTED_STATUS"].format(
454
+ status_code=response.status_code, page=params["page"]
455
+ )
456
+ logger.error(error_msg)
457
+ return BoxList([]), error_msg
458
+
459
+ # Parse the response as a flat list of items
460
+ response_data = response.json()
461
+ if not isinstance(response_data, list):
462
+ error_msg = ERROR_MESSAGES["EMPTY_RESULTS"].format(page=params["page"])
463
+ logger.warn(error_msg)
464
+ return BoxList([]), error_msg
465
+
466
+ data = convert_keys_to_snake(response_data)
467
+
468
+ # If searching for a specific item, stop if we find a match
469
+ if search:
470
+ for item in data:
471
+ if item.get("name") == search:
472
+ ret_data.append(item)
473
+ return BoxList(ret_data), None
474
+
475
+ # If no search, collect all data from the current page
476
+ ret_data.extend(data)
477
+
478
+ # Stop if we've processed all available pages
479
+ if len(data) < params["pagesize"]:
480
+ break
449
481
 
450
- if not data: # Checks for empty data
451
- logger.info(self.ERROR_MESSAGES["EMPTY_RESULTS"].format(page=page))
452
- break
482
+ # Move to the next page
483
+ params["page"] += 1
453
484
 
454
- ret_data.extend(convert_keys_to_snake(data))
485
+ finally:
486
+ time.sleep(2) # Ensure a delay between requests regardless of outcome
455
487
 
456
- # Check for more pages
457
- if len(data) == 0 or isinstance(data_json, dict) and int(response.json().get("totalPages")) <= page + 1:
458
- break
488
+ if not ret_data:
489
+ error_msg = ERROR_MESSAGES["EMPTY_RESULTS"].format(page=params["page"])
490
+ logger.warn(error_msg)
491
+ return BoxList([]), error_msg
459
492
 
460
- page += 1
493
+ return BoxList(ret_data), None
461
494
 
462
- return BoxList(ret_data), error_message
463
495
 
464
496
  @property
465
497
  def admin_and_role_management(self):
@@ -48,7 +48,8 @@ class AdminAndRoleManagementAPI:
48
48
  >>> users = zia.admin_and_role_management.list_users('admin@example.com')
49
49
 
50
50
  """
51
- return BoxList(Iterator(self.rest, "adminUsers", **kwargs))
51
+ list, _ = self.rest.get_paginated_data(path="/adminUsers", **kwargs)
52
+ return list
52
53
 
53
54
  def get_user(self, user_id: str) -> Box:
54
55
  """
@@ -58,7 +58,8 @@ class RuleLabelsAPI:
58
58
  ... print(label)
59
59
 
60
60
  """
61
- return BoxList(Iterator(self.rest, "ruleLabels", **kwargs))
61
+ list, _ = self.rest.get_paginated_data(path="/ruleLabels", **kwargs)
62
+ return list
62
63
 
63
64
  def get_label(self, label_id: str) -> Box:
64
65
  """
@@ -64,7 +64,8 @@ class LocationsAPI:
64
64
  ... print(location)
65
65
 
66
66
  """
67
- return BoxList(Iterator(self.rest, "locations", **kwargs))
67
+ list, _ = self.rest.get_paginated_data(path="/locations", **kwargs)
68
+ return list
68
69
 
69
70
  def get_location(self, location_id: str = None, location_name: str = None) -> Box:
70
71
  """
@@ -642,7 +642,8 @@ class TrafficForwardingAPI:
642
642
  >>> for credential in zia.traffic.list_vpn_credentials(page_size=200, max_pages=2):
643
643
  ... print(credential)
644
644
  """
645
- return BoxList(Iterator(self.rest, "vpnCredentials", **kwargs))
645
+ list, _ = self.rest.get_paginated_data(path="/vpnCredentials", **kwargs)
646
+ return list
646
647
 
647
648
  def add_vpn_credential(self, authentication_type: str, pre_shared_key: str = None, **kwargs) -> Box:
648
649
  """
@@ -69,7 +69,8 @@ class UserManagementAPI:
69
69
  >>> for department in zia.users.list_departments(page_size=200, max_pages=2):
70
70
  ... print(department)
71
71
  """
72
- return BoxList(Iterator(self.rest, "departments", **kwargs))
72
+ list, _ = self.rest.get_paginated_data(path="/departments", **kwargs)
73
+ return list
73
74
 
74
75
  def get_department(self, department_id: str) -> Box:
75
76
  """
@@ -127,7 +128,8 @@ class UserManagementAPI:
127
128
  ... print(group)
128
129
 
129
130
  """
130
- return BoxList(Iterator(self.rest, "groups", **kwargs))
131
+ list, _ = self.rest.get_paginated_data(path="/groups", **kwargs)
132
+ return list
131
133
 
132
134
  def get_group(self, group_id: str) -> Box:
133
135
  """
@@ -194,7 +196,8 @@ class UserManagementAPI:
194
196
  ... print(user)
195
197
 
196
198
  """
197
- return BoxList(Iterator(self.rest, "users", **kwargs))
199
+ list, _ = self.rest.get_paginated_data(path="/users", **kwargs)
200
+ return list
198
201
 
199
202
  def add_user(self, name: str, email: str, groups: list, department: dict, **kwargs) -> Box:
200
203
  """
@@ -78,7 +78,14 @@ class PolicySetsAPI:
78
78
  "COUNTRY_CODE": [],
79
79
  }
80
80
 
81
+ current_operator = "OR" # Default operator
82
+
81
83
  for condition in conditions:
84
+ # Check if the first item is an operator, like "AND" or "OR"
85
+ if isinstance(condition, tuple) and isinstance(condition[0], str) and condition[0].upper() in ["AND", "OR"]:
86
+ current_operator = condition[0].upper() # Set the current operator
87
+ condition = condition[1] # The second element is the actual condition
88
+
82
89
  if isinstance(condition, tuple) and len(condition) == 3:
83
90
  # Handle each object type according to its pattern
84
91
  object_type = condition[0].upper()
@@ -110,10 +117,15 @@ class PolicySetsAPI:
110
117
  object_types_to_operands[object_type].append({"objectType": object_type, "lhs": lhs, "rhs": rhs})
111
118
  else:
112
119
  object_types_to_operands[object_type].append({"objectType": object_type, "lhs": "id", "rhs": rhs})
120
+
113
121
  elif isinstance(condition, dict):
122
+ # This part allows passing operator explicitly through conditions
123
+ if "operator" in condition:
124
+ current_operator = condition["operator"]
125
+ continue # Move to the next condition after setting the operator
126
+
114
127
  # Handle the dictionary logic based on the Go code schema
115
128
  condition_template = {}
116
-
117
129
  # Extracting keys from the condition dictionary
118
130
  for key in ["id", "negated", "operator"]:
119
131
  if key in condition:
@@ -144,12 +156,12 @@ class PolicySetsAPI:
144
156
 
145
157
  # Combine APP and APP_GROUP operands into one block
146
158
  if app_and_app_group_operands:
147
- template.append({"operator": "OR", "operands": app_and_app_group_operands})
159
+ template.append({"operator": current_operator, "operands": app_and_app_group_operands})
148
160
 
149
161
  # Combine other object types into their own blocks
150
162
  for object_type, operands in object_types_to_operands.items():
151
163
  if operands:
152
- template.append({"operator": "OR", "operands": operands})
164
+ template.append({"operator": current_operator, "operands": operands})
153
165
 
154
166
  return template
155
167
 
@@ -390,7 +402,9 @@ class PolicySetsAPI:
390
402
  ('app', 'id', '88888'),
391
403
  ('app_group', 'id', '77777),
392
404
  ('client_type', 'zpn_client_type_exporter', 'zpn_client_type_zapp'),
393
- ('trusted_network', 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx', True)]
405
+ ("OR", 'trusted_network', 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx', True))
406
+ ("OR", ("posture", "d019df8b-ec97-4087-a892-749b5abca54c", "false")),
407
+ ]
394
408
  custom_msg (str):
395
409
  A custom message.
396
410
  description (str):