Skip to content

Commit 22a943e

Browse files
authored
feat(tasks): add task comments support (#216)
1 parent 6a84e71 commit 22a943e

File tree

3 files changed

+227
-0
lines changed

3 files changed

+227
-0
lines changed

crowdin_api/api_resources/tasks/resource.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
TaskSettingsTemplateLanguages,
2828
)
2929
from crowdin_api.sorting import Sorting
30+
from crowdin_api.api_resources.tasks.types import TaskCommentPatchRequest
3031

3132

3233
class TasksResource(BaseResource):
@@ -934,6 +935,133 @@ def list_user_tasks(
934935

935936
return self._get_entire_data(method="get", path="user/tasks", params=params)
936937

938+
# Task Comments
939+
def get_task_comments_path(
940+
self,
941+
projectId: int,
942+
taskId: int,
943+
taskCommentId: Optional[int] = None,
944+
):
945+
if taskCommentId is not None:
946+
return f"projects/{projectId}/tasks/{taskId}/comments/{taskCommentId}"
947+
948+
return f"projects/{projectId}/tasks/{taskId}/comments"
949+
950+
def list_task_comments(
951+
self,
952+
taskId: int,
953+
projectId: Optional[int] = None,
954+
orderBy: Optional[Sorting] = None,
955+
page: Optional[int] = None,
956+
offset: Optional[int] = None,
957+
limit: Optional[int] = None,
958+
):
959+
"""
960+
List Task Comments.
961+
962+
Link to documentation:
963+
https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.comments.getMany
964+
"""
965+
966+
projectId = projectId or self.get_project_id()
967+
params = {"orderBy": orderBy}
968+
params.update(self.get_page_params(page=page, offset=offset, limit=limit))
969+
970+
return self._get_entire_data(
971+
method="get",
972+
path=self.get_task_comments_path(projectId=projectId, taskId=taskId),
973+
params=params,
974+
)
975+
976+
def add_task_comment(
977+
self,
978+
text: str,
979+
taskId: int,
980+
projectId: Optional[int] = None,
981+
):
982+
"""
983+
Add Task Comment.
984+
985+
Link to documentation:
986+
https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.comments.post
987+
"""
988+
989+
projectId = projectId or self.get_project_id()
990+
991+
return self.requester.request(
992+
method="post",
993+
path=self.get_task_comments_path(projectId=projectId, taskId=taskId),
994+
request_data={"text": text},
995+
)
996+
997+
def get_task_comment(
998+
self,
999+
taskCommentId: int,
1000+
taskId: int,
1001+
projectId: Optional[int] = None,
1002+
):
1003+
"""
1004+
Get Task Comment.
1005+
1006+
Link to documentation:
1007+
https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.comments.get
1008+
"""
1009+
1010+
projectId = projectId or self.get_project_id()
1011+
1012+
return self.requester.request(
1013+
method="get",
1014+
path=self.get_task_comments_path(
1015+
projectId=projectId, taskId=taskId, taskCommentId=taskCommentId
1016+
),
1017+
)
1018+
1019+
def delete_task_comment(
1020+
self,
1021+
taskCommentId: int,
1022+
taskId: int,
1023+
projectId: Optional[int] = None,
1024+
):
1025+
"""
1026+
Delete Task Comment.
1027+
1028+
Link to documentation:
1029+
https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.comments.delete
1030+
"""
1031+
1032+
projectId = projectId or self.get_project_id()
1033+
1034+
return self.requester.request(
1035+
method="delete",
1036+
path=self.get_task_comments_path(
1037+
projectId=projectId, taskId=taskId, taskCommentId=taskCommentId
1038+
),
1039+
)
1040+
1041+
def edit_task_comment(
1042+
self,
1043+
taskCommentId: int,
1044+
data: Iterable[TaskCommentPatchRequest],
1045+
taskId: int,
1046+
projectId: Optional[int] = None,
1047+
):
1048+
"""
1049+
Edit Task Comment.
1050+
1051+
Link to documentation:
1052+
https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.comments.patch
1053+
"""
1054+
1055+
projectId = projectId or self.get_project_id()
1056+
1057+
return self.requester.request(
1058+
method="patch",
1059+
path=self.get_task_comments_path(
1060+
projectId=projectId, taskId=taskId, taskCommentId=taskCommentId
1061+
),
1062+
request_data=data,
1063+
)
1064+
9371065
def edit_task_archived_status(
9381066
self, taskId: int, isArchived: bool = True, projectId: Optional[int] = None
9391067
):

crowdin_api/api_resources/tasks/tests/test_tasks_resources.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,6 +1327,97 @@ def test_edit_task_archived_status(self, m_request, base_absolut_url):
13271327
request_data=[{"op": "replace", "path": "/isArchived", "value": False}],
13281328
)
13291329

1330+
# --- Task comments ---
1331+
@pytest.mark.parametrize(
1332+
"incoming_data, path",
1333+
(
1334+
({"projectId": 1, "taskId": 2}, "projects/1/tasks/2/comments"),
1335+
(
1336+
{"projectId": 1, "taskId": 2, "taskCommentId": 3},
1337+
"projects/1/tasks/2/comments/3",
1338+
),
1339+
),
1340+
)
1341+
def test_get_task_comments_path(self, incoming_data, path, base_absolut_url):
1342+
resource = self.get_resource(base_absolut_url)
1343+
assert resource.get_task_comments_path(**incoming_data) == path
1344+
1345+
@pytest.mark.parametrize(
1346+
"incoming_data, request_params",
1347+
(
1348+
({}, {"orderBy": None, "offset": 0, "limit": 25}),
1349+
({"orderBy": Sorting([])}, {"orderBy": Sorting([]), "offset": 0, "limit": 25}),
1350+
),
1351+
)
1352+
@mock.patch("crowdin_api.requester.APIRequester.request")
1353+
def test_list_task_comments(self, m_request, incoming_data, request_params, base_absolut_url):
1354+
m_request.return_value = "response"
1355+
1356+
resource = self.get_resource(base_absolut_url)
1357+
assert resource.list_task_comments(projectId=1, taskId=2, **incoming_data) == "response"
1358+
m_request.assert_called_once_with(
1359+
method="get",
1360+
params=request_params,
1361+
path=resource.get_task_comments_path(projectId=1, taskId=2),
1362+
)
1363+
1364+
@mock.patch("crowdin_api.requester.APIRequester.request")
1365+
def test_add_task_comment(self, m_request, base_absolut_url):
1366+
m_request.return_value = "response"
1367+
1368+
resource = self.get_resource(base_absolut_url)
1369+
assert resource.add_task_comment(projectId=1, taskId=2, text="hello") == "response"
1370+
m_request.assert_called_once_with(
1371+
method="post",
1372+
path=resource.get_task_comments_path(projectId=1, taskId=2),
1373+
request_data={"text": "hello"},
1374+
)
1375+
1376+
@mock.patch("crowdin_api.requester.APIRequester.request")
1377+
def test_get_task_comment(self, m_request, base_absolut_url):
1378+
m_request.return_value = "response"
1379+
1380+
resource = self.get_resource(base_absolut_url)
1381+
assert resource.get_task_comment(projectId=1, taskId=2, taskCommentId=3) == "response"
1382+
m_request.assert_called_once_with(
1383+
method="get",
1384+
path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3),
1385+
)
1386+
1387+
@mock.patch("crowdin_api.requester.APIRequester.request")
1388+
def test_delete_task_comment(self, m_request, base_absolut_url):
1389+
m_request.return_value = "response"
1390+
1391+
resource = self.get_resource(base_absolut_url)
1392+
assert resource.delete_task_comment(projectId=1, taskId=2, taskCommentId=3) == "response"
1393+
m_request.assert_called_once_with(
1394+
method="delete",
1395+
path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3),
1396+
)
1397+
1398+
@mock.patch("crowdin_api.requester.APIRequester.request")
1399+
def test_edit_task_comment(self, m_request, base_absolut_url):
1400+
m_request.return_value = "response"
1401+
1402+
data = [
1403+
{
1404+
"value": "new text",
1405+
"op": PatchOperation.REPLACE,
1406+
"path": "/text",
1407+
}
1408+
]
1409+
1410+
resource = self.get_resource(base_absolut_url)
1411+
assert (
1412+
resource.edit_task_comment(projectId=1, taskId=2, taskCommentId=3, data=data)
1413+
== "response"
1414+
)
1415+
m_request.assert_called_once_with(
1416+
method="patch",
1417+
path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3),
1418+
request_data=data,
1419+
)
1420+
13301421

13311422
class TestEnterpriseTasksResource:
13321423
resource_class = EnterpriseTasksResource

crowdin_api/api_resources/tasks/types.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,11 @@ class EnterpriseTaskSettingsTemplateConfigLanguage(TypedDict):
5454

5555
class EnterpriseTaskSettingsTemplateLanguages(TypedDict):
5656
languages: Iterable[EnterpriseTaskSettingsTemplateConfigLanguage]
57+
58+
59+
# Task comments patch request (moved from removed task_comments package)
60+
class TaskCommentPatchRequest(TypedDict):
61+
value: Any
62+
op: PatchOperation
63+
# For now only /text is supported in edit operations
64+
path: str

0 commit comments

Comments
 (0)