From 91eb39f66064fa93c85acba345b1de27fe00fbce Mon Sep 17 00:00:00 2001 From: Max Inno <40697586+innomaxx@users.noreply.github.com> Date: Fri, 30 Jun 2023 15:15:21 +0300 Subject: [PATCH] feat(api): add the Translation Memory Segments API support (#158) --- .../TranslationMemoryApi.java | 99 +++++++++++ .../model/CreateTmSegmentRequest.java | 10 ++ .../translationmemory/model/TmSegment.java | 11 ++ .../model/TmSegmentRecord.java | 17 ++ .../model/TmSegmentRecordForm.java | 9 + .../model/TmSegmentRecordOperationAdd.java | 9 + .../model/TmSegmentResponseList.java | 25 +++ .../model/TmSegmentResponseObject.java | 8 + .../TranslationMemorySegmentsApiTest.java | 163 ++++++++++++++++++ .../segments/commonResponses_single.json | 17 ++ .../segments/createTmSegmentRequest.json | 8 + .../segments/editTmSegmentRequest.json | 19 ++ .../segments/listTmSegmentsResponse.json | 25 +++ 13 files changed, 420 insertions(+) create mode 100644 src/main/java/com/crowdin/client/translationmemory/model/CreateTmSegmentRequest.java create mode 100644 src/main/java/com/crowdin/client/translationmemory/model/TmSegment.java create mode 100644 src/main/java/com/crowdin/client/translationmemory/model/TmSegmentRecord.java create mode 100644 src/main/java/com/crowdin/client/translationmemory/model/TmSegmentRecordForm.java create mode 100644 src/main/java/com/crowdin/client/translationmemory/model/TmSegmentRecordOperationAdd.java create mode 100644 src/main/java/com/crowdin/client/translationmemory/model/TmSegmentResponseList.java create mode 100644 src/main/java/com/crowdin/client/translationmemory/model/TmSegmentResponseObject.java create mode 100644 src/test/java/com/crowdin/client/translationmemory/TranslationMemorySegmentsApiTest.java create mode 100644 src/test/resources/api/translationmemory/segments/commonResponses_single.json create mode 100644 src/test/resources/api/translationmemory/segments/createTmSegmentRequest.json create mode 100644 src/test/resources/api/translationmemory/segments/editTmSegmentRequest.json create mode 100644 src/test/resources/api/translationmemory/segments/listTmSegmentsResponse.json diff --git a/src/main/java/com/crowdin/client/translationmemory/TranslationMemoryApi.java b/src/main/java/com/crowdin/client/translationmemory/TranslationMemoryApi.java index 781c56c18..95985ffde 100644 --- a/src/main/java/com/crowdin/client/translationmemory/TranslationMemoryApi.java +++ b/src/main/java/com/crowdin/client/translationmemory/TranslationMemoryApi.java @@ -12,10 +12,14 @@ import com.crowdin.client.core.model.ResponseList; import com.crowdin.client.core.model.ResponseObject; import com.crowdin.client.translationmemory.model.AddTranslationMemoryRequest; +import com.crowdin.client.translationmemory.model.CreateTmSegmentRequest; import com.crowdin.client.translationmemory.model.SearchConcordance; import com.crowdin.client.translationmemory.model.SearchConcordanceRequest; import com.crowdin.client.translationmemory.model.SearchConcordanceResponse; import com.crowdin.client.translationmemory.model.SearchConcordanceResponseList; +import com.crowdin.client.translationmemory.model.TmSegment; +import com.crowdin.client.translationmemory.model.TmSegmentResponseList; +import com.crowdin.client.translationmemory.model.TmSegmentResponseObject; import com.crowdin.client.translationmemory.model.TranslationMemory; import com.crowdin.client.translationmemory.model.TranslationMemoryExportRequest; import com.crowdin.client.translationmemory.model.TranslationMemoryExportStatus; @@ -206,4 +210,99 @@ public ResponseObject checkTmImportStatus(Long tm TranslationMemoryImportStatusResponseObject translationMemoryImportStatusResponseObject = this.httpClient.get(this.url + "/tms/" + tmId + "/imports/" + importId, new HttpRequestConfig(), TranslationMemoryImportStatusResponseObject.class); return ResponseObject.of(translationMemoryImportStatusResponseObject.getData()); } + + // + + /** + * @param tmId translation memory identifier + * @param limit maximum number of items to retrieve (default 25) + * @param offset starting offset in the collection (default 0) + * @return list of translation memory segments + * @see + */ + public ResponseList listTmSegments(Long tmId, Integer limit, Integer offset) throws HttpException, HttpBadRequestException { + String url = formUrl_tmSegments(tmId); + Map> queryParams = HttpRequestConfig.buildUrlParams( + "limit", Optional.ofNullable(limit), + "offset", Optional.ofNullable(offset) + ); + TmSegmentResponseList responseList = this.httpClient.get(url, new HttpRequestConfig(queryParams), TmSegmentResponseList.class); + return TmSegmentResponseList.to(responseList); + } + + /** + * @param tmId translation memory identifier + * @param request request object + * @return newly created translation memory segment + * @see + */ + public ResponseObject createTmSegment(Long tmId, CreateTmSegmentRequest request) throws HttpException, HttpBadRequestException { + String url = formUrl_tmSegments(tmId); + TmSegmentResponseObject responseObject = this.httpClient.post(url, request, new HttpRequestConfig(), TmSegmentResponseObject.class); + return ResponseObject.of(responseObject.getData()); + } + + /** + * @param tmId translation memory identifier + * @param segmentId segment identifier + * @return translation memory segment + * @see + */ + public ResponseObject getTmSegment(Long tmId, Long segmentId) throws HttpException, HttpBadRequestException { + String url = formUrl_tmSegmentId(tmId, segmentId); + TmSegmentResponseObject responseObject = this.httpClient.get(url, new HttpRequestConfig(), TmSegmentResponseObject.class); + return ResponseObject.of(responseObject.getData()); + } + + /** + * @param tmId translation memory identifier + * @param segmentId segment identifier + * @see + */ + public void deleteTmSegment(Long tmId, Long segmentId) throws HttpException, HttpBadRequestException { + String url = formUrl_tmSegmentId(tmId, segmentId); + this.httpClient.delete(url, new HttpRequestConfig(), Void.class); + } + + /** + * @param tmId translation memory identifier + * @param segmentId segment identifier + * @param request request object + * @return updated translation memory segment + * @see + */ + public ResponseObject editTmSegment(Long tmId, Long segmentId, List request) throws HttpException, HttpBadRequestException { + String url = formUrl_tmSegmentId(tmId, segmentId); + TmSegmentResponseObject responseObject = this.httpClient.patch(url, request, new HttpRequestConfig(), TmSegmentResponseObject.class); + return ResponseObject.of(responseObject.getData()); + } + + // + + private String formUrl_tmSegments(Long tmId) { + return this.url + "/tms/" + tmId + "/segments"; + } + + private String formUrl_tmSegmentId(Long tmId, Long segmentId) { + return this.url + "/tms/" + tmId + "/segments/" + segmentId; + } + + // + + // } diff --git a/src/main/java/com/crowdin/client/translationmemory/model/CreateTmSegmentRequest.java b/src/main/java/com/crowdin/client/translationmemory/model/CreateTmSegmentRequest.java new file mode 100644 index 000000000..d78c11aa1 --- /dev/null +++ b/src/main/java/com/crowdin/client/translationmemory/model/CreateTmSegmentRequest.java @@ -0,0 +1,10 @@ +package com.crowdin.client.translationmemory.model; + +import lombok.Data; + +import java.util.List; + +@Data +public class CreateTmSegmentRequest { + private List records; +} diff --git a/src/main/java/com/crowdin/client/translationmemory/model/TmSegment.java b/src/main/java/com/crowdin/client/translationmemory/model/TmSegment.java new file mode 100644 index 000000000..9c8e237c1 --- /dev/null +++ b/src/main/java/com/crowdin/client/translationmemory/model/TmSegment.java @@ -0,0 +1,11 @@ +package com.crowdin.client.translationmemory.model; + +import lombok.Data; + +import java.util.List; + +@Data +public class TmSegment { + private Long id; + private List records; +} diff --git a/src/main/java/com/crowdin/client/translationmemory/model/TmSegmentRecord.java b/src/main/java/com/crowdin/client/translationmemory/model/TmSegmentRecord.java new file mode 100644 index 000000000..b85ceb533 --- /dev/null +++ b/src/main/java/com/crowdin/client/translationmemory/model/TmSegmentRecord.java @@ -0,0 +1,17 @@ +package com.crowdin.client.translationmemory.model; + +import lombok.Data; + +import java.util.Date; + +@Data +public class TmSegmentRecord { + private Long id; + private String languageId; + private String text; + private Long usageCount; + private Long createdBy; + private Long updatedBy; + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/crowdin/client/translationmemory/model/TmSegmentRecordForm.java b/src/main/java/com/crowdin/client/translationmemory/model/TmSegmentRecordForm.java new file mode 100644 index 000000000..974ec379e --- /dev/null +++ b/src/main/java/com/crowdin/client/translationmemory/model/TmSegmentRecordForm.java @@ -0,0 +1,9 @@ +package com.crowdin.client.translationmemory.model; + +import lombok.Data; + +@Data +public class TmSegmentRecordForm { + private String languageId; + private String text; +} diff --git a/src/main/java/com/crowdin/client/translationmemory/model/TmSegmentRecordOperationAdd.java b/src/main/java/com/crowdin/client/translationmemory/model/TmSegmentRecordOperationAdd.java new file mode 100644 index 000000000..10d960ab9 --- /dev/null +++ b/src/main/java/com/crowdin/client/translationmemory/model/TmSegmentRecordOperationAdd.java @@ -0,0 +1,9 @@ +package com.crowdin.client.translationmemory.model; + +import lombok.Data; + +@Data +public class TmSegmentRecordOperationAdd { + private String text; + private String languageId; +} diff --git a/src/main/java/com/crowdin/client/translationmemory/model/TmSegmentResponseList.java b/src/main/java/com/crowdin/client/translationmemory/model/TmSegmentResponseList.java new file mode 100644 index 000000000..0a1d3695b --- /dev/null +++ b/src/main/java/com/crowdin/client/translationmemory/model/TmSegmentResponseList.java @@ -0,0 +1,25 @@ +package com.crowdin.client.translationmemory.model; + +import com.crowdin.client.core.model.Pagination; +import com.crowdin.client.core.model.ResponseList; +import com.crowdin.client.core.model.ResponseObject; +import lombok.Data; + +import java.util.List; +import java.util.stream.Collectors; + +@Data +public class TmSegmentResponseList { + private List data; + private Pagination pagination; + + public static ResponseList to(TmSegmentResponseList responseList) { + return ResponseList.of( + responseList.getData().stream() + .map(TmSegmentResponseObject::getData) + .map(ResponseObject::of) + .collect(Collectors.toList()), + responseList.getPagination() + ); + } +} diff --git a/src/main/java/com/crowdin/client/translationmemory/model/TmSegmentResponseObject.java b/src/main/java/com/crowdin/client/translationmemory/model/TmSegmentResponseObject.java new file mode 100644 index 000000000..f7b5b4610 --- /dev/null +++ b/src/main/java/com/crowdin/client/translationmemory/model/TmSegmentResponseObject.java @@ -0,0 +1,8 @@ +package com.crowdin.client.translationmemory.model; + +import lombok.Data; + +@Data +public class TmSegmentResponseObject { + private TmSegment data; +} diff --git a/src/test/java/com/crowdin/client/translationmemory/TranslationMemorySegmentsApiTest.java b/src/test/java/com/crowdin/client/translationmemory/TranslationMemorySegmentsApiTest.java new file mode 100644 index 000000000..34a1e2a8d --- /dev/null +++ b/src/test/java/com/crowdin/client/translationmemory/TranslationMemorySegmentsApiTest.java @@ -0,0 +1,163 @@ +package com.crowdin.client.translationmemory; + +import com.crowdin.client.core.model.PatchOperation; +import com.crowdin.client.core.model.PatchRequest; +import com.crowdin.client.core.model.ResponseList; +import com.crowdin.client.core.model.ResponseObject; +import com.crowdin.client.framework.RequestMock; +import com.crowdin.client.framework.TestClient; +import com.crowdin.client.translationmemory.model.*; + +import lombok.SneakyThrows; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPatch; +import org.apache.http.client.methods.HttpPost; +import org.junit.jupiter.api.Test; + +import java.text.SimpleDateFormat; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class TranslationMemorySegmentsApiTest extends TestClient { + private final Long tmId = 1L; + private final Long segmentId = 1L; + + @Override + public List getMocks() { + return Arrays.asList( + // LIST + RequestMock.build( + formUrl_tmSegments(tmId), + HttpGet.METHOD_NAME, + "api/translationmemory/segments/listTmSegmentsResponse.json", + new HashMap() {{ + put("limit", 20); + put("offset", 10); + }} + ), + + // CREATE + RequestMock.build( + formUrl_tmSegments(tmId), + HttpPost.METHOD_NAME, + "api/translationmemory/segments/createTmSegmentRequest.json", + "api/translationmemory/segments/commonResponses_single.json" + ), + + // GET + RequestMock.build( + formUrl_tmSegmentId(tmId, segmentId), + HttpGet.METHOD_NAME, + "api/translationmemory/segments/commonResponses_single.json" + ), + + // DELETE + RequestMock.build( + formUrl_tmSegmentId(tmId, segmentId), + HttpDelete.METHOD_NAME + ), + + // EDIT + RequestMock.build( + formUrl_tmSegmentId(tmId, segmentId), + HttpPatch.METHOD_NAME, + "api/translationmemory/segments/editTmSegmentRequest.json", + "api/translationmemory/segments/commonResponses_single.json" + ) + ); + } + + // + + private String formUrl_tmSegments(Long tmId) { + return this.url + "/tms/" + tmId + "/segments"; + } + + private String formUrl_tmSegmentId(Long tmId, Long segmentId) { + return this.url + "/tms/" + tmId + "/segments/" + segmentId; + } + + // + + @Test + public void listTmSegments() { + ResponseList response = this.getTranslationMemoryApi().listTmSegments(tmId, 20, 10); + assertTmSegment(response.getData().get(0).getData()); + } + + @Test + public void createTmSegment() { + CreateTmSegmentRequest request = new CreateTmSegmentRequest() {{ + setRecords(Collections.singletonList(new TmSegmentRecordForm() {{ + setLanguageId("uk"); + setText("Перекладений текст"); + }})); + }}; + + ResponseObject response = this.getTranslationMemoryApi().createTmSegment(tmId, request); + assertTmSegment(response.getData()); + } + + @Test + public void getTmSegment() { + ResponseObject response = this.getTranslationMemoryApi().getTmSegment(tmId, segmentId); + assertTmSegment(response.getData()); + } + + @Test + public void deleteTmSegment() { + this.getTranslationMemoryApi().deleteTmSegment(tmId, segmentId); + } + + @Test + public void editTmSegment() { + List request = new ArrayList() {{ + add(new PatchRequest() {{ + setOp(PatchOperation.ADD); + setPath("/records/-"); + setValue(new TmSegmentRecordOperationAdd() {{ + setText("Перекладений текст"); + setLanguageId("uk"); + }}); + }}); + add(new PatchRequest() {{ + setOp(PatchOperation.REPLACE); + setPath("/records/1/text"); + setValue("Перекладений текст 2"); + }}); + add(new PatchRequest() {{ + setOp(PatchOperation.REMOVE); + setPath("/records/2"); + }}); + }}; + + ResponseObject response = this.getTranslationMemoryApi().editTmSegment(tmId, segmentId, request); + assertTmSegment(response.getData()); + } + + @SneakyThrows + private static void assertTmSegment(TmSegment tmSegment) { + assertNotNull(tmSegment); + + assertNotNull(tmSegment.getRecords()); + assertEquals(1, tmSegment.getRecords().size()); + + TmSegmentRecord record = tmSegment.getRecords().get(0); + assertNotNull(record); + + assertEquals(1, record.getId()); + assertEquals("uk", record.getLanguageId()); + assertEquals("Перекладений текст", record.getText()); + assertEquals(13, record.getUsageCount()); + assertEquals(1, record.getCreatedBy()); + assertEquals(1, record.getUpdatedBy()); + + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"); + + assertEquals(sdf.parse("2019-09-16T13:48:04+00:00"), record.getCreatedAt()); + assertEquals(sdf.parse("2019-09-16T13:48:04+00:00"), record.getUpdatedAt()); + } +} diff --git a/src/test/resources/api/translationmemory/segments/commonResponses_single.json b/src/test/resources/api/translationmemory/segments/commonResponses_single.json new file mode 100644 index 000000000..075394e5d --- /dev/null +++ b/src/test/resources/api/translationmemory/segments/commonResponses_single.json @@ -0,0 +1,17 @@ +{ + "data": { + "id": 4, + "records": [ + { + "id": 1, + "languageId": "uk", + "text": "Перекладений текст", + "usageCount": 13, + "createdBy": 1, + "updatedBy": 1, + "createdAt": "2019-09-16T13:48:04+00:00", + "updatedAt": "2019-09-16T13:48:04+00:00" + } + ] + } +} \ No newline at end of file diff --git a/src/test/resources/api/translationmemory/segments/createTmSegmentRequest.json b/src/test/resources/api/translationmemory/segments/createTmSegmentRequest.json new file mode 100644 index 000000000..dd81ffff1 --- /dev/null +++ b/src/test/resources/api/translationmemory/segments/createTmSegmentRequest.json @@ -0,0 +1,8 @@ +{ + "records": [ + { + "languageId": "uk", + "text": "Перекладений текст" + } + ] +} \ No newline at end of file diff --git a/src/test/resources/api/translationmemory/segments/editTmSegmentRequest.json b/src/test/resources/api/translationmemory/segments/editTmSegmentRequest.json new file mode 100644 index 000000000..dfb0a7a94 --- /dev/null +++ b/src/test/resources/api/translationmemory/segments/editTmSegmentRequest.json @@ -0,0 +1,19 @@ +[ + { + "op": "add", + "path": "/records/-", + "value": { + "text": "Перекладений текст", + "languageId": "uk" + } + }, + { + "op": "replace", + "path": "/records/1/text", + "value": "Перекладений текст 2" + }, + { + "op": "remove", + "path": "/records/2" + } +] \ No newline at end of file diff --git a/src/test/resources/api/translationmemory/segments/listTmSegmentsResponse.json b/src/test/resources/api/translationmemory/segments/listTmSegmentsResponse.json new file mode 100644 index 000000000..70e4eaa1f --- /dev/null +++ b/src/test/resources/api/translationmemory/segments/listTmSegmentsResponse.json @@ -0,0 +1,25 @@ +{ + "data": [ + { + "data": { + "id": 4, + "records": [ + { + "id": 1, + "languageId": "uk", + "text": "Перекладений текст", + "usageCount": 13, + "createdBy": 1, + "updatedBy": 1, + "createdAt": "2019-09-16T13:48:04+00:00", + "updatedAt": "2019-09-16T13:48:04+00:00" + } + ] + } + } + ], + "pagination": { + "offset": 0, + "limit": 25 + } +} \ No newline at end of file