From 5ef4f5d89c3371ea0f189aac875680d83d9d43f5 Mon Sep 17 00:00:00 2001 From: "nathaniel.strauss" Date: Tue, 25 Feb 2025 18:43:02 -0600 Subject: [PATCH 1/5] computers sort --- src/jamf_pro_sdk/models/pro/api_options.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/jamf_pro_sdk/models/pro/api_options.py b/src/jamf_pro_sdk/models/pro/api_options.py index 42bbe93..b00adfb 100644 --- a/src/jamf_pro_sdk/models/pro/api_options.py +++ b/src/jamf_pro_sdk/models/pro/api_options.py @@ -27,28 +27,27 @@ ] get_computer_inventory_v1_allowed_sort_fields = [ - "general.name", - "udid", - "id", - "general.assetTag", + "general.assetTag,", "general.jamfBinaryVersion", + "general.lastCloudBackupDate,", "general.lastContactTime", "general.lastEnrolledDate", - "general.lastCloudBackupDate", - "general.reportDate", - "general.remoteManagement.managementUsername", "general.mdmCertificateExpiration", + "general.name", "general.platform", + "general.reportDate,", "hardware.make", "hardware.model", + "id", "operatingSystem.build", - "operatingSystem.supplementalBuildVersion", - "operatingSystem.rapidSecurityResponse", "operatingSystem.name", - "operatingSystem.version", - "userAndLocation.realname", + "operatingSystem.rapidSecurityResponse", + "operatingSystem.supplementalBuildVersion", + "operatingSystem.version,", "purchasing.lifeExpectancy", "purchasing.warrantyDate", + "udid", + "userAndLocation.realname", ] get_computer_inventory_v1_allowed_filter_fields = [ From 48b705894562bdc70a0c4049b2b1eb2126600b6b Mon Sep 17 00:00:00 2001 From: "nathaniel.strauss" Date: Tue, 25 Feb 2025 18:47:52 -0600 Subject: [PATCH 2/5] computer sections alpha --- src/jamf_pro_sdk/models/pro/api_options.py | 34 +++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/jamf_pro_sdk/models/pro/api_options.py b/src/jamf_pro_sdk/models/pro/api_options.py index b00adfb..2d998b9 100644 --- a/src/jamf_pro_sdk/models/pro/api_options.py +++ b/src/jamf_pro_sdk/models/pro/api_options.py @@ -1,29 +1,29 @@ get_computer_inventory_v1_allowed_sections = [ "ALL", - "GENERAL", - "DISK_ENCRYPTION", - "PURCHASING", "APPLICATIONS", - "STORAGE", - "USER_AND_LOCATION", + "ATTACHMENTS", + "CERTIFICATES", "CONFIGURATION_PROFILES", - "PRINTERS", - "SERVICES", + "CONTENT_CACHING", + "DISK_ENCRYPTION", + "EXTENSION_ATTRIBUTES", + "FONTS", + "GENERAL", + "GROUP_MEMBERSHIPS", "HARDWARE", + "IBEACONS", + "LICENSED_SOFTWARE", "LOCAL_USER_ACCOUNTS", - "CERTIFICATES", - "ATTACHMENTS", - "PLUGINS", + "OPERATING_SYSTEM", "PACKAGE_RECEIPTS", - "FONTS", + "PLUGINS", + "PRINTERS", + "PURCHASING", "SECURITY", - "OPERATING_SYSTEM", - "LICENSED_SOFTWARE", - "IBEACONS", + "SERVICES", "SOFTWARE_UPDATES", - "EXTENSION_ATTRIBUTES", - "CONTENT_CACHING", - "GROUP_MEMBERSHIPS", + "STORAGE", + "USER_AND_LOCATION", ] get_computer_inventory_v1_allowed_sort_fields = [ From c38a42f43ca5d48b2e98b7cc7ea89219b6c5534a Mon Sep 17 00:00:00 2001 From: "nathaniel.strauss" Date: Tue, 25 Feb 2025 18:48:43 -0600 Subject: [PATCH 3/5] computer filter fields --- src/jamf_pro_sdk/models/pro/api_options.py | 42 +++++++++++----------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/jamf_pro_sdk/models/pro/api_options.py b/src/jamf_pro_sdk/models/pro/api_options.py index 2d998b9..6c6eab9 100644 --- a/src/jamf_pro_sdk/models/pro/api_options.py +++ b/src/jamf_pro_sdk/models/pro/api_options.py @@ -51,29 +51,28 @@ ] get_computer_inventory_v1_allowed_filter_fields = [ - "general.name", - "udid", - "id", + "diskEncryption.fileVault2Enabled", "general.assetTag", "general.barcode1", "general.barcode2", + "general.declarativeDeviceManagementEnabled", "general.enrolledViaAutomatedDeviceEnrollment", - "general.lastIpAddress", "general.itunesStoreAccountActive", "general.jamfBinaryVersion", + "general.lastCloudBackupDate", "general.lastContactTime", "general.lastEnrolledDate", - "general.lastCloudBackupDate", - "general.reportDate", + "general.lastIpAddress", "general.lastReportedIp", "general.managementId", - "general.remoteManagement.managed", "general.mdmCapable.capable", "general.mdmCertificateExpiration", + "general.name", "general.platform", + "general.remoteManagement.managed", + "general.reportDate", "general.supervised", "general.userApprovedMdm", - "general.declarativeDeviceManagementEnabled", "hardware.bleCapable", "hardware.macAddress", "hardware.make", @@ -82,31 +81,32 @@ "hardware.serialNumber", "hardware.supportsIosAppInstalls", "hardware.appleSilicon", + "id", "operatingSystem.activeDirectoryStatus", - "operatingSystem.fileVault2Status", "operatingSystem.build", - "operatingSystem.supplementalBuildVersion", - "operatingSystem.rapidSecurityResponse", + "operatingSystem.fileVault2Status", "operatingSystem.name", + "operatingSystem.rapidSecurityResponse", + "operatingSystem.supplementalBuildVersion", "operatingSystem.version", + "purchasing.appleCareId", + "purchasing.leased", + "purchasing.lifeExpectancy", + "purchasing.purchased", + "purchasing.vendor", + "purchasing.warrantyDate", "security.activationLockEnabled", - "security.recoveryLockEnabled", "security.firewallEnabled", - "serAndLocation.buildingId", + "security.recoveryLockEnabled", + "udid", + "userAndLocation.buildingId", "userAndLocation.departmentId", "userAndLocation.email", - "userAndLocation.realname", "userAndLocation.phone", "userAndLocation.position", + "userAndLocation.realname", "userAndLocation.room", "userAndLocation.username", - "diskEncryption.fileVault2Enabled", - "purchasing.appleCareId", - "purchasing.lifeExpectancy", - "purchasing.purchased", - "purchasing.leased", - "purchasing.vendor", - "purchasing.warrantyDate", ] get_packages_v1_allowed_sort_fields = [ From 0e23cb09b70c0c27ed886b7261d550021e1bdf23 Mon Sep 17 00:00:00 2001 From: "nathaniel.strauss" Date: Tue, 25 Feb 2025 19:04:52 -0600 Subject: [PATCH 4/5] mobile device sort filter --- src/jamf_pro_sdk/models/pro/api_options.py | 120 +++++++++++---------- 1 file changed, 61 insertions(+), 59 deletions(-) diff --git a/src/jamf_pro_sdk/models/pro/api_options.py b/src/jamf_pro_sdk/models/pro/api_options.py index 6c6eab9..e08627d 100644 --- a/src/jamf_pro_sdk/models/pro/api_options.py +++ b/src/jamf_pro_sdk/models/pro/api_options.py @@ -27,15 +27,15 @@ ] get_computer_inventory_v1_allowed_sort_fields = [ - "general.assetTag,", + "general.assetTag", "general.jamfBinaryVersion", - "general.lastCloudBackupDate,", + "general.lastCloudBackupDate" "general.lastContactTime", "general.lastEnrolledDate", "general.mdmCertificateExpiration", "general.name", "general.platform", - "general.reportDate,", + "general.reportDate", "hardware.make", "hardware.model", "id", @@ -43,7 +43,7 @@ "operatingSystem.name", "operatingSystem.rapidSecurityResponse", "operatingSystem.supplementalBuildVersion", - "operatingSystem.version,", + "operatingSystem.version", "purchasing.lifeExpectancy", "purchasing.warrantyDate", "udid", @@ -266,49 +266,92 @@ ] get_mobile_device_inventory_v2_allowed_sort_fields = [ + "activationLockEnabled", "airPlayPassword", "appAnalyticsEnabled", + "appleCareId", "assetTag", "availableSpaceMb", - "batteryLevel", "batteryHealth", + "batteryLevel", + "blockEncryptionCapable", "bluetoothLowEnergyCapable", "bluetoothMacAddress", + "building", "capacityMb", - "lostModeEnabledDate", + "carrierSettingsVersion", + "cellularTechnology", + "cloudBackupEnabled", + "currentCarrierNetwork", + "currentMobileCountryCode", + "currentMobileNetworkCode", + "dataProtection", + "dataRoamingEnabled", "declarativeDeviceManagementEnabled", + "department", "deviceId", "deviceLocatorServiceEnabled", + "deviceOwnershipType", "devicePhoneNumber", "diagnosticAndUsageReportingEnabled", "displayName", "doNotDisturbEnabled", + "eid", + "emailAddress" "enrollmentSessionTokenValid", "exchangeDeviceId", - "cloudBackupEnabled", - "osBuild", - "osSupplementalBuildVersion", - "osVersion", - "osRapidSecurityResponse", + "fileEncryptionCapable", + "fullName", + "hardwareEncryptionSupported", + "homeMobileCountryCode", + "homeMobileNetworkCode", + "iccid", + "imei", + "imei2", "ipAddress", "itunesStoreAccountActive", - "mobileDeviceId", + "jailbreakStatus", "languages", "lastBackupDate", - "lastEnrolledDate", "lastCloudBackupDate", + "lastEnrolledDate", "lastInventoryUpdateDate", + "leaseExpirationDate,lifeExpectancyYears", "locales", "locationServicesForSelfServiceMobileEnabled", "lostModeEnabled", + "lostModeEnabledDate", "managed", + "managementId", "mdmProfileExpirationDate", + "meid", + "mobileDeviceId", "model", "modelIdentifier", "modelNumber", "modemFirmwareVersion", + "network", + "osBuild", + "osRapidSecurityResponse", + "osSupplementalBuildVersion", + "osVersion", + "passcodeCompliant", + "passcodeCompliantWithProfile", + "passcodeLockGracePeriodEnforcedSeconds", + "passcodePresent", + "personalDeviceProfileCurrent", + "personalHotspotEnabled", + "poDate", + "poNumber", + "position", + "purchasedOrLeased", + "purchasePrice", + "purchasingAccount", + "purchasingContact", "quotaSize", "residentUsers", + "roaming", + "room", "serialNumber", "sharedIpad", "supervised", @@ -316,55 +359,12 @@ "timeZone", "udid", "usedSpacePercentage", - "wifiMacAddress", - "deviceOwnershipType", - "building", - "department", - "emailAddress", - "fullName", - "userPhoneNumber", - "position", - "room", "username", - "appleCareId", - "leaseExpirationDate", - "lifeExpectancyYears", - "poDate", - "poNumber", - "purchasePrice", - "purchasedOrLeased", - "purchasingAccount", - "purchasingContact", + "userPhoneNumber", "vendor", - "warrantyExpirationDate", - "activationLockEnabled", - "blockEncryptionCapable", - "dataProtection", - "fileEncryptionCapable", - "hardwareEncryptionSupported", - "jailbreakStatus", - "passcodeCompliant", - "passcodeCompliantWithProfile", - "passcodeLockGracePeriodEnforcedSeconds", - "passcodePresent", - "personalDeviceProfileCurrent", - "carrierSettingsVersion", - "cellularTechnology", - "currentCarrierNetwork", - "currentMobileCountryCode", - "currentMobileNetworkCode", - "dataRoamingEnabled", - "eid", - "network", - "homeMobileCountryCode", - "homeMobileNetworkCode", - "iccid", - "imei", - "imei2", - "meid", - "personalHotspotEnabled", "voiceRoamingEnabled", - "roaming", + "warrantyExpirationDate", + "wifiMacAddress", ] get_mobile_device_inventory_v2_allowed_filter_fields = [ @@ -392,7 +392,9 @@ "ipAddress", "itunesStoreAccountActive", "mobileDeviceId", + "managementId", "languages", + "lastInventoryUpdateDate", "locales", "locationServicesForSelfServiceMobileEnabled", "lostModeEnabled", From 593f09059a23a89066abfc846faa0f58242663c5 Mon Sep 17 00:00:00 2001 From: "nathaniel.strauss" Date: Tue, 25 Feb 2025 19:52:23 -0600 Subject: [PATCH 5/5] implement skip_expression_validation --- src/jamf_pro_sdk/clients/pro_api/__init__.py | 48 +++++++++++++++---- .../clients/pro_api/pagination.py | 6 +++ 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/jamf_pro_sdk/clients/pro_api/__init__.py b/src/jamf_pro_sdk/clients/pro_api/__init__.py index 9de1da3..b307883 100644 --- a/src/jamf_pro_sdk/clients/pro_api/__init__.py +++ b/src/jamf_pro_sdk/clients/pro_api/__init__.py @@ -64,6 +64,7 @@ def get_computer_inventory_v1( page_size: int = ..., sort_expression: Optional[SortExpression] = ..., filter_expression: Optional[FilterExpression] = ..., + skip_expression_validation: Optional[bool] = ..., return_generator: Literal[False] = False, ) -> List[Computer]: ... @@ -76,6 +77,7 @@ def get_computer_inventory_v1( page_size: int = ..., sort_expression: Optional[SortExpression] = ..., filter_expression: Optional[FilterExpression] = ..., + skip_expression_validation: Optional[bool] = ..., return_generator: Literal[True] = True, ) -> Iterator[Page]: ... @@ -87,6 +89,7 @@ def get_computer_inventory_v1( page_size: int = 100, sort_expression: Optional[SortExpression] = None, filter_expression: Optional[FilterExpression] = None, + skip_expression_validation: Optional[bool] = False, return_generator: bool = False, ) -> Union[List[Computer], Iterator[Page]]: """Returns a list of computer inventory records. @@ -131,6 +134,10 @@ def get_computer_inventory_v1( :type filter_expression: FilterExpression + :param skip_expression_validation: (optional) If ``True`` sort and filter field values validation is skipped. + Intended to be used in situations where a newer API version is ahead of the SDK release. + :type skip_expression_validation: bool + :param return_generator: If ``True`` a generator is returned to iterate over pages. By default, the results for all pages will be returned in a single response. :type return_generator: bool @@ -149,10 +156,10 @@ def get_computer_inventory_v1( f"Values for 'sections' must be one of: {', '.join(get_computer_inventory_v1_allowed_sections)}" ) - if sort_expression: + if sort_expression and not skip_expression_validation: sort_expression.validate(get_computer_inventory_v1_allowed_sort_fields) - if filter_expression: + if filter_expression and not skip_expression_validation: filter_expression.validate(get_computer_inventory_v1_allowed_filter_fields) paginator = Paginator( @@ -164,6 +171,7 @@ def get_computer_inventory_v1( page_size=page_size, sort_expression=sort_expression, filter_expression=filter_expression, + skip_expression_validation=skip_expression_validation, extra_params={"section": ",".join(sections)}, ) @@ -179,6 +187,7 @@ def get_packages_v1( page_size: int = ..., sort_expression: Optional[SortExpression] = ..., filter_expression: Optional[FilterExpression] = ..., + skip_expression_validation: Optional[bool] = ..., return_generator: Literal[False] = False, ) -> List[Package]: ... @@ -190,6 +199,7 @@ def get_packages_v1( page_size: int = ..., sort_expression: Optional[SortExpression] = ..., filter_expression: Optional[FilterExpression] = ..., + skip_expression_validation: Optional[bool] = ..., return_generator: Literal[True] = True, ) -> Iterator[Page]: ... @@ -200,6 +210,7 @@ def get_packages_v1( page_size: int = 100, sort_expression: Optional[SortExpression] = None, filter_expression: Optional[FilterExpression] = None, + skip_expression_validation: Optional[bool] = False, return_generator: bool = False, ) -> Union[List[Package], Iterator[Page]]: """Returns a list of package records. @@ -234,6 +245,10 @@ def get_packages_v1( :type filter_expression: FilterExpression + :param skip_expression_validation: (optional) If ``True`` sort and filter field values validation is skipped. + Intended to be used in situations where a newer API version is ahead of the SDK release. + :type skip_expression_validation: bool + :param return_generator: If ``True`` a generator is returned to iterate over pages. By default, the results for all pages will be returned in a single response. :type return_generator: bool @@ -242,10 +257,10 @@ def get_packages_v1( :rtype: List[~jamf_pro_sdk.models.pro.packages.package] | Iterator[Page] """ - if sort_expression: + if sort_expression and not skip_expression_validation: sort_expression.validate(get_packages_v1_allowed_sort_fields) - if filter_expression: + if filter_expression and not skip_expression_validation: filter_expression.validate(get_packages_v1_allowed_filter_fields) paginator = Paginator( @@ -257,6 +272,7 @@ def get_packages_v1( page_size=page_size, sort_expression=sort_expression, filter_expression=filter_expression, + skip_expression_validation=skip_expression_validation, ) return paginator(return_generator=return_generator) @@ -393,6 +409,7 @@ def get_mdm_commands_v2( end_page: Optional[int] = ..., page_size: int = ..., sort_expression: Optional[SortExpression] = ..., + skip_expression_validation: Optional[bool] = ..., return_generator: Literal[False] = False, ) -> List[MdmCommandStatus]: ... @@ -404,6 +421,7 @@ def get_mdm_commands_v2( end_page: Optional[int] = ..., page_size: int = ..., sort_expression: Optional[SortExpression] = ..., + skip_expression_validation: Optional[bool] = ..., return_generator: Literal[True] = True, ) -> Iterator[Page]: ... @@ -414,6 +432,7 @@ def get_mdm_commands_v2( end_page: Optional[int] = None, page_size: int = 100, sort_expression: Optional[SortExpression] = None, + skip_expression_validation: Optional[bool] = False, return_generator: bool = False, ) -> Union[List[MdmCommandStatus], Iterator[Page]]: """Returns a list of MDM commands. @@ -449,6 +468,10 @@ def get_mdm_commands_v2( :type sort_expression: SortExpression + :param skip_expression_validation: (optional) If ``True`` sort and filter field values validation is skipped. + Intended to be used in situations where a newer API version is ahead of the SDK release. + :type skip_expression_validation: bool + :param return_generator: If ``True`` an iterator is returned that yields pages. By default, the results for all pages will be returned in a single response. :type return_generator: bool @@ -465,10 +488,10 @@ def get_mdm_commands_v2( f"Values for 'command' filters must be one of: {', '.join(get_mdm_commands_v2_allowed_command_types)}" ) - if sort_expression: + if sort_expression and not skip_expression_validation: sort_expression.validate(get_mdm_commands_v2_allowed_sort_fields) - if filter_expression: + if filter_expression and not skip_expression_validation: filter_expression.validate(get_mdm_commands_v2_allowed_filter_fields) paginator = Paginator( @@ -480,6 +503,7 @@ def get_mdm_commands_v2( page_size=page_size, sort_expression=sort_expression, filter_expression=filter_expression, + skip_expression_validation=skip_expression_validation, ) return paginator(return_generator=return_generator) @@ -495,6 +519,7 @@ def get_mobile_device_inventory_v2( page_size: int = ..., sort_expression: Optional[SortExpression] = ..., filter_expression: Optional[FilterExpression] = ..., + skip_expression_validation: Optional[bool] = ..., return_generator: Literal[False] = False, ) -> List[MobileDevice]: ... @@ -507,6 +532,7 @@ def get_mobile_device_inventory_v2( page_size: int = ..., sort_expression: Optional[SortExpression] = ..., filter_expression: Optional[FilterExpression] = ..., + skip_expression_validation: Optional[bool] = ..., return_generator: Literal[True] = True, ) -> Iterator[Page]: ... @@ -518,6 +544,7 @@ def get_mobile_device_inventory_v2( page_size: int = 100, sort_expression: Optional[SortExpression] = None, filter_expression: Optional[FilterExpression] = None, + skip_expression_validation: Optional[bool] = False, return_generator: bool = False, ) -> Union[List[MobileDevice], Iterator[Page]]: """Returns a list of mobile device (iOS and tvOS) inventory records. @@ -562,6 +589,10 @@ def get_mobile_device_inventory_v2( :type filter_expression: FilterExpression + :param skip_expression_validation: (optional) If ``True`` sort and filter field values validation is skipped. + Intended to be used in situations where a newer API version is ahead of the SDK release. + :type skip_expression_validation: bool + :param return_generator: If ``True`` a generator is returned to iterate over pages. By default, the results for all pages will be returned in a single response. :type return_generator: bool @@ -580,10 +611,10 @@ def get_mobile_device_inventory_v2( f"Values for 'sections' must be one of: {', '.join(get_mobile_device_inventory_v2_allowed_sections)}" ) - if sort_expression: + if sort_expression and not skip_expression_validation: sort_expression.validate(get_mobile_device_inventory_v2_allowed_sort_fields) - if filter_expression: + if filter_expression and not skip_expression_validation: filter_expression.validate(get_mobile_device_inventory_v2_allowed_filter_fields) paginator = Paginator( @@ -595,6 +626,7 @@ def get_mobile_device_inventory_v2( page_size=page_size, sort_expression=sort_expression, filter_expression=filter_expression, + skip_expression_validation=skip_expression_validation, extra_params={"section": ",".join(sections)}, ) diff --git a/src/jamf_pro_sdk/clients/pro_api/pagination.py b/src/jamf_pro_sdk/clients/pro_api/pagination.py index 2ac046c..e528b6a 100644 --- a/src/jamf_pro_sdk/clients/pro_api/pagination.py +++ b/src/jamf_pro_sdk/clients/pro_api/pagination.py @@ -152,6 +152,7 @@ def __init__( page_size: int = 100, sort_expression: Optional[SortExpression] = None, filter_expression: Optional[FilterExpression] = None, + skip_expression_validation: Optional[bool] = False, extra_params: Optional[Dict[str, str]] = None, ): """A paginator for the Jamf Pro API. A paginator automatically iterates over an API if @@ -196,6 +197,10 @@ def __init__( documentation for :ref:`Pro API Filtering` for more information. :type filter_expression: FilterExpression + :param skip_expression_validation: (optional) If ``True`` sort and filter field values validation is skipped. + Intended to be used in situations where a newer API version is ahead of the SDK release. + :type skip_expression_validation: bool + :param extra_params: (optional) A dictionary of key-value pairs that will be added to the query string parameters of the requests. :type extra_params: Dict[str, str] @@ -209,6 +214,7 @@ def __init__( self.page_size = page_size self.sort_expression = sort_expression self.filter_expression = filter_expression + self.skip_expression_validation = skip_expression_validation self.extra_params = extra_params def _paginated_request(self, page: int) -> Page: