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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/Crowdin.Api/SourceStrings/ISourceStringsApiExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,25 @@ Task<ResponseList<SourceString>> StringBatchOperations(
long projectId,
IEnumerable<StringBatchOpPatch> patches);

Task<ResponseList<SourceString>> StringBatchOperations(
long projectId,
IEnumerable<StringBatchOpPatch> patches,
UpdateOption? updateOption);

Task<SourceString> GetString(long projectId, long stringId, bool denormalizePlaceholders = false);

Task DeleteString(long projectId, long stringId);

Task<SourceString> EditString(long projectId, long stringId, IEnumerable<SourceStringPatch> patches);

Task<SourceString> EditString(
long projectId,
long stringId,
IEnumerable<SourceStringPatch> patches,
UpdateOption? updateOption);

Task<StringUploadResponseModel> UploadStringsStatus(long projectId, string uploadId);

Task<StringUploadResponseModel> UploadStrings(long projectId, UploadStringsRequest request);
}
}
}
53 changes: 48 additions & 5 deletions src/Crowdin.Api/SourceStrings/SourceStringsApiExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,33 @@ public async Task<SourceString> AddString(long projectId, AddStringRequest reque
/// <a href="https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.strings.batchPatch">Crowdin Enterprise API</a>
/// </summary>
[PublicAPI]
public async Task<ResponseList<SourceString>> StringBatchOperations(
public Task<ResponseList<SourceString>> StringBatchOperations(
long projectId,
IEnumerable<StringBatchOpPatch> patches)
{
return StringBatchOperations(projectId, patches, null);
}

/// <summary>
/// String Batch Operations. Documentation:
/// <a href="https://developer.crowdin.com/api/v2/#operation/api.projects.strings.batchPatch">Crowdin API</a>
/// <a href="https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.strings.batchPatch">Crowdin Enterprise API</a>
/// </summary>
[PublicAPI]
public async Task<ResponseList<SourceString>> StringBatchOperations(
long projectId,
IEnumerable<StringBatchOpPatch> patches,
UpdateOption? updateOption)
{
string url = FormUrl_Strings(projectId);
CrowdinApiResult result = await _apiClient.SendPatchRequest(url, patches);
IDictionary<string, string>? queryParams = null;
if (updateOption.HasValue)
{
queryParams = new Dictionary<string, string>();
queryParams.AddDescriptionEnumValueIfPresent("updateOption", updateOption);
}

CrowdinApiResult result = await _apiClient.SendPatchRequest(url, patches, queryParams);
return _jsonParser.ParseResponseList<SourceString>(result.JsonObject);
}

Expand Down Expand Up @@ -164,10 +185,32 @@ public async Task DeleteString(long projectId, long stringId)
/// <a href="https://support.crowdin.com/enterprise/api/#operation/api.projects.strings.patch">Crowdin Enterprise API</a>
/// </summary>
[PublicAPI]
public async Task<SourceString> EditString(long projectId, long stringId, IEnumerable<SourceStringPatch> patches)
public Task<SourceString> EditString(long projectId, long stringId, IEnumerable<SourceStringPatch> patches)
{
return EditString(projectId, stringId, patches, null);
}

/// <summary>
/// Edit string. Documentation:
/// <a href="https://support.crowdin.com/api/v2/#operation/api.projects.strings.patch">Crowdin API</a>
/// <a href="https://support.crowdin.com/enterprise/api/#operation/api.projects.strings.patch">Crowdin Enterprise API</a>
/// </summary>
[PublicAPI]
public async Task<SourceString> EditString(
long projectId,
long stringId,
IEnumerable<SourceStringPatch> patches,
UpdateOption? updateOption)
{
string url = FormUrl_StringId(projectId, stringId);
CrowdinApiResult result = await _apiClient.SendPatchRequest(url, patches);
IDictionary<string, string>? queryParams = null;
if (updateOption.HasValue)
{
queryParams = new Dictionary<string, string>();
queryParams.AddDescriptionEnumValueIfPresent("updateOption", updateOption);
}

CrowdinApiResult result = await _apiClient.SendPatchRequest(url, patches, queryParams);
return _jsonParser.ParseResponseObject<SourceString>(result.JsonObject);
}

Expand Down Expand Up @@ -221,4 +264,4 @@ private static string FormUrl_StringsUploadId(long projectId, string uploadId)

#endregion
}
}
}
12 changes: 12 additions & 0 deletions tests/Crowdin.Api.UnitTesting/Resources/SourceStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 35 additions & 1 deletion tests/Crowdin.Api.UnitTesting/Resources/SourceStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,40 @@
}
},
"updateOption": "keep_translations_and_approvals"
}</value>
</data>
<data name="EditString_Request" xml:space="preserve">
<value>[
{
"path": "/text",
"op": "replace",
"value": "Updated string"
}
]</value>
</data>
<data name="EditString_Response" xml:space="preserve">
<value>{
"data": {
"id": 2814,
"projectId": 2,
"branchId": 12,
"identifier": "name",
"text": "Updated string",
"type": "text",
"context": "shown on main page",
"maxLength": 35,
"isHidden": false,
"isDuplicate": true,
"masterStringId": 1,
"revision": 1,
"hasPlurals": false,
"isIcu": false,
"labelIds": [
3
],
"createdAt": "2019-09-20T12:43:57+00:00",
"updatedAt": "2019-09-20T13:24:01+00:00"
}
}</value>
</data>
<data name="ListStrings_i18Next_bug" xml:space="preserve">
Expand Down Expand Up @@ -282,4 +316,4 @@
}
}</value>
</data>
</root>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,50 @@ public async Task UploadStrings()
Assert_StringUploadResponseModel(response);
}

[Fact]
public async Task EditString_WithUpdateOption()
{
const int projectId = 1;
const int stringId = 2814;

var patches = new[]
{
new SourceStringPatch
{
Operation = PatchOperation.Replace,
Path = StringPatchPath.Text,
Value = "Updated string"
}
};

string actualRequestJson = JsonConvert.SerializeObject(patches, DefaultSettings);
string expectedRequestJson = TestUtils.CompactJson(Resources.SourceStrings.EditString_Request);
Assert.Equal(expectedRequestJson, actualRequestJson);

Mock<ICrowdinApiClient> mockClient = TestUtils.CreateMockClientWithDefaultParser();

var url = $"/projects/{projectId}/strings/{stringId}";
IDictionary<string, string> queryParams = new Dictionary<string, string>
{
{ "updateOption", "keep_translations" }
};

mockClient
.Setup(client => client.SendPatchRequest(url, patches, queryParams))
.ReturnsAsync(new CrowdinApiResult
{
StatusCode = HttpStatusCode.OK,
JsonObject = JObject.Parse(Resources.SourceStrings.EditString_Response)
});

var executor = new SourceStringsApiExecutor(mockClient.Object);
SourceString response = await executor.EditString(
projectId, stringId, patches, UpdateOption.KeepTranslations);

Assert.Equal(stringId, response.Id);
Assert.Equal("Updated string", response.Text);
}

private static void Assert_StringUploadResponseModel(StringUploadResponseModel? response)
{
Assert.NotNull(response);
Expand Down Expand Up @@ -211,4 +255,4 @@ private static void Assert_StringUploadResponseModel(StringUploadResponseModel?
}, importOptions.Scheme);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
Expand Down Expand Up @@ -81,17 +82,22 @@ public async Task StringBatchOperations()
Mock<ICrowdinApiClient> mockClient = TestUtils.CreateMockClientWithDefaultParser();

var url = $"/projects/{projectId}/strings";
IDictionary<string, string> queryParams = new Dictionary<string, string>
{
{ "updateOption", "clear_translations_and_approvals" }
};

mockClient
.Setup(client => client.SendPatchRequest(url, patches, null))
.Setup(client => client.SendPatchRequest(url, patches, queryParams))
.ReturnsAsync(new CrowdinApiResult
{
StatusCode = HttpStatusCode.OK,
JsonObject = JObject.Parse(Resources.SourceStrings.CommonResponses_SingleStringInArray)
});

var executor = new SourceStringsApiExecutor(mockClient.Object);
ResponseList<SourceString> response = await executor.StringBatchOperations(projectId, patches);
ResponseList<SourceString> response = await executor.StringBatchOperations(
projectId, patches, UpdateOption.ClearTranslationsAndApprovals);

Assert.NotNull(response);
Assert_SourceString(response.Data?.Single());
Expand Down Expand Up @@ -148,4 +154,4 @@ private static void Assert_SourceString(SourceString? sourceString)
Assert.False(sourceString.IsIcu);
}
}
}
}
Loading