Skip to content

Commit e7c88be

Browse files
committed
feat: Add the parent folder uid functionality and adjust the documentation
1 parent ca148ea commit e7c88be

File tree

4 files changed

+174
-8
lines changed

4 files changed

+174
-8
lines changed

grafana_api/folder.py

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ def __init__(self, grafana_api_model: APIModel):
2323
def get_folders(self) -> list:
2424
"""The method includes a functionality to extract all folders inside the organization
2525
26+
Required Permissions:
27+
Action: folders:read
28+
Scope: folders:*
29+
2630
Raises:
2731
Exception: Unspecified error by executing the API call
2832
@@ -46,6 +50,10 @@ def get_folder_by_uid(self, uid: str) -> dict:
4650
Args:
4751
uid (str): Specify the uid of the folder
4852
53+
Required Permissions:
54+
Action: folders:read
55+
Scope: folders:*
56+
4957
Raises:
5058
ValueError: Missed specifying a necessary value
5159
Exception: Unspecified error by executing the API call
@@ -74,6 +82,10 @@ def get_folder_by_id(self, id: int) -> dict:
7482
Args:
7583
id (int): Specify the id of the folder
7684
85+
Required Permissions:
86+
Action: folders:read
87+
Scope: folders:*
88+
7789
Raises:
7890
ValueError: Missed specifying a necessary value
7991
Exception: Unspecified error by executing the API call
@@ -96,12 +108,17 @@ def get_folder_by_id(self, id: int) -> dict:
96108
logging.error("There is no folder id defined.")
97109
raise ValueError
98110

99-
def create_folder(self, title: str, uid: str = None) -> dict:
111+
def create_folder(self, title: str, uid: str = None, parent_uid: str = None) -> dict:
100112
"""The method includes a functionality to create a new folder inside the organization specified by the defined title and the optional uid
101113
102114
Args:
103115
title (str): Specify the title of the folder
104116
uid (str): Specify the uid of the folder (default None)
117+
parent_uid (str): Specify the parent_uid of the folder (default None)
118+
119+
Required Permissions:
120+
Action: folders:create, folders:write
121+
Scope: folders:*
105122
106123
Raises:
107124
ValueError: Missed specifying a necessary value
@@ -118,6 +135,9 @@ def create_folder(self, title: str, uid: str = None) -> dict:
118135
if uid is not None and len(uid) != 0:
119136
folder_information.update({"uid": uid})
120137

138+
if parent_uid is not None and len(parent_uid) != 0:
139+
folder_information.update({"parentUid": parent_uid})
140+
121141
api_call: dict = Api(self.grafana_api_model).call_the_api(
122142
APIEndpoints.FOLDERS.value,
123143
RequestsMethods.POST,
@@ -144,6 +164,10 @@ def update_folder(
144164
version (int): Specify the version of the folder (default 0)
145165
overwrite (bool): Should the already existing folder information be overwritten (default False)
146166
167+
Required Permissions:
168+
Action: folders:write
169+
Scope: folders:*
170+
147171
Raises:
148172
ValueError: Missed specifying a necessary value
149173
Exception: Unspecified error by executing the API call
@@ -179,12 +203,57 @@ def update_folder(
179203
logging.error("There is no folder title, version or uid defined.")
180204
raise ValueError
181205

206+
def move_folder(self, uid: str, parent_uid: str = None):
207+
"""The method includes a functionality to move a folder inside the organization specified by the defined uid. This feature is only relevant if nested folders are enabled
208+
209+
Args:
210+
uid (str): Specify the uid of the folder
211+
parent_uid (str): Specify the parent_uid of the folder. If the value is None, then the folder is moved under the root (default None)
212+
213+
Required Permissions:
214+
Action: folders:create, folders:write
215+
Scope: folders:*, folders:uid:<destination folder UID>
216+
217+
Raises:
218+
ValueError: Missed specifying a necessary value
219+
Exception: Unspecified error by executing the API call
220+
221+
Returns:
222+
api_call (dict): Returns the moved folder
223+
"""
224+
225+
if len(uid) != 0:
226+
folder_information: dict = dict()
227+
228+
if parent_uid is not None and len(parent_uid) != 0:
229+
folder_information.update({"parentUid": parent_uid})
230+
231+
api_call = Api(self.grafana_api_model).call_the_api(
232+
f"{APIEndpoints.FOLDERS.value}/{uid}/move",
233+
RequestsMethods.POST,
234+
json.dumps(folder_information),
235+
)
236+
237+
if api_call == dict() or api_call.get("id") is None:
238+
logging.error(f"Please, check the error: {api_call}.")
239+
raise Exception
240+
else:
241+
return api_call
242+
else:
243+
logging.error("There is no folder uid defined.")
244+
raise ValueError
245+
246+
182247
def delete_folder(self, uid: str):
183248
"""The method includes a functionality to delete a folder inside the organization specified by the defined uid
184249
185250
Args:
186251
uid (str): Specify the uid of the folder
187252
253+
Required Permissions:
254+
Action: folders:delete
255+
Scope: folders:*
256+
188257
Raises:
189258
ValueError: Missed specifying a necessary value
190259
Exception: Unspecified error by executing the API call
@@ -220,6 +289,10 @@ def get_folder_permissions(self, uid: str) -> list:
220289
Args:
221290
uid (str): Specify the uid of the folder
222291
292+
Required Permissions:
293+
Action: folders.permissions:read
294+
Scope: folders:*
295+
223296
Raises:
224297
ValueError: Missed specifying a necessary value
225298
Exception: Unspecified error by executing the API call
@@ -250,6 +323,10 @@ def update_folder_permissions(self, uid: str, permission_json: dict):
250323
uid (str): Specify the uid of the folder
251324
permission_json (dict): Specify the inserted permissions as dict
252325
326+
Required Permissions:
327+
Action: folders.permissions:write
328+
Scope: folders:*
329+
253330
Raises:
254331
ValueError: Missed specifying a necessary value
255332
Exception: Unspecified error by executing the API call

tests/integrationtest/test_folder.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,35 @@ def test_a_create_folder(self):
6969

7070
self.assertEqual("test1", self.folder.get_folders()[1].get("title"))
7171

72-
def test_b_update_folder(self):
72+
def test_b_subfolder(self):
73+
parent_uid = self.folder.get_folders()[1].get("uid")
74+
75+
subfolder: dict = self.folder.create_folder("test2", parent_uid=parent_uid)
76+
77+
self.assertEqual("test2", self.folder.get_folder_by_uid(subfolder["uid"]).get("title"))
78+
79+
def test_c_update_folder(self):
7380
self.folder.update_folder(
7481
"test2", self.folder.get_folders()[1].get("uid"), version=1
7582
)
7683

7784
self.assertEqual("test2", self.folder.get_folders()[1].get("title"))
7885

79-
def test_c_delete_folder(self):
86+
def test_d_move_folder(self):
87+
parent_uid = self.folder.get_folders()[1].get("uid")
88+
89+
folder_uid_a = self.folder.create_folder("test11", parent_uid=parent_uid)["uid"]
90+
folder_uid_b = self.folder.create_folder("test12")["uid"]
91+
92+
self.assertEqual("test12", self.folder.get_folder_by_uid(folder_uid_b)["title"])
93+
94+
moved_folder: dict = self.folder.move_folder(folder_uid_a, parent_uid=folder_uid_b)
95+
96+
self.assertEqual("test12", moved_folder["parents"][0]["title"])
97+
self.folder.delete_folder(moved_folder["parents"][0]["uid"])
98+
99+
100+
def test_e_delete_folder(self):
80101
self.folder.delete_folder(self.folder.get_folders()[1].get("uid"))
81102

82103
self.assertEqual(1, len(self.folder.get_folders()))
@@ -110,7 +131,7 @@ def test_get_folder_permissions(self):
110131
self.folder.get_folder_permissions("6U_QdWJnz"),
111132
)
112133

113-
def test_d_update_folder_permissions(self):
134+
def test_f_update_folder_permissions(self):
114135
permission_dict: dict = dict({"items": [{"role": "Viewer", "permission": 2}]})
115136

116137
self.folder.update_folder_permissions("6U_QdWJnz", permission_dict)

tests/unittests/test_alerting.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ def test_test_backtest_rule(self, call_the_api_mock):
738738
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
739739
alerting: Alerting = Alerting(grafana_api_model=model)
740740
datasource_rule_query: DatasourceRuleQuery = DatasourceRuleQuery(
741-
"test", {"test": "test"}, "test", "test", {"test": "test"}
741+
"test", {"test": "test"}, "datasourceUid", "test", {"test": "test"}
742742
)
743743

744744
call_the_api_mock.return_value = dict({"test": "test"})
@@ -756,17 +756,30 @@ def test_test_backtest_rule_no_condition(self):
756756
alerting.test_backtest_rule("", list())
757757

758758
@patch("grafana_api.api.Api.call_the_api")
759-
def test_test_recipient_rule_test_not_possible(self, call_the_api_mock):
759+
def test_test_backtest_rule_no_fields(self, call_the_api_mock):
760760
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
761761
alerting: Alerting = Alerting(grafana_api_model=model)
762762
datasource_rule_query: DatasourceRuleQuery = DatasourceRuleQuery(
763-
"test", {"test": "test"}, "test", "test", {"test": "test"}
763+
"test", {"test": "test"}, "datasourceUid", "test", {"test": "test"}
764+
)
765+
766+
call_the_api_mock.return_value = dict()
767+
768+
with self.assertRaises(Exception):
769+
alerting.test_backtest_rule("test", [datasource_rule_query])
770+
771+
@patch("grafana_api.api.Api.call_the_api")
772+
def test_test_datasource_uid_rule_test_not_possible(self, call_the_api_mock):
773+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
774+
alerting: Alerting = Alerting(grafana_api_model=model)
775+
datasource_rule_query: DatasourceRuleQuery = DatasourceRuleQuery(
776+
"test", {"test": "test"}, "datasourceUid", "test", {"test": "test"}
764777
)
765778

766779
call_the_api_mock.return_value = dict()
767780

768781
with self.assertRaises(Exception):
769-
alerting.test_recipient_rule("test", "test", [datasource_rule_query])
782+
alerting.test_datasource_uid_rule("test", "test", [datasource_rule_query])
770783

771784
@patch("grafana_api.api.Api.call_the_api")
772785
def test_delete_ngalert_organization_configuration(self, call_the_api_mock):

tests/unittests/test_folder.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,18 @@ def test_create_folder_specified_uid(self, call_the_api_mock):
108108
folder.create_folder("test", "test"),
109109
)
110110

111+
@patch("grafana_api.api.Api.call_the_api")
112+
def test_create_folder_parent_uid(self, call_the_api_mock):
113+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
114+
folder: Folder = Folder(grafana_api_model=model)
115+
116+
call_the_api_mock.return_value = dict({"title": None, "id": 12, "parent_uid": "test"})
117+
118+
self.assertEqual(
119+
dict({"title": None, "id": 12, "parent_uid": "test"}),
120+
folder.create_folder("test", parent_uid="test"),
121+
)
122+
111123
@patch("grafana_api.api.Api.call_the_api")
112124
def test_create_folder_no_title(self, call_the_api_mock):
113125
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
@@ -184,6 +196,49 @@ def test_update_folder_error_response(self, call_the_api_mock):
184196
with self.assertRaises(Exception):
185197
folder.update_folder("test", "test", 10)
186198

199+
@patch("grafana_api.api.Api.call_the_api")
200+
def test_move_folder(self, call_the_api_mock):
201+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
202+
folder: Folder = Folder(grafana_api_model=model)
203+
204+
call_the_api_mock.return_value = dict({"title": "test1", "id": 12})
205+
206+
self.assertEqual(
207+
dict({"title": "test1", "id": 12}),
208+
folder.move_folder("test"),
209+
)
210+
211+
def test_move_folder_no_uid(self):
212+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
213+
folder: Folder = Folder(grafana_api_model=model)
214+
215+
with self.assertRaises(ValueError):
216+
folder.move_folder("")
217+
218+
219+
@patch("grafana_api.api.Api.call_the_api")
220+
def test_move_folder_parent_uid(self, call_the_api_mock):
221+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
222+
folder: Folder = Folder(grafana_api_model=model)
223+
224+
call_the_api_mock.return_value = dict({"title": "test", "id": 12})
225+
226+
self.assertEqual(
227+
dict({"title": "test", "id": 12}),
228+
folder.move_folder("test", "test"),
229+
)
230+
231+
@patch("grafana_api.api.Api.call_the_api")
232+
def test_move_folder_no_id(self, call_the_api_mock):
233+
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())
234+
folder: Folder = Folder(grafana_api_model=model)
235+
236+
call_the_api_mock.return_value = dict({})
237+
238+
with self.assertRaises(Exception):
239+
folder.move_folder("test")
240+
241+
187242
@patch("grafana_api.api.Api.call_the_api")
188243
def test_delete_folder(self, call_the_api_mock):
189244
model: APIModel = APIModel(host=MagicMock(), token=MagicMock())

0 commit comments

Comments
 (0)