From 1b0d3b44f84199c4e4c511ecc94731c83b757812 Mon Sep 17 00:00:00 2001
From: Max Inno <40697586+innomaxx@users.noreply.github.com>
Date: Thu, 30 May 2024 15:21:48 +0300
Subject: [PATCH] feat(api): add String-based API support (#235)
* feat(api): add String-based API support
* chore: deprecate branch methods in Source Files section
---
src/Crowdin.Api/AI/AiPromptConfiguration.cs | 2 +-
src/Crowdin.Api/Branches/AddBranchRequest.cs | 20 ++
src/Crowdin.Api/Branches/Branch.cs | 29 ++
src/Crowdin.Api/Branches/BranchCloneStatus.cs | 35 +++
src/Crowdin.Api/Branches/BranchMergeStatus.cs | 45 ++++
.../Branches/BranchMergeStatusId.cs | 22 ++
.../Branches/BranchMergeSummary.cs | 41 +++
src/Crowdin.Api/Branches/BranchPatch.cs | 30 +++
.../Branches/BranchesApiExecutor.cs | 196 ++++++++++++++
.../Branches/CloneBranchRequest.cs | 20 ++
.../Branches/MergeBranchRequest.cs | 19 ++
src/Crowdin.Api/Core/Constants.cs | 2 +
.../ProjectsGroups/EnterpriseProjectForm.cs | 12 +
.../ProjectsGroups/FileBasedProjectForm.cs | 6 +
src/Crowdin.Api/ProjectsGroups/ProjectBase.cs | 6 +
.../ProjectsGroups/ProjectInfoPatch.cs | 9 +-
.../ProjectsGroups/ProjectSettingPatch.cs | 27 +-
.../ProjectsGroups/ProjectSettings.cs | 12 +
.../ProjectsGroupsApiExecutor.cs | 6 +
.../ProjectsGroups/StringsBasedProjectForm.cs | 15 ++
.../ProjectsGroups/TmContextType.cs | 19 ++
.../WorkflowTemplateStepConfig.cs | 75 ++++++
src/Crowdin.Api/Reports/ReportStatus.cs | 5 +
.../SourceFiles/AddBranchRequest.cs | 15 +-
src/Crowdin.Api/SourceFiles/Branch.cs | 24 +-
src/Crowdin.Api/SourceFiles/BranchPatch.cs | 6 +
.../SourceFiles/SourceFilesApiExecutor.cs | 10 +-
.../SourceStrings/AddStringRequest.cs | 4 +-
src/Crowdin.Api/SourceStrings/SourceString.cs | 4 +-
.../SourceStrings/SourceStringsApiExecutor.cs | 36 +++
.../StringBasedProjectFileType.cs | 37 +++
.../StringUploadResponseModel.cs | 64 +++++
.../SourceStrings/UploadStringsRequest.cs | 40 +++
.../StringTranslations/StringTranslation.cs | 6 +
.../Tasks/LanguageServiceTaskCreateForm.cs | 11 +-
src/Crowdin.Api/Tasks/TaskCreateForm.cs | 7 +-
.../Tasks/VendorGengoTaskCreateForm.cs | 7 +-
.../Tasks/VendorManualTaskCreateForm.cs | 9 +-
.../Tasks/VendorOhtTaskCreateForm.cs | 7 +-
.../Tasks/VendorTranslatedTaskCreateForm.cs | 7 +-
.../ApplyPreTranslationRequest.cs | 7 +-
.../Translations/PreTranslateAttributes.cs | 12 +-
.../Translations/UploadTranslationsRequest.cs | 7 +-
.../UploadTranslationsResponse.cs | 5 +-
.../Branches/BranchesCrudApiTests.cs | 182 +++++++++++++
.../Branches/BranchesOperationsApiTests.cs | 255 ++++++++++++++++++
.../Core/Resources/Branches.Designer.cs | 102 +++++++
.../Core/Resources/Branches.resx | 133 +++++++++
.../Core/Resources/SourceStrings.Designer.cs | 59 ++++
.../Core/Resources/SourceStrings.resx | 58 ++++
.../Core/Resources/Tasks.Designer.cs | 7 +-
.../Core/Resources/Tasks.resx | 7 +-
.../Crowdin.Api.Tests.csproj | 45 ++++
.../SourceStrings/SourceStringsApiTests.cs | 131 ++++++++-
54 files changed, 1885 insertions(+), 72 deletions(-)
create mode 100644 src/Crowdin.Api/Branches/AddBranchRequest.cs
create mode 100644 src/Crowdin.Api/Branches/Branch.cs
create mode 100644 src/Crowdin.Api/Branches/BranchCloneStatus.cs
create mode 100644 src/Crowdin.Api/Branches/BranchMergeStatus.cs
create mode 100644 src/Crowdin.Api/Branches/BranchMergeStatusId.cs
create mode 100644 src/Crowdin.Api/Branches/BranchMergeSummary.cs
create mode 100644 src/Crowdin.Api/Branches/BranchPatch.cs
create mode 100644 src/Crowdin.Api/Branches/BranchesApiExecutor.cs
create mode 100644 src/Crowdin.Api/Branches/CloneBranchRequest.cs
create mode 100644 src/Crowdin.Api/Branches/MergeBranchRequest.cs
create mode 100644 src/Crowdin.Api/ProjectsGroups/TmContextType.cs
create mode 100644 src/Crowdin.Api/ProjectsGroups/WorkflowTemplateStepConfig.cs
create mode 100644 src/Crowdin.Api/SourceStrings/StringBasedProjectFileType.cs
create mode 100644 src/Crowdin.Api/SourceStrings/StringUploadResponseModel.cs
create mode 100644 src/Crowdin.Api/SourceStrings/UploadStringsRequest.cs
create mode 100644 tests/Crowdin.Api.Tests/Branches/BranchesCrudApiTests.cs
create mode 100644 tests/Crowdin.Api.Tests/Branches/BranchesOperationsApiTests.cs
create mode 100644 tests/Crowdin.Api.Tests/Core/Resources/Branches.Designer.cs
create mode 100644 tests/Crowdin.Api.Tests/Core/Resources/Branches.resx
diff --git a/src/Crowdin.Api/AI/AiPromptConfiguration.cs b/src/Crowdin.Api/AI/AiPromptConfiguration.cs
index 10a94d5f..27268a84 100644
--- a/src/Crowdin.Api/AI/AiPromptConfiguration.cs
+++ b/src/Crowdin.Api/AI/AiPromptConfiguration.cs
@@ -45,7 +45,7 @@ public class BasicModeAiPromptConfiguration : AiPromptConfiguration
public bool PublicProjectDescription { get; set; }
[PublicAPI]
- public class OtherLanguageTranslationsConfig // TODO: to outer?
+ public class OtherLanguageTranslationsConfig
{
[JsonProperty("isEnabled")]
public bool IsEnabled { get; set; }
diff --git a/src/Crowdin.Api/Branches/AddBranchRequest.cs b/src/Crowdin.Api/Branches/AddBranchRequest.cs
new file mode 100644
index 00000000..e126e37b
--- /dev/null
+++ b/src/Crowdin.Api/Branches/AddBranchRequest.cs
@@ -0,0 +1,20 @@
+
+using JetBrains.Annotations;
+using Newtonsoft.Json;
+
+#nullable enable
+
+namespace Crowdin.Api.Branches
+{
+ [PublicAPI]
+ public class AddBranchRequest
+ {
+ [JsonProperty("name")]
+#pragma warning disable CS8618
+ public string Name { get; set; }
+#pragma warning restore CS8618
+
+ [JsonProperty("title")]
+ public string? Title { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Crowdin.Api/Branches/Branch.cs b/src/Crowdin.Api/Branches/Branch.cs
new file mode 100644
index 00000000..a46854bf
--- /dev/null
+++ b/src/Crowdin.Api/Branches/Branch.cs
@@ -0,0 +1,29 @@
+
+using System;
+using JetBrains.Annotations;
+using Newtonsoft.Json;
+
+namespace Crowdin.Api.Branches
+{
+ [PublicAPI]
+ public class Branch
+ {
+ [JsonProperty("id")]
+ public int Id { get; set; }
+
+ [JsonProperty("projectId")]
+ public int ProjectId { get; set; }
+
+ [JsonProperty("name")]
+ public string Name { get; set; }
+
+ [JsonProperty("title")]
+ public string Title { get; set; }
+
+ [JsonProperty("createdAt")]
+ public DateTimeOffset CreatedAt { get; set; }
+
+ [JsonProperty("updatedAt")]
+ public DateTimeOffset? UpdatedAt { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Crowdin.Api/Branches/BranchCloneStatus.cs b/src/Crowdin.Api/Branches/BranchCloneStatus.cs
new file mode 100644
index 00000000..02efc6ca
--- /dev/null
+++ b/src/Crowdin.Api/Branches/BranchCloneStatus.cs
@@ -0,0 +1,35 @@
+
+using System;
+using JetBrains.Annotations;
+using Newtonsoft.Json;
+
+namespace Crowdin.Api.Branches
+{
+ [PublicAPI]
+ public class BranchCloneStatus
+ {
+ [JsonProperty("identifier")]
+ public string Identifier { get; set; }
+
+ [JsonProperty("status")]
+ public OperationStatus Status { get; set; }
+
+ [JsonProperty("progress")]
+ public int Progress { get; set; }
+
+ [JsonProperty("attributes")]
+ public object Attributes { get; set; }
+
+ [JsonProperty("createdAt")]
+ public DateTimeOffset CreatedAt { get; set; }
+
+ [JsonProperty("updatedAt")]
+ public DateTimeOffset? UpdatedAt { get; set; }
+
+ [JsonProperty("startedAt")]
+ public DateTimeOffset? StartedAt { get; set; }
+
+ [JsonProperty("finishedAt")]
+ public DateTimeOffset? FinishedAt { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Crowdin.Api/Branches/BranchMergeStatus.cs b/src/Crowdin.Api/Branches/BranchMergeStatus.cs
new file mode 100644
index 00000000..28e2a6f3
--- /dev/null
+++ b/src/Crowdin.Api/Branches/BranchMergeStatus.cs
@@ -0,0 +1,45 @@
+
+using System;
+using JetBrains.Annotations;
+using Newtonsoft.Json;
+
+namespace Crowdin.Api.Branches
+{
+ [PublicAPI]
+ public class BranchMergeStatus
+ {
+ [JsonProperty("identifier")]
+ public string Identifier { get; set; }
+
+ [JsonProperty("status")]
+ public OperationStatus Status { get; set; }
+
+ [JsonProperty("progress")]
+ public int Progress { get; set; }
+
+ [JsonProperty("attributes")]
+ public AttributesData Attributes { get; set; }
+
+ [JsonProperty("createdAt")]
+ public DateTimeOffset CreatedAt { get; set; }
+
+ [JsonProperty("updatedAt")]
+ public DateTimeOffset? UpdatedAt { get; set; }
+
+ [JsonProperty("startedAt")]
+ public DateTimeOffset? StartedAt { get; set; }
+
+ [JsonProperty("finishedAt")]
+ public DateTimeOffset FinishedAt { get; set; }
+
+ [PublicAPI]
+ public class AttributesData
+ {
+ [JsonProperty("sourceBranchId")]
+ public int SourceBranchId { get; set; }
+
+ [JsonProperty("deleteAfterMerge")]
+ public bool DeleteAfterMerge { get; set; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Crowdin.Api/Branches/BranchMergeStatusId.cs b/src/Crowdin.Api/Branches/BranchMergeStatusId.cs
new file mode 100644
index 00000000..c70b13e5
--- /dev/null
+++ b/src/Crowdin.Api/Branches/BranchMergeStatusId.cs
@@ -0,0 +1,22 @@
+
+using System.ComponentModel;
+using JetBrains.Annotations;
+
+namespace Crowdin.Api.Branches
+{
+ [PublicAPI]
+ public enum BranchMergeStatusId
+ {
+ [Description("conflict")]
+ Conflict,
+
+ [Description("failed")]
+ Failed,
+
+ [Description("inProgress")]
+ InProgress,
+
+ [Description("merged")]
+ Merged
+ }
+}
\ No newline at end of file
diff --git a/src/Crowdin.Api/Branches/BranchMergeSummary.cs b/src/Crowdin.Api/Branches/BranchMergeSummary.cs
new file mode 100644
index 00000000..54f219dd
--- /dev/null
+++ b/src/Crowdin.Api/Branches/BranchMergeSummary.cs
@@ -0,0 +1,41 @@
+
+using JetBrains.Annotations;
+using Newtonsoft.Json;
+
+namespace Crowdin.Api.Branches
+{
+ [PublicAPI]
+ public class BranchMergeSummary
+ {
+ [JsonProperty("status")]
+ public BranchMergeStatusId Status { get; set; }
+
+ [JsonProperty("sourceBranchId")]
+ public int SourceBranchId { get; set; }
+
+ [JsonProperty("targetBranchId")]
+ public int TargetBranchId { get; set; }
+
+ [JsonProperty("dryRun")]
+ public bool DryRun { get; set; }
+
+ [JsonProperty("details")]
+ public DetailsData Details { get; set; }
+
+ [PublicAPI]
+ public class DetailsData
+ {
+ [JsonProperty("added")]
+ public int Added { get; set; }
+
+ [JsonProperty("deleted")]
+ public int Deleted { get; set; }
+
+ [JsonProperty("updated")]
+ public int Updated { get; set; }
+
+ [JsonProperty("conflicted")]
+ public int Conflicted { get; set; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Crowdin.Api/Branches/BranchPatch.cs b/src/Crowdin.Api/Branches/BranchPatch.cs
new file mode 100644
index 00000000..0dbf084d
--- /dev/null
+++ b/src/Crowdin.Api/Branches/BranchPatch.cs
@@ -0,0 +1,30 @@
+
+using System.ComponentModel;
+using JetBrains.Annotations;
+using Newtonsoft.Json;
+
+namespace Crowdin.Api.Branches
+{
+ [PublicAPI]
+ public class BranchPatch : PatchEntry
+ {
+ [JsonProperty("path")]
+ public BranchPatchPath Path { get; set; }
+ }
+
+ [PublicAPI]
+ public enum BranchPatchPath
+ {
+ [Description("/name")]
+ Name,
+
+ [Description("/title")]
+ Title,
+
+ [Description("/exportPattern")]
+ ExportPattern,
+
+ [Description("/priority")]
+ Priority
+ }
+}
\ No newline at end of file
diff --git a/src/Crowdin.Api/Branches/BranchesApiExecutor.cs b/src/Crowdin.Api/Branches/BranchesApiExecutor.cs
new file mode 100644
index 00000000..1d75c7a5
--- /dev/null
+++ b/src/Crowdin.Api/Branches/BranchesApiExecutor.cs
@@ -0,0 +1,196 @@
+
+using System.Collections.Generic;
+using System.Net;
+using System.Threading.Tasks;
+
+using JetBrains.Annotations;
+
+using Crowdin.Api.Core;
+
+#nullable enable
+
+namespace Crowdin.Api.Branches
+{
+ public class BranchesApiExecutor
+ {
+ private readonly ICrowdinApiClient _apiClient;
+ private readonly IJsonParser _jsonParser;
+
+ public BranchesApiExecutor(ICrowdinApiClient apiClient)
+ {
+ _apiClient = apiClient;
+ _jsonParser = apiClient.DefaultJsonParser;
+ }
+
+ public BranchesApiExecutor(ICrowdinApiClient apiClient, IJsonParser jsonParser)
+ {
+ _apiClient = apiClient;
+ _jsonParser = jsonParser;
+ }
+
+ ///
+ /// Get Cloned Branch. Documentation:
+ /// Crowdin API
+ /// Crowdin Enterprise API
+ ///
+ [PublicAPI]
+ public async Task GetClonedBranch(int projectId, int branchId, string cloneId)
+ {
+ var url = $"/projects/{projectId}/branches/{branchId}/clones/{cloneId}/branch";
+ CrowdinApiResult result = await _apiClient.SendGetRequest(url);
+ return _jsonParser.ParseResponseObject(result.JsonObject);
+ }
+
+ ///
+ /// Clone Branch. Documentation:
+ /// Crowdin API
+ /// Crowdin Enterprise API
+ ///
+ [PublicAPI]
+ public async Task CloneBranch(int projectId, int branchId, CloneBranchRequest request)
+ {
+ var url = $"/projects/{projectId}/branches/{branchId}/clones";
+ CrowdinApiResult result = await _apiClient.SendPostRequest(url, request);
+ return _jsonParser.ParseResponseObject(result.JsonObject);
+ }
+
+ ///
+ /// Check Branch Clone Status. Documentation:
+ /// Crowdin API
+ /// Crowdin Enterprise API
+ ///
+ [PublicAPI]
+ public async Task CheckBranchCloneStatus(int projectId, int branchId, string cloneId)
+ {
+ var url = $"/projects/{projectId}/branches/{branchId}/clones/{cloneId}";
+ CrowdinApiResult result = await _apiClient.SendGetRequest(url);
+ return _jsonParser.ParseResponseObject(result.JsonObject);
+ }
+
+ ///
+ /// List Branches. Documentation:
+ /// Crowdin API
+ /// Crowdin Enterprise API
+ ///
+ [PublicAPI]
+ public async Task> ListBranches(
+ int projectId,
+ string? name = null,
+ int limit = 25,
+ int offset = 0)
+ {
+ string url = FormUrl_Branches(projectId);
+
+ IDictionary queryParams = Utils.CreateQueryParamsFromPaging(limit, offset);
+ queryParams.AddParamIfPresent("name", name);
+
+ CrowdinApiResult result = await _apiClient.SendGetRequest(url, queryParams);
+ return _jsonParser.ParseResponseList(result.JsonObject);
+ }
+
+ ///
+ /// Add Branch. Documentation:
+ /// Crowdin API
+ /// Crowdin Enterprise API
+ ///
+ [PublicAPI]
+ public async Task AddBranch(int projectId, AddBranchRequest request)
+ {
+ string url = FormUrl_Branches(projectId);
+ CrowdinApiResult result = await _apiClient.SendPostRequest(url, request);
+ return _jsonParser.ParseResponseObject(result.JsonObject);
+ }
+
+ ///
+ /// Get Branch. Documentation:
+ /// Crowdin API
+ /// Crowdin Enterprise API
+ ///
+ [PublicAPI]
+ public async Task GetBranch(int projectId, int branchId)
+ {
+ string url = FormUrl_BranchId(projectId, branchId);
+ CrowdinApiResult result = await _apiClient.SendGetRequest(url);
+ return _jsonParser.ParseResponseObject(result.JsonObject);
+ }
+
+ ///
+ /// Delete Branch. Documentation:
+ /// Crowdin API
+ /// Crowdin Enterprise API
+ ///
+ [PublicAPI]
+ public async Task DeleteBranch(int projectId, int branchId)
+ {
+ string url = FormUrl_BranchId(projectId, branchId);
+ HttpStatusCode statusCode = await _apiClient.SendDeleteRequest(url);
+ Utils.ThrowIfStatusNot204(statusCode, $"Branch {branchId} removal failed");
+ }
+
+ ///
+ /// Edit Branch. Documentation:
+ /// Crowdin API
+ /// Crowdin Enterprise API
+ ///
+ [PublicAPI]
+ public async Task EditBranch(int projectId, int branchId, IEnumerable patches)
+ {
+ string url = FormUrl_BranchId(projectId, branchId);
+ CrowdinApiResult result = await _apiClient.SendPatchRequest(url, patches);
+ return _jsonParser.ParseResponseObject(result.JsonObject);
+ }
+
+ ///
+ /// Merge Branch. Documentation:
+ /// Crowdin API
+ /// Crowdin Enterprise API
+ ///
+ [PublicAPI]
+ public async Task MergeBranch(int projectId, int branchId, MergeBranchRequest request)
+ {
+ var url = $"/projects/{projectId}/branches/{branchId}/merges";
+ CrowdinApiResult result = await _apiClient.SendPostRequest(url, request);
+ return _jsonParser.ParseResponseObject(result.JsonObject);
+ }
+
+ ///
+ /// Check Branch Merge Status. Documentation:
+ /// Crowdin API
+ /// Crowdin Enterprise API
+ ///
+ [PublicAPI]
+ public async Task CheckBranchMergeStatus(int projectId, int branchId, string mergeId)
+ {
+ var url = $"/projects/{projectId}/branches/{branchId}/merges/{mergeId}";
+ CrowdinApiResult result = await _apiClient.SendGetRequest(url);
+ return _jsonParser.ParseResponseObject(result.JsonObject);
+ }
+
+ ///
+ /// Get Branch Merge Summary. Documentation:
+ /// Crowdin API
+ /// Crowdin Enterprise API
+ ///
+ [PublicAPI]
+ public async Task GetBranchMergeSummary(int projectId, int branchId, string mergeId)
+ {
+ var url = $"/projects/{projectId}/branches/{branchId}/merges/{mergeId}/summary";
+ CrowdinApiResult result = await _apiClient.SendGetRequest(url);
+ return _jsonParser.ParseResponseObject(result.JsonObject);
+ }
+
+ #region Helper methods
+
+ private static string FormUrl_Branches(int projectId)
+ {
+ return $"/projects/{projectId}/branches";
+ }
+
+ private static string FormUrl_BranchId(int projectId, int branchId)
+ {
+ return $"/projects/{projectId}/branches/{branchId}";
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Crowdin.Api/Branches/CloneBranchRequest.cs b/src/Crowdin.Api/Branches/CloneBranchRequest.cs
new file mode 100644
index 00000000..b2c6a49f
--- /dev/null
+++ b/src/Crowdin.Api/Branches/CloneBranchRequest.cs
@@ -0,0 +1,20 @@
+
+using JetBrains.Annotations;
+using Newtonsoft.Json;
+
+#nullable enable
+
+namespace Crowdin.Api.Branches
+{
+ [PublicAPI]
+ public class CloneBranchRequest
+ {
+ [JsonProperty("name")]
+#pragma warning disable CS8618
+ public string Name { get; set; }
+#pragma warning restore CS8618
+
+ [JsonProperty("title")]
+ public string? Title { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Crowdin.Api/Branches/MergeBranchRequest.cs b/src/Crowdin.Api/Branches/MergeBranchRequest.cs
new file mode 100644
index 00000000..74ea7b97
--- /dev/null
+++ b/src/Crowdin.Api/Branches/MergeBranchRequest.cs
@@ -0,0 +1,19 @@
+
+using JetBrains.Annotations;
+using Newtonsoft.Json;
+
+namespace Crowdin.Api.Branches
+{
+ [PublicAPI]
+ public class MergeBranchRequest
+ {
+ [JsonProperty("deleteAfterMerge")]
+ public bool? DeleteAfterMerge { get; set; }
+
+ [JsonProperty("sourceBranchId")]
+ public int SourceBranchId { get; set; }
+
+ [JsonProperty("dryRun")]
+ public bool? DryRun { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Crowdin.Api/Core/Constants.cs b/src/Crowdin.Api/Core/Constants.cs
index 742c2951..cfda4667 100644
--- a/src/Crowdin.Api/Core/Constants.cs
+++ b/src/Crowdin.Api/Core/Constants.cs
@@ -6,5 +6,7 @@ internal static class MessageTexts
public const string DeprecatedProperty = "This property is deprecated, please avoid using it";
public const string DeprecatedModel = "This model is deprecated, see API docs for alternative";
+
+ public const string UseBranchesNamespace = "This API is deprecated, see Crowdin.Api.Branches namespace";
}
}
\ No newline at end of file
diff --git a/src/Crowdin.Api/ProjectsGroups/EnterpriseProjectForm.cs b/src/Crowdin.Api/ProjectsGroups/EnterpriseProjectForm.cs
index 68c08ad2..3fbc01e6 100644
--- a/src/Crowdin.Api/ProjectsGroups/EnterpriseProjectForm.cs
+++ b/src/Crowdin.Api/ProjectsGroups/EnterpriseProjectForm.cs
@@ -23,6 +23,9 @@ public class EnterpriseProjectForm : AddProjectRequest
[JsonProperty("templateId")]
public int? TemplateId { get; set; }
+ [JsonProperty("steps")]
+ public ICollection? Steps { get; set; }
+
[JsonProperty("groupId")]
public int? GroupId { get; set; }
@@ -47,6 +50,9 @@ public class EnterpriseProjectForm : AddProjectRequest
[JsonProperty("isMtAllowed")]
public bool? IsMtAllowed { get; set; }
+ [JsonProperty("taskBasedAccessControl")]
+ public bool? TaskBasedAccessControl { get; set; }
+
[JsonProperty("autoSubstitution")]
public bool? AutoSubstitution { get; set; }
@@ -89,6 +95,9 @@ public class EnterpriseProjectForm : AddProjectRequest
[JsonProperty("qaCheckIsActive")]
public bool? QaCheckIsActive { get; set; }
+ [JsonProperty("qaApprovalsCount")]
+ public int? QaApprovalsCount { get; set; }
+
[JsonProperty("qaCheckCategories")]
public QaCheckCategories? QaCheckCategories { get; set; }
@@ -98,6 +107,9 @@ public class EnterpriseProjectForm : AddProjectRequest
[JsonProperty("customQaCheckIds")]
public ICollection? CustomQaCheckIds { get; set; }
+ [JsonProperty("tmContextType")]
+ public TmContextType? TmContextType { get; set; }
+
[JsonProperty("languageMapping")]
public IDictionary? LanguageMapping { get; set; }
diff --git a/src/Crowdin.Api/ProjectsGroups/FileBasedProjectForm.cs b/src/Crowdin.Api/ProjectsGroups/FileBasedProjectForm.cs
index b81f0873..ee669b14 100644
--- a/src/Crowdin.Api/ProjectsGroups/FileBasedProjectForm.cs
+++ b/src/Crowdin.Api/ProjectsGroups/FileBasedProjectForm.cs
@@ -56,6 +56,9 @@ public class FileBasedProjectForm : ProjectForm
[JsonProperty("isMtAllowed")]
public bool? IsMtAllowed { get; set; }
+ [JsonProperty("taskBasedAccessControl")]
+ public bool? TaskBasedAccessControl { get; set; }
+
[JsonProperty("autoSubstitution")]
public bool? AutoSubstitution { get; set; }
@@ -103,5 +106,8 @@ public class FileBasedProjectForm : ProjectForm
[JsonProperty("glossaryAccess")]
public bool? GlossaryAccess { get; set; }
+
+ [JsonProperty("tmContextType")]
+ public TmContextType? TmContextType { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Crowdin.Api/ProjectsGroups/ProjectBase.cs b/src/Crowdin.Api/ProjectsGroups/ProjectBase.cs
index 4829c06d..403ee9c1 100644
--- a/src/Crowdin.Api/ProjectsGroups/ProjectBase.cs
+++ b/src/Crowdin.Api/ProjectsGroups/ProjectBase.cs
@@ -12,6 +12,9 @@ public class ProjectBase
[JsonProperty("id")]
public int Id { get; set; }
+ [JsonProperty("type")]
+ public ProjectType Type { get; set; }
+
[JsonProperty("userId")]
public int UserId { get; set; }
@@ -45,6 +48,9 @@ public class ProjectBase
[JsonProperty("lastActivity")]
public DateTimeOffset? LastActivity { get; set; }
+ [JsonProperty("sourceLanguage")]
+ public Language SourceLanguage { get; set; }
+
[JsonProperty("targetLanguages")]
public Language[] TargetLanguages { get; set; }
}
diff --git a/src/Crowdin.Api/ProjectsGroups/ProjectInfoPatch.cs b/src/Crowdin.Api/ProjectsGroups/ProjectInfoPatch.cs
index c2677628..45f37c91 100644
--- a/src/Crowdin.Api/ProjectsGroups/ProjectInfoPatch.cs
+++ b/src/Crowdin.Api/ProjectsGroups/ProjectInfoPatch.cs
@@ -1,11 +1,13 @@
using System.Collections.Generic;
using System.ComponentModel;
-using Crowdin.Api.Core;
-using Crowdin.Api.Core.Converters;
+
using JetBrains.Annotations;
using Newtonsoft.Json;
+using Crowdin.Api.Core;
+using Crowdin.Api.Core.Converters;
+
namespace Crowdin.Api.ProjectsGroups
{
[PublicAPI]
@@ -82,6 +84,9 @@ public enum ProjectInfoPathCode
[Description("/isMtAllowed")]
IsMachineTranslationAllowed,
+ [Description("/taskBasedAccessControl")]
+ TaskBasedAccessControl,
+
[Description("/autoSubstitution")]
AutoSubstitution,
diff --git a/src/Crowdin.Api/ProjectsGroups/ProjectSettingPatch.cs b/src/Crowdin.Api/ProjectsGroups/ProjectSettingPatch.cs
index 31d92b1a..e4d1ce2d 100644
--- a/src/Crowdin.Api/ProjectsGroups/ProjectSettingPatch.cs
+++ b/src/Crowdin.Api/ProjectsGroups/ProjectSettingPatch.cs
@@ -1,11 +1,13 @@
using System.Collections.Generic;
using System.ComponentModel;
-using Crowdin.Api.Core;
-using Crowdin.Api.Core.Converters;
+
using JetBrains.Annotations;
using Newtonsoft.Json;
+using Crowdin.Api.Core;
+using Crowdin.Api.Core.Converters;
+
namespace Crowdin.Api.ProjectsGroups
{
[PublicAPI]
@@ -64,6 +66,9 @@ public enum ProjectSettingPathCode
[Description("/autoSubstitution")]
AutoSubstitution,
+ [Description("/skipUntranslatedFiles")]
+ SkipUntranslatedFiles,
+
[Description("/skipUntranslatedStrings")]
SkipUntranslatedStrings,
@@ -79,6 +84,9 @@ public enum ProjectSettingPathCode
[Description("/useGlobalTm")]
UseGlobalTm,
+ [Description("/showTmSuggestionsDialects")]
+ ShowTmSuggestionsDialects,
+
[Description("/normalizePlaceholder")]
NormalizePlaceholder,
@@ -88,6 +96,12 @@ public enum ProjectSettingPathCode
[Description("/inContext")]
InContext,
+ [Description("/inContextPseudoLanguageId")]
+ InContextPseudoLanguageId,
+
+ [Description("/inContextProcessHiddenStrings")]
+ InContextProcessHiddenStrings,
+
[Description("/pseudoLanguageId")]
PseudoLanguageId,
@@ -113,5 +127,14 @@ public enum ProjectSettingPathCode
TmPenalties,
// /tmPenalties/{penaltyKey}
+
+ [Description("/tmContextType")]
+ TmContextType,
+
+ [Description("/tmPreTranslate")]
+ TmPreTranslate,
+
+ [Description("/mtPreTranslate")]
+ MtPreTranslate,
}
}
\ No newline at end of file
diff --git a/src/Crowdin.Api/ProjectsGroups/ProjectSettings.cs b/src/Crowdin.Api/ProjectsGroups/ProjectSettings.cs
index b19d1574..71004c1a 100644
--- a/src/Crowdin.Api/ProjectsGroups/ProjectSettings.cs
+++ b/src/Crowdin.Api/ProjectsGroups/ProjectSettings.cs
@@ -9,6 +9,9 @@ namespace Crowdin.Api.ProjectsGroups
[PublicAPI]
public class ProjectSettings : Project
{
+ [JsonProperty("clientOrganizationId")]
+ public int ClientOrganizationId { get; set; }
+
[JsonProperty("translateDuplicates")]
public DupTranslateAction TranslateDuplicates { get; set; }
@@ -21,6 +24,9 @@ public class ProjectSettings : Project
[JsonProperty("isMtAllowed")]
public bool IsMachineTranslationAllowed { get; set; }
+ [JsonProperty("taskBasedAccessControl")]
+ public bool TaskBasedAccessControl { get; set; }
+
[JsonProperty("hiddenStringsProofreadersAccess")]
public bool HiddenStringsProofreadersAccess { get; set; }
@@ -48,6 +54,9 @@ public class ProjectSettings : Project
[JsonProperty("useGlobalTm")]
public bool UseGlobalTm { get; set; }
+ [JsonProperty("tmContextType")]
+ public TmContextType TmContextType { get; set; }
+
[JsonProperty("normalizePlaceholder")]
public bool NormalizePlaceholder { get; set; }
@@ -73,6 +82,9 @@ public class ProjectSettings : Project
[JsonProperty("qaCheckIsActive")]
public bool QaCheckIsActive { get; set; }
+ [JsonProperty("qaApprovalsCount")]
+ public int QaApprovalsCount { get; set; }
+
[JsonProperty("qaCheckCategories")]
public QaCheckCategories QaCheckCategories { get; set; }
diff --git a/src/Crowdin.Api/ProjectsGroups/ProjectsGroupsApiExecutor.cs b/src/Crowdin.Api/ProjectsGroups/ProjectsGroupsApiExecutor.cs
index 43b1a658..31ab2d95 100644
--- a/src/Crowdin.Api/ProjectsGroups/ProjectsGroupsApiExecutor.cs
+++ b/src/Crowdin.Api/ProjectsGroups/ProjectsGroupsApiExecutor.cs
@@ -110,6 +110,7 @@ public async Task EditGroup(int groupId, IEnumerable patches)
public async Task> ListProjects(
int? userId = null, int? groupId = null,
bool hasManagerAccess = false,
+ ProjectType? type = null,
int limit = 25, int offset = 0)
where TProject : ProjectBase // Project, EnterpriseProject
{
@@ -117,6 +118,11 @@ public async Task> ListProjects(
queryParams.AddParamIfPresent("userId", userId);
queryParams.AddParamIfPresent("groupId", groupId);
queryParams.Add("hasManagerAccess", hasManagerAccess ? "1" : "0");
+
+ if (type.HasValue)
+ {
+ queryParams.Add("type", ((int) type).ToString());
+ }
CrowdinApiResult result = await _apiClient.SendGetRequest(BaseProjectsSubUrl, queryParams);
diff --git a/src/Crowdin.Api/ProjectsGroups/StringsBasedProjectForm.cs b/src/Crowdin.Api/ProjectsGroups/StringsBasedProjectForm.cs
index 95fa950a..0c224544 100644
--- a/src/Crowdin.Api/ProjectsGroups/StringsBasedProjectForm.cs
+++ b/src/Crowdin.Api/ProjectsGroups/StringsBasedProjectForm.cs
@@ -47,6 +47,9 @@ public class StringsBasedProjectForm : ProjectForm
[JsonProperty("isMtAllowed")]
public bool? IsMtAllowed { get; set; }
+ [JsonProperty("taskBasedAccessControl")]
+ public bool? TaskBasedAccessControl { get; set; }
+
[JsonProperty("autoSubstitution")]
public bool? AutoSubstitution { get; set; }
@@ -92,7 +95,19 @@ public class StringsBasedProjectForm : ProjectForm
[JsonProperty("languageMapping")]
public IDictionary? LanguageMapping { get; set; }
+ [JsonProperty("glossaryAccess")]
+ public bool? GlossaryAccess { get; set; }
+
[JsonProperty("notificationSettings")]
public NotificationSettings? NotificationSettings { get; set; }
+
+ [JsonProperty("tmPenalties")]
+ public bool? TmPenalties { get; set; }
+
+ [JsonProperty("normalizePlaceholder")]
+ public bool? NormalizePlaceholder { get; set; }
+
+ [JsonProperty("tmContextType")]
+ public TmContextType? TmContextType { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Crowdin.Api/ProjectsGroups/TmContextType.cs b/src/Crowdin.Api/ProjectsGroups/TmContextType.cs
new file mode 100644
index 00000000..842a300f
--- /dev/null
+++ b/src/Crowdin.Api/ProjectsGroups/TmContextType.cs
@@ -0,0 +1,19 @@
+
+using System.ComponentModel;
+using JetBrains.Annotations;
+
+namespace Crowdin.Api.ProjectsGroups
+{
+ [PublicAPI]
+ public enum TmContextType
+ {
+ [Description("segmentContext")]
+ SegmentContext,
+
+ [Description("auto")]
+ Auto,
+
+ [Description("prevAndNextSegment")]
+ PrevAndNextSegment
+ }
+}
\ No newline at end of file
diff --git a/src/Crowdin.Api/ProjectsGroups/WorkflowTemplateStepConfig.cs b/src/Crowdin.Api/ProjectsGroups/WorkflowTemplateStepConfig.cs
new file mode 100644
index 00000000..e6ccd2d8
--- /dev/null
+++ b/src/Crowdin.Api/ProjectsGroups/WorkflowTemplateStepConfig.cs
@@ -0,0 +1,75 @@
+
+using System.Collections.Generic;
+using JetBrains.Annotations;
+using Newtonsoft.Json;
+
+#nullable enable
+
+namespace Crowdin.Api.ProjectsGroups
+{
+ [PublicAPI]
+ public abstract class WorkflowTemplateStepConfig
+ {
+ [PublicAPI]
+ public class TranslateProofread : WorkflowTemplateStepConfig
+ {
+ [JsonProperty("id")]
+ public int? Id { get; set; }
+
+ [JsonProperty("languages")]
+ public List? Languages { get; set; }
+
+ [JsonProperty("assignees")]
+ public List? Assignees { get; set; }
+ }
+
+ [PublicAPI]
+ public class ConfigVendor : WorkflowTemplateStepConfig
+ {
+ [JsonProperty("id")]
+ public int? Id { get; set; }
+
+ [JsonProperty("languages")]
+ public List? Languages { get; set; }
+
+ [JsonProperty("vendorId")]
+ public int? VendorId { get; set; }
+ }
+
+ [PublicAPI]
+ public class TmPreTranslate : WorkflowTemplateStepConfig
+ {
+ [JsonProperty("id")]
+ public int? Id { get; set; }
+
+ [JsonProperty("languages")]
+ public List? Languages { get; set; }
+
+ [JsonProperty("config")]
+ public Config? Config { get; set; }
+ }
+
+ [PublicAPI]
+ public class MtPreTranslate : WorkflowTemplateStepConfig
+ {
+ [JsonProperty("id")]
+ public int? Id { get; set; }
+
+ [JsonProperty("languages")]
+ public List? Languages { get; set; }
+
+ [JsonProperty("mtId")]
+ public int? MtId { get; set; }
+ }
+
+ [PublicAPI]
+ public class Config
+ {
+ [JsonProperty("minRelevant")]
+ public int? MinRelevant { get; set; }
+
+ [JsonProperty("autoSubstitution")]
+ public bool? AutoSubstitution { get; set; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Crowdin.Api/Reports/ReportStatus.cs b/src/Crowdin.Api/Reports/ReportStatus.cs
index 201c97bb..72d57c38 100644
--- a/src/Crowdin.Api/Reports/ReportStatus.cs
+++ b/src/Crowdin.Api/Reports/ReportStatus.cs
@@ -1,5 +1,7 @@
using System;
+using System.Collections.Generic;
+
using JetBrains.Annotations;
using Newtonsoft.Json;
@@ -43,6 +45,9 @@ public class ReportAttributes
[JsonProperty("schema")]
public object Schema { get; set; }
+
+ [JsonProperty("projectIds")]
+ public List ProjectIds { get; set; }
}
}
}
\ No newline at end of file
diff --git a/src/Crowdin.Api/SourceFiles/AddBranchRequest.cs b/src/Crowdin.Api/SourceFiles/AddBranchRequest.cs
index 5c6b3207..a8474968 100644
--- a/src/Crowdin.Api/SourceFiles/AddBranchRequest.cs
+++ b/src/Crowdin.Api/SourceFiles/AddBranchRequest.cs
@@ -1,22 +1,19 @@
+using System;
+
using JetBrains.Annotations;
using Newtonsoft.Json;
+using Crowdin.Api.Core;
+
#nullable enable
namespace Crowdin.Api.SourceFiles
{
[PublicAPI]
- public class AddBranchRequest
+ [Obsolete(MessageTexts.UseBranchesNamespace)]
+ public class AddBranchRequest : Crowdin.Api.Branches.AddBranchRequest
{
- [JsonProperty("name")]
-#pragma warning disable CS8618
- public string Name { get; set; }
-#pragma warning restore CS8618
-
- [JsonProperty("title")]
- public string? Title { get; set; }
-
[JsonProperty("exportPattern")]
public string? ExportPattern { get; set; }
diff --git a/src/Crowdin.Api/SourceFiles/Branch.cs b/src/Crowdin.Api/SourceFiles/Branch.cs
index fa728686..2feb2086 100644
--- a/src/Crowdin.Api/SourceFiles/Branch.cs
+++ b/src/Crowdin.Api/SourceFiles/Branch.cs
@@ -1,35 +1,21 @@
using System;
+
using JetBrains.Annotations;
using Newtonsoft.Json;
+using Crowdin.Api.Core;
+
namespace Crowdin.Api.SourceFiles
{
[PublicAPI]
- public class Branch
+ [Obsolete(MessageTexts.UseBranchesNamespace)]
+ public class Branch : Crowdin.Api.Branches.Branch
{
- [JsonProperty("id")]
- public int Id { get; set; }
-
- [JsonProperty("projectId")]
- public int ProjectId { get; set; }
-
- [JsonProperty("name")]
- public string Name { get; set; }
-
- [JsonProperty("title")]
- public string Title { get; set; }
-
[JsonProperty("exportPattern")]
public string ExportPattern { get; set; }
[JsonProperty("priority")]
public Priority Priority { get; set; }
-
- [JsonProperty("createdAt")]
- public DateTimeOffset CreatedAt { get; set; }
-
- [JsonProperty("updatedAt")]
- public DateTimeOffset? UpdatedAt { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Crowdin.Api/SourceFiles/BranchPatch.cs b/src/Crowdin.Api/SourceFiles/BranchPatch.cs
index 88902962..82624d75 100644
--- a/src/Crowdin.Api/SourceFiles/BranchPatch.cs
+++ b/src/Crowdin.Api/SourceFiles/BranchPatch.cs
@@ -1,11 +1,16 @@
+using System;
using System.ComponentModel;
+
using JetBrains.Annotations;
using Newtonsoft.Json;
+using Crowdin.Api.Core;
+
namespace Crowdin.Api.SourceFiles
{
[PublicAPI]
+ [Obsolete(MessageTexts.UseBranchesNamespace)]
public class BranchPatch : PatchEntry
{
[JsonProperty("path")]
@@ -13,6 +18,7 @@ public class BranchPatch : PatchEntry
}
[PublicAPI]
+ [Obsolete(MessageTexts.UseBranchesNamespace)]
public enum BranchPatchPath
{
[Description("/name")]
diff --git a/src/Crowdin.Api/SourceFiles/SourceFilesApiExecutor.cs b/src/Crowdin.Api/SourceFiles/SourceFilesApiExecutor.cs
index 1a5bf1e6..d77eecff 100644
--- a/src/Crowdin.Api/SourceFiles/SourceFilesApiExecutor.cs
+++ b/src/Crowdin.Api/SourceFiles/SourceFilesApiExecutor.cs
@@ -1,11 +1,14 @@
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
-using Crowdin.Api.Core;
+
using JetBrains.Annotations;
+using Crowdin.Api.Core;
+
#nullable enable
namespace Crowdin.Api.SourceFiles
@@ -35,6 +38,7 @@ public SourceFilesApiExecutor(ICrowdinApiClient apiClient, IJsonParser jsonParse
/// Crowdin Enterprise API
///
[PublicAPI]
+ [Obsolete(MessageTexts.UseBranchesNamespace)]
public async Task> ListBranches(
int projectId, string? name = null, int limit = 25, int offset = 0)
{
@@ -52,6 +56,7 @@ public async Task> ListBranches(
/// Crowdin Enterprise API
///
[PublicAPI]
+ [Obsolete(MessageTexts.UseBranchesNamespace)]
public async Task AddBranch(int projectId, AddBranchRequest request)
{
string url = FormUrl_ProjectBranches(projectId);
@@ -65,6 +70,7 @@ public async Task AddBranch(int projectId, AddBranchRequest request)
/// Crowdin Enterprise API
///
[PublicAPI]
+ [Obsolete(MessageTexts.UseBranchesNamespace)]
public async Task GetBranch(int projectId, int branchId)
{
string url = FormUrl_ProjectIdBranchId(projectId, branchId);
@@ -78,6 +84,7 @@ public async Task GetBranch(int projectId, int branchId)
/// Crowdin Enterprise API
///
[PublicAPI]
+ [Obsolete(MessageTexts.UseBranchesNamespace)]
public async Task DeleteBranch(int projectId, int branchId)
{
string url = FormUrl_ProjectIdBranchId(projectId, branchId);
@@ -91,6 +98,7 @@ public async Task DeleteBranch(int projectId, int branchId)
/// Crowdin Enterprise API
///
[PublicAPI]
+ [Obsolete(MessageTexts.UseBranchesNamespace)]
public async Task EditBranch(int projectId, int branchId, IEnumerable patches)
{
string url = FormUrl_ProjectIdBranchId(projectId, branchId);
diff --git a/src/Crowdin.Api/SourceStrings/AddStringRequest.cs b/src/Crowdin.Api/SourceStrings/AddStringRequest.cs
index 5d0816bc..a351963c 100644
--- a/src/Crowdin.Api/SourceStrings/AddStringRequest.cs
+++ b/src/Crowdin.Api/SourceStrings/AddStringRequest.cs
@@ -1,5 +1,4 @@
-using System.Collections;
using System.Collections.Generic;
using JetBrains.Annotations;
using Newtonsoft.Json;
@@ -22,6 +21,9 @@ public class AddStringRequest
[JsonProperty("fileId")]
public int? FileId { get; set; }
+ [JsonProperty("branchId")]
+ public int? BranchId { get; set; }
+
[JsonProperty("context")]
public string? Context { get; set; }
diff --git a/src/Crowdin.Api/SourceStrings/SourceString.cs b/src/Crowdin.Api/SourceStrings/SourceString.cs
index 9eea6eaa..0e6962d1 100644
--- a/src/Crowdin.Api/SourceStrings/SourceString.cs
+++ b/src/Crowdin.Api/SourceStrings/SourceString.cs
@@ -15,7 +15,7 @@ public class SourceString
public int ProjectId { get; set; }
[JsonProperty("fileId")]
- public int FileId { get; set; }
+ public int? FileId { get; set; }
[JsonProperty("branchId")]
public int? BranchId { get; set; }
@@ -48,7 +48,7 @@ public class SourceString
public int? MasterStringId { get; set; }
[JsonProperty("revision")]
- public int Revision { get; set; }
+ public int? Revision { get; set; }
[JsonProperty("hasPlurals")]
public bool HasPlurals { get; set; }
diff --git a/src/Crowdin.Api/SourceStrings/SourceStringsApiExecutor.cs b/src/Crowdin.Api/SourceStrings/SourceStringsApiExecutor.cs
index f1dcb64f..d87b257c 100644
--- a/src/Crowdin.Api/SourceStrings/SourceStringsApiExecutor.cs
+++ b/src/Crowdin.Api/SourceStrings/SourceStringsApiExecutor.cs
@@ -126,6 +126,32 @@ public async Task EditString(int projectId, int stringId, IEnumera
CrowdinApiResult result = await _apiClient.SendPatchRequest(url, patches);
return _jsonParser.ParseResponseObject(result.JsonObject);
}
+
+ ///
+ /// Upload strings status. Documentation:
+ /// Crowdin API
+ /// Crowdin Enterprise API
+ ///
+ [PublicAPI]
+ public async Task UploadStringsStatus(int projectId, string uploadId)
+ {
+ string url = FormUrl_StringsUploadId(projectId, uploadId);
+ CrowdinApiResult result = await _apiClient.SendGetRequest(url);
+ return _jsonParser.ParseResponseObject(result.JsonObject);
+ }
+
+ ///
+ /// Upload strings. Documentation:
+ /// Crowdin API
+ /// Crowdin Enterprise API
+ ///
+ [PublicAPI]
+ public async Task UploadStrings(int projectId, UploadStringsRequest request)
+ {
+ string url = FormUrl_StringsUpload(projectId);
+ CrowdinApiResult result = await _apiClient.SendPostRequest(url, request);
+ return _jsonParser.ParseResponseObject(result.JsonObject);
+ }
#region Helper methods
@@ -138,6 +164,16 @@ private static string FormUrl_StringId(int projectId, int stringId)
{
return $"/projects/{projectId}/strings/{stringId}";
}
+
+ private static string FormUrl_StringsUpload(int projectId)
+ {
+ return $"/projects/{projectId}/strings/upload";
+ }
+
+ private static string FormUrl_StringsUploadId(int projectId, string uploadId)
+ {
+ return $"/projects/{projectId}/strings/uploads/{uploadId}";
+ }
#endregion
}
diff --git a/src/Crowdin.Api/SourceStrings/StringBasedProjectFileType.cs b/src/Crowdin.Api/SourceStrings/StringBasedProjectFileType.cs
new file mode 100644
index 00000000..00f9adc2
--- /dev/null
+++ b/src/Crowdin.Api/SourceStrings/StringBasedProjectFileType.cs
@@ -0,0 +1,37 @@
+
+using System.ComponentModel;
+using JetBrains.Annotations;
+
+namespace Crowdin.Api.SourceStrings
+{
+ [PublicAPI]
+ public enum StringBasedProjectFileType
+ {
+ [Description("auto")]
+ Auto,
+
+ [Description("android")]
+ Android,
+
+ [Description("macosx")]
+ MacOsX,
+
+ [Description("arb")]
+ Arb,
+
+ [Description("csv")]
+ Csv,
+
+ [Description("json")]
+ Json,
+
+ [Description("xlsx")]
+ Xlsx,
+
+ [Description("xliff")]
+ Xliff,
+
+ [Description("xliff_two")]
+ XliffTwo
+ }
+}
\ No newline at end of file
diff --git a/src/Crowdin.Api/SourceStrings/StringUploadResponseModel.cs b/src/Crowdin.Api/SourceStrings/StringUploadResponseModel.cs
new file mode 100644
index 00000000..46e328bd
--- /dev/null
+++ b/src/Crowdin.Api/SourceStrings/StringUploadResponseModel.cs
@@ -0,0 +1,64 @@
+
+using System;
+using JetBrains.Annotations;
+using Newtonsoft.Json;
+using Crowdin.Api.SourceFiles;
+
+namespace Crowdin.Api.SourceStrings
+{
+ [PublicAPI]
+ public class StringUploadResponseModel
+ {
+ [JsonProperty("identifier")]
+ public string Identifier { get; set; }
+
+ [JsonProperty("status")]
+ public OperationStatus Status { get; set; }
+
+ [JsonProperty("progress")]
+ public int Progress { get; set; }
+
+ [JsonProperty("attributes")]
+ public AttributesData Attributes { get; set; }
+
+ [JsonProperty("createdAt")]
+ public DateTimeOffset CreatedAt { get; set; }
+
+ [JsonProperty("updatedAt")]
+ public DateTimeOffset? UpdatedAt { get; set; }
+
+ [JsonProperty("startedAt")]
+ public DateTimeOffset? StartedAt { get; set; }
+
+ [JsonProperty("finishedAt")]
+ public DateTimeOffset? FinishedAt { get; set; }
+
+ [PublicAPI]
+ public class AttributesData
+ {
+ [JsonProperty("branchId")]
+ public int BranchId { get; set; }
+
+ [JsonProperty("storageId")]
+ public int StorageId { get; set; }
+
+ [JsonProperty("fileType")]
+ public string FileType { get; set; }
+
+ [JsonProperty("parserVersion")]
+ public int ParserVersion { get; set; }
+
+ [JsonProperty("labelIds")]
+ public int[] LabelIds { get; set; }
+
+ [JsonProperty("importOptions")]
+ public SpreadsheetFileImportOptions ImportOptions { get; set; }
+
+ [JsonProperty("updateStrings")]
+ public bool UpdateStrings { get; set; }
+
+ [JsonProperty("cleanupMode")]
+ public bool CleanupMode { get; set; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Crowdin.Api/SourceStrings/UploadStringsRequest.cs b/src/Crowdin.Api/SourceStrings/UploadStringsRequest.cs
new file mode 100644
index 00000000..1eb2ea56
--- /dev/null
+++ b/src/Crowdin.Api/SourceStrings/UploadStringsRequest.cs
@@ -0,0 +1,40 @@
+
+using System.Collections.Generic;
+
+using JetBrains.Annotations;
+using Newtonsoft.Json;
+
+using Crowdin.Api.SourceFiles;
+
+#nullable enable
+
+namespace Crowdin.Api.SourceStrings
+{
+ [PublicAPI]
+ public class UploadStringsRequest
+ {
+ [JsonProperty("storageId")]
+ public int StorageId { get; set; }
+
+ [JsonProperty("branchId")]
+ public int BranchId { get; set; }
+
+ [JsonProperty("type")]
+ public StringBasedProjectFileType? Type { get; set; }
+
+ [JsonProperty("parserVersion")]
+ public int? ParserVersion { get; set; }
+
+ [JsonProperty("labelIds")]
+ public ICollection? LabelIds { get; set; }
+
+ [JsonProperty("updateStrings")]
+ public bool? UpdateStrings { get; set; }
+
+ [JsonProperty("cleanupMode")]
+ public bool? CleanupMode { get; set; }
+
+ [JsonProperty("importOptions")]
+ public SpreadsheetFileImportOptions? ImportOptions { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Crowdin.Api/StringTranslations/StringTranslation.cs b/src/Crowdin.Api/StringTranslations/StringTranslation.cs
index 3ba255e4..98427012 100644
--- a/src/Crowdin.Api/StringTranslations/StringTranslation.cs
+++ b/src/Crowdin.Api/StringTranslations/StringTranslation.cs
@@ -23,6 +23,12 @@ public class StringTranslation
[JsonProperty("rating")]
public int Rating { get; set; }
+ [JsonProperty("provider")]
+ public string Provider { get; set; }
+
+ [JsonProperty("isPreTranslated")]
+ public bool IsPreTranslated { get; set; }
+
[JsonProperty("createdAt")]
public DateTimeOffset CreatedAt { get; set; }
}
diff --git a/src/Crowdin.Api/Tasks/LanguageServiceTaskCreateForm.cs b/src/Crowdin.Api/Tasks/LanguageServiceTaskCreateForm.cs
index 75375314..b409cb3f 100644
--- a/src/Crowdin.Api/Tasks/LanguageServiceTaskCreateForm.cs
+++ b/src/Crowdin.Api/Tasks/LanguageServiceTaskCreateForm.cs
@@ -1,5 +1,7 @@
-using System;
+
+using System;
using System.Collections.Generic;
+
using JetBrains.Annotations;
using Newtonsoft.Json;
@@ -20,10 +22,11 @@ public class LanguageServiceTaskCreateForm : AddTaskRequest
public string LanguageId { get; set; }
#pragma warning restore CS8618
+ [JsonProperty("branchIds")]
+ public ICollection? BranchIds { get; set; }
+
[JsonProperty("fileIds")]
-#pragma warning disable CS8618
- public ICollection FileIds { get; set; }
-#pragma warning restore CS8618
+ public ICollection? FileIds { get; set; }
[JsonProperty("type")]
public TaskType Type { get; set; }
diff --git a/src/Crowdin.Api/Tasks/TaskCreateForm.cs b/src/Crowdin.Api/Tasks/TaskCreateForm.cs
index 17129f65..69eed09a 100644
--- a/src/Crowdin.Api/Tasks/TaskCreateForm.cs
+++ b/src/Crowdin.Api/Tasks/TaskCreateForm.cs
@@ -21,10 +21,11 @@ public class TaskCreateForm : AddTaskRequest
public string LanguageId { get; set; }
#pragma warning restore CS8618
+ [JsonProperty("branchIds")]
+ public ICollection? BranchIds { get; set; }
+
[JsonProperty("fileIds")]
-#pragma warning disable CS8618
- public ICollection FileIds { get; set; }
-#pragma warning restore CS8618
+ public ICollection? FileIds { get; set; }
[JsonProperty("type")]
public TaskType Type { get; set; }
diff --git a/src/Crowdin.Api/Tasks/VendorGengoTaskCreateForm.cs b/src/Crowdin.Api/Tasks/VendorGengoTaskCreateForm.cs
index cae5b4bf..f42324f0 100644
--- a/src/Crowdin.Api/Tasks/VendorGengoTaskCreateForm.cs
+++ b/src/Crowdin.Api/Tasks/VendorGengoTaskCreateForm.cs
@@ -23,10 +23,11 @@ public class VendorGengoTaskCreateForm : AddTaskRequest
public string LanguageId { get; set; }
#pragma warning restore CS8618
+ [JsonProperty("branchIds")]
+ public ICollection? BranchIds { get; set; }
+
[JsonProperty("fileIds")]
-#pragma warning disable CS8618
- public ICollection FileIds { get; set; }
-#pragma warning restore CS8618
+ public ICollection? FileIds { get; set; }
[JsonProperty("type")]
public TaskType Type { get; set; }
diff --git a/src/Crowdin.Api/Tasks/VendorManualTaskCreateForm.cs b/src/Crowdin.Api/Tasks/VendorManualTaskCreateForm.cs
index ed3a69b5..7bc68a62 100644
--- a/src/Crowdin.Api/Tasks/VendorManualTaskCreateForm.cs
+++ b/src/Crowdin.Api/Tasks/VendorManualTaskCreateForm.cs
@@ -19,9 +19,6 @@ public class VendorManualTaskCreateForm : AddTaskRequest
[JsonProperty("languageId")]
public string LanguageId { get; set; }
- [JsonProperty("fileIds")]
- public ICollection FileIds { get; set; }
-
[JsonProperty("type")]
public TaskType Type { get; set; }
@@ -36,6 +33,12 @@ public class VendorManualTaskCreateForm : AddTaskRequest
[JsonProperty("description")]
public string? Description { get; set; }
+ [JsonProperty("branchIds")]
+ public ICollection? BranchIds { get; set; }
+
+ [JsonProperty("fileIds")]
+ public ICollection? FileIds { get; set; }
+
[JsonProperty("skipAssignedStrings")]
public bool? SkipAssignedStrings { get; set; }
diff --git a/src/Crowdin.Api/Tasks/VendorOhtTaskCreateForm.cs b/src/Crowdin.Api/Tasks/VendorOhtTaskCreateForm.cs
index d9cd8f30..53655317 100644
--- a/src/Crowdin.Api/Tasks/VendorOhtTaskCreateForm.cs
+++ b/src/Crowdin.Api/Tasks/VendorOhtTaskCreateForm.cs
@@ -22,10 +22,11 @@ public class VendorOhtTaskCreateForm : AddTaskRequest
public string LanguageId { get; set; }
#pragma warning restore CS8618
+ [JsonProperty("branchIds")]
+ public ICollection? BranchIds { get; set; }
+
[JsonProperty("fileIds")]
-#pragma warning disable CS8618
- public ICollection FileIds { get; set; }
-#pragma warning restore CS8618
+ public ICollection? FileIds { get; set; }
[JsonProperty("type")]
public TaskType Type { get; set; }
diff --git a/src/Crowdin.Api/Tasks/VendorTranslatedTaskCreateForm.cs b/src/Crowdin.Api/Tasks/VendorTranslatedTaskCreateForm.cs
index b66ff147..552995fe 100644
--- a/src/Crowdin.Api/Tasks/VendorTranslatedTaskCreateForm.cs
+++ b/src/Crowdin.Api/Tasks/VendorTranslatedTaskCreateForm.cs
@@ -22,10 +22,11 @@ public class VendorTranslatedTaskCreateForm : AddTaskRequest
public string LanguageId { get; set; }
#pragma warning restore CS8618
+ [JsonProperty("branchIds")]
+ public ICollection? BranchIds { get; set; }
+
[JsonProperty("fileIds")]
-#pragma warning disable CS8618
- public ICollection FileIds { get; set; }
-#pragma warning restore CS8618
+ public ICollection? FileIds { get; set; }
[JsonProperty("type")]
public TaskType Type { get; set; }
diff --git a/src/Crowdin.Api/Translations/ApplyPreTranslationRequest.cs b/src/Crowdin.Api/Translations/ApplyPreTranslationRequest.cs
index 68bf586e..0806a934 100644
--- a/src/Crowdin.Api/Translations/ApplyPreTranslationRequest.cs
+++ b/src/Crowdin.Api/Translations/ApplyPreTranslationRequest.cs
@@ -1,4 +1,4 @@
-
+
using System.Collections.Generic;
using JetBrains.Annotations;
using Newtonsoft.Json;
@@ -13,8 +13,11 @@ public class ApplyPreTranslationRequest
[JsonProperty("languageIds")]
public ICollection LanguageIds { get; set; } = new List();
+ [JsonProperty("branchIds")]
+ public ICollection? BranchIds { get; set; }
+
[JsonProperty("fileIds")]
- public ICollection FileIds { get; set; } = new List();
+ public ICollection? FileIds { get; set; }
[JsonProperty("method")]
public PreTranslationMethod? Method { get; set; }
diff --git a/src/Crowdin.Api/Translations/PreTranslateAttributes.cs b/src/Crowdin.Api/Translations/PreTranslateAttributes.cs
index 5565dd5b..329026bb 100644
--- a/src/Crowdin.Api/Translations/PreTranslateAttributes.cs
+++ b/src/Crowdin.Api/Translations/PreTranslateAttributes.cs
@@ -1,17 +1,23 @@
-
+
+using System;
using JetBrains.Annotations;
using Newtonsoft.Json;
+#nullable enable
+
namespace Crowdin.Api.Translations
{
[PublicAPI]
public class PreTranslateAttributes
{
[JsonProperty("languageIds")]
- public string[] LanguageIds { get; set; }
+ public string[] LanguageIds { get; set; } = Array.Empty();
+
+ [JsonProperty("branchIds")]
+ public string[] BranchIds { get; set; } = Array.Empty();
[JsonProperty("fileIds")]
- public int[] FileIds { get; set; }
+ public int[]? FileIds { get; set; }
[JsonProperty("method")]
public PreTranslationMethod Method { get; set; }
diff --git a/src/Crowdin.Api/Translations/UploadTranslationsRequest.cs b/src/Crowdin.Api/Translations/UploadTranslationsRequest.cs
index cba941c9..1ea9662b 100644
--- a/src/Crowdin.Api/Translations/UploadTranslationsRequest.cs
+++ b/src/Crowdin.Api/Translations/UploadTranslationsRequest.cs
@@ -1,4 +1,4 @@
-
+
using JetBrains.Annotations;
using Newtonsoft.Json;
@@ -10,8 +10,11 @@ public class UploadTranslationsRequest
[JsonProperty("storageId")]
public int StorageId { get; set; }
+ [JsonProperty("branchId")]
+ public int? BranchId { get; set; }
+
[JsonProperty("fileId")]
- public int FileId { get; set; }
+ public int? FileId { get; set; }
[JsonProperty("importEqSuggestions")]
public bool? ImportEqSuggestions { get; set; }
diff --git a/src/Crowdin.Api/Translations/UploadTranslationsResponse.cs b/src/Crowdin.Api/Translations/UploadTranslationsResponse.cs
index ef1e6796..059e0934 100644
--- a/src/Crowdin.Api/Translations/UploadTranslationsResponse.cs
+++ b/src/Crowdin.Api/Translations/UploadTranslationsResponse.cs
@@ -17,6 +17,9 @@ public class UploadTranslationsResponse
public string LanguageId { get; set; }
[JsonProperty("fileId")]
- public int FileId { get; set; }
+ public int? FileId { get; set; }
+
+ [JsonProperty("branchId")]
+ public int? BranchId { get; set; }
}
}
\ No newline at end of file
diff --git a/tests/Crowdin.Api.Tests/Branches/BranchesCrudApiTests.cs b/tests/Crowdin.Api.Tests/Branches/BranchesCrudApiTests.cs
new file mode 100644
index 00000000..77431851
--- /dev/null
+++ b/tests/Crowdin.Api.Tests/Branches/BranchesCrudApiTests.cs
@@ -0,0 +1,182 @@
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Threading.Tasks;
+
+using Moq;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Xunit;
+
+using Crowdin.Api.Branches;
+using Crowdin.Api.Core;
+using Crowdin.Api.Tests.Core;
+
+namespace Crowdin.Api.Tests.Branches
+{
+ public class BranchesApiTests
+ {
+ private static readonly JsonSerializerSettings JsonSettings = TestUtils.CreateJsonSerializerOptions();
+
+ [Fact]
+ public async Task ListBranches()
+ {
+ const int projectId = 1;
+ const string branchName = "name";
+
+ Mock mockClient = TestUtils.CreateMockClientWithDefaultParser();
+
+ var url = $"/projects/{projectId}/branches";
+
+ IDictionary queryParams = TestUtils.CreateQueryParamsFromPaging();
+ queryParams.Add("name", branchName);
+
+ mockClient
+ .Setup(client => client.SendGetRequest(url, queryParams))
+ .ReturnsAsync(new CrowdinApiResult
+ {
+ StatusCode = HttpStatusCode.OK,
+ JsonObject = JObject.Parse(Core.Resources.Branches.Response_Common_Multi)
+ });
+
+ var executor = new BranchesApiExecutor(mockClient.Object);
+ ResponseList response = await executor.ListBranches(projectId, branchName);
+
+ Branch? branch = response.Data.FirstOrDefault();
+ Assert_Branch(branch);
+ }
+
+ [Fact]
+ public async Task AddBranch()
+ {
+ const int projectId = 1;
+
+ var request = new AddBranchRequest
+ {
+ Name = "develop-master",
+ Title = "Master branch"
+ };
+
+ string actualRequestJson = JsonConvert.SerializeObject(request, JsonSettings);
+ string expectedRequestJson = TestUtils.CompactJson(Core.Resources.Branches.Request_AddBranch);
+ Assert.Equal(expectedRequestJson, actualRequestJson);
+
+ Mock mockClient = TestUtils.CreateMockClientWithDefaultParser();
+
+ var url = $"/projects/{projectId}/branches";
+
+ mockClient
+ .Setup(client => client.SendPostRequest(url, request, null))
+ .ReturnsAsync(new CrowdinApiResult
+ {
+ StatusCode = HttpStatusCode.Created,
+ JsonObject = JObject.Parse(Core.Resources.Branches.Response_Common_Single)
+ });
+
+ var executor = new BranchesApiExecutor(mockClient.Object);
+ Branch response = await executor.AddBranch(projectId, request);
+
+ Assert_Branch(response);
+ }
+
+ [Fact]
+ public async Task GetBranch()
+ {
+ const int projectId = 1;
+ const int branchId = 2;
+
+ Mock mockClient = TestUtils.CreateMockClientWithDefaultParser();
+
+ var url = $"/projects/{projectId}/branches/{branchId}";
+
+ mockClient
+ .Setup(client => client.SendGetRequest(url, null))
+ .ReturnsAsync(new CrowdinApiResult
+ {
+ StatusCode = HttpStatusCode.OK,
+ JsonObject = JObject.Parse(Core.Resources.Branches.Response_Common_Single)
+ });
+
+ var executor = new BranchesApiExecutor(mockClient.Object);
+ Branch response = await executor.GetBranch(projectId, branchId);
+
+ Assert_Branch(response);
+ }
+
+ [Fact]
+ public async Task DeleteBranch()
+ {
+ const int projectId = 1;
+ const int branchId = 2;
+
+ Mock mockClient = TestUtils.CreateMockClientWithDefaultParser();
+
+ var url = $"/projects/{projectId}/branches/{branchId}";
+
+ mockClient
+ .Setup(client => client.SendDeleteRequest(url, null))
+ .ReturnsAsync(HttpStatusCode.NoContent);
+
+ var executor = new BranchesApiExecutor(mockClient.Object);
+ await executor.DeleteBranch(projectId, branchId);
+ }
+
+ [Fact]
+ public async Task EditBranch()
+ {
+ const int projectId = 1;
+ const int branchId = 2;
+
+ var patches = new[]
+ {
+ new BranchPatch
+ {
+ Operation = PatchOperation.Replace,
+ Path = BranchPatchPath.Name,
+ Value = "develop-master"
+ },
+ new BranchPatch
+ {
+ Operation = PatchOperation.Replace,
+ Path = BranchPatchPath.Title,
+ Value = "Master branch"
+ }
+ };
+
+ string actualRequestJson = JsonConvert.SerializeObject(patches, JsonSettings);
+ string expectedRequestJson = TestUtils.CompactJson(Core.Resources.Branches.Request_EditBranch);
+ Assert.Equal(expectedRequestJson, actualRequestJson);
+
+ Mock mockClient = TestUtils.CreateMockClientWithDefaultParser();
+
+ var url = $"/projects/{projectId}/branches/{branchId}";
+
+ mockClient
+ .Setup(client => client.SendPatchRequest(url, patches, null))
+ .ReturnsAsync(new CrowdinApiResult
+ {
+ StatusCode = HttpStatusCode.OK,
+ JsonObject = JObject.Parse(Core.Resources.Branches.Response_Common_Single)
+ });
+
+ var executor = new BranchesApiExecutor(mockClient.Object);
+ Branch response = await executor.EditBranch(projectId, branchId, patches);
+
+ Assert_Branch(response);
+ }
+
+ private static void Assert_Branch(Branch? branch)
+ {
+ ArgumentNullException.ThrowIfNull(branch);
+
+ Assert.Equal(34, branch.Id);
+ Assert.Equal(2, branch.ProjectId);
+ Assert.Equal("develop-master", branch.Name);
+ Assert.Equal("Master branch", branch.Title);
+ Assert.Equal(DateTimeOffset.Parse("2019-09-16T13:48:04+00:00"), branch.CreatedAt);
+ Assert.Equal(DateTimeOffset.Parse("2019-09-19T13:25:27+00:00"), branch.UpdatedAt);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/Crowdin.Api.Tests/Branches/BranchesOperationsApiTests.cs b/tests/Crowdin.Api.Tests/Branches/BranchesOperationsApiTests.cs
new file mode 100644
index 00000000..af76fd58
--- /dev/null
+++ b/tests/Crowdin.Api.Tests/Branches/BranchesOperationsApiTests.cs
@@ -0,0 +1,255 @@
+
+using System;
+using System.Net;
+using System.Threading.Tasks;
+
+using Moq;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Xunit;
+
+using Crowdin.Api.Branches;
+using Crowdin.Api.Core;
+using Crowdin.Api.Tests.Core;
+
+namespace Crowdin.Api.Tests.Branches
+{
+ public class BranchesOperationsApiTests
+ {
+ private static readonly JsonSerializerSettings JsonSettings = TestUtils.CreateJsonSerializerOptions();
+
+ [Fact]
+ public async Task GetClonedBranch()
+ {
+ const int projectId = 1;
+ const int branchId = 2;
+ const string cloneId = "id";
+
+ Mock mockClient = TestUtils.CreateMockClientWithDefaultParser();
+
+ var url = $"/projects/{projectId}/branches/{branchId}/clones/{cloneId}/branch";
+
+ mockClient
+ .Setup(client => client.SendGetRequest(url, null))
+ .ReturnsAsync(new CrowdinApiResult
+ {
+ StatusCode = HttpStatusCode.OK,
+ JsonObject = JObject.Parse(Core.Resources.Branches.Response_Common_Single)
+ });
+
+ var executor = new BranchesApiExecutor(mockClient.Object);
+ Branch response = await executor.GetClonedBranch(projectId, branchId, cloneId);
+
+ Assert_Branch(response);
+ }
+
+ [Fact]
+ public async Task CloneBranch()
+ {
+ const int projectId = 1;
+ const int branchId = 2;
+
+ var request = new CloneBranchRequest
+ {
+ Name = "develop-master",
+ Title = "Master branch"
+ };
+
+ string actualRequestJson = JsonConvert.SerializeObject(request, JsonSettings);
+ string expectedRequestJson = TestUtils.CompactJson(Core.Resources.Branches.Request_CloneBranch);
+ Assert.Equal(expectedRequestJson, actualRequestJson);
+
+ Mock mockClient = TestUtils.CreateMockClientWithDefaultParser();
+
+ var url = $"/projects/{projectId}/branches/{branchId}/clones";
+
+ mockClient
+ .Setup(client => client.SendPostRequest(url, request, null))
+ .ReturnsAsync(new CrowdinApiResult
+ {
+ StatusCode = HttpStatusCode.Accepted,
+ JsonObject = JObject.Parse(Core.Resources.Branches.Response_BranchCloneStatus)
+ });
+
+ var executor = new BranchesApiExecutor(mockClient.Object);
+ BranchCloneStatus response = await executor.CloneBranch(projectId, branchId, request);
+
+ Assert_BranchCloneStatus(response);
+ }
+
+ [Fact]
+ public async Task CheckBranchCloneStatus()
+ {
+ const int projectId = 1;
+ const int branchId = 2;
+ const string cloneId = "id";
+
+ Mock mockClient = TestUtils.CreateMockClientWithDefaultParser();
+
+ var url = $"/projects/{projectId}/branches/{branchId}/clones/{cloneId}";
+
+ mockClient
+ .Setup(client => client.SendGetRequest(url, null))
+ .ReturnsAsync(new CrowdinApiResult
+ {
+ StatusCode = HttpStatusCode.OK,
+ JsonObject = JObject.Parse(Core.Resources.Branches.Response_BranchCloneStatus)
+ });
+
+ var executor = new BranchesApiExecutor(mockClient.Object);
+ BranchCloneStatus response = await executor.CheckBranchCloneStatus(projectId, branchId, cloneId);
+
+ Assert_BranchCloneStatus(response);
+ }
+
+ [Fact]
+ public async Task MergeBranch()
+ {
+ const int projectId = 1;
+ const int branchId = 2;
+
+ var request = new MergeBranchRequest
+ {
+ DeleteAfterMerge = true,
+ SourceBranchId = 8,
+ DryRun = true
+ };
+
+ string actualRequestJson = JsonConvert.SerializeObject(request, JsonSettings);
+ string expectedRequestJson = TestUtils.CompactJson(Core.Resources.Branches.Request_MergeBranch);
+ Assert.Equal(expectedRequestJson, actualRequestJson);
+
+ Mock mockClient = TestUtils.CreateMockClientWithDefaultParser();
+
+ var url = $"/projects/{projectId}/branches/{branchId}/merges";
+
+ mockClient
+ .Setup(client => client.SendPostRequest(url, request, null))
+ .ReturnsAsync(new CrowdinApiResult
+ {
+ StatusCode = HttpStatusCode.Accepted,
+ JsonObject = JObject.Parse(Core.Resources.Branches.Response_BranchMergeStatus)
+ });
+
+ var executor = new BranchesApiExecutor(mockClient.Object);
+ BranchMergeStatus response = await executor.MergeBranch(projectId, branchId, request);
+
+ Assert_BranchMergeStatus(response);
+ }
+
+ [Fact]
+ public async Task CheckBranchMergeStatus()
+ {
+ const int projectId = 1;
+ const int branchId = 2;
+ const string mergeId = "id";
+
+ Mock mockClient = TestUtils.CreateMockClientWithDefaultParser();
+
+ var url = $"/projects/{projectId}/branches/{branchId}/merges/{mergeId}";
+
+ mockClient
+ .Setup(client => client.SendGetRequest(url, null))
+ .ReturnsAsync(new CrowdinApiResult
+ {
+ StatusCode = HttpStatusCode.OK,
+ JsonObject = JObject.Parse(Core.Resources.Branches.Response_BranchMergeStatus)
+ });
+
+ var executor = new BranchesApiExecutor(mockClient.Object);
+ BranchMergeStatus response = await executor.CheckBranchMergeStatus(projectId, branchId, mergeId);
+
+ Assert_BranchMergeStatus(response);
+ }
+
+ [Fact]
+ public async Task GetBranchMergeSummary()
+ {
+ const int projectId = 1;
+ const int branchId = 2;
+ const string mergeId = "id";
+
+ Mock mockClient = TestUtils.CreateMockClientWithDefaultParser();
+
+ var url = $"/projects/{projectId}/branches/{branchId}/merges/{mergeId}/summary";
+
+ mockClient
+ .Setup(client => client.SendGetRequest(url, null))
+ .ReturnsAsync(new CrowdinApiResult
+ {
+ StatusCode = HttpStatusCode.OK,
+ JsonObject = JObject.Parse(Core.Resources.Branches.Response_BranchMergeSummary)
+ });
+
+ var executor = new BranchesApiExecutor(mockClient.Object);
+ BranchMergeSummary response = await executor.GetBranchMergeSummary(projectId, branchId, mergeId);
+
+ Assert_BranchMergeSummary(response);
+ }
+
+ private static void Assert_Branch(Branch? branch)
+ {
+ ArgumentNullException.ThrowIfNull(branch);
+
+ Assert.Equal(34, branch.Id);
+ Assert.Equal(2, branch.ProjectId);
+ Assert.Equal("develop-master", branch.Name);
+ Assert.Equal("Master branch", branch.Title);
+ Assert.Equal(DateTimeOffset.Parse("2019-09-16T13:48:04+00:00"), branch.CreatedAt);
+ Assert.Equal(DateTimeOffset.Parse("2019-09-19T13:25:27+00:00"), branch.UpdatedAt);
+ }
+
+ private static void Assert_BranchCloneStatus(BranchCloneStatus? status)
+ {
+ ArgumentNullException.ThrowIfNull(status);
+
+ Assert.Equal("50fb3506-4127-4ba8-8296-f97dc7e3e0c3", status.Identifier);
+ Assert.Equal(OperationStatus.Finished, status.Status);
+ Assert.Equal(100, status.Progress);
+ Assert.NotNull(status.Attributes);
+
+ DateTimeOffset date = DateTimeOffset.Parse("2019-09-23T11:26:54+00:00");
+ Assert.Equal(date, status.CreatedAt);
+ Assert.Equal(date, status.UpdatedAt);
+ Assert.Equal(date, status.StartedAt);
+ Assert.Equal(date, status.FinishedAt);
+ }
+
+ private static void Assert_BranchMergeStatus(BranchMergeStatus? status)
+ {
+ ArgumentNullException.ThrowIfNull(status);
+
+ Assert.Equal("50fb3506-4127-4ba8-8296-f97dc7e3e0c3", status.Identifier);
+ Assert.Equal(OperationStatus.Finished, status.Status);
+ Assert.Equal(100, status.Progress);
+
+ BranchMergeStatus.AttributesData? attributes = status.Attributes;
+ ArgumentNullException.ThrowIfNull(status.Attributes);
+ Assert.Equal(38, attributes.SourceBranchId);
+ Assert.False(attributes.DeleteAfterMerge);
+
+ DateTimeOffset date = DateTimeOffset.Parse("2019-09-23T11:26:54+00:00");
+ Assert.Equal(date, status.CreatedAt);
+ Assert.Equal(date, status.UpdatedAt);
+ Assert.Equal(date, status.StartedAt);
+ Assert.Equal(date, status.FinishedAt);
+ }
+
+ private static void Assert_BranchMergeSummary(BranchMergeSummary? summary)
+ {
+ ArgumentNullException.ThrowIfNull(summary);
+
+ Assert.Equal(BranchMergeStatusId.Merged, summary.Status);
+ Assert.Equal(100, summary.SourceBranchId);
+ Assert.Equal(100, summary.TargetBranchId);
+ Assert.False(summary.DryRun);
+
+ BranchMergeSummary.DetailsData? details = summary.Details;
+ ArgumentNullException.ThrowIfNull(details);
+ Assert.Equal(1, details.Added);
+ Assert.Equal(2, details.Deleted);
+ Assert.Equal(3, details.Updated);
+ Assert.Equal(7, details.Conflicted);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/Crowdin.Api.Tests/Core/Resources/Branches.Designer.cs b/tests/Crowdin.Api.Tests/Core/Resources/Branches.Designer.cs
new file mode 100644
index 00000000..405ee77c
--- /dev/null
+++ b/tests/Crowdin.Api.Tests/Core/Resources/Branches.Designer.cs
@@ -0,0 +1,102 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Crowdin.Api.Tests.Core.Resources {
+ using System;
+
+
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Branches {
+
+ private static System.Resources.ResourceManager resourceMan;
+
+ private static System.Globalization.CultureInfo resourceCulture;
+
+ [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Branches() {
+ }
+
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.Equals(null, resourceMan)) {
+ System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Crowdin.Api.Tests.Core.Resources.Branches", typeof(Branches).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ internal static string Response_Common_Multi {
+ get {
+ return ResourceManager.GetString("Response_Common_Multi", resourceCulture);
+ }
+ }
+
+ internal static string Request_AddBranch {
+ get {
+ return ResourceManager.GetString("Request_AddBranch", resourceCulture);
+ }
+ }
+
+ internal static string Response_Common_Single {
+ get {
+ return ResourceManager.GetString("Response_Common_Single", resourceCulture);
+ }
+ }
+
+ internal static string Request_EditBranch {
+ get {
+ return ResourceManager.GetString("Request_EditBranch", resourceCulture);
+ }
+ }
+
+ internal static string Request_CloneBranch {
+ get {
+ return ResourceManager.GetString("Request_CloneBranch", resourceCulture);
+ }
+ }
+
+ internal static string Response_BranchCloneStatus {
+ get {
+ return ResourceManager.GetString("Response_BranchCloneStatus", resourceCulture);
+ }
+ }
+
+ internal static string Request_MergeBranch {
+ get {
+ return ResourceManager.GetString("Request_MergeBranch", resourceCulture);
+ }
+ }
+
+ internal static string Response_BranchMergeStatus {
+ get {
+ return ResourceManager.GetString("Response_BranchMergeStatus", resourceCulture);
+ }
+ }
+
+ internal static string Response_BranchMergeSummary {
+ get {
+ return ResourceManager.GetString("Response_BranchMergeSummary", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/tests/Crowdin.Api.Tests/Core/Resources/Branches.resx b/tests/Crowdin.Api.Tests/Core/Resources/Branches.resx
new file mode 100644
index 00000000..15b9a8d4
--- /dev/null
+++ b/tests/Crowdin.Api.Tests/Core/Resources/Branches.resx
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 1.3
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ {
+ "data": [
+ {
+ "data": {
+ "id": 34,
+ "projectId": 2,
+ "name": "develop-master",
+ "title": "Master branch",
+ "createdAt": "2019-09-16T13:48:04+00:00",
+ "updatedAt": "2019-09-19T13:25:27+00:00"
+ }
+ }
+ ],
+ "pagination": {
+ "offset": 0,
+ "limit": 25
+ }
+}
+
+
+ {
+ "name": "develop-master",
+ "title": "Master branch"
+}
+
+
+ {
+ "data": {
+ "id": 34,
+ "projectId": 2,
+ "name": "develop-master",
+ "title": "Master branch",
+ "createdAt": "2019-09-16T13:48:04+00:00",
+ "updatedAt": "2019-09-19T13:25:27+00:00"
+ }
+}
+
+
+ [
+ {
+ "path": "/name",
+ "op": "replace",
+ "value": "develop-master"
+ },
+ {
+ "path": "/title",
+ "op": "replace",
+ "value": "Master branch"
+ }
+]
+
+
+ {
+ "name": "develop-master",
+ "title": "Master branch"
+}
+
+
+ {
+ "data": {
+ "identifier": "50fb3506-4127-4ba8-8296-f97dc7e3e0c3",
+ "status": "finished",
+ "progress": 100,
+ "attributes": {},
+ "createdAt": "2019-09-23T11:26:54+00:00",
+ "updatedAt": "2019-09-23T11:26:54+00:00",
+ "startedAt": "2019-09-23T11:26:54+00:00",
+ "finishedAt": "2019-09-23T11:26:54+00:00"
+ }
+}
+
+
+ {
+ "deleteAfterMerge": true,
+ "sourceBranchId": 8,
+ "dryRun": true
+}
+
+
+ {
+ "data": {
+ "identifier": "50fb3506-4127-4ba8-8296-f97dc7e3e0c3",
+ "status": "finished",
+ "progress": 100,
+ "attributes": {
+ "sourceBranchId": 38,
+ "deleteAfterMerge": false
+ },
+ "createdAt": "2019-09-23T11:26:54+00:00",
+ "updatedAt": "2019-09-23T11:26:54+00:00",
+ "startedAt": "2019-09-23T11:26:54+00:00",
+ "finishedAt": "2019-09-23T11:26:54+00:00"
+ }
+}
+
+
+ {
+ "data": {
+ "status": "merged",
+ "sourceBranchId": 100,
+ "targetBranchId": 100,
+ "dryRun": false,
+ "details": {
+ "added": 1,
+ "deleted": 2,
+ "updated": 3,
+ "conflicted": 7
+ }
+ }
+}
+
+
\ No newline at end of file
diff --git a/tests/Crowdin.Api.Tests/Core/Resources/SourceStrings.Designer.cs b/tests/Crowdin.Api.Tests/Core/Resources/SourceStrings.Designer.cs
index 13668b95..0618a243 100644
--- a/tests/Crowdin.Api.Tests/Core/Resources/SourceStrings.Designer.cs
+++ b/tests/Crowdin.Api.Tests/Core/Resources/SourceStrings.Designer.cs
@@ -87,6 +87,36 @@ internal static string CommonResponses_SingleStringInArray {
}
}
+ ///
+ /// Looks up a localized string similar to {
+ /// "data": {
+ /// "identifier": "50fb3506-4127-4ba8-8296-f97dc7e3e0c3",
+ /// "status": "finished",
+ /// "progress": 100,
+ /// "attributes": {
+ /// "branchId": 38,
+ /// "storageId": 38,
+ /// "fileType": "android",
+ /// "parserVersion": 8,
+ /// "labelIds": [
+ /// 1,
+ /// 2
+ /// ],
+ /// "importOptions": {
+ /// "firstLineContainsHeader": false,
+ /// "importTranslations": true,
+ /// "scheme": {
+ /// "identifier": 0,
+ /// "sourcePhrase": 1,
+ /// "en": 2,
+ /// [rest of string was truncated]";.
+ ///
+ internal static string CommonResponses_UploadStrings {
+ get {
+ return ResourceManager.GetString("CommonResponses_UploadStrings", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to [
/// {
@@ -178,5 +208,34 @@ internal static string StringBatchOperations_Response_NoPagination {
return ResourceManager.GetString("StringBatchOperations_Response_NoPagination", resourceCulture);
}
}
+
+ ///
+ /// Looks up a localized string similar to {
+ /// "storageId": 61,
+ /// "branchId": 34,
+ /// "type": "xliff",
+ /// "parserVersion": 1,
+ /// "labelIds": [
+ /// 1, 2, 3
+ /// ],
+ /// "updateStrings": true,
+ /// "cleanupMode": true,
+ /// "importOptions": {
+ /// "firstLineContainsHeader": false,
+ /// "importTranslations": true,
+ /// "scheme": {
+ /// "identifier": 0,
+ /// "sourcePhrase": 1,
+ /// "en": 2,
+ /// "de": 3
+ /// }
+ /// }
+ ///}.
+ ///
+ internal static string UploadStrings_Request {
+ get {
+ return ResourceManager.GetString("UploadStrings_Request", resourceCulture);
+ }
+ }
}
}
diff --git a/tests/Crowdin.Api.Tests/Core/Resources/SourceStrings.resx b/tests/Crowdin.Api.Tests/Core/Resources/SourceStrings.resx
index 91f7cc7d..593b0880 100644
--- a/tests/Crowdin.Api.Tests/Core/Resources/SourceStrings.resx
+++ b/tests/Crowdin.Api.Tests/Core/Resources/SourceStrings.resx
@@ -149,6 +149,64 @@
}
}
]
+}
+
+
+ {
+ "data": {
+ "identifier": "50fb3506-4127-4ba8-8296-f97dc7e3e0c3",
+ "status": "finished",
+ "progress": 100,
+ "attributes": {
+ "branchId": 38,
+ "storageId": 38,
+ "fileType": "android",
+ "parserVersion": 8,
+ "labelIds": [
+ 1,
+ 2
+ ],
+ "importOptions": {
+ "firstLineContainsHeader": false,
+ "importTranslations": true,
+ "scheme": {
+ "identifier": 0,
+ "sourcePhrase": 1,
+ "en": 2,
+ "de": 3
+ }
+ },
+ "updateStrings": false,
+ "cleanupMode": false
+ },
+ "createdAt": "2019-09-23T11:26:54+00:00",
+ "updatedAt": "2019-09-23T11:26:54+00:00",
+ "startedAt": "2019-09-23T11:26:54+00:00",
+ "finishedAt": "2019-09-23T11:26:54+00:00"
+ }
+}
+
+
+ {
+ "storageId": 61,
+ "branchId": 34,
+ "type": "xliff",
+ "parserVersion": 1,
+ "labelIds": [
+ 1, 2, 3
+ ],
+ "updateStrings": true,
+ "cleanupMode": true,
+ "importOptions": {
+ "firstLineContainsHeader": false,
+ "importTranslations": true,
+ "scheme": {
+ "identifier": 0,
+ "sourcePhrase": 1,
+ "en": 2,
+ "de": 3
+ }
+ }
}
\ No newline at end of file
diff --git a/tests/Crowdin.Api.Tests/Core/Resources/Tasks.Designer.cs b/tests/Crowdin.Api.Tests/Core/Resources/Tasks.Designer.cs
index 8db497e4..c56b05ea 100644
--- a/tests/Crowdin.Api.Tests/Core/Resources/Tasks.Designer.cs
+++ b/tests/Crowdin.Api.Tests/Core/Resources/Tasks.Designer.cs
@@ -90,13 +90,14 @@ internal static string AddTask_RightRequestJson_VendorGengo_ToneOther {
/// Looks up a localized string similar to {
/// "title": "My task",
/// "languageId": "es",
- /// "fileIds": [
- /// 1,2,3
- /// ],
/// "type": 2,
/// "vendor": "lingo24",
/// "status": "in_progress",
/// "description": "My amazing task",
+ ///
+ /// "fileIds": [
+ /// 1,2,3
+ /// ],
/// "skipAssignedStrings": true,
/// "skipUntranslatedStrings": true,
/// "labelIds": [
diff --git a/tests/Crowdin.Api.Tests/Core/Resources/Tasks.resx b/tests/Crowdin.Api.Tests/Core/Resources/Tasks.resx
index 125217ea..d0c13d47 100644
--- a/tests/Crowdin.Api.Tests/Core/Resources/Tasks.resx
+++ b/tests/Crowdin.Api.Tests/Core/Resources/Tasks.resx
@@ -31,13 +31,14 @@
{
"title": "My task",
"languageId": "es",
- "fileIds": [
- 1,2,3
- ],
"type": 2,
"vendor": "lingo24",
"status": "in_progress",
"description": "My amazing task",
+
+ "fileIds": [
+ 1,2,3
+ ],
"skipAssignedStrings": true,
"skipUntranslatedStrings": true,
"labelIds": [
diff --git a/tests/Crowdin.Api.Tests/Crowdin.Api.Tests.csproj b/tests/Crowdin.Api.Tests/Crowdin.Api.Tests.csproj
index 7c94659b..15459904 100644
--- a/tests/Crowdin.Api.Tests/Crowdin.Api.Tests.csproj
+++ b/tests/Crowdin.Api.Tests/Crowdin.Api.Tests.csproj
@@ -198,6 +198,26 @@
ResXFileCodeGenerator
AI_Misc.Designer.cs
+
+ ResXFileCodeGenerator
+ Branches.Designer.cs
+
+
+ ResXFileCodeGenerator
+ Branches.Designer.cs
+
+
+ ResXFileCodeGenerator
+ AI.Designer.cs
+
+
+ ResXFileCodeGenerator
+ AI_Providers.Designer.cs
+
+
+ ResXFileCodeGenerator
+ AI_Misc.Designer.cs
+
@@ -391,6 +411,11 @@
True
Fields.resx
+
+ True
+ True
+ Branches.resx
+
True
True
@@ -406,6 +431,26 @@
True
AI_Misc.resx
+
+ True
+ True
+ AI_Prompts.resx
+
+
+ True
+ True
+ AI_Providers.resx
+
+
+ True
+ True
+ AI_Misc.resx
+
+
+ True
+ True
+ Branches.resx
+
diff --git a/tests/Crowdin.Api.Tests/SourceStrings/SourceStringsApiTests.cs b/tests/Crowdin.Api.Tests/SourceStrings/SourceStringsApiTests.cs
index 3fae33a3..f1edb307 100644
--- a/tests/Crowdin.Api.Tests/SourceStrings/SourceStringsApiTests.cs
+++ b/tests/Crowdin.Api.Tests/SourceStrings/SourceStringsApiTests.cs
@@ -1,12 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Threading.Tasks;
+
+using Moq;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Xunit;
+
+using Crowdin.Api.Core;
+using Crowdin.Api.SourceFiles;
using Crowdin.Api.SourceStrings;
using Crowdin.Api.Tests.Core;
-using Xunit;
namespace Crowdin.Api.Tests.SourceStrings
{
public class SourceStringsApiTests
{
+ private static readonly JsonSerializerSettings DefaultSettings = TestUtils.CreateJsonSerializerOptions();
+
[Fact]
public void ListStrings_QueryStringConstruction()
{
@@ -17,7 +30,121 @@ public void ListStrings_QueryStringConstruction()
Scope = StringScope.Context
};
- Assert.Equal(expectedQueryString, @params.ToQueryParams().ToQueryString());
+ Assert.Equal(expectedQueryString, TestUtils.ToQueryString(@params.ToQueryParams()));
+ }
+
+ [Fact]
+ public async Task UploadStringsStatus()
+ {
+ const int projectId = 1;
+ const string uploadId = "50fb3506-4127-4ba8-8296-f97dc7e3e0c3";
+
+ Mock mockClient = TestUtils.CreateMockClientWithDefaultParser();
+
+ var url = $"/projects/{projectId}/strings/uploads/{uploadId}";
+
+ mockClient
+ .Setup(client => client.SendGetRequest(url, null))
+ .ReturnsAsync(new CrowdinApiResult
+ {
+ StatusCode = HttpStatusCode.OK,
+ JsonObject = JObject.Parse(Core.Resources.SourceStrings.CommonResponses_UploadStrings)
+ });
+
+ var executor = new SourceStringsApiExecutor(mockClient.Object);
+ StringUploadResponseModel response = await executor.UploadStringsStatus(projectId, uploadId);
+
+ Assert_StringUploadResponseModel(response);
+ }
+
+ [Fact]
+ public async Task UploadStrings()
+ {
+ const int projectId = 1;
+
+ var request = new UploadStringsRequest
+ {
+ StorageId = 61,
+ BranchId = 34,
+ Type = StringBasedProjectFileType.Xliff,
+ ParserVersion = 1,
+ LabelIds = new[] { 1, 2, 3 },
+ UpdateStrings = true,
+ CleanupMode = true,
+ ImportOptions = new SpreadsheetFileImportOptions
+ {
+ FirstLineContainsHeader = false,
+ ImportTranslations = true,
+ Scheme = new Dictionary
+ {
+ [ColumnType.Identifier] = 0,
+ [ColumnType.SourcePhrase] = 1,
+ ["en"] = 2,
+ ["de"] = 3
+ }
+ }
+ };
+
+ string actualRequestJson = JsonConvert.SerializeObject(request, DefaultSettings);
+ string expectedRequestJson = TestUtils.CompactJson(Core.Resources.SourceStrings.UploadStrings_Request);
+ Assert.Equal(expectedRequestJson, actualRequestJson);
+
+ Mock mockClient = TestUtils.CreateMockClientWithDefaultParser();
+
+ var url = $"/projects/{projectId}/strings/upload";
+
+ mockClient
+ .Setup(client => client.SendPostRequest(url, request, null))
+ .ReturnsAsync(new CrowdinApiResult
+ {
+ StatusCode = HttpStatusCode.OK,
+ JsonObject = JObject.Parse(Core.Resources.SourceStrings.CommonResponses_UploadStrings)
+ });
+
+ var executor = new SourceStringsApiExecutor(mockClient.Object);
+ StringUploadResponseModel response = await executor.UploadStrings(projectId, request);
+
+ Assert_StringUploadResponseModel(response);
+ }
+
+ private static void Assert_StringUploadResponseModel(StringUploadResponseModel? response)
+ {
+ Assert.NotNull(response);
+ ArgumentNullException.ThrowIfNull(response);
+
+ Assert.Equal("50fb3506-4127-4ba8-8296-f97dc7e3e0c3", response.Identifier);
+ Assert.Equal(OperationStatus.Finished, response.Status);
+ Assert.Equal(100, response.Progress);
+
+ DateTimeOffset date = DateTimeOffset.Parse("2019-09-23T11:26:54+00:00");
+ Assert.Equal(date, response.CreatedAt);
+ Assert.Equal(date, response.UpdatedAt);
+ Assert.Equal(date, response.StartedAt);
+ Assert.Equal(date, response.FinishedAt);
+
+ StringUploadResponseModel.AttributesData? attributes = response.Attributes;
+ Assert.NotNull(attributes);
+
+ Assert.Equal(38, attributes.BranchId);
+ Assert.Equal(38, attributes.StorageId);
+ Assert.Equal("android", attributes.FileType);
+ Assert.Equal(8, attributes.ParserVersion);
+ Assert.Equal(new[] { 1, 2 }, attributes.LabelIds);
+ Assert.False(attributes.UpdateStrings);
+ Assert.False(attributes.CleanupMode);
+
+ SpreadsheetFileImportOptions? importOptions = attributes.ImportOptions;
+ Assert.NotNull(importOptions);
+
+ Assert.False(importOptions.FirstLineContainsHeader);
+ Assert.True(importOptions.ImportTranslations);
+ Assert.Equal(new Dictionary
+ {
+ [ColumnType.Identifier] = 0,
+ [ColumnType.SourcePhrase] = 1,
+ ["en"] = 2,
+ ["de"] = 3
+ }, importOptions.Scheme);
}
}
}
\ No newline at end of file