Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions crowdin_api/api_resources/tasks/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
TaskSettingsTemplateLanguages,
)
from crowdin_api.sorting import Sorting
from crowdin_api.api_resources.tasks.types import TaskCommentPatchRequest


class TasksResource(BaseResource):
Expand Down Expand Up @@ -934,6 +935,133 @@ def list_user_tasks(

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

# Task Comments
def get_task_comments_path(
self,
projectId: int,
taskId: int,
taskCommentId: Optional[int] = None,
):
if taskCommentId is not None:
return f"projects/{projectId}/tasks/{taskId}/comments/{taskCommentId}"

return f"projects/{projectId}/tasks/{taskId}/comments"

def list_task_comments(
self,
taskId: int,
projectId: Optional[int] = None,
orderBy: Optional[Sorting] = None,
page: Optional[int] = None,
offset: Optional[int] = None,
limit: Optional[int] = None,
):
"""
List Task Comments.

Link to documentation:
https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.comments.getMany
"""

projectId = projectId or self.get_project_id()
params = {"orderBy": orderBy}
params.update(self.get_page_params(page=page, offset=offset, limit=limit))

return self._get_entire_data(
method="get",
path=self.get_task_comments_path(projectId=projectId, taskId=taskId),
params=params,
)

def add_task_comment(
self,
text: str,
taskId: int,
projectId: Optional[int] = None,
):
"""
Add Task Comment.

Link to documentation:
https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.comments.post
"""

projectId = projectId or self.get_project_id()

return self.requester.request(
method="post",
path=self.get_task_comments_path(projectId=projectId, taskId=taskId),
request_data={"text": text},
)

def get_task_comment(
self,
taskCommentId: int,
taskId: int,
projectId: Optional[int] = None,
):
"""
Get Task Comment.

Link to documentation:
https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.comments.get
"""

projectId = projectId or self.get_project_id()

return self.requester.request(
method="get",
path=self.get_task_comments_path(
projectId=projectId, taskId=taskId, taskCommentId=taskCommentId
),
)

def delete_task_comment(
self,
taskCommentId: int,
taskId: int,
projectId: Optional[int] = None,
):
"""
Delete Task Comment.

Link to documentation:
https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.comments.delete
"""

projectId = projectId or self.get_project_id()

return self.requester.request(
method="delete",
path=self.get_task_comments_path(
projectId=projectId, taskId=taskId, taskCommentId=taskCommentId
),
)

def edit_task_comment(
self,
taskCommentId: int,
data: Iterable[TaskCommentPatchRequest],
taskId: int,
projectId: Optional[int] = None,
):
"""
Edit Task Comment.

Link to documentation:
https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.comments.patch
"""

projectId = projectId or self.get_project_id()

return self.requester.request(
method="patch",
path=self.get_task_comments_path(
projectId=projectId, taskId=taskId, taskCommentId=taskCommentId
),
request_data=data,
)

def edit_task_archived_status(
self, taskId: int, isArchived: bool = True, projectId: Optional[int] = None
):
Expand Down
91 changes: 91 additions & 0 deletions crowdin_api/api_resources/tasks/tests/test_tasks_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -1327,6 +1327,97 @@ def test_edit_task_archived_status(self, m_request, base_absolut_url):
request_data=[{"op": "replace", "path": "/isArchived", "value": False}],
)

# --- Task comments ---
@pytest.mark.parametrize(
"incoming_data, path",
(
({"projectId": 1, "taskId": 2}, "projects/1/tasks/2/comments"),
(
{"projectId": 1, "taskId": 2, "taskCommentId": 3},
"projects/1/tasks/2/comments/3",
),
),
)
def test_get_task_comments_path(self, incoming_data, path, base_absolut_url):
resource = self.get_resource(base_absolut_url)
assert resource.get_task_comments_path(**incoming_data) == path

@pytest.mark.parametrize(
"incoming_data, request_params",
(
({}, {"orderBy": None, "offset": 0, "limit": 25}),
({"orderBy": Sorting([])}, {"orderBy": Sorting([]), "offset": 0, "limit": 25}),
),
)
@mock.patch("crowdin_api.requester.APIRequester.request")
def test_list_task_comments(self, m_request, incoming_data, request_params, base_absolut_url):
m_request.return_value = "response"

resource = self.get_resource(base_absolut_url)
assert resource.list_task_comments(projectId=1, taskId=2, **incoming_data) == "response"
m_request.assert_called_once_with(
method="get",
params=request_params,
path=resource.get_task_comments_path(projectId=1, taskId=2),
)

@mock.patch("crowdin_api.requester.APIRequester.request")
def test_add_task_comment(self, m_request, base_absolut_url):
m_request.return_value = "response"

resource = self.get_resource(base_absolut_url)
assert resource.add_task_comment(projectId=1, taskId=2, text="hello") == "response"
m_request.assert_called_once_with(
method="post",
path=resource.get_task_comments_path(projectId=1, taskId=2),
request_data={"text": "hello"},
)

@mock.patch("crowdin_api.requester.APIRequester.request")
def test_get_task_comment(self, m_request, base_absolut_url):
m_request.return_value = "response"

resource = self.get_resource(base_absolut_url)
assert resource.get_task_comment(projectId=1, taskId=2, taskCommentId=3) == "response"
m_request.assert_called_once_with(
method="get",
path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3),
)

@mock.patch("crowdin_api.requester.APIRequester.request")
def test_delete_task_comment(self, m_request, base_absolut_url):
m_request.return_value = "response"

resource = self.get_resource(base_absolut_url)
assert resource.delete_task_comment(projectId=1, taskId=2, taskCommentId=3) == "response"
m_request.assert_called_once_with(
method="delete",
path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3),
)

@mock.patch("crowdin_api.requester.APIRequester.request")
def test_edit_task_comment(self, m_request, base_absolut_url):
m_request.return_value = "response"

data = [
{
"value": "new text",
"op": PatchOperation.REPLACE,
"path": "/text",
}
]

resource = self.get_resource(base_absolut_url)
assert (
resource.edit_task_comment(projectId=1, taskId=2, taskCommentId=3, data=data)
== "response"
)
m_request.assert_called_once_with(
method="patch",
path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3),
request_data=data,
)


class TestEnterpriseTasksResource:
resource_class = EnterpriseTasksResource
Expand Down
8 changes: 8 additions & 0 deletions crowdin_api/api_resources/tasks/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,11 @@ class EnterpriseTaskSettingsTemplateConfigLanguage(TypedDict):

class EnterpriseTaskSettingsTemplateLanguages(TypedDict):
languages: Iterable[EnterpriseTaskSettingsTemplateConfigLanguage]


# Task comments patch request (moved from removed task_comments package)
class TaskCommentPatchRequest(TypedDict):
value: Any
op: PatchOperation
# For now only /text is supported in edit operations
path: str