From ef022712d34d7039be6e787849c75a0f915112f6 Mon Sep 17 00:00:00 2001 From: Tony Williams Date: Fri, 27 Oct 2023 20:33:03 +1100 Subject: [PATCH 1/2] sites with model, test, doco, and additions to classic_api.py --- docs/reference/models_classic.rst | 11 +++ src/jamf_pro_sdk/clients/classic_api.py | 98 +++++++++++++++++++++++ src/jamf_pro_sdk/models/classic/sites.py | 31 +++++++ tests/models/test_models_classic_sites.py | 24 ++++++ 4 files changed, 164 insertions(+) create mode 100644 src/jamf_pro_sdk/models/classic/sites.py create mode 100644 tests/models/test_models_classic_sites.py diff --git a/docs/reference/models_classic.rst b/docs/reference/models_classic.rst index 166f93f..d17334d 100644 --- a/docs/reference/models_classic.rst +++ b/docs/reference/models_classic.rst @@ -113,6 +113,17 @@ Packages ClassicPackage ClassicPackageItem +Sites +----- + +.. currentmodule:: jamf_pro_sdk.models.classic.sites + +.. autosummary:: + :toctree: _autosummary + + ClassicSite + ClassicSiteItem + Group and Search Criteria ------------------------- diff --git a/src/jamf_pro_sdk/clients/classic_api.py b/src/jamf_pro_sdk/clients/classic_api.py index 02af4c8..7d29d19 100644 --- a/src/jamf_pro_sdk/clients/classic_api.py +++ b/src/jamf_pro_sdk/clients/classic_api.py @@ -10,18 +10,24 @@ ClassicAdvancedComputerSearch, ClassicAdvancedComputerSearchesItem, ) + from ..models.classic.categories import ClassicCategoriesItem, ClassicCategory + from ..models.classic.computer_groups import ( ClassicComputerGroup, ClassicComputerGroupMember, ClassicComputerGroupMembershipUpdate, ) + from ..models.classic.computers import ( ClassicComputer, ClassicComputersItem, ) + from ..models.classic.packages import ClassicPackage, ClassicPackageItem +from ..models.classic.sites import ClassicSite, ClassicSitesItem + if TYPE_CHECKING: import requests @@ -45,6 +51,7 @@ int, ClassicAdvancedComputerSearch, ClassicAdvancedComputerSearchesItem ] PackageId = Union[int, ClassicPackage, ClassicPackageItem] +SiteId = Union[int, ClassicSite, ClassicSitesItem] def parse_response_id(xml: str) -> int: @@ -554,3 +561,94 @@ def delete_package_by_id(self, package: PackageId) -> None: """ package_id = ClassicApi._parse_id(package) self.api_request(method="delete", resource_path=f"packages/id/{package_id}") + + +# /sites APIs + + +def create_site(self, data: Union[str, ClassicSite]) -> int: + """Create a new site. + + Only the ``name`` is required. + + :param data: Can be an XML string or a + :class:`~jamf_pro_sdk.models.classic.sites.ClassicSite` object. + :type data: Union[str, ClassicSite] + + :return: ID of the new site. + :rtype: int + + """ + resp = self.api_request(method="post", resource_path="sites/id/0", data=data) + return parse_response_id(resp.text) + + +def list_all_sites(self) -> List[ClassicSitesItem]: + """Returns a list of all sites. + + :return: List of sites. + :rtype: List[~jamf_pro_sdk.models.classic.sites.ClassicSitesItem] + + """ + resp = self.api_request(method="get", resource_path="sites") + return [ClassicSitesItem(**i) for i in resp.json()["sites"]] + + +def get_site_by_id(self, site: SiteId) -> ClassicSite: + """Returns a single site record using the ID. + + :param site: A site ID or supported Classic API model. + :type site: Union[int, ClassicSite, ClassicSitesItem] + + :return: Site. + :rtype: ~jamf_pro_sdk.models.classic.sites.ClassicSite + + """ + site_id = ClassicApi._parse_id(site) + resp = self.api_request(method="get", resource_path=f"sites/id/{site_id}") + return ClassicSite(**resp.json()["site"]) + + +def update_site_by_id( + self, site: SiteId, data: Union[str, ClassicSite], return_updated: bool = False +): + """Update a site using the ID. + + :param site: A site ID or supported Classic API model. + :type site: Union[int, ClassicSite, ClassicSitesItem] + + :param data: Can be an XML string or a + :class:`~jamf_pro_sdk.models.classic.sites.ClassicSite` object. + :type data: Union[str, ClassicSite] + + """ + site_id = ClassicApi._parse_id(site) + self.api_request(method="put", resource_path=f"sites/id/{site_id}", data=data) + if return_updated: + return self.get_site_by_id(site_id) + + +def delete_site_by_id(self, site: SiteId) -> None: + """Delete a site using the ID. + + :param site: A site ID or supported Classic API model. + :type site: Union[int, ClassicSite, ClassicSitesItem] + + """ + site_id = ClassicApi._parse_id(site) + self.api_request(method="delete", resource_path=f"sites/id/{site_id}") + + +def create_site(self, data: Union[str, ClassicSite]) -> int: + """Create a new site. + + :param data: Can be an XML string or a + :class:`~jamf_pro_sdk.models.classic.sites.ClassicSite` object. + :type data: Union[str, ClassicSite] + + :return: ID of the new site. + :rtype: int + + """ + resp = self.api_request(method="post", resource_path="sites/id/0", data=data) + return parse_response_id(resp.text) diff --git a/src/jamf_pro_sdk/models/classic/sites.py b/src/jamf_pro_sdk/models/classic/sites.py new file mode 100644 index 0000000..f89ab66 --- /dev/null +++ b/src/jamf_pro_sdk/models/classic/sites.py @@ -0,0 +1,31 @@ +from typing import Optional + +from pydantic import Extra + +from .. import BaseModel +from . import ClassicApiModel + +_XML_ARRAY_ITEM_NAMES = {} + + +class ClassicSiteItem(BaseModel, extra=Extra.allow): + """Represents a site record returned by the + :meth:`~jamf_pro_sdk.clients.classic_api.ClassicApi.list_sites` operation. + """ + + id: Optional[int] + name: Optional[str] + + +class ClassicSite(ClassicApiModel): + """Represents a site record returned by the + :meth:`~jamf_pro_sdk.clients.classic_api.ClassicApi.get_site_by_id` operation. + Note that due to the simplicity of the model this information is available in the list. + """ + + _xml_root_name = "site" + _xml_array_item_names = _XML_ARRAY_ITEM_NAMES + _xml_write_fields = {"name"} + + id: Optional[int] + name: Optional[str] diff --git a/tests/models/test_models_classic_sites.py b/tests/models/test_models_classic_sites.py new file mode 100644 index 0000000..a6e22ce --- /dev/null +++ b/tests/models/test_models_classic_sites.py @@ -0,0 +1,24 @@ +import json + +from deepdiff import DeepDiff +from src.jamf_pro_sdk.models.classic.sites import ClassicSite + +SITE_JSON = {"site": {"id": 1, "name": "Test Site"}} + + +def test_site_model_parsings(): + """Verify select attributes across the Site model.""" + site = ClassicSite(**SITE_JSON["site"]) + + assert site is not None # mypy + assert site.name == "Test Site" + assert site.id == 1 + + +def test_site_model_json_output_matches_input(): + site = ClassicSite(**SITE_JSON["site"]) + serialized_output = json.loads(site.json(exclude_none=True)) + + diff = DeepDiff(SITE_JSON["site"], serialized_output, ignore_order=True) + + assert not diff From ed3c3c7b3c401603e537a772b28504453448659e Mon Sep 17 00:00:00 2001 From: Tony Williams Date: Fri, 27 Oct 2023 20:54:25 +1100 Subject: [PATCH 2/2] fixed a variable name spelling error in --- src/jamf_pro_sdk/clients/classic_api.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/jamf_pro_sdk/clients/classic_api.py b/src/jamf_pro_sdk/clients/classic_api.py index 7d29d19..900d77c 100644 --- a/src/jamf_pro_sdk/clients/classic_api.py +++ b/src/jamf_pro_sdk/clients/classic_api.py @@ -10,23 +10,18 @@ ClassicAdvancedComputerSearch, ClassicAdvancedComputerSearchesItem, ) - from ..models.classic.categories import ClassicCategoriesItem, ClassicCategory - from ..models.classic.computer_groups import ( ClassicComputerGroup, ClassicComputerGroupMember, ClassicComputerGroupMembershipUpdate, ) - from ..models.classic.computers import ( ClassicComputer, ClassicComputersItem, ) - from ..models.classic.packages import ClassicPackage, ClassicPackageItem - -from ..models.classic.sites import ClassicSite, ClassicSitesItem +from ..models.classic.sites import ClassicSite, ClassicSiteItem if TYPE_CHECKING: import requests @@ -51,7 +46,7 @@ int, ClassicAdvancedComputerSearch, ClassicAdvancedComputerSearchesItem ] PackageId = Union[int, ClassicPackage, ClassicPackageItem] -SiteId = Union[int, ClassicSite, ClassicSitesItem] +SiteId = Union[int, ClassicSite, ClassicSiteItem] def parse_response_id(xml: str) -> int: @@ -583,22 +578,22 @@ def create_site(self, data: Union[str, ClassicSite]) -> int: return parse_response_id(resp.text) -def list_all_sites(self) -> List[ClassicSitesItem]: +def list_all_sites(self) -> List[ClassicSiteItem]: """Returns a list of all sites. :return: List of sites. - :rtype: List[~jamf_pro_sdk.models.classic.sites.ClassicSitesItem] + :rtype: List[~jamf_pro_sdk.models.classic.sites.ClassicSiteItem] """ resp = self.api_request(method="get", resource_path="sites") - return [ClassicSitesItem(**i) for i in resp.json()["sites"]] + return [ClassicSiteItem(**i) for i in resp.json()["sites"]] def get_site_by_id(self, site: SiteId) -> ClassicSite: """Returns a single site record using the ID. :param site: A site ID or supported Classic API model. - :type site: Union[int, ClassicSite, ClassicSitesItem] + :type site: Union[int, ClassicSite, ClassicSiteItem] :return: Site. :rtype: ~jamf_pro_sdk.models.classic.sites.ClassicSite @@ -615,7 +610,7 @@ def update_site_by_id( """Update a site using the ID. :param site: A site ID or supported Classic API model. - :type site: Union[int, ClassicSite, ClassicSitesItem] + :type site: Union[int, ClassicSite, ClassicSiteItem] :param data: Can be an XML string or a :class:`~jamf_pro_sdk.models.classic.sites.ClassicSite` object. @@ -632,7 +627,7 @@ def delete_site_by_id(self, site: SiteId) -> None: """Delete a site using the ID. :param site: A site ID or supported Classic API model. - :type site: Union[int, ClassicSite, ClassicSitesItem] + :type site: Union[int, ClassicSite, ClassicSiteItem] """ site_id = ClassicApi._parse_id(site)