diff --git a/tests/conftest.py b/tests/conftest.py index 6d0b361..10ba979 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -121,7 +121,7 @@ def test_case_template(thehive: TheHiveApi) -> OutputCaseTemplate: case_template={ "name": name, "description": "...", - "tags": ["whatever"], + "tags": ["template-tag"], } ) @@ -129,8 +129,16 @@ def test_case_template(thehive: TheHiveApi) -> OutputCaseTemplate: @pytest.fixture def test_case_templates(thehive: TheHiveApi) -> List[OutputCaseTemplate]: case_templates: List[InputCaseTemplate] = [ - {"name": "my first case template", "description": "..."}, - {"name": "my second case template", "description": "..."}, + { + "name": "my first case template", + "description": "...", + "tags": ["template-tag-1"], + }, + { + "name": "my second case template", + "description": "...", + "tags": ["template-tag-2"], + }, ] return [ thehive.case_template.create(case_template=case_template) diff --git a/tests/test_case_endpoint.py b/tests/test_case_endpoint.py index 29ac1d1..9685db6 100644 --- a/tests/test_case_endpoint.py +++ b/tests/test_case_endpoint.py @@ -16,6 +16,7 @@ InputUpdateCase, OutputCase, ) +from thehive4py.types.case_template import OutputCaseTemplate from thehive4py.types.observable import InputObservable from thehive4py.types.page import InputUpdateCasePage, OutputCasePage from thehive4py.types.share import InputShare @@ -168,6 +169,37 @@ def test_get_timeline(self, thehive: TheHiveApi, test_case: OutputCase): timeline = thehive.case.get_timeline(case_id=test_case["_id"]) assert timeline["events"] + def test_apply_case_template( + self, + thehive: TheHiveApi, + test_case: OutputCase, + test_case_template: OutputCaseTemplate, + ): + + assert ( + set(test_case_template.get("tags", [])).issubset( + set(test_case.get("tags", [])) + ) + is False + ) + + thehive.case.apply_case_template( + fields={ + "ids": [test_case["_id"]], + "caseTemplate": test_case_template["name"], + "updateTags": True, + } + ) + + updated_case = thehive.case.get(case_id=test_case["_id"]) + + assert ( + set(test_case_template.get("tags", [])).issubset( + set(updated_case.get("tags", [])) + ) + is True + ) + def test_add_and_download_attachment( self, thehive: TheHiveApi, test_case: OutputCase, tmp_path: Path ): diff --git a/thehive4py/endpoints/case.py b/thehive4py/endpoints/case.py index e85ce26..71ca40a 100644 --- a/thehive4py/endpoints/case.py +++ b/thehive4py/endpoints/case.py @@ -13,6 +13,7 @@ CaseStatus, CaseStatusValue, ImpactStatusValue, + InputApplyCaseTemplate, InputBulkUpdateCase, InputCase, InputImportCase, @@ -113,6 +114,11 @@ def export_to_file(self, case_id: CaseId, password: str, export_path: str) -> No def get_timeline(self, case_id: CaseId) -> OutputTimeline: return self._session.make_request("GET", f"/api/v1/case/{case_id}/timeline") + def apply_case_template(self, fields: InputApplyCaseTemplate) -> None: + return self._session.make_request( + "POST", "/api/v1/case/_bulk/caseTemplate", json=fields + ) + def add_attachment( self, case_id: CaseId, attachment_paths: List[str] ) -> List[OutputAttachment]: diff --git a/thehive4py/types/case.py b/thehive4py/types/case.py index b2a0608..2d7ff88 100644 --- a/thehive4py/types/case.py +++ b/thehive4py/types/case.py @@ -140,3 +140,21 @@ class InputImportCase(InputImportCaseRequired, total=False): sharingParameters: List[InputShare] taskRule: str observableRule: str + + +class InputApplyCaseTemplateRequired(TypedDict): + ids: List[str] + caseTemplate: str + + +class InputApplyCaseTemplate(InputApplyCaseTemplateRequired, total=False): + updateTitlePrefix: bool + updateDescription: bool + updateTags: bool + updateSeverity: bool + updateFlag: bool + updateTlp: bool + updatePap: bool + updateCustomFields: bool + importTasks: List[str] + importPages: List[str]