diff --git a/docs/reference/models_pro.rst b/docs/reference/models_pro.rst index 2987054..0e8ac9f 100644 --- a/docs/reference/models_pro.rst +++ b/docs/reference/models_pro.rst @@ -94,3 +94,14 @@ Pagination Page FilterEntry + + +Scripts +------- + +.. currentmodule:: jamf_pro_sdk.models.pro.scripts + +.. autosummary:: + :toctree: _autosummary + + Script diff --git a/src/jamf_pro_sdk/clients/pro_api/__init__.py b/src/jamf_pro_sdk/clients/pro_api/__init__.py index d368eda..e4432d1 100644 --- a/src/jamf_pro_sdk/clients/pro_api/__init__.py +++ b/src/jamf_pro_sdk/clients/pro_api/__init__.py @@ -20,6 +20,8 @@ SetRecoveryLockCommand, ShutDownDeviceCommand, ) +from ...models.pro.scripts import * + from .pagination import Paginator if TYPE_CHECKING: @@ -325,3 +327,119 @@ def get_mdm_commands_v2( ) return paginator(return_generator=return_generator) + + def get_scripts_v1( + self, + start_page: int = 0, + end_page: int = None, + page_size: int = 100, + sort_expression: SortExpression = None, + filter_expression: FilterExpression = None, + return_generator: bool = False, + ) -> Union[List[Script], Iterator[Page]]: + """Returns a list of script records. + + :param start_page: (optional) The page to begin returning results from. See + :class:`Paginator` for more information. + :type start_page: int + + :param end_page: (optional) The page to end returning results at. See :class:`Paginator` for + more information. + :type start_page: int + + :param page_size: (optional) The number of results to include in each requested page. See + :class:`Paginator` for more information. + :type page_size: int + + :param sort_expression: (optional) The sort fields to apply to the request. See the + documentation for :ref:`Pro API Sorting` for more information. + + Allowed sort fields: + + .. autoapioptions:: jamf_pro_sdk.models.pro.api_options.get_scripts_v1_allowed_sort_criteria + + :type sort_expression: SortExpression + + :param filter_expression: (optional) The filter expression to apply to the request. See the + documentation for :ref:`Pro API Filtering` for more information. + + Allowed filter fields: + + .. autoapioptions:: jamf_pro_sdk.models.pro.api_options.get_scripts_inventory_v1_allowed_filter_criteriascripts + + :type filter_expression: FilterExpression + + :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 + + :return: List of scripts OR a paginator generator. + :rtype: List[~jamf_pro_sdk.models.pro.script.Script] | Iterator[Page] + """ + if sort_expression: + sort_expression.validate(get_scripts_v1_allowed_sort_fields) + + if filter_expression: + filter_expression.validate(get_scripts_v1_allowed_filter_fields) + + paginator = Paginator( + api_client=self, + resource_path="v1/scripts", + return_model=Script, + start_page=start_page, + end_page=end_page, + page_size=page_size, + sort_expression=sort_expression, + filter_expression=filter_expression, + ) + + return paginator(return_generator=return_generator) + + def get_script_v1(self, script_id: int) -> Script: + """Returns a script record. + + :param script_id: The ID of the script to return. + :type script_id: int + + :return: A script record. + :rtype: ~jamf_pro_sdk.models.pro.script.Script + """ + resp = self.api_request(method="get", resource_path=f"v1/scripts/id/{script_id}") + return Script(**resp.json()) + + def set_script(self, script_id: int, script: Script) -> Script: + """Updates or creates a script record. + + :param script_id: The ID of the script to update. + :type script_id: int + + :param script: The script record to update. + :type script: ~jamf_pro_sdk.models.pro.script.Script + + :return: The updated script record. + :rtype: ~jamf_pro_sdk.models.pro.script.Script + """ + resp = self.api_request( + method="put", resource_path=f"v1/scripts/id/{script_id}", data=script + ) + return Script(**resp.json()) + + def delete_script(self, script_id: int) -> None: + """Deletes a script record. + + :param script_id: The ID of the script to delete. + :type script_id: int + """ + self.api_request(method="delete", resource_path=f"v1/scripts/id/{script_id}") + + def create_script(self, script: Script) -> Script: + """Creates a script record. + + :param script: The script record to create. + :type script: ~jamf_pro_sdk.models.pro.script.Script + + :return: The created script record. + :rtype: ~jamf_pro_sdk.models.pro.script.Script + """ + resp = self.api_request(method="post", resource_path="v1/scripts", data=script) + return Script(**resp.json()) diff --git a/src/jamf_pro_sdk/models/pro/api_options.py b/src/jamf_pro_sdk/models/pro/api_options.py index 1441cf7..8d5f6d1 100644 --- a/src/jamf_pro_sdk/models/pro/api_options.py +++ b/src/jamf_pro_sdk/models/pro/api_options.py @@ -223,3 +223,44 @@ "SET_AUTO_ADMIN_PASSWORD", "UNKNOWN", ] + + +get_scripts_v1_allowed_sort_fields = [ + "id", + "name", + "info", + "notes", + "priority", + "categoryId", + "categoryName", + "parameter4", + "parameter5", + "parameter6", + "parameter7", + "parameter8", + "parameter9", + "parameter10", + "parameter11", + "osRequirements", + "scriptContents", +] + +get_scripts_v1_allowed_filter_fields = [ + "id", + "name", + "info", + "notes", + "priority", + "categoryId", + "categoryName", + "parameter4", + "parameter5", + "parameter6", + "parameter7", + "parameter8", + "parameter9", + "parameter10", + "parameter11", + "osRequirements", + "scriptContents", +] diff --git a/src/jamf_pro_sdk/models/pro/scripts.py b/src/jamf_pro_sdk/models/pro/scripts.py new file mode 100644 index 0000000..6b6371f --- /dev/null +++ b/src/jamf_pro_sdk/models/pro/scripts.py @@ -0,0 +1,35 @@ +from enum import Enum +from typing import Optional + +from pydantic import Extra + +from .. import BaseModel + + +class ScriptPriority(str, Enum): + BEFORE: str = "BEFORE" + AFTER: str = "AFTER" + AT_REBOOT: str = "AT_REBOOT" + + +class Script(BaseModel, extra=Extra.allow): + """Represents a script record. The same data is + returned for both GET scripts and GET script by ID.""" + + id: Optional[int] + name: Optional[str] + info: Optional[str] + notes: Optional[str] + priority: Optional[ScriptPriority] + parameter4: Optional[str] + parameter5: Optional[str] + parameter6: Optional[str] + parameter7: Optional[str] + parameter8: Optional[str] + parameter9: Optional[str] + parameter10: Optional[str] + parameter11: Optional[str] + osRequirements: Optional[str] + scriptContents: Optional[str] + categoryId: Optional[int] + categoryName: Optional[str] diff --git a/tests/models/test_models_pro_scripts.py b/tests/models/test_models_pro_scripts.py new file mode 100644 index 0000000..0f21092 --- /dev/null +++ b/tests/models/test_models_pro_scripts.py @@ -0,0 +1,58 @@ +import json + +from deepdiff import DeepDiff +from src.jamf_pro_sdk.models.pro.scripts import Script + +SCRIPT_JSON = { + "script": { + "id": 73, + "name": "1_Set_Organization_Priorities-1.0.2.sh", + "info": "Some information", + "notes": "v1.0.2 31/1/2019", + "priority": "AFTER", + "parameter4": "", + "parameter5": "", + "parameter6": "", + "parameter7": "", + "parameter8": "", + "parameter9": "", + "parameter10": "", + "parameter11": "", + "osRequirements": "", + "scriptContents": '#!/bin/bash\n\norganization="My Organization"', + "categoryId": 15, + "categoryName": "CIS", + } +} + + +def test_script_model_parsings(): + """Verify select attributes across the Script model.""" + script = Script(**SCRIPT_JSON["script"]) + + assert script is not None # mypy + assert script.id == 73 + assert script.name == "1_Set_Organization_Priorities-1.0.2.sh" + assert script.info == "Some information" + assert script.notes == "v1.0.2 31/1/2019" + assert script.priority == "AFTER" + assert script.parameter4 == "" + assert script.parameter5 == "" + assert script.parameter6 == "" + assert script.parameter7 == "" + assert script.parameter8 == "" + assert script.parameter9 == "" + assert script.parameter10 == "" + assert script.parameter11 == "" + assert script.scriptContents == '#!/bin/bash\n\norganization="My Organization"' + assert script.categoryId == 15 + assert script.categoryName == "CIS" + + +def test_script_json_output_matches_input(): + script = Script(**SCRIPT_JSON["script"]) + serialized_output = json.loads(script.json(exclude_none=True)) + + diff = DeepDiff(SCRIPT_JSON["script"], serialized_output, ignore_order=True) + + assert not diff