diff --git a/crowdin_api/api_resources/string_corrections/__init__.py b/crowdin_api/api_resources/string_corrections/__init__.py new file mode 100644 index 0000000..9f77d63 --- /dev/null +++ b/crowdin_api/api_resources/string_corrections/__init__.py @@ -0,0 +1 @@ +__pdoc__ = {'tests': False} diff --git a/crowdin_api/api_resources/string_corrections/enums.py b/crowdin_api/api_resources/string_corrections/enums.py new file mode 100644 index 0000000..8f56d49 --- /dev/null +++ b/crowdin_api/api_resources/string_corrections/enums.py @@ -0,0 +1,7 @@ +from enum import Enum + + +class ListCorrectionsOrderBy(Enum): + ID = "id" + TEXT = "text" + CREATED_AT = "createdAt" diff --git a/crowdin_api/api_resources/string_corrections/resource.py b/crowdin_api/api_resources/string_corrections/resource.py new file mode 100644 index 0000000..1e095b4 --- /dev/null +++ b/crowdin_api/api_resources/string_corrections/resource.py @@ -0,0 +1,156 @@ +from typing import Optional + +from crowdin_api.api_resources.abstract.resources import BaseResource +from crowdin_api.api_resources.enums import DenormalizePlaceholders, PluralCategoryName +from crowdin_api.sorting import Sorting +from crowdin_api.utils import convert_enum_to_string_if_exists + + +class StringCorrectionsResource(BaseResource): + """ + Resource for String Corrections. + + Use API to add or remove strings translations, approvals, and votes. + + Link to documentation: + https://support.crowdin.com/developer/enterprise/api/v2/#tag/String-Corrections + """ + + def get_string_corrections_path(self, project_id: int, correction_id: Optional[int] = None): + if correction_id is not None: + return f"projects/{project_id}/corrections/{correction_id}" + + return f"projects/{project_id}/corrections" + + def list_corrections( + self, + project_id: int, + string_id: int, + limit: Optional[int] = None, + offset: Optional[int] = None, + order_by: Optional[Sorting] = None, + denormalize_placeholders: Optional[DenormalizePlaceholders] = None, + ): + """ + List Corrections + + Link to documentation: + https://support.crowdin.com/developer/enterprise/api/v2/#tag/String-Corrections/operation/api.projects.corrections.getMany + """ + + params = { + "stringId": string_id, + "limit": limit, + "offset": offset, + "orderBy": str(order_by) if order_by is not None else None, + "denormalizePlaceholders": convert_enum_to_string_if_exists(denormalize_placeholders) + } + + return self.requester.request( + method="get", + path=self.get_string_corrections_path(project_id), + params=params + ) + + def add_correction( + self, + project_id: int, + string_id: int, + text: str, + plural_category_name: Optional[PluralCategoryName] = None, + ): + """ + Add Correction + + Link to documentation: + https://support.crowdin.com/developer/enterprise/api/v2/#tag/String-Corrections/operation/api.projects.corrections.post + """ + + params = { + "stringId": string_id, + "text": text, + "pluralCategoryName": convert_enum_to_string_if_exists(plural_category_name), + } + + return self.requester.request( + method="post", + path=self.get_string_corrections_path(project_id), + request_data=params + ) + + def delete_corrections( + self, + project_id: int, + string_id: int + ): + """ + Delete Corrections + + Link to documentation: + https://support.crowdin.com/developer/enterprise/api/v2/#tag/String-Corrections/operation/api.projects.corrections.deleteMany + """ + + params = { + "stringId": string_id, + } + + return self.requester.request( + method="delete", + path=self.get_string_corrections_path(project_id), + params=params + ) + + def get_correction( + self, + project_id: int, + correction_id: int, + denormalize_placeholders: Optional[DenormalizePlaceholders] = None, + ): + """ + Get Correction + + Link to documentation: + https://support.crowdin.com/developer/enterprise/api/v2/#tag/String-Corrections/operation/api.projects.corrections.get + """ + + return self.requester.request( + method="get", + path=self.get_string_corrections_path(project_id, correction_id), + params={ + "denormalizePlaceholders": convert_enum_to_string_if_exists(denormalize_placeholders), + } + ) + + def restore_correction( + self, + project_id: int, + correction_id: int, + ): + """ + Restore Correction + + Link to documentation: + https://support.crowdin.com/developer/enterprise/api/v2/#tag/String-Corrections/operation/api.projects.corrections.put + """ + + return self.requester.request( + method="put", + path=self.get_string_corrections_path(project_id, correction_id), + ) + + def delete_correction( + self, + project_id: int, + correction_id: int + ): + """ + Delete Correction + + Link to documentation: + https://support.crowdin.com/developer/enterprise/api/v2/#tag/String-Corrections/operation/api.projects.corrections.delete + """ + + return self.requester.request( + method="delete", + path=self.get_string_corrections_path(project_id, correction_id) + ) diff --git a/crowdin_api/api_resources/string_corrections/tests/test_string_corrections_resource.py b/crowdin_api/api_resources/string_corrections/tests/test_string_corrections_resource.py new file mode 100644 index 0000000..1b90c65 --- /dev/null +++ b/crowdin_api/api_resources/string_corrections/tests/test_string_corrections_resource.py @@ -0,0 +1,180 @@ +from unittest import mock + +import pytest + +from crowdin_api.api_resources.enums import DenormalizePlaceholders, PluralCategoryName +from crowdin_api.api_resources.string_corrections.enums import ListCorrectionsOrderBy +from crowdin_api.api_resources.string_corrections.resource import StringCorrectionsResource +from crowdin_api.requester import APIRequester +from crowdin_api.sorting import SortingRule, Sorting, SortingOrder + + +class TestStringCorrectionsResource: + resource_class = StringCorrectionsResource + + def get_resource(self, base_absolut_url): + return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + + @pytest.mark.parametrize( + "in_params, request_params", + ( + ( + { + "string_id": 1 + }, + { + "stringId": 1, + "limit": None, + "offset": None, + "orderBy": None, + "denormalizePlaceholders": None + }, + ), + ( + { + "string_id": 1, + "limit": 25, + "offset": 0, + "order_by": Sorting( + [ + SortingRule(ListCorrectionsOrderBy.CREATED_AT, SortingOrder.DESC), + SortingRule(ListCorrectionsOrderBy.ID) + ] + ), + "denormalize_placeholders": DenormalizePlaceholders.ENABLE + }, + { + "stringId": 1, + "limit": 25, + "offset": 0, + "orderBy": "createdAt desc,id", + "denormalizePlaceholders": 1 + } + ), + ), + ) + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_list_corrections(self, m_request, in_params, request_params, base_absolut_url): + m_request.return_value = "response" + + project_id = 1 + + resource = self.get_resource(base_absolut_url) + assert resource.list_corrections(project_id, **in_params) == "response" + m_request.assert_called_with( + method="get", + path=f"projects/{project_id}/corrections", + params=request_params + ) + + @pytest.mark.parametrize( + "in_params, request_params", + ( + ( + { + "string_id": 1, + "text": "sample", + "plural_category_name": PluralCategoryName.ZERO + }, + { + "stringId": 1, + "text": "sample", + "pluralCategoryName": "zero" + }, + ), + ), + ) + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_add_correction(self, m_request, in_params, request_params, base_absolut_url): + m_request.return_value = "response" + + project_id = 1 + + resource = self.get_resource(base_absolut_url) + assert resource.add_correction(project_id, **in_params) == "response" + m_request.assert_called_with( + method="post", + path=f"projects/{project_id}/corrections", + request_data=request_params + ) + + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_delete_corrections(self, m_request, base_absolut_url): + m_request.return_value = "response" + + project_id = 1 + string_id = 2 + resource = self.get_resource(base_absolut_url) + assert resource.delete_corrections(project_id, string_id) == "response" + + m_request.assert_called_with( + method="delete", + path=f"projects/{project_id}/corrections", + params={ + "stringId": string_id, + } + ) + + @pytest.mark.parametrize( + "in_params, request_params", + ( + ( + { + "denormalize_placeholders": DenormalizePlaceholders.ENABLE, + }, + { + "denormalizePlaceholders": 1 + } + ), + ), + ) + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_get_correction(self, m_request, in_params, request_params, base_absolut_url): + m_request.return_value = "response" + + project_id = 1 + correction_id = 2 + + resource = self.get_resource(base_absolut_url) + assert resource.get_correction(project_id, correction_id, **in_params) == "response" + m_request.assert_called_with( + method="get", + path=f"projects/{project_id}/corrections/{correction_id}", + params=request_params + ) + + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_restore_correction(self, m_request, base_absolut_url): + m_request.return_value = "response" + + project_id = 1 + correction_id = 2 + + resource = self.get_resource(base_absolut_url) + assert resource.restore_correction(project_id, correction_id) == "response" + m_request.assert_called_with( + method="put", + path=f"projects/{project_id}/corrections/{correction_id}", + ) + + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_delete_correction(self, m_request, base_absolut_url): + m_request.return_value = "response" + + project_id = 1 + correction_id = 2 + + resource = self.get_resource(base_absolut_url) + assert resource.delete_correction(project_id, correction_id) == "response" + + m_request.assert_called_with( + method="delete", + path=f"projects/{project_id}/corrections/{correction_id}", + )