Skip to content

Commit 29924da

Browse files
committed
#440 - Review case template endpoints and add page template endpoints
1 parent ad4974c commit 29924da

File tree

10 files changed

+382
-35
lines changed

10 files changed

+382
-35
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ name = "thehive4py"
77
description = "Python client for TheHive5"
88
version = "2.0.0b11"
99
requires-python = ">=3.9"
10-
dependencies = ["requests~=2.27"]
10+
dependencies = ["requests~=2.27", "typing_extensions==4.*"]
1111
readme = "README.md"
1212
keywords = ["thehive5", "api", "client"]
1313
license = { text = "MIT" }

tests/conftest.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from thehive4py.types.observable import InputObservable, OutputObservable
1414
from thehive4py.types.observable_type import OutputObservableType
1515
from thehive4py.types.page import OutputCasePage
16+
from thehive4py.types.page_template import InputPageTemplate, OutputPageTemplate
1617
from thehive4py.types.procedure import OutputProcedure
1718
from thehive4py.types.profile import OutputProfile
1819
from thehive4py.types.task import InputTask, OutputTask
@@ -146,6 +147,37 @@ def test_case_templates(thehive: TheHiveApi) -> List[OutputCaseTemplate]:
146147
]
147148

148149

150+
@pytest.fixture
151+
def test_page_template(thehive: TheHiveApi) -> OutputPageTemplate:
152+
return thehive.page_template.create(
153+
page_template={
154+
"title": "my first page template",
155+
"category": "testing",
156+
"content": "...",
157+
}
158+
)
159+
160+
161+
@pytest.fixture
162+
def test_page_templates(thehive: TheHiveApi) -> List[OutputPageTemplate]:
163+
page_templates: List[InputPageTemplate] = [
164+
{
165+
"title": "my first page template",
166+
"category": "testing",
167+
"content": "...",
168+
},
169+
{
170+
"title": "my second case template",
171+
"category": "testing",
172+
"content": "...",
173+
},
174+
]
175+
return [
176+
thehive.page_template.create(page_template=page_template)
177+
for page_template in page_templates
178+
]
179+
180+
149181
@pytest.fixture
150182
def test_observable(thehive: TheHiveApi, test_case: OutputCase) -> OutputObservable:
151183
return thehive.observable.create_in_case(

tests/test_case_template_endpoint.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from typing import List
22

33
import pytest
4+
45
from thehive4py.client import TheHiveApi
56
from thehive4py.errors import TheHiveError
67
from thehive4py.types.case_template import InputCaseTemplate, OutputCaseTemplate
@@ -39,6 +40,31 @@ def test_delete(self, thehive: TheHiveApi, test_case_template: OutputCaseTemplat
3940
with pytest.raises(TheHiveError):
4041
thehive.case_template.get(case_template_id=case_template_id)
4142

43+
def test_link_and_find_page_templates(
44+
self,
45+
thehive: TheHiveApi,
46+
test_case_template: OutputCaseTemplate,
47+
test_page_templates: List[dict],
48+
):
49+
case_template_id = test_case_template["_id"]
50+
page_template_ids = [
51+
page_template["_id"] for page_template in test_page_templates
52+
]
53+
54+
thehive.case_template.link_page_templates(
55+
case_template_id=case_template_id,
56+
page_template_ids=page_template_ids,
57+
)
58+
59+
linked_page_templates = thehive.case_template.find_page_templates(
60+
case_template_id=case_template_id
61+
)
62+
63+
linked_page_template_ids = [
64+
page_template["_id"] for page_template in linked_page_templates
65+
]
66+
assert sorted(linked_page_template_ids) == sorted(page_template_ids)
67+
4268
def test_find(
4369
self,
4470
thehive: TheHiveApi,
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from typing import List
2+
3+
import pytest
4+
5+
from thehive4py.client import TheHiveApi
6+
from thehive4py.errors import TheHiveError
7+
from thehive4py.types.page_template import InputUpdatePageTemplate, OutputPageTemplate
8+
9+
10+
class TestPageTemplateEndpoint:
11+
def test_create_and_get(self, thehive: TheHiveApi):
12+
created_page_template = thehive.page_template.create(
13+
page_template={
14+
"title": "my page template",
15+
"category": "testing",
16+
"content": "...",
17+
}
18+
)
19+
fetched_page_template = thehive.page_template.get(created_page_template["_id"])
20+
assert created_page_template == fetched_page_template
21+
22+
def test_update(self, thehive: TheHiveApi, test_page_template: OutputPageTemplate):
23+
page_template_id = test_page_template["_id"]
24+
update_fields: InputUpdatePageTemplate = {
25+
"title": "updated page template name",
26+
"content": "updated page template description",
27+
}
28+
thehive.page_template.update(
29+
page_template_id=page_template_id, fields=update_fields
30+
)
31+
updated_page_template = thehive.page_template.get(
32+
page_template_id=page_template_id
33+
)
34+
35+
for key, value in update_fields.items():
36+
assert updated_page_template.get(key) == value
37+
38+
def test_delete(self, thehive: TheHiveApi, test_page_template: OutputPageTemplate):
39+
page_template_id = test_page_template["_id"]
40+
thehive.page_template.delete(page_template_id=page_template_id)
41+
with pytest.raises(TheHiveError):
42+
thehive.page_template.get(page_template_id=page_template_id)
43+
44+
def test_find(
45+
self,
46+
thehive: TheHiveApi,
47+
test_page_templates: List[OutputPageTemplate],
48+
):
49+
found_templates = thehive.page_template.find()
50+
original_ids = [template["_id"] for template in test_page_templates]
51+
found_ids = [template["_id"] for template in found_templates]
52+
assert sorted(found_ids) == sorted(original_ids)

tests/utils.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ def _reset_hive_org(hive_url: str, test_config: TestConfig, organisation: str) -
9898
attachments = client.organisation.find_attachments(org_id=organisation)
9999
cases = client.case.find()
100100
case_templates = client.case_template.find()
101+
page_templates = client.page_template.find()
101102

102103
with ThreadPoolExecutor() as executor:
103104
executor.map(client.alert.delete, [alert["_id"] for alert in alerts])
@@ -110,6 +111,10 @@ def _reset_hive_org(hive_url: str, test_config: TestConfig, organisation: str) -
110111
client.case_template.delete,
111112
[case_template["_id"] for case_template in case_templates],
112113
)
114+
executor.map(
115+
client.page_template.delete,
116+
[page_template["_id"] for page_template in page_templates],
117+
)
113118

114119

115120
def _reset_hive_admin_org(hive_url: str, test_config: TestConfig) -> None:

thehive4py/client.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from thehive4py.endpoints.cortex import CortexEndpoint
1818
from thehive4py.endpoints.custom_field import CustomFieldEndpoint
1919
from thehive4py.endpoints.observable_type import ObservableTypeEndpoint
20+
from thehive4py.endpoints.page_template import PageTemplateEndpoint
2021
from thehive4py.endpoints.query import QueryEndpoint
2122
from thehive4py.session import DEFAULT_RETRY, RetryValue, TheHiveSession, VerifyValue
2223

@@ -66,6 +67,7 @@ def __init__(
6667
self.case_template = CaseTemplateEndpoint(self.session)
6768
self.comment = CommentEndpoint(self.session)
6869
self.observable = ObservableEndpoint(self.session)
70+
self.page_template = PageTemplateEndpoint(self.session)
6971
self.procedure = ProcedureEndpoint(self.session)
7072
self.task = TaskEndpoint(self.session)
7173
self.task_log = TaskLogEndpoint(self.session)
Lines changed: 110 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,102 @@
1+
from typing import List, Optional
2+
13
from thehive4py.endpoints._base import EndpointBase
24
from thehive4py.query import QueryExpr
35
from thehive4py.query.filters import FilterExpr
46
from thehive4py.query.page import Paginate
57
from thehive4py.query.sort import SortExpr
6-
from thehive4py.types.case_template import OutputCaseTemplate, InputCaseTemplate
7-
from typing import List, Optional
8+
from thehive4py.types.case_template import InputCaseTemplate, OutputCaseTemplate
9+
from thehive4py.types.page_template import OutputPageTemplate
810

911

1012
class CaseTemplateEndpoint(EndpointBase):
13+
def create(self, case_template: InputCaseTemplate) -> OutputCaseTemplate:
14+
"""Create a case template.
15+
16+
Args:
17+
case_template: The body of the case template.
18+
19+
Returns:
20+
The created case template.
21+
"""
22+
return self._session.make_request(
23+
"POST", path="/api/v1/caseTemplate", json=case_template
24+
)
25+
26+
def get(self, case_template_id: str) -> OutputCaseTemplate:
27+
"""Get a case template by id.
28+
29+
Args:
30+
case_template_id: The id of the case template.
31+
32+
Returns:
33+
The case template specified by the id.
34+
"""
35+
return self._session.make_request(
36+
"GET", path=f"/api/v1/caseTemplate/{case_template_id}"
37+
)
38+
39+
def delete(self, case_template_id: str) -> None:
40+
"""Delete a case template.
41+
42+
Args:
43+
case_template_id: The id of the case template.
44+
45+
Returns:
46+
N/A
47+
"""
48+
return self._session.make_request(
49+
"DELETE", path=f"/api/v1/caseTemplate/{case_template_id}"
50+
)
51+
52+
def update(self, case_template_id: str, fields: InputCaseTemplate) -> None:
53+
"""Update a case template.
54+
55+
Args:
56+
case_template_id: The id of the case template.
57+
fields: The fields of the case template to update.
58+
59+
Returns:
60+
N/A
61+
"""
62+
return self._session.make_request(
63+
"PATCH", path=f"/api/v1/caseTemplate/{case_template_id}", json=fields
64+
)
65+
66+
def link_page_templates(
67+
self, case_template_id: str, page_template_ids: List[str]
68+
) -> None:
69+
"""Link page templates to a case template.
70+
71+
Args:
72+
case_template_id: The id or name of the case template.
73+
page_template_ids: The list of page template ids to link.
74+
75+
Returns:
76+
N/A
77+
"""
78+
return self._session.make_request(
79+
"PUT",
80+
path=f"/api/v1/caseTemplate/{case_template_id}/pageTemplate/link",
81+
json={"pageTemplateIds": page_template_ids},
82+
)
83+
1184
def find(
1285
self,
1386
filters: Optional[FilterExpr] = None,
1487
sortby: Optional[SortExpr] = None,
1588
paginate: Optional[Paginate] = None,
1689
) -> List[OutputCaseTemplate]:
90+
"""Find multiple case templates.
91+
92+
Args:
93+
filters: The filter expressions to apply in the query.
94+
sortby: The sort expressions to apply in the query.
95+
paginate: The pagination expression to apply in the query.
96+
97+
Returns:
98+
The list of case templates matched by the query or an empty list.
99+
"""
17100
query: QueryExpr = [
18101
{"_name": "listCaseTemplate"},
19102
*self._build_subquery(filters=filters, sortby=sortby, paginate=paginate),
@@ -26,22 +109,33 @@ def find(
26109
params={"name": "caseTemplate"},
27110
)
28111

29-
def get(self, case_template_id: str) -> OutputCaseTemplate:
30-
return self._session.make_request(
31-
"GET", path=f"/api/v1/caseTemplate/{case_template_id}"
32-
)
112+
def find_page_templates(
113+
self,
114+
case_template_id: str,
115+
filters: Optional[FilterExpr] = None,
116+
sortby: Optional[SortExpr] = None,
117+
paginate: Optional[Paginate] = None,
118+
) -> List[OutputPageTemplate]:
119+
"""Find page templates related to a case template.
33120
34-
def create(self, case_template: InputCaseTemplate) -> OutputCaseTemplate:
35-
return self._session.make_request(
36-
"POST", path="/api/v1/caseTemplate", json=case_template
37-
)
121+
Args:
122+
case_template_id: The case template id.
123+
filters: The filter expressions to apply in the query.
124+
sortby: The sort expressions to apply in the query.
125+
paginate: The pagination expression to apply in the query.
38126
39-
def delete(self, case_template_id: str) -> None:
40-
return self._session.make_request(
41-
"DELETE", path=f"/api/v1/caseTemplate/{case_template_id}"
42-
)
127+
Returns:
128+
The list of page templates matched by the query or an empty list.
129+
"""
130+
query: QueryExpr = [
131+
{"_name": "getCaseTemplate", "idOrName": case_template_id},
132+
*self._build_subquery(filters=filters, sortby=sortby, paginate=paginate),
133+
{"_name": "pageTemplates"},
134+
]
43135

44-
def update(self, case_template_id: str, fields: InputCaseTemplate) -> None:
45136
return self._session.make_request(
46-
"PATCH", path=f"/api/v1/caseTemplate/{case_template_id}", json=fields
137+
"POST",
138+
path="/api/v1/query",
139+
json={"query": query},
140+
params={"name": "pageTemplate"},
47141
)

0 commit comments

Comments
 (0)