From 089d6e749180687c63a2f6c205bb7652c229e884 Mon Sep 17 00:00:00 2001 From: Kateryna Oblakevych Date: Sun, 18 Oct 2026 21:12:30 -0700 Subject: [PATCH 1/2] fix(core): deserialize unknown enum values as null Enum values the SDK does not know yet (for example ones added to the API after a release) used to make the whole response fail with an IllegalArgumentException. They are now deserialized as null so the rest of the response is still usable. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../core/http/impl/json/EnumDeserializer.java | 22 +++++++++++++++---- .../core/http/EnumSerializationTest.java | 16 ++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/crowdin/client/core/http/impl/json/EnumDeserializer.java b/src/main/java/com/crowdin/client/core/http/impl/json/EnumDeserializer.java index ff92b5e84..7d44de701 100644 --- a/src/main/java/com/crowdin/client/core/http/impl/json/EnumDeserializer.java +++ b/src/main/java/com/crowdin/client/core/http/impl/json/EnumDeserializer.java @@ -12,6 +12,7 @@ import lombok.SneakyThrows; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; public class EnumDeserializer extends JsonDeserializer implements ContextualDeserializer { @@ -40,12 +41,25 @@ public Enum deserialize(JsonParser p, DeserializationContext ctxt) throws IOExce } + /** + * Values unknown to the SDK (e.g. added to the API after this SDK version was released) + * are deserialized as {@code null} instead of failing the whole response. + */ @SneakyThrows private Enum deserialize(Class type, String value) { - if (EnumConverter.class.isAssignableFrom(type)) { - return (Enum) type.getMethod("from", String.class).invoke(null, value); - } else { - return Enum.valueOf(type, value); + try { + if (EnumConverter.class.isAssignableFrom(type)) { + return (Enum) type.getMethod("from", String.class).invoke(null, value); + } else { + return Enum.valueOf(type, value); + } + } catch (InvocationTargetException e) { + if (e.getCause() instanceof IllegalArgumentException) { + return null; + } + throw e; + } catch (IllegalArgumentException e) { + return null; } } } diff --git a/src/test/java/com/crowdin/client/core/http/EnumSerializationTest.java b/src/test/java/com/crowdin/client/core/http/EnumSerializationTest.java index 9e967defe..977218941 100644 --- a/src/test/java/com/crowdin/client/core/http/EnumSerializationTest.java +++ b/src/test/java/com/crowdin/client/core/http/EnumSerializationTest.java @@ -7,10 +7,12 @@ import com.crowdin.client.sourcefiles.model.ExportQuotes; import com.crowdin.client.webhooks.model.OrganizationEvent; +import lombok.Data; import lombok.SneakyThrows; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; public class EnumSerializationTest { @@ -81,6 +83,20 @@ public void webhooks_OrganizationEvent() { // + @Test + @SneakyThrows + public void unknownEnumValueIsDeserializedAsNull() { + EnumHolder holder = jsonTransformer.parse("{\"type\":\"unknown_value\",\"quotes\":\"single\"}", EnumHolder.class); + assertNull(holder.getType()); + assertEquals(ExportQuotes.SINGLE, holder.getQuotes()); + } + + @Data + public static class EnumHolder { + private JsonFileType type; + private ExportQuotes quotes; + } + @SneakyThrows private > void serializeAndCompare(T enumValue, Object expectedEnumValue) { String enumValueString = jsonTransformer.convert(enumValue); From 56e081468ac099ec9758077651907515832834d0 Mon Sep 17 00:00:00 2001 From: Kateryna Oblakevych Date: Sun, 18 Oct 2026 21:16:21 -0700 Subject: [PATCH 2/2] feat(source-files): update source files and branches API to the latest docs Source files: - add missing import options fields (Docx, Spreadsheet, Xml, Html, HtmlWithFrontMatter) and new import options classes for WebXml, Vsdx, Idml, Md, MdxV2, StringCatalog, Adoc and Vdf files - add export options classes for Md, MdxV1, MdxV2 and Docx files - add Enterprise custom `fields` to AddFileRequest and FileInfo/File - resolve import/export options by the file type, so Html, Md, Mdx and other richer options are returned instead of the generic classes; new classes extend OtherFileImportOptions/GeneralFileExportOptions so existing casts keep working - deprecate FileRevision.info, which is no longer part of the API Branches: - add isProtected to Branch, AddBranchRequest, CloneBranchRequest and ClonedBranch (string-based projects) - add dryRun to BranchMergeStatus attributes and acceptSourceChanges to BranchMergeSummary - fix the checkMergeBranchStatus Javadoc link and add Enterprise links Co-Authored-By: Claude Opus 5.5 (1M context) --- .../crowdin/client/branches/BranchesApi.java | 8 +- .../branches/model/BranchMergeStatus.java | 1 + .../branches/model/BranchMergeSummary.java | 1 + .../branches/model/CloneBranchRequest.java | 1 + .../client/branches/model/ClonedBranch.java | 1 + .../json/FileExportOptionsDeserializer.java | 47 ++- .../json/FileImportOptionsDeserializer.java | 75 ++++- .../http/impl/json/FileInfoDeserializer.java | 30 +- .../impl/json/JacksonJsonTransformer.java | 7 +- .../sourcefiles/model/AddBranchRequest.java | 4 + .../sourcefiles/model/AddFileRequest.java | 5 + .../model/AdocFileImportOptions.java | 16 + .../client/sourcefiles/model/Branch.java | 1 + .../model/DocxFileExportOptions.java | 17 + .../model/DocxFileImportOptions.java | 36 +++ .../client/sourcefiles/model/FileInfo.java | 6 + .../sourcefiles/model/FileRevision.java | 4 + .../sourcefiles/model/FileRevisionInfo.java | 4 + .../model/FileRevisionInfoAttribute.java | 4 + .../model/HtmlFileImportOptions.java | 14 +- .../HtmlWithFrontMatterFileImportOptions.java | 14 +- .../model/IdmlFileImportOptions.java | 16 + .../model/MdFileExportOptions.java | 20 ++ .../model/MdFileImportOptions.java | 20 ++ .../model/MdFrontMatterQuotes.java | 24 ++ .../client/sourcefiles/model/MdMarker.java | 24 ++ .../sourcefiles/model/MdTableColumnWidth.java | 24 ++ .../model/MdUnorderedListBullet.java | 24 ++ .../model/MdxV1FileExportOptions.java | 19 ++ .../model/MdxV1FileImportOptions.java | 12 +- .../model/MdxV2FileExportOptions.java | 19 ++ .../model/MdxV2FileImportOptions.java | 19 ++ .../model/OtherFileImportOptions.java | 8 + .../model/SpreadsheetFileImportOptions.java | 15 + .../model/StringCatalogFileImportOptions.java | 17 + .../model/VdfFileImportOptions.java | 17 + .../model/VsdxFileImportOptions.java | 17 + .../model/WebXmlFileImportOptions.java | 19 ++ .../model/XmlFileImportOptions.java | 4 + .../client/branches/BranchesApiTest.java | 14 + .../FileOptionsDeserializationTest.java | 196 ++++++++++++ .../sourcefiles/SourceFilesApiTest.java | 158 +++++++++ .../api/branches/branchMergeStatus.json | 3 +- .../api/branches/branchMergeSummary.json | 1 + .../api/branches/cloneBranchRequest.json | 3 +- .../resources/api/branches/clonedBranch.json | 11 + .../api/sourcefiles/addBranchRequest.json | 3 +- .../addFileWithOptionsRequest.json | 33 ++ .../resources/api/sourcefiles/branch.json | 1 + src/test/resources/api/sourcefiles/file.json | 4 + .../listFilesWithFormatOptions.json | 300 ++++++++++++++++++ 51 files changed, 1319 insertions(+), 22 deletions(-) create mode 100644 src/main/java/com/crowdin/client/sourcefiles/model/AdocFileImportOptions.java create mode 100644 src/main/java/com/crowdin/client/sourcefiles/model/DocxFileExportOptions.java create mode 100644 src/main/java/com/crowdin/client/sourcefiles/model/IdmlFileImportOptions.java create mode 100644 src/main/java/com/crowdin/client/sourcefiles/model/MdFileExportOptions.java create mode 100644 src/main/java/com/crowdin/client/sourcefiles/model/MdFileImportOptions.java create mode 100644 src/main/java/com/crowdin/client/sourcefiles/model/MdFrontMatterQuotes.java create mode 100644 src/main/java/com/crowdin/client/sourcefiles/model/MdMarker.java create mode 100644 src/main/java/com/crowdin/client/sourcefiles/model/MdTableColumnWidth.java create mode 100644 src/main/java/com/crowdin/client/sourcefiles/model/MdUnorderedListBullet.java create mode 100644 src/main/java/com/crowdin/client/sourcefiles/model/MdxV1FileExportOptions.java create mode 100644 src/main/java/com/crowdin/client/sourcefiles/model/MdxV2FileExportOptions.java create mode 100644 src/main/java/com/crowdin/client/sourcefiles/model/MdxV2FileImportOptions.java create mode 100644 src/main/java/com/crowdin/client/sourcefiles/model/StringCatalogFileImportOptions.java create mode 100644 src/main/java/com/crowdin/client/sourcefiles/model/VdfFileImportOptions.java create mode 100644 src/main/java/com/crowdin/client/sourcefiles/model/VsdxFileImportOptions.java create mode 100644 src/main/java/com/crowdin/client/sourcefiles/model/WebXmlFileImportOptions.java create mode 100644 src/test/java/com/crowdin/client/sourcefiles/FileOptionsDeserializationTest.java create mode 100644 src/test/resources/api/branches/clonedBranch.json create mode 100644 src/test/resources/api/sourcefiles/addFileWithOptionsRequest.json create mode 100644 src/test/resources/api/sourcefiles/listFilesWithFormatOptions.json diff --git a/src/main/java/com/crowdin/client/branches/BranchesApi.java b/src/main/java/com/crowdin/client/branches/BranchesApi.java index a51d967ed..d33ff528e 100644 --- a/src/main/java/com/crowdin/client/branches/BranchesApi.java +++ b/src/main/java/com/crowdin/client/branches/BranchesApi.java @@ -86,6 +86,7 @@ public ResponseObject checkBranchDeletionStatus(Long projectId, * @return clone status * @see */ public ResponseObject cloneBranch(Long projectId, Long branchId, CloneBranchRequest request) throws HttpException, HttpBadRequestException { @@ -100,6 +101,7 @@ public ResponseObject cloneBranch(Long projectId, Long branch * @return clone status * @see */ public ResponseObject checkCloneBranchStatus(Long projectId, Long branchId, String cloneId) throws HttpException, HttpBadRequestException { @@ -114,6 +116,7 @@ public ResponseObject checkCloneBranchStatus(Long projectId, * @return cloned branch * @see */ public ResponseObject getClonedBranch(Long projectId, Long branchId, String cloneId) throws HttpException, HttpBadRequestException { @@ -128,6 +131,7 @@ public ResponseObject getClonedBranch(Long projectId, Long branchI * @return merge status * @see */ public ResponseObject mergeBranch(Long projectId, Long branchId, MergeBranchRequest request) throws HttpException, HttpBadRequestException { @@ -141,7 +145,8 @@ public ResponseObject mergeBranch(Long projectId, Long branch * @param mergeId merge identifier * @return merge status * @see */ public ResponseObject checkMergeBranchStatus(Long projectId, Long branchId, String mergeId) throws HttpException, HttpBadRequestException { @@ -156,6 +161,7 @@ public ResponseObject checkMergeBranchStatus(Long projectId, * @return merge summary * @see */ public ResponseObject getMergeBranchSummary(Long projectId, Long branchId, String mergeId) throws HttpException, HttpBadRequestException { diff --git a/src/main/java/com/crowdin/client/branches/model/BranchMergeStatus.java b/src/main/java/com/crowdin/client/branches/model/BranchMergeStatus.java index bb3ff770c..49c2a71f6 100644 --- a/src/main/java/com/crowdin/client/branches/model/BranchMergeStatus.java +++ b/src/main/java/com/crowdin/client/branches/model/BranchMergeStatus.java @@ -22,5 +22,6 @@ public static class Attributes { private Integer sourceBranchId; private Boolean deleteAfterMerge; private Boolean acceptSourceChanges; + private Boolean dryRun; } } diff --git a/src/main/java/com/crowdin/client/branches/model/BranchMergeSummary.java b/src/main/java/com/crowdin/client/branches/model/BranchMergeSummary.java index a37ae8d56..c62d1221d 100644 --- a/src/main/java/com/crowdin/client/branches/model/BranchMergeSummary.java +++ b/src/main/java/com/crowdin/client/branches/model/BranchMergeSummary.java @@ -11,5 +11,6 @@ public class BranchMergeSummary { private Long sourceBranchId; private Long targetBranchId; private Boolean dryRun; + private Boolean acceptSourceChanges; private Map details; } diff --git a/src/main/java/com/crowdin/client/branches/model/CloneBranchRequest.java b/src/main/java/com/crowdin/client/branches/model/CloneBranchRequest.java index 5ef974dd2..f22382699 100644 --- a/src/main/java/com/crowdin/client/branches/model/CloneBranchRequest.java +++ b/src/main/java/com/crowdin/client/branches/model/CloneBranchRequest.java @@ -7,4 +7,5 @@ public class CloneBranchRequest { private String name; private String title; + private Boolean isProtected; } diff --git a/src/main/java/com/crowdin/client/branches/model/ClonedBranch.java b/src/main/java/com/crowdin/client/branches/model/ClonedBranch.java index a9c638830..7f135a677 100644 --- a/src/main/java/com/crowdin/client/branches/model/ClonedBranch.java +++ b/src/main/java/com/crowdin/client/branches/model/ClonedBranch.java @@ -11,6 +11,7 @@ public class ClonedBranch { private Long projectId; private String name; private String title; + private Boolean isProtected; private Date createdAt; private Date updatedAt; } diff --git a/src/main/java/com/crowdin/client/core/http/impl/json/FileExportOptionsDeserializer.java b/src/main/java/com/crowdin/client/core/http/impl/json/FileExportOptionsDeserializer.java index 4a10b2ee5..e0f31e3dd 100644 --- a/src/main/java/com/crowdin/client/core/http/impl/json/FileExportOptionsDeserializer.java +++ b/src/main/java/com/crowdin/client/core/http/impl/json/FileExportOptionsDeserializer.java @@ -1,8 +1,12 @@ package com.crowdin.client.core.http.impl.json; +import com.crowdin.client.sourcefiles.model.DocxFileExportOptions; import com.crowdin.client.sourcefiles.model.ExportOptions; import com.crowdin.client.sourcefiles.model.GeneralFileExportOptions; import com.crowdin.client.sourcefiles.model.JavaScriptFileExportOptions; +import com.crowdin.client.sourcefiles.model.MdFileExportOptions; +import com.crowdin.client.sourcefiles.model.MdxV1FileExportOptions; +import com.crowdin.client.sourcefiles.model.MdxV2FileExportOptions; import com.crowdin.client.sourcefiles.model.PropertyFileExportOptions; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; @@ -16,6 +20,15 @@ import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import static com.crowdin.client.core.http.impl.json.FileInfoDeserializer.containsAny; + +/** + * Resolves the concrete {@link ExportOptions} class. + *

+ * Property and JavaScript options are resolved by their keys as before. All other options resolve to + * {@link GeneralFileExportOptions} or one of its format-specific subclasses, chosen by the parent file {@code type} + * (when known) or by format-specific keys. + */ public class FileExportOptionsDeserializer extends JsonDeserializer { private final ObjectMapper objectMapper; @@ -36,7 +49,39 @@ public ExportOptions deserialize(JsonParser p, DeserializationContext ctxt) thro } else if (fields.contains("exportQuotes")) { return this.objectMapper.readValue(treeNode.toString(), JavaScriptFileExportOptions.class); } else { - return this.objectMapper.readValue(treeNode.toString(), GeneralFileExportOptions.class); + Class clazz = resolveByFileType(FileInfoDeserializer.getFileType(ctxt)); + if (clazz == null) { + clazz = resolveByFields(fields); + } + return this.objectMapper.readValue(treeNode.toString(), clazz); + } + } + + private static Class resolveByFileType(String fileType) { + if (fileType == null) { + return null; + } + switch (fileType) { + case "md": + return MdFileExportOptions.class; + case "mdx_v1": + return MdxV1FileExportOptions.class; + case "mdx_v2": + return MdxV2FileExportOptions.class; + case "docx": + return DocxFileExportOptions.class; + default: + return null; + } + } + + private static Class resolveByFields(List fields) { + if (containsAny(fields, "allowWordStyleOptimization", "translateExcelExcludeColors")) { + return DocxFileExportOptions.class; + } else if (containsAny(fields, "strongMarker", "emphasisMarker", "unorderedListBullet", "tableColumnWidth", "frontMatterQuotes")) { + return MdFileExportOptions.class; + } else { + return GeneralFileExportOptions.class; } } } diff --git a/src/main/java/com/crowdin/client/core/http/impl/json/FileImportOptionsDeserializer.java b/src/main/java/com/crowdin/client/core/http/impl/json/FileImportOptionsDeserializer.java index af905ceab..dc019123c 100644 --- a/src/main/java/com/crowdin/client/core/http/impl/json/FileImportOptionsDeserializer.java +++ b/src/main/java/com/crowdin/client/core/http/impl/json/FileImportOptionsDeserializer.java @@ -1,9 +1,19 @@ package com.crowdin.client.core.http.impl.json; +import com.crowdin.client.sourcefiles.model.AdocFileImportOptions; import com.crowdin.client.sourcefiles.model.DocxFileImportOptions; +import com.crowdin.client.sourcefiles.model.HtmlFileImportOptions; +import com.crowdin.client.sourcefiles.model.HtmlWithFrontMatterFileImportOptions; +import com.crowdin.client.sourcefiles.model.IdmlFileImportOptions; import com.crowdin.client.sourcefiles.model.ImportOptions; +import com.crowdin.client.sourcefiles.model.MdFileImportOptions; +import com.crowdin.client.sourcefiles.model.MdxV1FileImportOptions; +import com.crowdin.client.sourcefiles.model.MdxV2FileImportOptions; import com.crowdin.client.sourcefiles.model.OtherFileImportOptions; import com.crowdin.client.sourcefiles.model.SpreadsheetFileImportOptions; +import com.crowdin.client.sourcefiles.model.StringCatalogFileImportOptions; +import com.crowdin.client.sourcefiles.model.VdfFileImportOptions; +import com.crowdin.client.sourcefiles.model.WebXmlFileImportOptions; import com.crowdin.client.sourcefiles.model.XmlFileImportOptions; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; @@ -17,6 +27,15 @@ import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import static com.crowdin.client.core.http.impl.json.FileInfoDeserializer.containsAny; + +/** + * Resolves the concrete {@link ImportOptions} class. + *

+ * Options with Docx, Spreadsheet or Xml specific keys are resolved as before. All other options resolve to + * {@link OtherFileImportOptions} or one of its format-specific subclasses, chosen by the parent file {@code type} + * (when known) or by format-specific keys. + */ public class FileImportOptionsDeserializer extends JsonDeserializer { private final ObjectMapper objectMapper; @@ -39,7 +58,61 @@ public ImportOptions deserialize(JsonParser p, DeserializationContext ctxt) thro } else if (fields.contains("translateContent")) { return this.objectMapper.readValue(treeNode.toString(), XmlFileImportOptions.class); } else { - return this.objectMapper.readValue(treeNode.toString(), OtherFileImportOptions.class); + Class clazz = resolveByFileType(FileInfoDeserializer.getFileType(ctxt)); + if (clazz == null) { + clazz = resolveByFields(fields); + } + return this.objectMapper.readValue(treeNode.toString(), clazz); + } + } + + private static Class resolveByFileType(String fileType) { + if (fileType == null) { + return null; + } + switch (fileType) { + case "html": + return HtmlFileImportOptions.class; + case "fm_html": + return HtmlWithFrontMatterFileImportOptions.class; + case "md": + return MdFileImportOptions.class; + case "mdx_v1": + return MdxV1FileImportOptions.class; + case "mdx_v2": + return MdxV2FileImportOptions.class; + case "webxml": + return WebXmlFileImportOptions.class; + case "idml": + return IdmlFileImportOptions.class; + case "adoc": + return AdocFileImportOptions.class; + case "vdf": + return VdfFileImportOptions.class; + default: + return null; + } + } + + private static Class resolveByFields(List fields) { + if (fields.contains("excludedElements")) { + return fields.contains("excludedFrontMatterElements") + ? HtmlWithFrontMatterFileImportOptions.class + : HtmlFileImportOptions.class; + } else if (containsAny(fields, "excludeCodeBlocks", "excludedFrontMatterElements")) { + return MdFileImportOptions.class; + } else if (containsAny(fields, "hideAttributeValues", "inlineTags")) { + return HtmlFileImportOptions.class; + } else if (fields.contains("inlineHyperlinkText")) { + return IdmlFileImportOptions.class; + } else if (fields.contains("importKeyAsSource")) { + return StringCatalogFileImportOptions.class; + } else if (fields.contains("excludeIncludeDirectives")) { + return AdocFileImportOptions.class; + } else if (containsAny(fields, "convertIcu", "addGenderArgument")) { + return VdfFileImportOptions.class; + } else { + return OtherFileImportOptions.class; } } } diff --git a/src/main/java/com/crowdin/client/core/http/impl/json/FileInfoDeserializer.java b/src/main/java/com/crowdin/client/core/http/impl/json/FileInfoDeserializer.java index 372e71d83..d4cfc9900 100644 --- a/src/main/java/com/crowdin/client/core/http/impl/json/FileInfoDeserializer.java +++ b/src/main/java/com/crowdin/client/core/http/impl/json/FileInfoDeserializer.java @@ -7,7 +7,9 @@ import com.fasterxml.jackson.core.TreeNode; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; import java.io.IOException; import java.util.List; @@ -16,6 +18,12 @@ public class FileInfoDeserializer extends JsonDeserializer { + /** + * Deserialization context attribute holding the {@code type} of the file whose import/export options are being + * deserialized. Used by {@link FileImportOptionsDeserializer} and {@link FileExportOptionsDeserializer}. + */ + public static final String FILE_TYPE_ATTRIBUTE = "crowdin.sourcefiles.fileType"; + private final ObjectMapper objectMapper; public FileInfoDeserializer(ObjectMapper objectMapper) { @@ -30,13 +38,31 @@ public FileInfo deserialize(JsonParser p, DeserializationContext ctxt) throws IO .stream(iterable.spliterator(), false) .collect(Collectors.toList()); if (containsAny(fields, "revisionId", "parserVersion", "priority", "importOptions", "exportOptions", "excludedTargetLanguages", "createdAt", "updatedAt")) { - return this.objectMapper.readValue(treeNode.toString(), File.class); + ObjectReader reader = this.objectMapper.readerFor(File.class); + String fileType = getFileType(treeNode); + if (fileType != null) { + reader = reader.withAttribute(FILE_TYPE_ATTRIBUTE, fileType); + } + return reader.readValue(treeNode.toString()); } else { return this.objectMapper.readValue(treeNode.toString(), FileInfo.class); } } - private static boolean containsAny(List fields, String... values) { + private static String getFileType(TreeNode treeNode) { + TreeNode typeNode = treeNode.get("type"); + if (typeNode instanceof JsonNode && ((JsonNode) typeNode).isTextual()) { + return ((JsonNode) typeNode).asText(); + } + return null; + } + + static String getFileType(DeserializationContext ctxt) { + Object fileType = ctxt.getAttribute(FILE_TYPE_ATTRIBUTE); + return fileType instanceof String ? (String) fileType : null; + } + + static boolean containsAny(List fields, String... values) { for (String value : values) { if (fields.contains(value)) { return true; diff --git a/src/main/java/com/crowdin/client/core/http/impl/json/JacksonJsonTransformer.java b/src/main/java/com/crowdin/client/core/http/impl/json/JacksonJsonTransformer.java index 3d6ec8d03..80f66b295 100644 --- a/src/main/java/com/crowdin/client/core/http/impl/json/JacksonJsonTransformer.java +++ b/src/main/java/com/crowdin/client/core/http/impl/json/JacksonJsonTransformer.java @@ -33,6 +33,9 @@ public JacksonJsonTransformer() { SimpleModule enumModule = new SimpleModule() .addDeserializer(Enum.class, new EnumDeserializer()); + ObjectMapper fileOptionsObjectMapper = cleanObjectMapper.copy() + .registerModule(enumModule); + SimpleModule module = new SimpleModule() .addDeserializer(Date.class, new DateDeserializer()) .addSerializer(Enum.class, new EnumSerializer()) @@ -43,8 +46,8 @@ public JacksonJsonTransformer() { .addDeserializer(FileInfo.class, new FileInfoDeserializer(cleanObjectMapper.copy() .registerModule(enumModule) .registerModule(new SimpleModule() - .addDeserializer(ImportOptions.class, new FileImportOptionsDeserializer(cleanObjectMapper)) - .addDeserializer(ExportOptions.class, new FileExportOptionsDeserializer(cleanObjectMapper))))) + .addDeserializer(ImportOptions.class, new FileImportOptionsDeserializer(fileOptionsObjectMapper)) + .addDeserializer(ExportOptions.class, new FileExportOptionsDeserializer(fileOptionsObjectMapper))))) .addDeserializer(LanguageTranslations.class, new LanguageTranslationsDeserializer(cleanObjectMapper)) .addDeserializer(FileFormatSettingsResource.class, new FileFormatSettingsDeserializer(cleanObjectMapper)) .addDeserializer(StringsExporterSettingsResource.class, new StringsExporterSettingsDeserializer(cleanObjectMapper)); diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/AddBranchRequest.java b/src/main/java/com/crowdin/client/sourcefiles/model/AddBranchRequest.java index c6f52e05e..3b7102ec2 100644 --- a/src/main/java/com/crowdin/client/sourcefiles/model/AddBranchRequest.java +++ b/src/main/java/com/crowdin/client/sourcefiles/model/AddBranchRequest.java @@ -10,4 +10,8 @@ public class AddBranchRequest { private String title; private String exportPattern; private Priority priority; + /** + * String-based projects only + */ + private Boolean isProtected; } diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/AddFileRequest.java b/src/main/java/com/crowdin/client/sourcefiles/model/AddFileRequest.java index 629b01061..913073dcb 100644 --- a/src/main/java/com/crowdin/client/sourcefiles/model/AddFileRequest.java +++ b/src/main/java/com/crowdin/client/sourcefiles/model/AddFileRequest.java @@ -3,6 +3,7 @@ import lombok.Data; import java.util.List; +import java.util.Map; @Data public class AddFileRequest { @@ -19,4 +20,8 @@ public class AddFileRequest { private ExportOptions exportOptions; private List excludedTargetLanguages; private List attachLabelIds; + /** + * Custom fields (Enterprise only) + */ + private Map fields; } diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/AdocFileImportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/AdocFileImportOptions.java new file mode 100644 index 000000000..eaf374d4b --- /dev/null +++ b/src/main/java/com/crowdin/client/sourcefiles/model/AdocFileImportOptions.java @@ -0,0 +1,16 @@ +package com.crowdin.client.sourcefiles.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * Import options for AsciiDoc files. Extends {@link OtherFileImportOptions} only for backward compatibility of deserialized responses: the API documents just {@code excludeIncludeDirectives} for this format. + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class AdocFileImportOptions extends OtherFileImportOptions { + + private Boolean excludeIncludeDirectives; +} diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/Branch.java b/src/main/java/com/crowdin/client/sourcefiles/model/Branch.java index a1a0b7c97..4f714dbae 100644 --- a/src/main/java/com/crowdin/client/sourcefiles/model/Branch.java +++ b/src/main/java/com/crowdin/client/sourcefiles/model/Branch.java @@ -14,6 +14,7 @@ public class Branch { private String title; private String exportPattern; private Priority priority; + private Boolean isProtected; private Date createdAt; private Date updatedAt; } diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/DocxFileExportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/DocxFileExportOptions.java new file mode 100644 index 000000000..05d47e6af --- /dev/null +++ b/src/main/java/com/crowdin/client/sourcefiles/model/DocxFileExportOptions.java @@ -0,0 +1,17 @@ +package com.crowdin.client.sourcefiles.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * Export options for Office documents. {@code exportPattern} is inherited from {@link GeneralFileExportOptions}. + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class DocxFileExportOptions extends GeneralFileExportOptions { + + private Boolean allowWordStyleOptimization; + private Boolean translateExcelExcludeColors; +} diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/DocxFileImportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/DocxFileImportOptions.java index a00dd7594..c8900f18c 100644 --- a/src/main/java/com/crowdin/client/sourcefiles/model/DocxFileImportOptions.java +++ b/src/main/java/com/crowdin/client/sourcefiles/model/DocxFileImportOptions.java @@ -3,6 +3,12 @@ import lombok.Data; import lombok.EqualsAndHashCode; +import java.util.List; + +/** + * Import options for Office documents (docx, xlsx, pptx and similar formats). + * Also returned by the API for vsdx files. + */ @Data @EqualsAndHashCode(callSuper = false) public class DocxFileImportOptions extends ImportOptions { @@ -14,6 +20,36 @@ public class DocxFileImportOptions extends ImportOptions { private Boolean importNotes; private Boolean importHiddenSlides; private Boolean contentSegmentation; + /** + * Returned in responses only. + */ + private Boolean customSegmentation; private Integer srxStorageId; + private Boolean translateDocProperties; + private Boolean translateComments; + private Boolean ignoreWhitespaceStyles; + private Boolean addTabAsCharacter; + private Boolean addLineSeparatorAsCharacter; + private String lineSeparatorReplacement; + private Boolean replaceNoBreakHyphenTag; + private Boolean ignoreSoftHyphenTag; + private List complexFieldDefinitionsToExtract; + private Boolean translateWordHeadersFooters; + private Boolean translateWordGraphicName; + private Boolean translateWordGraphicDescription; + private Boolean ignoreWordFontColors; + private String wordFontColorsMinIgnoranceThreshold; + private String wordFontColorsMaxIgnoranceThreshold; + private List excludeWordStyles; + private Boolean translateWordInExcludeStyleMode; + private List wordHighlightColors; + private Boolean translateWordInExcludeHighlightMode; + private Boolean translateWordExcludeColors; + private List wordExcludedColors; + private Boolean translateExcelCellsCopied; + private Boolean translateExcelSheetNames; + private List excelExcludedColors; + private Boolean translateExcelDiagramData; + private Boolean translateExcelDrawings; } diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/FileInfo.java b/src/main/java/com/crowdin/client/sourcefiles/model/FileInfo.java index e59a0021a..a06efa86d 100644 --- a/src/main/java/com/crowdin/client/sourcefiles/model/FileInfo.java +++ b/src/main/java/com/crowdin/client/sourcefiles/model/FileInfo.java @@ -2,6 +2,8 @@ import lombok.Data; +import java.util.Map; + @Data public class FileInfo { @@ -15,4 +17,8 @@ public class FileInfo { private String type; private String path; private String status; + /** + * Custom fields (Enterprise only) + */ + private Map fields; } diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/FileRevision.java b/src/main/java/com/crowdin/client/sourcefiles/model/FileRevision.java index d1f3c53a7..9079b7fea 100644 --- a/src/main/java/com/crowdin/client/sourcefiles/model/FileRevision.java +++ b/src/main/java/com/crowdin/client/sourcefiles/model/FileRevision.java @@ -11,6 +11,10 @@ public class FileRevision { private Long projectId; private Long fileId; private Long restoreToRevision; + /** + * @deprecated not part of the File Revision resource in the current API documentation; always {@code null} + */ + @Deprecated private FileRevisionInfo info; private Date date; } diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/FileRevisionInfo.java b/src/main/java/com/crowdin/client/sourcefiles/model/FileRevisionInfo.java index 988995748..f2594b0ed 100644 --- a/src/main/java/com/crowdin/client/sourcefiles/model/FileRevisionInfo.java +++ b/src/main/java/com/crowdin/client/sourcefiles/model/FileRevisionInfo.java @@ -2,6 +2,10 @@ import lombok.Data; +/** + * @deprecated not part of the File Revision resource in the current API documentation + */ +@Deprecated @Data public class FileRevisionInfo { diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/FileRevisionInfoAttribute.java b/src/main/java/com/crowdin/client/sourcefiles/model/FileRevisionInfoAttribute.java index a233a22c6..a0e4e6e93 100644 --- a/src/main/java/com/crowdin/client/sourcefiles/model/FileRevisionInfoAttribute.java +++ b/src/main/java/com/crowdin/client/sourcefiles/model/FileRevisionInfoAttribute.java @@ -2,6 +2,10 @@ import lombok.Data; +/** + * @deprecated not part of the File Revision resource in the current API documentation + */ +@Deprecated @Data public class FileRevisionInfoAttribute { diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/HtmlFileImportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/HtmlFileImportOptions.java index e104a96ab..8c6859b83 100644 --- a/src/main/java/com/crowdin/client/sourcefiles/model/HtmlFileImportOptions.java +++ b/src/main/java/com/crowdin/client/sourcefiles/model/HtmlFileImportOptions.java @@ -2,13 +2,19 @@ import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.ToString; import java.util.List; +/** + * Import options for HTML files. {@code contentSegmentation} and {@code srxStorageId} are inherited + * from {@link OtherFileImportOptions}. + */ @Data -@EqualsAndHashCode(callSuper = false) -public class HtmlFileImportOptions extends ImportOptions { +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class HtmlFileImportOptions extends OtherFileImportOptions { private List excludedElements; - private Boolean contentSegmentation; - private Long srxStorageId; + private List inlineTags; + private Boolean hideAttributeValues; } diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/HtmlWithFrontMatterFileImportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/HtmlWithFrontMatterFileImportOptions.java index c023383ba..3ac0af319 100644 --- a/src/main/java/com/crowdin/client/sourcefiles/model/HtmlWithFrontMatterFileImportOptions.java +++ b/src/main/java/com/crowdin/client/sourcefiles/model/HtmlWithFrontMatterFileImportOptions.java @@ -2,14 +2,20 @@ import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.ToString; import java.util.List; +/** + * Import options for HTML with Front Matter files. {@code contentSegmentation} and {@code srxStorageId} are inherited + * from {@link OtherFileImportOptions}. + */ @Data -@EqualsAndHashCode(callSuper = false) -public class HtmlWithFrontMatterFileImportOptions extends ImportOptions { +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class HtmlWithFrontMatterFileImportOptions extends OtherFileImportOptions { private List excludedElements; private List excludedFrontMatterElements; - private Boolean contentSegmentation; - private Long srxStorageId; + private List inlineTags; + private Boolean hideAttributeValues; } diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/IdmlFileImportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/IdmlFileImportOptions.java new file mode 100644 index 000000000..71ed26ad1 --- /dev/null +++ b/src/main/java/com/crowdin/client/sourcefiles/model/IdmlFileImportOptions.java @@ -0,0 +1,16 @@ +package com.crowdin.client.sourcefiles.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * Import options for IDML files. {@code contentSegmentation} and {@code srxStorageId} are inherited from {@link OtherFileImportOptions}. + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class IdmlFileImportOptions extends OtherFileImportOptions { + + private Boolean inlineHyperlinkText; +} diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/MdFileExportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/MdFileExportOptions.java new file mode 100644 index 000000000..6c322cfc0 --- /dev/null +++ b/src/main/java/com/crowdin/client/sourcefiles/model/MdFileExportOptions.java @@ -0,0 +1,20 @@ +package com.crowdin.client.sourcefiles.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * Export options for Markdown files. {@code exportPattern} is inherited from {@link GeneralFileExportOptions}. + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class MdFileExportOptions extends GeneralFileExportOptions { + + private MdMarker strongMarker; + private MdMarker emphasisMarker; + private MdUnorderedListBullet unorderedListBullet; + private MdTableColumnWidth tableColumnWidth; + private MdFrontMatterQuotes frontMatterQuotes; +} diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/MdFileImportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/MdFileImportOptions.java new file mode 100644 index 000000000..b04a9d5d7 --- /dev/null +++ b/src/main/java/com/crowdin/client/sourcefiles/model/MdFileImportOptions.java @@ -0,0 +1,20 @@ +package com.crowdin.client.sourcefiles.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.List; + +/** + * Import options for Markdown files. {@code contentSegmentation} and {@code srxStorageId} are inherited from {@link OtherFileImportOptions}. + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class MdFileImportOptions extends OtherFileImportOptions { + + private List excludedFrontMatterElements; + private Boolean excludeCodeBlocks; + private List inlineTags; +} diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/MdFrontMatterQuotes.java b/src/main/java/com/crowdin/client/sourcefiles/model/MdFrontMatterQuotes.java new file mode 100644 index 000000000..b046c4d3a --- /dev/null +++ b/src/main/java/com/crowdin/client/sourcefiles/model/MdFrontMatterQuotes.java @@ -0,0 +1,24 @@ +package com.crowdin.client.sourcefiles.model; + +import com.crowdin.client.core.model.EnumConverter; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Quotes used for front matter values in exported Markdown files. + */ +public enum MdFrontMatterQuotes implements EnumConverter { + + AUTO, SINGLE, DOUBLE; + + @JsonCreator + public static MdFrontMatterQuotes from(String value) { + return MdFrontMatterQuotes.valueOf(value.toUpperCase()); + } + + @JsonValue + @Override + public String to(MdFrontMatterQuotes v) { + return v.name().toLowerCase(); + } +} diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/MdMarker.java b/src/main/java/com/crowdin/client/sourcefiles/model/MdMarker.java new file mode 100644 index 000000000..3a8c47159 --- /dev/null +++ b/src/main/java/com/crowdin/client/sourcefiles/model/MdMarker.java @@ -0,0 +1,24 @@ +package com.crowdin.client.sourcefiles.model; + +import com.crowdin.client.core.model.EnumConverter; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Marker used for strong and emphasis text in exported Markdown/MDX files. + */ +public enum MdMarker implements EnumConverter { + + ASTERISK, UNDERSCORE; + + @JsonCreator + public static MdMarker from(String value) { + return MdMarker.valueOf(value.toUpperCase()); + } + + @JsonValue + @Override + public String to(MdMarker v) { + return v.name().toLowerCase(); + } +} diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/MdTableColumnWidth.java b/src/main/java/com/crowdin/client/sourcefiles/model/MdTableColumnWidth.java new file mode 100644 index 000000000..771968bdc --- /dev/null +++ b/src/main/java/com/crowdin/client/sourcefiles/model/MdTableColumnWidth.java @@ -0,0 +1,24 @@ +package com.crowdin.client.sourcefiles.model; + +import com.crowdin.client.core.model.EnumConverter; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Table formatting in exported Markdown/MDX files. + */ +public enum MdTableColumnWidth implements EnumConverter { + + CONSOLIDATE, EVENLY_DISTRIBUTE_CELLS; + + @JsonCreator + public static MdTableColumnWidth from(String value) { + return MdTableColumnWidth.valueOf(value.toUpperCase()); + } + + @JsonValue + @Override + public String to(MdTableColumnWidth v) { + return v.name().toLowerCase(); + } +} diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/MdUnorderedListBullet.java b/src/main/java/com/crowdin/client/sourcefiles/model/MdUnorderedListBullet.java new file mode 100644 index 000000000..345bc706f --- /dev/null +++ b/src/main/java/com/crowdin/client/sourcefiles/model/MdUnorderedListBullet.java @@ -0,0 +1,24 @@ +package com.crowdin.client.sourcefiles.model; + +import com.crowdin.client.core.model.EnumConverter; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Marker used for unordered list bullets in exported Markdown/MDX files. + */ +public enum MdUnorderedListBullet implements EnumConverter { + + ASTERISKS, PLUS, DASH; + + @JsonCreator + public static MdUnorderedListBullet from(String value) { + return MdUnorderedListBullet.valueOf(value.toUpperCase()); + } + + @JsonValue + @Override + public String to(MdUnorderedListBullet v) { + return v.name().toLowerCase(); + } +} diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/MdxV1FileExportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/MdxV1FileExportOptions.java new file mode 100644 index 000000000..865c29f24 --- /dev/null +++ b/src/main/java/com/crowdin/client/sourcefiles/model/MdxV1FileExportOptions.java @@ -0,0 +1,19 @@ +package com.crowdin.client.sourcefiles.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * Export options for MDX v1 files. {@code exportPattern} is inherited from {@link GeneralFileExportOptions}. + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class MdxV1FileExportOptions extends GeneralFileExportOptions { + + private MdMarker strongMarker; + private MdMarker emphasisMarker; + private MdUnorderedListBullet unorderedListBullet; + private MdTableColumnWidth tableColumnWidth; +} diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/MdxV1FileImportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/MdxV1FileImportOptions.java index a39e4fbb8..908d0bae6 100644 --- a/src/main/java/com/crowdin/client/sourcefiles/model/MdxV1FileImportOptions.java +++ b/src/main/java/com/crowdin/client/sourcefiles/model/MdxV1FileImportOptions.java @@ -2,14 +2,18 @@ import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.ToString; import java.util.List; +/** + * Import options for MDX v1 files. {@code contentSegmentation} and {@code srxStorageId} are inherited + * from {@link OtherFileImportOptions}. + */ @Data -@EqualsAndHashCode(callSuper = false) -public class MdxV1FileImportOptions extends ImportOptions { +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class MdxV1FileImportOptions extends OtherFileImportOptions { private List excludedFrontMatterElements; private Boolean excludeCodeBlocks; - private Boolean contentSegmentation; - private Long srxStorageId; } diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/MdxV2FileExportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/MdxV2FileExportOptions.java new file mode 100644 index 000000000..dc2811c30 --- /dev/null +++ b/src/main/java/com/crowdin/client/sourcefiles/model/MdxV2FileExportOptions.java @@ -0,0 +1,19 @@ +package com.crowdin.client.sourcefiles.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * Export options for MDX v2 files. {@code exportPattern} is inherited from {@link GeneralFileExportOptions}. + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class MdxV2FileExportOptions extends GeneralFileExportOptions { + + private MdMarker strongMarker; + private MdMarker emphasisMarker; + private MdUnorderedListBullet unorderedListBullet; + private MdTableColumnWidth tableColumnWidth; +} diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/MdxV2FileImportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/MdxV2FileImportOptions.java new file mode 100644 index 000000000..9ecb456ed --- /dev/null +++ b/src/main/java/com/crowdin/client/sourcefiles/model/MdxV2FileImportOptions.java @@ -0,0 +1,19 @@ +package com.crowdin.client.sourcefiles.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.List; + +/** + * Import options for MDX v2 files. {@code contentSegmentation} and {@code srxStorageId} are inherited from {@link OtherFileImportOptions}. + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class MdxV2FileImportOptions extends OtherFileImportOptions { + + private List excludedFrontMatterElements; + private Boolean excludeCodeBlocks; +} diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/OtherFileImportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/OtherFileImportOptions.java index 42e1c7cbf..0914f8b97 100644 --- a/src/main/java/com/crowdin/client/sourcefiles/model/OtherFileImportOptions.java +++ b/src/main/java/com/crowdin/client/sourcefiles/model/OtherFileImportOptions.java @@ -3,11 +3,19 @@ import lombok.Data; import lombok.EqualsAndHashCode; +/** + * Import options for file formats without a dedicated options class. + * Format-specific import options returned by the API for html, fm_html, md, mdx, webxml, idml and similar + * formats are deserialized into subclasses of this class. + */ @Data @EqualsAndHashCode(callSuper = false) public class OtherFileImportOptions extends ImportOptions { private Boolean contentSegmentation; + /** + * Returned in responses only. + */ private Boolean customSegmentation; private Long srxStorageId; } diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/SpreadsheetFileImportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/SpreadsheetFileImportOptions.java index 246346d65..190411adf 100644 --- a/src/main/java/com/crowdin/client/sourcefiles/model/SpreadsheetFileImportOptions.java +++ b/src/main/java/com/crowdin/client/sourcefiles/model/SpreadsheetFileImportOptions.java @@ -10,6 +10,21 @@ public class SpreadsheetFileImportOptions extends ImportOptions { private Boolean firstLineContainsHeader; + private Boolean importHiddenSheets; + private Boolean importHiddenRows; + private Boolean importEqSuggestions; + private Boolean autoApproveImported; + private Boolean translateHidden; + private Boolean addToTm; + private Boolean contentSegmentation; + /** + * Returned in responses only. + */ + private Boolean customSegmentation; + private Long srxStorageId; + /** + * Accepted in requests. Marked as deprecated in the API response schema. + */ private Boolean importTranslations; private Map scheme; } diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/StringCatalogFileImportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/StringCatalogFileImportOptions.java new file mode 100644 index 000000000..30c36e211 --- /dev/null +++ b/src/main/java/com/crowdin/client/sourcefiles/model/StringCatalogFileImportOptions.java @@ -0,0 +1,17 @@ +package com.crowdin.client.sourcefiles.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * Import options for String Catalog files. Extends {@link OtherFileImportOptions} only for backward compatibility of deserialized responses: the API documents just {@code importKeyAsSource} and {@code importTranslations} for this format. + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class StringCatalogFileImportOptions extends OtherFileImportOptions { + + private Boolean importKeyAsSource; + private Boolean importTranslations; +} diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/VdfFileImportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/VdfFileImportOptions.java new file mode 100644 index 000000000..dbfad842a --- /dev/null +++ b/src/main/java/com/crowdin/client/sourcefiles/model/VdfFileImportOptions.java @@ -0,0 +1,17 @@ +package com.crowdin.client.sourcefiles.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * Import options for VDF files. Extends {@link OtherFileImportOptions} only for backward compatibility of deserialized responses: the API documents just {@code convertIcu} and {@code addGenderArgument} for this format. + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class VdfFileImportOptions extends OtherFileImportOptions { + + private Boolean convertIcu; + private Boolean addGenderArgument; +} diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/VsdxFileImportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/VsdxFileImportOptions.java new file mode 100644 index 000000000..f81d8d2aa --- /dev/null +++ b/src/main/java/com/crowdin/client/sourcefiles/model/VsdxFileImportOptions.java @@ -0,0 +1,17 @@ +package com.crowdin.client.sourcefiles.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * Import options for Visio (vsdx) files. Responses for vsdx files are deserialized into {@link DocxFileImportOptions}, which contains the same fields. + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class VsdxFileImportOptions extends ImportOptions { + + private Boolean cleanTagsAggressively; + private Boolean translateHyperlinkUrls; + private Boolean contentSegmentation; + private Long srxStorageId; +} diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/WebXmlFileImportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/WebXmlFileImportOptions.java new file mode 100644 index 000000000..8d4daf551 --- /dev/null +++ b/src/main/java/com/crowdin/client/sourcefiles/model/WebXmlFileImportOptions.java @@ -0,0 +1,19 @@ +package com.crowdin.client.sourcefiles.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.List; + +/** + * Import options for Web XML files. {@code contentSegmentation} and {@code srxStorageId} are inherited from {@link OtherFileImportOptions}. + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class WebXmlFileImportOptions extends OtherFileImportOptions { + + private List inlineTags; + private Boolean hideAttributeValues; +} diff --git a/src/main/java/com/crowdin/client/sourcefiles/model/XmlFileImportOptions.java b/src/main/java/com/crowdin/client/sourcefiles/model/XmlFileImportOptions.java index 69c5329eb..083b1871f 100644 --- a/src/main/java/com/crowdin/client/sourcefiles/model/XmlFileImportOptions.java +++ b/src/main/java/com/crowdin/client/sourcefiles/model/XmlFileImportOptions.java @@ -12,7 +12,11 @@ public class XmlFileImportOptions extends ImportOptions { private Boolean translateContent; private Boolean translateAttributes; private Boolean contentSegmentation; + /** + * Returned in responses only. + */ private Boolean customSegmentation; private List translatableElements; + private List inlineTags; private Long srxStorageId; } diff --git a/src/test/java/com/crowdin/client/branches/BranchesApiTest.java b/src/test/java/com/crowdin/client/branches/BranchesApiTest.java index 52f110b86..97b471428 100644 --- a/src/test/java/com/crowdin/client/branches/BranchesApiTest.java +++ b/src/test/java/com/crowdin/client/branches/BranchesApiTest.java @@ -15,6 +15,7 @@ import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; class BranchesApiTest extends TestClient { @@ -36,6 +37,7 @@ public List getMocks() { RequestMock.build(this.url + "/projects/" + projectId + "/branches/" + id + "/jobs/" + deleteJobIdentifier, HttpGet.METHOD_NAME, "api/branches/deleteJobStatus.json"), RequestMock.build(this.url + "/projects/" + projectId + "/branches/" + id + "/clones", HttpPost.METHOD_NAME, "api/branches/cloneBranchRequest.json", "api/branches/branchCloneStatus.json"), RequestMock.build(this.url + "/projects/" + projectId + "/branches/" + id + "/clones/" + cloneId, HttpGet.METHOD_NAME, "api/branches/branchCloneStatus.json"), + RequestMock.build(this.url + "/projects/" + projectId + "/branches/" + id + "/clones/" + cloneId + "/branch", HttpGet.METHOD_NAME, "api/branches/clonedBranch.json"), RequestMock.build(this.url + "/projects/" + projectId + "/branches/" + id + "/merges", HttpPost.METHOD_NAME, "api/branches/mergeBranchRequest.json", "api/branches/branchMergeStatus.json"), RequestMock.build(this.url + "/projects/" + projectId + "/branches/" + id + "/merges/" + mergeId, HttpGet.METHOD_NAME, "api/branches/branchMergeStatus.json"), RequestMock.build(this.url + "/projects/" + projectId + "/branches/" + id + "/merges/" + mergeId + "/summary", HttpGet.METHOD_NAME, "api/branches/branchMergeSummary.json") @@ -47,6 +49,7 @@ public void cloneBranchTest() { CloneBranchRequest request = new CloneBranchRequest(); request.setName(name); request.setTitle(title); + request.setIsProtected(true); ResponseObject response = this.getBranchesApi().cloneBranch(projectId, id, request); assertEquals(response.getData().getIdentifier(), cloneId); @@ -58,6 +61,15 @@ public void checkCloneBranchStatusTest() { assertEquals(response.getData().getIdentifier(), cloneId); } + @Test + public void getClonedBranchTest() { + ResponseObject response = this.getBranchesApi().getClonedBranch(projectId, id, cloneId); + assertEquals(Long.valueOf(15L), response.getData().getId()); + assertEquals(name, response.getData().getName()); + assertEquals(title, response.getData().getTitle()); + assertTrue(response.getData().getIsProtected()); + } + @Test public void deleteBranchTest() { this.getBranchesApi().deleteBranch(projectId, id); @@ -95,6 +107,7 @@ public void mergeBranchTest() { public void checkMergeBranchStatusTest() { ResponseObject response = this.getBranchesApi().checkMergeBranchStatus(projectId, id, mergeId); assertEquals(response.getData().getIdentifier(), mergeId); + assertFalse(response.getData().getAttributes().getDryRun()); } @Test @@ -102,5 +115,6 @@ public void getMergeBranchSummaryTest() { ResponseObject response = this.getBranchesApi().getMergeBranchSummary(projectId, id, mergeId); assertEquals(response.getData().getTargetBranchId(), id); assertEquals(response.getData().getSourceBranchId(), sourceBranchId); + assertTrue(response.getData().getAcceptSourceChanges()); } } diff --git a/src/test/java/com/crowdin/client/sourcefiles/FileOptionsDeserializationTest.java b/src/test/java/com/crowdin/client/sourcefiles/FileOptionsDeserializationTest.java new file mode 100644 index 000000000..2fd2aafaf --- /dev/null +++ b/src/test/java/com/crowdin/client/sourcefiles/FileOptionsDeserializationTest.java @@ -0,0 +1,196 @@ +package com.crowdin.client.sourcefiles; + +import com.crowdin.client.core.http.JsonTransformer; +import com.crowdin.client.core.http.impl.json.JacksonJsonTransformer; +import com.crowdin.client.sourcefiles.model.*; +import org.junit.jupiter.api.Test; + +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class FileOptionsDeserializationTest { + + private final JsonTransformer jsonTransformer = new JacksonJsonTransformer(); + + @Test + public void importOptionsRoundTripByFileType() { + HtmlFileImportOptions html = new HtmlFileImportOptions(); + html.setExcludedElements(singletonList("p")); + html.setInlineTags(singletonList("span")); + html.setHideAttributeValues(true); + html.setContentSegmentation(true); + html.setSrxStorageId(1L); + assertImportRoundTrip("html", html); + + HtmlWithFrontMatterFileImportOptions fmHtml = new HtmlWithFrontMatterFileImportOptions(); + fmHtml.setExcludedElements(singletonList("p")); + fmHtml.setExcludedFrontMatterElements(singletonList("title")); + fmHtml.setInlineTags(singletonList("b")); + fmHtml.setHideAttributeValues(false); + assertImportRoundTrip("fm_html", fmHtml); + + MdFileImportOptions md = new MdFileImportOptions(); + md.setExcludedFrontMatterElements(singletonList("author")); + md.setExcludeCodeBlocks(true); + md.setInlineTags(singletonList("kbd")); + assertImportRoundTrip("md", md); + + MdxV1FileImportOptions mdxV1 = new MdxV1FileImportOptions(); + mdxV1.setExcludedFrontMatterElements(singletonList("slug")); + mdxV1.setExcludeCodeBlocks(false); + assertImportRoundTrip("mdx_v1", mdxV1); + + MdxV2FileImportOptions mdxV2 = new MdxV2FileImportOptions(); + mdxV2.setExcludedFrontMatterElements(singletonList("id")); + mdxV2.setExcludeCodeBlocks(true); + mdxV2.setSrxStorageId(5L); + assertImportRoundTrip("mdx_v2", mdxV2); + + WebXmlFileImportOptions webXml = new WebXmlFileImportOptions(); + webXml.setInlineTags(singletonList("i")); + webXml.setHideAttributeValues(true); + assertImportRoundTrip("webxml", webXml); + + IdmlFileImportOptions idml = new IdmlFileImportOptions(); + idml.setInlineHyperlinkText(true); + idml.setContentSegmentation(false); + assertImportRoundTrip("idml", idml); + + AdocFileImportOptions adoc = new AdocFileImportOptions(); + adoc.setExcludeIncludeDirectives(true); + assertImportRoundTrip("adoc", adoc); + + VdfFileImportOptions vdf = new VdfFileImportOptions(); + vdf.setConvertIcu(true); + vdf.setAddGenderArgument(true); + assertImportRoundTrip("vdf", vdf); + + StringCatalogFileImportOptions stringCatalog = new StringCatalogFileImportOptions(); + stringCatalog.setImportKeyAsSource(true); + stringCatalog.setImportTranslations(false); + assertImportRoundTrip("auto", stringCatalog); + + SpreadsheetFileImportOptions spreadsheet = new SpreadsheetFileImportOptions(); + spreadsheet.setFirstLineContainsHeader(true); + spreadsheet.setImportHiddenSheets(true); + spreadsheet.setImportHiddenRows(false); + spreadsheet.setImportEqSuggestions(true); + spreadsheet.setAutoApproveImported(false); + spreadsheet.setTranslateHidden(true); + spreadsheet.setAddToTm(false); + spreadsheet.setContentSegmentation(true); + spreadsheet.setSrxStorageId(7L); + assertImportRoundTrip("csv", spreadsheet); + + XmlFileImportOptions xml = new XmlFileImportOptions(); + xml.setTranslateContent(true); + xml.setInlineTags(singletonList("b")); + assertImportRoundTrip("xml", xml); + + DocxFileImportOptions docx = new DocxFileImportOptions(); + docx.setCleanTagsAggressively(true); + docx.setTranslateExcelSheetNames(true); + docx.setWordHighlightColors(singletonList("yellow")); + assertImportRoundTrip("docx", docx); + } + + @Test + public void vsdxImportOptionsAreReturnedAsDocx() { + VsdxFileImportOptions vsdx = new VsdxFileImportOptions(); + vsdx.setCleanTagsAggressively(true); + vsdx.setTranslateHyperlinkUrls(false); + vsdx.setContentSegmentation(true); + vsdx.setSrxStorageId(3L); + + File file = parseFile("vsdx", "importOptions", jsonTransformer.convert(vsdx)); + assertEquals(DocxFileImportOptions.class, file.getImportOptions().getClass()); + DocxFileImportOptions docx = (DocxFileImportOptions) file.getImportOptions(); + assertTrue(docx.getCleanTagsAggressively()); + assertEquals(Integer.valueOf(3), docx.getSrxStorageId()); + } + + @Test + public void importOptionsResolvedByKeysWithoutFileType() { + assertEquals(HtmlFileImportOptions.class, parseFile(null, "importOptions", "{\"excludedElements\":[\"p\"]}").getImportOptions().getClass()); + assertEquals(HtmlWithFrontMatterFileImportOptions.class, parseFile(null, "importOptions", "{\"excludedElements\":[\"p\"],\"excludedFrontMatterElements\":[\"a\"]}").getImportOptions().getClass()); + assertEquals(MdFileImportOptions.class, parseFile(null, "importOptions", "{\"excludeCodeBlocks\":true}").getImportOptions().getClass()); + assertEquals(IdmlFileImportOptions.class, parseFile(null, "importOptions", "{\"inlineHyperlinkText\":true}").getImportOptions().getClass()); + assertEquals(StringCatalogFileImportOptions.class, parseFile(null, "importOptions", "{\"importKeyAsSource\":true}").getImportOptions().getClass()); + assertEquals(AdocFileImportOptions.class, parseFile(null, "importOptions", "{\"excludeIncludeDirectives\":true}").getImportOptions().getClass()); + assertEquals(VdfFileImportOptions.class, parseFile(null, "importOptions", "{\"convertIcu\":true}").getImportOptions().getClass()); + assertEquals(OtherFileImportOptions.class, parseFile(null, "importOptions", "{\"contentSegmentation\":true}").getImportOptions().getClass()); + assertEquals(OtherFileImportOptions.class, parseFile("json", "importOptions", "{\"contentSegmentation\":true}").getImportOptions().getClass()); + } + + @Test + public void exportOptionsRoundTrip() { + MdFileExportOptions md = new MdFileExportOptions(); + md.setExportPattern("/%locale%/%original_file_name%"); + md.setStrongMarker(MdMarker.UNDERSCORE); + md.setEmphasisMarker(MdMarker.ASTERISK); + md.setUnorderedListBullet(MdUnorderedListBullet.PLUS); + md.setTableColumnWidth(MdTableColumnWidth.CONSOLIDATE); + md.setFrontMatterQuotes(MdFrontMatterQuotes.SINGLE); + assertExportRoundTrip("md", md); + assertExportRoundTrip(null, md); + + MdxV1FileExportOptions mdxV1 = new MdxV1FileExportOptions(); + mdxV1.setExportPattern("/%locale%/%original_file_name%"); + mdxV1.setStrongMarker(MdMarker.ASTERISK); + mdxV1.setTableColumnWidth(MdTableColumnWidth.EVENLY_DISTRIBUTE_CELLS); + assertExportRoundTrip("mdx_v1", mdxV1); + + MdxV2FileExportOptions mdxV2 = new MdxV2FileExportOptions(); + mdxV2.setExportPattern("/%locale%/%original_file_name%"); + mdxV2.setUnorderedListBullet(MdUnorderedListBullet.ASTERISKS); + assertExportRoundTrip("mdx_v2", mdxV2); + + DocxFileExportOptions docx = new DocxFileExportOptions(); + docx.setExportPattern("/%locale%/%original_file_name%"); + docx.setAllowWordStyleOptimization(false); + docx.setTranslateExcelExcludeColors(true); + assertExportRoundTrip("docx", docx); + assertExportRoundTrip(null, docx); + + GeneralFileExportOptions general = new GeneralFileExportOptions(); + general.setExportPattern("/%locale%/%original_file_name%"); + assertExportRoundTrip("json", general); + } + + @Test + public void exportOptionsSerialization() { + MdFileExportOptions md = new MdFileExportOptions(); + md.setExportPattern("/a"); + md.setStrongMarker(MdMarker.ASTERISK); + md.setUnorderedListBullet(MdUnorderedListBullet.DASH); + md.setTableColumnWidth(MdTableColumnWidth.EVENLY_DISTRIBUTE_CELLS); + md.setFrontMatterQuotes(MdFrontMatterQuotes.AUTO); + assertEquals( + "{\"exportPattern\":\"/a\",\"strongMarker\":\"asterisk\",\"unorderedListBullet\":\"dash\",\"tableColumnWidth\":\"evenly_distribute_cells\",\"frontMatterQuotes\":\"auto\"}", + jsonTransformer.convert(md)); + } + + private void assertImportRoundTrip(String fileType, ImportOptions options) { + File file = parseFile(fileType, "importOptions", jsonTransformer.convert(options)); + assertInstanceOf(ImportOptions.class, file.getImportOptions()); + assertEquals(options.getClass(), file.getImportOptions().getClass()); + assertEquals(options, file.getImportOptions()); + } + + private void assertExportRoundTrip(String fileType, ExportOptions options) { + File file = parseFile(fileType, "exportOptions", jsonTransformer.convert(options)); + assertEquals(options.getClass(), file.getExportOptions().getClass()); + assertEquals(options, file.getExportOptions()); + } + + private File parseFile(String fileType, String optionsKey, String optionsJson) { + String json = "{\"data\":{\"id\":1," + + (fileType != null ? "\"type\":\"" + fileType + "\"," : "") + + "\"" + optionsKey + "\":" + optionsJson + "}}"; + FileResponseObject response = jsonTransformer.parse(json, FileResponseObject.class); + assertInstanceOf(File.class, response.getData()); + return (File) response.getData(); + } +} diff --git a/src/test/java/com/crowdin/client/sourcefiles/SourceFilesApiTest.java b/src/test/java/com/crowdin/client/sourcefiles/SourceFilesApiTest.java index dab3df5a3..60fd09fa4 100644 --- a/src/test/java/com/crowdin/client/sourcefiles/SourceFilesApiTest.java +++ b/src/test/java/com/crowdin/client/sourcefiles/SourceFilesApiTest.java @@ -15,6 +15,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.TimeZone; @@ -36,6 +37,8 @@ public class SourceFilesApiTest extends TestClient { private final Long project3Id = 5L; private final Long project4Id = 6L; private final Long project5Id = 2L; + private final Long project6Id = 7L; + private final Long project7Id = 8L; private final Long fileId = 44L; private final Long storageId = 61L; private final Long referenceId = 123L; @@ -109,6 +112,8 @@ public List getMocks() { }}), RequestMock.build(String.format("%s/projects/%s/files", this.url, project2Id), HttpGet.METHOD_NAME, "api/sourcefiles/listFileInfos.json"), RequestMock.build(this.url + "/projects/" + projectId + "/files", HttpPost.METHOD_NAME, "api/sourcefiles/addFileRequest.json", "api/sourcefiles/file.json"), + RequestMock.build(this.url + "/projects/" + project6Id + "/files", HttpGet.METHOD_NAME, "api/sourcefiles/listFilesWithFormatOptions.json"), + RequestMock.build(this.url + "/projects/" + project7Id + "/files", HttpPost.METHOD_NAME, "api/sourcefiles/addFileWithOptionsRequest.json", "api/sourcefiles/file.json"), RequestMock.build(this.url + "/projects/" + projectId + "/files/" + fileId, HttpGet.METHOD_NAME, "api/sourcefiles/file.json"), RequestMock.build(this.url + "/projects/" + projectId + "/files/" + fileId, HttpPut.METHOD_NAME, "api/sourcefiles/updateOrRestoreFileRequest.json", "api/sourcefiles/file.json"), RequestMock.build(this.url + "/projects/" + projectId + "/files/" + fileId, HttpDelete.METHOD_NAME), @@ -204,9 +209,11 @@ public void listBranchesTest_orderByIdDesc() { public void addBranchTest() { AddBranchRequest request = new AddBranchRequest(); request.setName(branchName); + request.setIsProtected(true); ResponseObject branchResponseObject = this.getSourceFilesApi().addBranch(projectId, request); assertEquals(branchResponseObject.getData().getId(), branchId); assertEquals(branchResponseObject.getData().getName(), branchName); + assertFalse(branchResponseObject.getData().getIsProtected()); } @Test @@ -518,12 +525,163 @@ public void addFileTest() { assertEquals(fileResponseObject.getData().getContext(), context); } + @Test + public void addFileWithFormatOptionsTest() { + AddFileRequest request = new AddFileRequest(); + request.setName("README.md"); + request.setStorageId(storageId); + request.setType("md"); + MdFileImportOptions importOptions = new MdFileImportOptions(); + importOptions.setExcludedFrontMatterElements(singletonList("author")); + importOptions.setExcludeCodeBlocks(true); + importOptions.setInlineTags(singletonList("kbd")); + importOptions.setContentSegmentation(true); + importOptions.setSrxStorageId(62L); + request.setImportOptions(importOptions); + MdFileExportOptions exportOptions = new MdFileExportOptions(); + exportOptions.setExportPattern("/md/%locale%/%original_file_name%"); + exportOptions.setStrongMarker(MdMarker.ASTERISK); + exportOptions.setEmphasisMarker(MdMarker.UNDERSCORE); + exportOptions.setUnorderedListBullet(MdUnorderedListBullet.DASH); + exportOptions.setTableColumnWidth(MdTableColumnWidth.EVENLY_DISTRIBUTE_CELLS); + exportOptions.setFrontMatterQuotes(MdFrontMatterQuotes.AUTO); + request.setExportOptions(exportOptions); + Map fields = new LinkedHashMap<>(); + fields.put("some-field-1", "some value 1"); + fields.put("some-field-2", 12); + fields.put("some-field-3", true); + fields.put("some-field-4", Arrays.asList("en", "ja")); + request.setFields(fields); + ResponseObject fileResponseObject = this.getSourceFilesApi().addFile(project7Id, request); + assertEquals(fileId, fileResponseObject.getData().getId()); + } + @Test public void getFileTest() { ResponseObject fileResponseObject = (ResponseObject) this.getSourceFilesApi().getFile(projectId, fileId); assertEquals(fileResponseObject.getData().getId(), fileId); assertEquals(fileResponseObject.getData().getName(), fileName); assertEquals(fileResponseObject.getData().getContext(), context); + assertEquals("some value 1", fileResponseObject.getData().getFields().get("some-field-1")); + assertEquals(12, fileResponseObject.getData().getFields().get("some-field-2")); + assertInstanceOf(SpreadsheetFileImportOptions.class, fileResponseObject.getData().getImportOptions()); + assertInstanceOf(GeneralFileExportOptions.class, fileResponseObject.getData().getExportOptions()); + } + + @Test + public void listFilesWithFormatOptionsTest() { + ResponseList response = (ResponseList) this.getSourceFilesApi().listFiles(project6Id, null, null, null, null, null, null); + assertEquals(9, response.getData().size()); + + File html = response.getData().get(0).getData(); + assertInstanceOf(HtmlFileImportOptions.class, html.getImportOptions()); + assertInstanceOf(OtherFileImportOptions.class, html.getImportOptions()); + HtmlFileImportOptions htmlImport = (HtmlFileImportOptions) html.getImportOptions(); + assertEquals(singletonList("section p"), htmlImport.getExcludedElements()); + assertEquals(singletonList("span"), htmlImport.getInlineTags()); + assertTrue(htmlImport.getHideAttributeValues()); + assertTrue(htmlImport.getContentSegmentation()); + assertFalse(htmlImport.getCustomSegmentation()); + assertEquals(GeneralFileExportOptions.class, html.getExportOptions().getClass()); + + File fmHtml = response.getData().get(1).getData(); + assertInstanceOf(HtmlWithFrontMatterFileImportOptions.class, fmHtml.getImportOptions()); + HtmlWithFrontMatterFileImportOptions fmHtmlImport = (HtmlWithFrontMatterFileImportOptions) fmHtml.getImportOptions(); + assertEquals(singletonList("pre"), fmHtmlImport.getExcludedElements()); + assertEquals(singletonList("title"), fmHtmlImport.getExcludedFrontMatterElements()); + assertEquals(singletonList("b"), fmHtmlImport.getInlineTags()); + assertFalse(fmHtmlImport.getHideAttributeValues()); + + File md = response.getData().get(2).getData(); + assertInstanceOf(MdFileImportOptions.class, md.getImportOptions()); + MdFileImportOptions mdImport = (MdFileImportOptions) md.getImportOptions(); + assertTrue(mdImport.getExcludeCodeBlocks()); + assertEquals(singletonList("author"), mdImport.getExcludedFrontMatterElements()); + assertEquals(singletonList("kbd"), mdImport.getInlineTags()); + assertInstanceOf(MdFileExportOptions.class, md.getExportOptions()); + assertInstanceOf(GeneralFileExportOptions.class, md.getExportOptions()); + MdFileExportOptions mdExport = (MdFileExportOptions) md.getExportOptions(); + assertEquals("/md/%locale%/%original_file_name%", mdExport.getExportPattern()); + assertEquals(MdMarker.ASTERISK, mdExport.getStrongMarker()); + assertEquals(MdMarker.UNDERSCORE, mdExport.getEmphasisMarker()); + assertEquals(MdUnorderedListBullet.DASH, mdExport.getUnorderedListBullet()); + assertEquals(MdTableColumnWidth.CONSOLIDATE, mdExport.getTableColumnWidth()); + assertEquals(MdFrontMatterQuotes.DOUBLE, mdExport.getFrontMatterQuotes()); + + File mdxV1 = response.getData().get(3).getData(); + assertInstanceOf(MdxV1FileImportOptions.class, mdxV1.getImportOptions()); + assertFalse(((MdxV1FileImportOptions) mdxV1.getImportOptions()).getExcludeCodeBlocks()); + assertEquals(singletonList("slug"), ((MdxV1FileImportOptions) mdxV1.getImportOptions()).getExcludedFrontMatterElements()); + assertInstanceOf(MdxV1FileExportOptions.class, mdxV1.getExportOptions()); + MdxV1FileExportOptions mdxV1Export = (MdxV1FileExportOptions) mdxV1.getExportOptions(); + assertEquals(MdMarker.UNDERSCORE, mdxV1Export.getStrongMarker()); + assertEquals(MdMarker.ASTERISK, mdxV1Export.getEmphasisMarker()); + assertEquals(MdUnorderedListBullet.PLUS, mdxV1Export.getUnorderedListBullet()); + assertEquals(MdTableColumnWidth.EVENLY_DISTRIBUTE_CELLS, mdxV1Export.getTableColumnWidth()); + + File mdxV2 = response.getData().get(4).getData(); + assertInstanceOf(MdxV2FileImportOptions.class, mdxV2.getImportOptions()); + assertTrue(((MdxV2FileImportOptions) mdxV2.getImportOptions()).getExcludeCodeBlocks()); + assertInstanceOf(MdxV2FileExportOptions.class, mdxV2.getExportOptions()); + assertEquals(MdUnorderedListBullet.ASTERISKS, ((MdxV2FileExportOptions) mdxV2.getExportOptions()).getUnorderedListBullet()); + + File webXml = response.getData().get(5).getData(); + assertInstanceOf(WebXmlFileImportOptions.class, webXml.getImportOptions()); + assertEquals(singletonList("i"), ((WebXmlFileImportOptions) webXml.getImportOptions()).getInlineTags()); + assertTrue(((WebXmlFileImportOptions) webXml.getImportOptions()).getHideAttributeValues()); + + File docx = response.getData().get(6).getData(); + assertInstanceOf(DocxFileImportOptions.class, docx.getImportOptions()); + DocxFileImportOptions docxImport = (DocxFileImportOptions) docx.getImportOptions(); + assertTrue(docxImport.getCleanTagsAggressively()); + assertTrue(docxImport.getTranslateDocProperties()); + assertFalse(docxImport.getTranslateComments()); + assertTrue(docxImport.getIgnoreWhitespaceStyles()); + assertTrue(docxImport.getAddTabAsCharacter()); + assertTrue(docxImport.getAddLineSeparatorAsCharacter()); + assertEquals("|", docxImport.getLineSeparatorReplacement()); + assertTrue(docxImport.getReplaceNoBreakHyphenTag()); + assertFalse(docxImport.getIgnoreSoftHyphenTag()); + assertEquals(Arrays.asList("HYPERLINK", "FORMTEXT"), docxImport.getComplexFieldDefinitionsToExtract()); + assertTrue(docxImport.getTranslateWordHeadersFooters()); + assertFalse(docxImport.getTranslateWordGraphicName()); + assertTrue(docxImport.getTranslateWordGraphicDescription()); + assertTrue(docxImport.getIgnoreWordFontColors()); + assertEquals("#000000", docxImport.getWordFontColorsMinIgnoranceThreshold()); + assertEquals("#FFFFFF", docxImport.getWordFontColorsMaxIgnoranceThreshold()); + assertEquals(singletonList("Heading1"), docxImport.getExcludeWordStyles()); + assertTrue(docxImport.getTranslateWordInExcludeStyleMode()); + assertEquals(singletonList("yellow"), docxImport.getWordHighlightColors()); + assertFalse(docxImport.getTranslateWordInExcludeHighlightMode()); + assertTrue(docxImport.getTranslateWordExcludeColors()); + assertEquals(singletonList("#FF0000"), docxImport.getWordExcludedColors()); + assertFalse(docxImport.getTranslateExcelCellsCopied()); + assertTrue(docxImport.getTranslateExcelSheetNames()); + assertEquals(singletonList("#00FF00"), docxImport.getExcelExcludedColors()); + assertTrue(docxImport.getTranslateExcelDiagramData()); + assertFalse(docxImport.getTranslateExcelDrawings()); + assertFalse(docxImport.getCustomSegmentation()); + assertInstanceOf(DocxFileExportOptions.class, docx.getExportOptions()); + DocxFileExportOptions docxExport = (DocxFileExportOptions) docx.getExportOptions(); + assertEquals("/docx/%locale%/%original_file_name%", docxExport.getExportPattern()); + assertTrue(docxExport.getAllowWordStyleOptimization()); + assertFalse(docxExport.getTranslateExcelExcludeColors()); + assertEquals(4, docx.getFields().size()); + assertEquals("some value 1", docx.getFields().get("some-field-1")); + assertEquals(12, docx.getFields().get("some-field-2")); + assertEquals(true, docx.getFields().get("some-field-3")); + assertEquals(Arrays.asList("en", "ja"), docx.getFields().get("some-field-4")); + + File vdf = response.getData().get(7).getData(); + assertInstanceOf(VdfFileImportOptions.class, vdf.getImportOptions()); + assertTrue(((VdfFileImportOptions) vdf.getImportOptions()).getConvertIcu()); + assertFalse(((VdfFileImportOptions) vdf.getImportOptions()).getAddGenderArgument()); + + File json = response.getData().get(8).getData(); + assertEquals(OtherFileImportOptions.class, json.getImportOptions().getClass()); + assertFalse(((OtherFileImportOptions) json.getImportOptions()).getContentSegmentation()); + assertEquals(GeneralFileExportOptions.class, json.getExportOptions().getClass()); + assertNull(json.getFields()); } @Test diff --git a/src/test/resources/api/branches/branchMergeStatus.json b/src/test/resources/api/branches/branchMergeStatus.json index 4539d9b0b..265d2a08a 100644 --- a/src/test/resources/api/branches/branchMergeStatus.json +++ b/src/test/resources/api/branches/branchMergeStatus.json @@ -6,7 +6,8 @@ "attributes": { "sourceBranchId": 8, "deleteAfterMerge": false, - "acceptSourceChanges": true + "acceptSourceChanges": true, + "dryRun": false }, "createdAt": "2019-09-23T11:26:54+00:00", "updatedAt": "2019-09-23T11:26:54+00:00", diff --git a/src/test/resources/api/branches/branchMergeSummary.json b/src/test/resources/api/branches/branchMergeSummary.json index 642dd91ef..24d1d3bd9 100644 --- a/src/test/resources/api/branches/branchMergeSummary.json +++ b/src/test/resources/api/branches/branchMergeSummary.json @@ -4,6 +4,7 @@ "sourceBranchId": 8, "targetBranchId": 14, "dryRun": false, + "acceptSourceChanges": true, "details": { "added": 1, "deleted": 2, diff --git a/src/test/resources/api/branches/cloneBranchRequest.json b/src/test/resources/api/branches/cloneBranchRequest.json index bff11aa28..55beed21b 100644 --- a/src/test/resources/api/branches/cloneBranchRequest.json +++ b/src/test/resources/api/branches/cloneBranchRequest.json @@ -1,4 +1,5 @@ { "name": "cloned", - "title": "Cloned Branch" + "title": "Cloned Branch", + "isProtected": true } diff --git a/src/test/resources/api/branches/clonedBranch.json b/src/test/resources/api/branches/clonedBranch.json new file mode 100644 index 000000000..5105293c7 --- /dev/null +++ b/src/test/resources/api/branches/clonedBranch.json @@ -0,0 +1,11 @@ +{ + "data": { + "id": 15, + "projectId": 1, + "name": "cloned", + "title": "Cloned Branch", + "isProtected": true, + "createdAt": "2024-04-16T16:26:44+00:00", + "updatedAt": "2024-04-16T16:26:44+00:00" + } +} diff --git a/src/test/resources/api/sourcefiles/addBranchRequest.json b/src/test/resources/api/sourcefiles/addBranchRequest.json index ae61fa5e5..5b7670f12 100644 --- a/src/test/resources/api/sourcefiles/addBranchRequest.json +++ b/src/test/resources/api/sourcefiles/addBranchRequest.json @@ -1,3 +1,4 @@ { - "name": "develop-master" + "name": "develop-master", + "isProtected": true } diff --git a/src/test/resources/api/sourcefiles/addFileWithOptionsRequest.json b/src/test/resources/api/sourcefiles/addFileWithOptionsRequest.json new file mode 100644 index 000000000..cf3178a79 --- /dev/null +++ b/src/test/resources/api/sourcefiles/addFileWithOptionsRequest.json @@ -0,0 +1,33 @@ +{ + "storageId": 61, + "name": "README.md", + "type": "md", + "importOptions": { + "excludedFrontMatterElements": [ + "author" + ], + "excludeCodeBlocks": true, + "inlineTags": [ + "kbd" + ], + "contentSegmentation": true, + "srxStorageId": 62 + }, + "exportOptions": { + "exportPattern": "/md/%locale%/%original_file_name%", + "strongMarker": "asterisk", + "emphasisMarker": "underscore", + "unorderedListBullet": "dash", + "tableColumnWidth": "evenly_distribute_cells", + "frontMatterQuotes": "auto" + }, + "fields": { + "some-field-1": "some value 1", + "some-field-2": 12, + "some-field-3": true, + "some-field-4": [ + "en", + "ja" + ] + } +} diff --git a/src/test/resources/api/sourcefiles/branch.json b/src/test/resources/api/sourcefiles/branch.json index 94661106d..7e2ec0def 100644 --- a/src/test/resources/api/sourcefiles/branch.json +++ b/src/test/resources/api/sourcefiles/branch.json @@ -6,6 +6,7 @@ "title": "Master branch", "exportPattern": "%three_letters_code%", "priority": "normal", + "isProtected": false, "createdAt": "2019-09-16T13:48:04+00:00", "updatedAt": "2019-09-19T13:25:27+00:00" } diff --git a/src/test/resources/api/sourcefiles/file.json b/src/test/resources/api/sourcefiles/file.json index c51fc8416..7f747e04e 100644 --- a/src/test/resources/api/sourcefiles/file.json +++ b/src/test/resources/api/sourcefiles/file.json @@ -25,6 +25,10 @@ "exportOptions": { "exportPattern": "/localization/%locale%/%file_name%.%file_extension%" }, + "fields": { + "some-field-1": "some value 1", + "some-field-2": 12 + }, "excludedTargetLanguages": [ "en", "es", diff --git a/src/test/resources/api/sourcefiles/listFilesWithFormatOptions.json b/src/test/resources/api/sourcefiles/listFilesWithFormatOptions.json new file mode 100644 index 000000000..e7519bd69 --- /dev/null +++ b/src/test/resources/api/sourcefiles/listFilesWithFormatOptions.json @@ -0,0 +1,300 @@ +{ + "data": [ + { + "data": { + "id": 101, + "projectId": 7, + "name": "index.html", + "type": "html", + "path": "/index.html", + "status": "active", + "revisionId": 1, + "priority": "normal", + "importOptions": { + "contentSegmentation": true, + "customSegmentation": false, + "excludedElements": [ + "section p" + ], + "inlineTags": [ + "span" + ], + "hideAttributeValues": true + }, + "exportOptions": { + "exportPattern": "/html/%locale%/%original_file_name%" + }, + "createdAt": "2019-09-19T15:10:43+00:00", + "updatedAt": "2019-09-19T15:10:46+00:00" + } + }, + { + "data": { + "id": 102, + "projectId": 7, + "name": "page.html", + "type": "fm_html", + "path": "/page.html", + "status": "active", + "revisionId": 1, + "priority": "normal", + "importOptions": { + "contentSegmentation": false, + "customSegmentation": false, + "excludedElements": [ + "pre" + ], + "excludedFrontMatterElements": [ + "title" + ], + "inlineTags": [ + "b" + ], + "hideAttributeValues": false + }, + "exportOptions": { + "exportPattern": "/fm/%locale%/%original_file_name%" + }, + "createdAt": "2019-09-19T15:10:43+00:00", + "updatedAt": "2019-09-19T15:10:46+00:00" + } + }, + { + "data": { + "id": 103, + "projectId": 7, + "name": "README.md", + "type": "md", + "path": "/README.md", + "status": "active", + "revisionId": 1, + "priority": "normal", + "importOptions": { + "contentSegmentation": true, + "customSegmentation": false, + "excludeCodeBlocks": true, + "excludedFrontMatterElements": [ + "author" + ], + "inlineTags": [ + "kbd" + ] + }, + "exportOptions": { + "exportPattern": "/md/%locale%/%original_file_name%", + "strongMarker": "asterisk", + "emphasisMarker": "underscore", + "unorderedListBullet": "dash", + "tableColumnWidth": "consolidate", + "frontMatterQuotes": "double" + }, + "createdAt": "2019-09-19T15:10:43+00:00", + "updatedAt": "2019-09-19T15:10:46+00:00" + } + }, + { + "data": { + "id": 104, + "projectId": 7, + "name": "intro.mdx", + "type": "mdx_v1", + "path": "/intro.mdx", + "status": "active", + "revisionId": 1, + "priority": "normal", + "importOptions": { + "contentSegmentation": false, + "customSegmentation": false, + "excludeCodeBlocks": false, + "excludedFrontMatterElements": [ + "slug" + ] + }, + "exportOptions": { + "exportPattern": "/mdx1/%locale%/%original_file_name%", + "strongMarker": "underscore", + "emphasisMarker": "asterisk", + "unorderedListBullet": "plus", + "tableColumnWidth": "evenly_distribute_cells" + }, + "createdAt": "2019-09-19T15:10:43+00:00", + "updatedAt": "2019-09-19T15:10:46+00:00" + } + }, + { + "data": { + "id": 105, + "projectId": 7, + "name": "guide.mdx", + "type": "mdx_v2", + "path": "/guide.mdx", + "status": "active", + "revisionId": 1, + "priority": "normal", + "importOptions": { + "contentSegmentation": true, + "customSegmentation": false, + "excludeCodeBlocks": true, + "excludedFrontMatterElements": [ + "id" + ] + }, + "exportOptions": { + "exportPattern": "/mdx2/%locale%/%original_file_name%", + "strongMarker": "asterisk", + "emphasisMarker": "underscore", + "unorderedListBullet": "asterisks", + "tableColumnWidth": "consolidate" + }, + "createdAt": "2019-09-19T15:10:43+00:00", + "updatedAt": "2019-09-19T15:10:46+00:00" + } + }, + { + "data": { + "id": 106, + "projectId": 7, + "name": "web.xml", + "type": "webxml", + "path": "/web.xml", + "status": "active", + "revisionId": 1, + "priority": "normal", + "importOptions": { + "contentSegmentation": false, + "customSegmentation": false, + "inlineTags": [ + "i" + ], + "hideAttributeValues": true + }, + "exportOptions": { + "exportPattern": "/webxml/%locale%/%original_file_name%" + }, + "createdAt": "2019-09-19T15:10:43+00:00", + "updatedAt": "2019-09-19T15:10:46+00:00" + } + }, + { + "data": { + "id": 107, + "projectId": 7, + "name": "manual.docx", + "type": "docx", + "path": "/manual.docx", + "status": "active", + "revisionId": 1, + "priority": "high", + "importOptions": { + "cleanTagsAggressively": true, + "translateHiddenText": false, + "translateHyperlinkUrls": false, + "translateHiddenRowsAndColumns": false, + "importNotes": true, + "importHiddenSlides": false, + "contentSegmentation": true, + "customSegmentation": false, + "translateDocProperties": true, + "translateComments": false, + "ignoreWhitespaceStyles": true, + "addTabAsCharacter": true, + "addLineSeparatorAsCharacter": true, + "lineSeparatorReplacement": "|", + "replaceNoBreakHyphenTag": true, + "ignoreSoftHyphenTag": false, + "complexFieldDefinitionsToExtract": [ + "HYPERLINK", + "FORMTEXT" + ], + "translateWordHeadersFooters": true, + "translateWordGraphicName": false, + "translateWordGraphicDescription": true, + "ignoreWordFontColors": true, + "wordFontColorsMinIgnoranceThreshold": "#000000", + "wordFontColorsMaxIgnoranceThreshold": "#FFFFFF", + "excludeWordStyles": [ + "Heading1" + ], + "translateWordInExcludeStyleMode": true, + "wordHighlightColors": [ + "yellow" + ], + "translateWordInExcludeHighlightMode": false, + "translateWordExcludeColors": true, + "wordExcludedColors": [ + "#FF0000" + ], + "translateExcelCellsCopied": false, + "translateExcelSheetNames": true, + "excelExcludedColors": [ + "#00FF00" + ], + "translateExcelDiagramData": true, + "translateExcelDrawings": false + }, + "exportOptions": { + "exportPattern": "/docx/%locale%/%original_file_name%", + "allowWordStyleOptimization": true, + "translateExcelExcludeColors": false + }, + "fields": { + "some-field-1": "some value 1", + "some-field-2": 12, + "some-field-3": true, + "some-field-4": [ + "en", + "ja" + ] + }, + "createdAt": "2019-09-19T15:10:43+00:00", + "updatedAt": "2019-09-19T15:10:46+00:00" + } + }, + { + "data": { + "id": 108, + "projectId": 7, + "name": "strings.vdf", + "type": "vdf", + "path": "/strings.vdf", + "status": "active", + "revisionId": 1, + "priority": "normal", + "importOptions": { + "convertIcu": true, + "addGenderArgument": false + }, + "exportOptions": { + "exportPattern": "/vdf/%locale%/%original_file_name%" + }, + "createdAt": "2019-09-19T15:10:43+00:00", + "updatedAt": "2019-09-19T15:10:46+00:00" + } + }, + { + "data": { + "id": 109, + "projectId": 7, + "name": "strings.json", + "type": "json", + "path": "/strings.json", + "status": "active", + "revisionId": 1, + "priority": "normal", + "importOptions": { + "contentSegmentation": false, + "customSegmentation": false + }, + "exportOptions": { + "exportPattern": "/json/%locale%/%original_file_name%" + }, + "createdAt": "2019-09-19T15:10:43+00:00", + "updatedAt": "2019-09-19T15:10:46+00:00" + } + } + ], + "pagination": { + "offset": 0, + "limit": 25 + } +}